2 主成分分析
2.1 Example Dataset
先从一个二维数据集开始,将其压缩为一维。
PCA就是一种降维算法,将n维的特征映射到k维上,这k维是全新的正交特征也被称为主成分,是在原有n维特征的基础上重新构造出来的k维特征。
步骤:①数据预处理(均值归一化/特征缩放);②计算协方差矩阵;③取U矩阵(特征向量矩阵)种前k个向量得到一个n*k维的矩阵,用他的转置乘以数据x就可以得到降维后的数据z =
先导入数据并且可视化数据:
import numpy as np
import matplotlib.pyplot as plt
import scipy.io as sio
data = sio.loadmat('ex7data1.mat')
print(data.keys())
X = data['X']
print(X.shape) # (50, 2)
# 可视化
plt.scatter(X[:,0],X[:,1])
plt.show()
2.2 Implementing PCA用PCA开始压缩
数据归一化:
# 对数据x归一化
def meanx(X):
mean = X.mean(axis=0) # 求每列的均值
sigma = X.std(axis=0, ddof=1) # 求方差
X = (X-mean)/sigma
return X, mean, sigma
Mean_x,mean,sigma = meanx(X)
plt.scatter(Mean_x[:,0],Mean_x[:,1])
plt.show()
计算协方差和特征向量:
# 计算协方差和特征向量U
def pca(X):
m = len(X)
Sigma = (X.T @ X)/m
U,S,V = np.linalg.svd(Sigma) # SVD奇异值分解计算特征向量U
return U,S
U, S = pca(Mean_x)
# 画出最后的特征向量
plt.figure(figsize=(6,6))
plt.scatter(X[:,0],X[:,1],marker='o',facecolors = 'orange', edgecolors='blue')
plt.plot([mean[0],mean[0]+1.5*S[0]*U[0,0]],[mean[1],mean[1]+1.5*S[0]*U[1,0]],'k')# 两个点之间的连线
plt.plot([mean[0],mean[0]+1.5*S[1]*U[0,1]],[mean[1],mean[1]+1.5*S[1]*U[1,1]],'k')# 1.5和S表示特征向量的长度
plt.title('Computed eigenbectors of the dataset')
plt.show()
2.3 用PCA实现降维
将归一化后的数据投影到特征向量上
# 降维,将归一化候得数据投影到特征向量上
def X_reduction(x, U, K):
U_reduce = U[:, 0:K] # 选择特征向量矩阵的前K列
return X@U_reduce
# 降维后的数据
z = X_reduction(Mean_x, U, 1) # 让K=1
print(z.shape) # (50, 1)
此时降维后的数据变成了一维
PCA可以降维,也可以恢复数据维度
#重现数据
def restoreData(z, U, K):
U_reduce = U[:, 0:K]
return z@U_reduce.T
#重建后的数据如下
Restore_x = restoreData(z, U, 1)
可视化归一化后的数据和重现数据:
#可视化投影,并且画出归一化数据和降维后又重现的数据对应点用虚线链接
plt.scatter(Mean_x[:,0],Mean_x[:,1], marker = 'o',facecolors = 'orange',edgecolors='blue')
plt.scatter(Restore_x[:,0],Restore_x[:,1],marker='o',facecolor='blue',edgecolors='red')
for i in range(len(X)):
plt.plot([Mean_x[i,0],Restore_x[i,0]],[Mean_x[i,1],Restore_x[i,1]],'k--')
plt.title('The normalized and projuected data after PCA')
plt.show()
计算一下降维后的数据保留了原始数据多少差异性:86.78%
#计算保留差异性
def retained_variance(S, K):
rv = np.sum(S[:K])/np.sum(S)
return print('{:.2f}%'.format(rv*100))
retained_variance(S, 1) # 86.78%
2.4 用PCA进行图像降维压缩
先导入图像然后可视化其中100张图,此时的图片很清晰。
# 导入图像数据
facedata = sio.loadmat('ex7faces.mat')
print(facedata.keys())
A = facedata['X']
print(A.shape) # (5000, 1024)
# 打印100个图像
def plot_100_images(A):
fig,axs = plt.subplots(ncols=10,nrows=10,figsize = (10,10)) # 定义n*n的画布
for c in range(10):
for r in range(10):
axs[c,r].imshow(A[10*c+r].reshape(32,32).T,cmap = 'Greys_r') #显示单通道的灰图
axs[c,r].set_xticks([])
axs[c,r].set_yticks([])
plt.show()
plot_100_images(A)
对图片集开始降为还是调用之前的方法,降维后的图片变得模糊。
# 对A降维
A_reduction = meanA@U1
print(A_reduction.shape) # (5000, 36)
A_recover = A_reduction @ U1.T + np.mean(A, axis=0)
plot_100_images(A_recover),plot_100_images(A)