X_mean=np.mean(X,axis=0)
X_norm=X-X_mean
X_cov=np.cov(X_norm,rowvar=False)
print(X_cov.shape)
eigvalues, eigvectors =np.linalg.eig(X_cov)
max_eigvalue_index = np.argsort(-eigvalues)[:K]
W = eigvectors[:,max_eigvalue_index]
X_new = np.dot(X_norm, W)
X_rec = np.dot(X_new,W.T) + X_mean
return W, X_mean,X_new,X_rec
return X_rec
pca对一张图片降维,X_mean=np.mean(X,axis=0),这里为什么要对X每一列求均值,不应该是把每一个像素作为一个特征吗,但这句语句是把每一列当成一个特征了吗?
PCA 图片降维,可以有多种理解。例如:
(1)多张(m张) 图片,降维至 p(p<m) 张图片来表达,这在天文、遥感等多光谱图片中非常常见;
(2)一张图片,多通道,常见通道数为 3,降维,或将主要方差集中到第 0 维。
(3)一张图片,二维对象的方向校正,通过主成分分析(PCA)获得目标的主方向,将数据投影到主方向及其垂直方向上。
所以,你先要搞清楚你写的这两行程序,是针对哪种情况用的。
在PCA对一张图片进行降维时,要对X中的每一列进行均值中心化操作,是因为PCA是通过数据的协方差矩阵进行降维的,如果数据没有经过中心化处理,就会存在方差过大或过小的问题,导致降维结果不准确。因此,我们需要对每一列进行均值中心化操作,即对每个像素进行处理,让所有像素都在均值为0的基础上进行降维操作。
PCA降维的其他步骤包括:
1.计算协方差矩阵 使用numpy中的cov函数,该函数默认将每一行看作一个变量,每一列看作一个样本,返回的协方差矩阵的每个值都是两个变量之间的协方差。
2.计算协方差矩阵的特征值和特征向量 使用numpy中的linalg.eig函数,该函数可以计算矩阵的特征值和特征向量,特征向量表示数据在该特征空间下的投影方向。
3.选取特征值最大的前k个特征向量 特征值越大表示该特征对应的方差越大,即该特征包含的信息越多。因此,我们选择前k个特征值对应的特征向量作为新的特征空间。
4.将数据投影到新的特征空间上 使用新的特征向量将原始数据进行投影,即将每个样本表示为由k个特征值组成的向量,在新的特征空间中进行降维。
5.还原数据 将降维后的数据通过特征向量的逆矩阵乘以降维后的数据,还原数据到原始的空间中。
下面是一个简单的Python示例代码:
import numpy as np
import matplotlib.pyplot as plt
def center(X):
# 对每一列进行均值中心化操作
mean = np.mean(X, axis=0)
return X - mean
def PCA(X, k):
# 计算协方差矩阵
cov = np.cov(center(X).T)
# 计算协方差矩阵的特征值和特征向量
eigvals, eigvecs = np.linalg.eig(cov)
# 将特征向量按照特征值从大到小排序
idx = np.argsort(eigvals)[::-1][:k]
# 选取前k个特征向量,并将其组成特征矩阵
eigvecs = eigvecs[:, idx]
# 将数据投影到新的特征空间上
new_X = np.dot(center(X), eigvecs)
# 还原数据
X_reconstructed = np.dot(new_X, eigvecs.T) + np.mean(X, axis=0)
return new_X, X_reconstructed
# 加载图片数据
img = plt.imread('test.jpg')
# 将图片展平
X = img.reshape(-1, 3)
# 进行PCA降维,选取前2个主成分
new_X, X_reconstructed = PCA(X, 2)
# 显示降维后的图片
plt.subplot(121)
plt.imshow(X_reconstructed.reshape(img.shape))
# 显示降维后的数据分布
plt.subplot(122)
plt.scatter(new_X[:, 0], new_X[:, 1])
plt.show()
其中,'test.jpg'为待降维的图片路径,运行结果为降维后的图像和降维后的数据分布。