主成分分析是最为简单粗暴的一种数据降维方式,顾名思义就是找到数据中最为主要的方面,用这些方面来替代原始数据。具体来说,假设我们有一个具有n维特征的数据集,共有m
个样本点,我们希望将这m
个样本的特征维度从n
维降到b
维,希望b
维数据尽可能的替代原始数据集。
其中最为重要的因素就是如何保证减少维度后数据损失尽可能的小
如下图所示,我们试图将二维数据降到一维,图中列出两个维度PC1和PC2,显然PC1维度可以更加好的代表原始数据,因为把数据投影到PC1后,它们之间的方差最大,即PC1这个方向上包含了更多的信息量。这个PC1就是第一主成分,与PC1正交的PC2包含较少的信息量,为第二主成分,如果第一主成分包含的信息量足够大,那么光用第一主成分就可以很好的表示原始数据。
以此类推,PCA算法就是希望找到原始数据中最重要的维度,然后把原始数据投影到这些维度上,即把高维数据映射到低维度空间表示,由于映射后新生成的样本点之间方差最大,样本间的差异也最大限度的保存下来。
k
个特征值,即前k
个主成分对应的特征向量。具体k
如何选择,需要计算前k
个特征值的累计贡献率来决定k
个特征向量组成的低维度空间,转化为新样本。通过原始数据乘以这k
个特征向量即可得到sklearn.decomposition.PCA(n_components=None, copy=True, whiten=False)
参数说明:
n_components:
意义:PCA算法中所要保留的主成分个数n,也即保留下来的特征个数n
类型:int 或者 string,缺省时默认为None,所有成分被保留。
赋值为int,比如n_components=1,将把原始数据降到一个维度。
赋值为string,比如n_components='mle',将自动选取特征个数n,使得满足所要求的方差百分比。
copy:
类型:bool,True或者False,缺省时默认为True。
意义:表示是否在运行算法时,将原始训练数据复制一份。
若为True,则运行PCA算法后,原始训练数据的值不会有任何改变,因为是在原始数据的副本上进行运算;
若为False,则运行PCA算法后,原始训练数据的值会改,因为是在原始数据上进行降维计算。
whiten:
类型:bool,缺省时默认为False
意义:白化,使得每个特征具有相同的方差。
2、PCA对象的属性
components_ :返回具有最大方差的成分。
explained_variance_ratio_:返回 所保留的n个成分各自的方差百分比。
n_components_:返回所保留的成分个数n。
mean_:
noise_variance_:
3、PCA对象的方法
fit(X,y=None)
fit()可以说是scikit-learn中通用的方法,每个需要训练的算法都会有fit()方法,它其实就是算法中的“训练”这一步骤。因为PCA是无监督学习算法,此处y自然等于None。
fit(X),表示用数据X来训练PCA模型。
函数返回值:调用fit方法的对象本身。比如pca.fit(X),表示用X对pca这个对象进行训练。
fit_transform(X)
用X来训练PCA模型,同时返回降维后的数据。
newX=pca.fit_transform(X),newX就是降维后的数据。
inverse_transform()
将降维后的数据转换成原始数据,X=pca.inverse_transform(newX)
transform(X)
将数据X转换成降维后的数据。当模型训练好后,对于新输入的数据,都可以用transform方法来降维。
此外,还有get_covariance()、get_precision()、get_params(deep=True)、score(X, y=None)等方法,以后用到再补充吧。
采用的数据集是MNIST手写数据集,选择划分后的训练集样本作为数据集,共有60000个手写数据,每个样本的形状为(28,28)。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
import tensorflow as tf
# 导入数据集
data = tf.keras.datasets.mnist
(x_train, y_train), (_,_) = data.load_data()
x_trainnew = x_train.reshape(60000, 784)
pca = PCA()
pca.fit(x_trainnew)
# 显示数据集的64个数据
plt.figure()
fig, ax = plt.subplots(8, 8, figsize=(6, 6), dpi=600) # ax是一个(8,8)的数组
for i, axi in enumerate(ax.flat): # enumerate()函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。i是数据下标,axi是数据
axi.imshow(x_train[i], cmap='binary')
axi.set(xticks=[], yticks=[]) # 取消子图X,Y轴的刻度
# 计算各个N下的累计贡献率,找出累计贡献率大于90%时对应的K值
cumsum = np.cumsum(pca.explained_variance_ratio_)
d = np.argmax(cumsum >= 0.9)
# 进行数据降维,并且根据降维后的数据生成原始数据
xr = []
for n in [5, 30, d]:
pca = PCA(n_components=n)
x_reduced = pca.fit_transform(x_trainnew)
x_recovered = pca.inverse_transform(x_reduced)
xr.append(x_recovered)
instances=[]
for i in range(5):
# 在列表instances中增加训练集中标签为i的第一个数据
instances.append(x_train[y_train == i][0])
print(x_train[y_train == i].shape)
for j in range(3):
# 将降维后的训练集中标标签为i的第一个数据增加到instances中,xr也是列表,包含三个数组(即三个降维后的训练集)
instances.append(xr[j][y_train == i][0])
print(xr[j][y_train == i][0])
images = [instance.reshape(28, 28) for instance in instances]
plt.figure()
fix, ax = plt.subplots(5, 4, dpi=600)
for i, axi in enumerate(ax.flat):
axi.imshow(images[i], cmap='binary')
axi.set(xticks=[], yticks=[])
plt.show()
压缩后的数据,分为为原始数据,主成分数量为5,30,86时对应的压缩后的数据:可以看出当主成分数量为86时,压缩后的图片比较清晰。