机器学习理论《统计学习方法》学习笔记:主成分分析(PCA)
第十六章 主成分分析(PCA)摘要1 总体主成分分析1.1 基本思想1.2 总体主成分分析定义1.3 主成分的个数1.4 规范化变量的总体主成分分析2 样本主成分分析2.1 样本主成分的定义和性质摘要主成分分析(Principal component analysis, PCA)是一种常用的无监督学习方法。这一方法利用正交变换,把由线性相关变量表示的观测数据,转换为少数几个由线性无关变量表示的数据
第十六章 主成分分析(PCA)
摘要
- 主成分分析(Principal component analysis, PCA)是一种常用的无监督学习方法。这一方法利用正交变换,把由线性相关变量表示的观测数据,转换为少数几个由线性无关变量表示的数据,线性无关的变量称为主成分。
- 主成分的个数通常小于原始变量的个数,所以主成分分析属于降维方法。主成分分析主要用于发现数据中的基本结构,即数据中变量之间的关系,是数据分析的有力工具,也用于其他机器学习方法的前处理。主成分分析属于多元统计分析的经典方法。
1 总体主成分分析
1.1 基本思想
统计分析中,数据的变量之间可能存在相关性,以致增加了分析的难度。于是,考虑由少数不相关的变量来代替相关的变量,用来表示数据,并且要求能够保留数据中的大部分信息。
主成分分析中,首先对给定数据进行规范化,使得数据每一变量的平均值为0,方差为1.之后对数据进行正交变换,原来由线性相关变量表示的数据,通过正交变换成若干个新变量表示的数据。新变量是可能的正交变换中变量的方差的和(信息保存)最大的,方差表示在新变量上信息的大小。将新变量依次称为第一主成分、第二主成分。这就是主成分的基本思想。通过主成分分析,可以利用主成分近似地表示原始数据,可理解为发现数据的“基本结构”;也可以把数据由少数主成分表示,可理解为对数据降维。
在数据总体上进行道的主成分分析称为总体主成分分析,在有限样本上进行的主成分分析称为样本主成分分析,总体主成分分析是样本主成分分析的基础。
1.2 总体主成分分析定义
假设 x = ( x 1 , x 2 , ⋯ , x m ) T x=(x_1,x_2,\cdots,x_m)^T x=(x1,x2,⋯,xm)T是m维随机变量,其均值向量是 μ \mu μ
μ = E ( x ) = ( μ 1 , μ 2 , ⋯ , μ m ) T \mu=E(x)=(\mu_1,\mu_2,\cdots,\mu_m)^T μ=E(x)=(μ1,μ2,⋯,μm)T
协方差矩阵是 Σ \Sigma Σ
Σ = c o v ( x , x ) = E [ ( x − μ ) ( x − μ ) T ] \Sigma=cov(x,x)=E[(x-\mu)(x-\mu)^T] Σ=cov(x,x)=E[(x−μ)(x−μ)T]
考虑由m维随机变量x到m维随机变量 y = ( y 1 , y 2 , ⋯ , y m ) T y=(y_1,y_2,\cdots,y_m)^T y=(y1,y2,⋯,ym)T的线性变换
y i = a i T x = a 1 i x 1 + a 2 i x 2 + ⋯ + a m i x m y_i=a_i^Tx=a_{1i}x_1+a_{2i}x_2+\cdots+a_{mi}x_m yi=aiTx=a1ix1+a2ix2+⋯+amixm
如果满足下列条件:
(1)系数向量 a i T a_i^T aiT是单位向量,即 a i T a i = 1 , i = 1 , 2 , ⋯ , m a_i^Ta_i=1,i=1,2,\cdots,m aiTai=1,i=1,2,⋯,m;
(2)变量 y i y_i yi与 y j y_j yj互不相关,即 c o v ( y i , y j ) = 0 ( i ≠ j ) cov(y_i,y_j)=0(i\neq j) cov(yi,yj)=0(i=j)
(3)变量 y 1 y_1 y1是x的所有线性变换中方差最大的; y 2 y_2 y2是与 y 1 y_1 y1不相关的x的所有线性变换中方差最大的;一般地, y i y_i yi是与 y 1 , y 2 , ⋯ , y i − 1 ( i = 1 , 2 , ⋯ , m ) y_1,y_2,\cdots,y_{i-1}(i=1,2,\cdots,m) y1,y2,⋯,yi−1(i=1,2,⋯,m)都不相关的x的所有线性变换中方差最大的;这时分别称 y 1 , y 2 , ⋯ , y m y_1,y_2,\cdots,y_m y1,y2,⋯,ym为x的第一主成分、第二主成分、、、第m主成分。
1.3 主成分的个数
主成分分析的主要目的就是降维,所以一般选择 k ( k ≪ m ) k(k \ll m) k(k≪m)个主成分(线性无关变量)来代替m个原有变量(线性相关变量),使问题得以简化,并能保留原有变量的大部分信息。这里所说的信息是指原有变量的方差,
假设x是m维随机变量,其协方差矩阵是 Σ \Sigma Σ, Σ \Sigma Σ的特征值分别是 λ 1 ≥ λ 2 ≥ ⋯ λ m ≥ 0 \lambda_1 \ge \lambda_2 \ge \cdots \lambda_m \ge 0 λ1≥λ2≥⋯λm≥0,特征值对应的单位特征向量是 a 1 , a 2 , ⋯ , a m a_1,a_2,\cdots,a_m a1,a2,⋯,am,则x的第i主成分可以写作
y i = a i T x = ∑ k = 1 m a k i x k , i = 1 , 2 , ⋯ , m y_i=a_i^Tx=\sum_{k=1}^ma_{ki}x_k,i=1,2,\cdots,m yi=aiTx=k=1∑makixk,i=1,2,⋯,m
并且,x的第i主成分的方差是协方差矩阵 Σ \Sigma Σ的第i个特征值,即
v a r ( y i ) = a i T Σ a i = λ i var(y_i)=a_i^T\Sigma a_i=\lambda_i var(yi)=aiTΣai=λi
1.4 规范化变量的总体主成分分析
在实际问题中,不同变量可能有不同的量纲,直接求主成分有时会产生不合理的结果。为了消除这个影响,常常对各个随机变量实施规范化,使其均值为0,方差为1.
设 x = ( x 1 , x 2 , ⋯ , x m ) T x=(x_1,x_2,\cdots,x_m)^T x=(x1,x2,⋯,xm)T为m维随机变量, x i x_i xi为第i个随机变量, i = 1 , 2 , ⋯ , m i=1,2,\cdots,m i=1,2,⋯,m,令
x i ∗ = x i − E ( x i ) ( v a r ( x i ) ) , i = 1 , 2 , ⋯ , m x_i^*={{x_i-E(x_i)}\over{\sqrt(var(x_i))}},i=1,2,\cdots,m xi∗=(var(xi))xi−E(xi),i=1,2,⋯,m
其中, E ( x i ) , v a r ( x i ) E(x_i),var(x_i) E(xi),var(xi)分别是随机变量 x i x_i xi的均值和方差,这时 x i ∗ x_i^* xi∗就是 x i x_i xi的规范化随机变量。
显然,规范化随机变量的协方差矩阵就是相关矩阵R。主成分分析通常在规范化随机变量的协方差矩阵即相关矩阵上进行。
2 样本主成分分析
在实际问题中,需要在观测数据上进行主成分分析,这就是样本主成分分析。样本主成分也和总体主成分具有相同的性质。
2.1 样本主成分的定义和性质
给定样本矩阵X。样本第一主成分 y 1 = a 1 T x y_1=a_1^Tx y1=a1Tx是在 a 1 T a 1 = 1 a_1^Ta_1=1 a1Ta1=1条件下,使得 a 1 T x j ( j = 1 , 2 , ⋯ , n ) a_1^Tx_j(j=1,2,\cdots,n) a1Txj(j=1,2,⋯,n)的样本方差 a 1 S a 1 a_1Sa_1 a1Sa1最大的x的线性变换;
样本第二主成分 y 2 = a 2 T x y_2=a_2^Tx y2=a2Tx是在 a 2 T a 2 = 1 a_2^Ta_2=1 a2Ta2=1和 a 2 T x j a_2^Tx_j a2Txj与 a 1 T x j ( j = 1 , 2 , ⋯ , n ) a_1^Tx_j(j=1,2,\cdots,n) a1Txj(j=1,2,⋯,n)的样本协方差 a 1 T S a 2 = 0 a_1^TSa_2=0 a1TSa2=0条件下,使得 a 2 T x j ( j = 1 , 2 , ⋯ , n ) a_2^Tx_j(j=1,2,\cdots,n) a2Txj(j=1,2,⋯,n)的样本方差 a 2 T S a 2 a_2^TSa_2 a2TSa2最大的x的线性变换。
2.2 主成分分析方法
主成分分析方法主要有两种,可以通过相关矩阵的特征值分解或样本矩阵的奇异值分解进行。
2.2.1 相关矩阵的特征值分解
相关矩阵的特征值分解算法
针对 m × n m\times n m×n样本矩 X X X,求样本相关矩阵
R = 1 n − 1 X X T R={1\over{n-1}}XX^T R=n−11XXT
再求样本相关矩阵的k个特征值和对应的单位特征向量,构成正交矩阵
V = ( v 1 , v 2 , ⋯ , v k ) V=(v_1,v_2,\cdots,v_k) V=(v1,v2,⋯,vk)
V V V的每一列对应一个主成分,得到 k × n k\times n k×n样本主成分矩阵
Y = V T X Y=V^TX Y=VTX
2.2.2 样本矩阵的奇异值分解
矩阵X的奇异值分解算法
针对 m × n m\times n m×n样本矩阵 X X X
X ′ = 1 ( n − 1 ) X T X^{'}={1\over{\sqrt(n-1)}}X^T X′=(n−1)1XT
对矩阵 X ′ X^{'} X′进行截断奇异值分解,保留k个奇异值、奇异向量,得到
X ′ = U S V T X^{'}=USV^T X′=USVT
V的每一列对应一个主成分,得到 k × n k\times n k×n样本主成分矩阵Y
Y = V T X Y=V^TX Y=VTX
3 主成分分析应用
3.1 数据降维
- 数据压缩:从二维数据压缩到一维数据
- 数据压缩:从三维数据压缩到二维数据
- 降维分析:找到数据最重要的方向,即方差最大的方向
- 降维分析:第一个主成分就是从数据差异性最大(方差最大)的地方提取出来的,第二个主成分则来自于数据差异次大的方向,并且要与第一个主成分方向正交。
- PCA不是线性回归
3.2 PCA算法流程
- 数据预处理:中心化 X − X ˉ X-\bar X X−Xˉ
- 求样本的协方差矩阵 1 m X X T {1\over m}XX^T m1XXT
- 对协方差矩阵 1 m X X T {1\over m}XX^T m1XXT做特征值分解
- 选出最大的K个特征值对应的K个特征向量
- 将原始数据投影到选取的特征向量上
- 输出投影后的数据集
方差描述一个数据的离散程度。
v a r ( X ) = ∑ i = 1 n ( X i − X ˉ ) ( X i − X ˉ ) n − 1 var(X)={{\sum_{i=1}^n(X_i-\bar X)(X_i-\bar X)}\over{n-1}} var(X)=n−1∑i=1n(Xi−Xˉ)(Xi−Xˉ)
协方差描述两个数据的相关性,接近1就是正相关,接近-1就是负相关,接近0就是不相关。
c o v ( X , Y ) = ∑ i = 1 n ( X i − X ˉ ) ( Y i − Y ˉ ) n − 1 cov(X,Y)={{\sum_{i=1}^n(X_i-\bar X)(Y_i-\bar Y)}\over{n-1}} cov(X,Y)=n−1∑i=1n(Xi−Xˉ)(Yi−Yˉ)
协方差只能处理二维问题,对于多维数据自然需要计算多个协方差,可以使用矩阵来组织这些数据。协方差是一个对称矩阵,而且对角线线是各个维度的方差。
二维数据
C = ( c o v ( x , x ) c o v ( x , y ) c o v ( y , x ) c o v ( y , y ) ) C= \begin{pmatrix} cov(x,x) & cov(x,y) \\ cov(y,x) & cov(y,y) \\ \end{pmatrix} C=(cov(x,x)cov(y,x)cov(x,y)cov(y,y))
三维数据
C = ( c o v ( x , x ) c o v ( x , y ) c o v ( x , z ) c o v ( y , x ) c o v ( y , y ) c o v ( y , z ) c o v ( z , x ) c o v ( z , y ) c o v ( z , z ) ) C= \begin{pmatrix} cov(x,x) & cov(x,y) & cov(x,z) \\ cov(y,x) & cov(y,y) & cov(y,z) \\ cov(z,x) & cov(z,y) & cov(z,z) \\ \end{pmatrix} C=⎝⎛cov(x,x)cov(y,x)cov(z,x)cov(x,y)cov(y,y)cov(z,y)cov(x,z)cov(y,z)cov(z,z)⎠⎞
3.3 特征值与特征向量
通过数据集的协方差矩阵及其特征值分析,可以得到协方差矩阵的特征向量和特征值,需要保留K个维度的特征就选取最大的K个特征值。
3.4 Python实现PCA降维
原始数据
完整程序
import numpy as np
import matplotlib.pyplot as plt
# 载入数据
data = np.genfromtxt('./dataset/data.csv', delimiter=',', dtype=np.float, skip_header=1)
x_data = data[:, 0]
y_data = data[:, 1]
plt.scatter(x_data, y_data)
plt.show()
# 数据中心化
def zeroMean(dataMat):
# 按列求平均,即各个特征的平均
meanVal = np.mean(dataMat, axis=0)
newData = dataMat - meanVal
return newData, meanVal
newData, meanVal = zeroMean(data)
# np.cov用来求协方差矩阵,参数rowvar=0说明数据一行代表一个样本
covMat = np.cov(newData, rowvar=0)
print('协方差矩阵:', covMat)
# 求矩阵的特征值和特征向量
eigVals, eigVects = np.linalg.eig(np.mat(covMat))
print('特征值:\n', eigVals)
print('特征向量:\n', eigVects)
# 对特征值从小到大排序
eigValIndice = np.argsort(eigVals)
print('eigValIndice:', eigValIndice)
top = 1
# 最大的top个特征值的下标
n_eigValIndice = eigValIndice[-1:-(top + 1):-1]
print("n_eigValIndice:", n_eigValIndice)
# 最大的n个特征值对应的特征向量
n_eigVect = eigVects[:, n_eigValIndice]
print("n_eigVect:", n_eigVect)
# 低维特征空间的数据
lowDDataMat = newData * n_eigVect
print("lowDDataMat:\n", lowDDataMat)
# 利用低维度数据重构原始数据
reconMat = (lowDDataMat * n_eigVect.T) + meanVal
print("reconMat:\n", reconMat)
# 载入数据
data = np.genfromtxt('./dataset/data.csv', delimiter=',', skip_header=1)
x_data = data[:, 0]
y_data = data[:, 1]
plt.scatter(x_data, y_data)
# 重构数据
x_data = np.array(reconMat)[:, 0]
y_data = np.array(reconMat)[:, 1]
plt.scatter(x_data, y_data, c='r')
plt.show()
print(type(reconMat))
print(reconMat.shape)
print(type(np.array(reconMat)))
print(np.array(reconMat).shape)
蓝色为原始数据,红色为PCA降维数据
3.5 手写数字识别降维及可视化
from sklearn.neural_network import MLPClassifier
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
import numpy as np
import matplotlib.pyplot as plt
digits = load_digits() # 载入数据
x_data = digits.data # 数据
print('x_data.shape:', x_data.shape)
y_data = digits.target # 标签
print('y_data.shape:', y_data.shape)
# 分割数据:0.75训练集,0.25测试集
x_train, x_test, y_train, y_test = train_test_split(x_data, y_data)
# 建立多层全连接神经网络,第一层100个神经元,第二层50个神经元
mlp = MLPClassifier(hidden_layer_sizes=(100, 50), max_iter=500)
print(mlp)
mlp.fit(x_train, y_train)
score = mlp.score(x_train, y_train)
print(score)
# 数据中心化
def zeroMean(dataMat):
# 按列求平均,即各个特征的平均
meanVal = np.mean(dataMat, axis=0)
newData = dataMat - meanVal
return newData, meanVal
def pca(dataMat, top):
newData, meanVal = zeroMean(dataMat) # 数据中心化
covMat = np.cov(newData, rowvar=0) # 求协方差矩阵,每一行代表一个样本
eigVals, eigVects = np.linalg.eig(np.mat(covMat)) # 求矩阵的特征值和特征向量
eigValIndice = np.argsort(eigVals) # 对特征值从小到大排序
n_eigValIndice = eigValIndice[-1:-(top + 1):-1] # 最大的n个特征值的下标
n_eigVect = eigVects[:, n_eigValIndice] # 最大的n个特征值对应的特征向量
lowDDataMat = newData * n_eigVect # 低维特征空间的数据
reconMat = (lowDDataMat * n_eigVect.T) + meanVal # 利用低维度数据来重构原始数据
# 返回低维特征空间的数据和重构的矩阵
return lowDDataMat, reconMat
def pca_64_to_2():
# 从64维下降到2维
lowDDataMat, reconMat = pca(x_data, 2)
# 重构的数据
x = np.array(lowDDataMat)[:, 0]
y = np.array(lowDDataMat)[:, 1]
plt.scatter(x, y, c='r')
plt.show()
# 重构的数据
predictions = mlp.predict(x_data)
x = np.array(lowDDataMat)[:, 0]
y = np.array(lowDDataMat)[:, 1]
plt.scatter(x, y, c=predictions)
plt.show()
def pca_64_to_3():
# 从64维下降到3维
lowDDataMat, reconMat = pca(x_data, 3)
# 重构的数据
from mpl_toolkits.mplot3d import Axes3D
x = np.array(lowDDataMat)[:, 0]
y = np.array(lowDDataMat)[:, 1]
z = np.array(lowDDataMat)[:, 2]
ax = plt.figure().add_subplot(111, projection='3d')
ax.scatter(x, y, z, c=y_data, s=10)
plt.show()
if __name__ == '__main__':
pca_64_to_3()
4 数据降维在图像识别领域的应用
4.1 导入模块
"""
1.导入模块
"""
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVC # 向量机
# 主成分分析,主要用于数据降维
from sklearn.decomposition import PCA
# 用于切割训练数据集和样本数据
from sklearn.model_selection import train_test_split
# 手写数字识别数据集
from sklearn.datasets import load_digits
4.2 生成训练数据和测试数据
"""
2.生成训练数据和测试数据
"""
digits = load_digits() # 载入数据
x_data = digits.data # 数据
print('x_data:', x_data.shape) # x_data: (1797, 64)
y_data = digits.target # 标签
print('y_data:', y_data.shape) # y_data: (1797,)
# 分割数据:0.8训练集,0.2测试集
x_train, x_test, y_train, y_test = train_test_split(x_data, y_data, test_size=0.2)
print('train:', x_train.shape, y_train.shape) # train: (1437, 64) (1437,)
print('test:', x_test.shape, y_test.shape) # test: (360, 64) (360,)
展示数据
def show_img():
img = x_data[1, :]
img = img.reshape(8, 8)
label = y_data[1]
print(img.shape) # (8, 8)
plt.imshow(img)
plt.title('label:' + str(label))
plt.show()
4.3 对数据进行降维处理
"""
3.对数据进行降维处理
"""
# PCA用于数据降维,减少运算时间,避免过拟合
# n_components参数设置需要保留特征的数量,如果是小数,则表示保留特征的比例
# 3.1 创建PCA对象
pca = PCA(n_components=32, whiten=True)
# 3.2 使用PCA训练数据
pca.fit(x_train, y_train)
# 3.3 对训练数据进行降维
x_train_pca = pca.transform(x_train)
x_test_pca = pca.transform(x_test)
# 由原来的64个特征降为现在的32个特征
print('x_train_pca:', x_train_pca.shape) # (1437, 32)
print('x_test_pca:', x_test_pca.shape) # (360, 32)
4.4 创建学习模型
"""
4.创建学习模型
"""
svc_pca = SVC(kernel='rbf')
svc = SVC(kernel='rbf')
4.5 使用降维后的数据进行模型训练
"""
5.使用降维后的数据进行模型训练
"""
svc_pca.fit(x_train_pca, y_train)
# 模型执行降维后数据的评分
score_train_pca = svc_pca.score(x_train_pca, y_train)
score_test_pca = svc_pca.score(x_test_pca, y_test)
print('score_train_pca:', score_train_pca) # 1.0
print('score_test_pca:', score_test_pca) # 0.9888
svc.fit(x_train, y_train)
# 模型不执行降维后数据的评分
score_train = svc.score(x_train, y_train)
score_test = svc.score(x_test, y_test)
print('score_train:', score_train) # 0.9951
print('score_test:', score_test) # 0.9655
4.6 预测结果
"""
6.预测结果
"""
y_pre_svc_pca = svc_pca.predict(x_test_pca)
4.7 展示结果
"""
7.展示结果
"""
# 展示前100个测试样本数据
samples = x_test[:100]
y_pre = y_pre_svc_pca[:100]
plt.figure(figsize=(12, 18))
for i in range(100):
plt.subplot(10, 10, i + 1)
plt.imshow(samples[i].reshape(8, 8), cmap='gray')
title = 'True:' + str(y_test[i]) + '\nSVC:' + str(y_pre[i])
plt.title(title)
plt.xticks([])
plt.yticks([])
plt.show()
5 PCA降维应用:高维数据可视化
- 在数据预处理和特征工程部分,有一种重要的特征选择方法:方差过滤。如果一个特征的方差很小,则意味着这个特征上很可能有着大量取值都相同,比如90%都是1,只有10%是0,甚至100%都是1,那么这个特征的取值对样本而言就没有区分度,这样的特征几乎不包含任何有效信息。
- 从方差的这种应用可以推断出,如果一个特征的方差很大,则说明这个特征上带有大量的信息。因此在降维中,PCA使用的信息量衡量指标就是样本方差,又称为解释性方差。如果某一特征的方差越大,该特征所带的信息量就越多。
5.1 鸢尾花数据降维
- 基于Sklearn中PCA方法对鸢尾花数据集进行可视化
- 鸢尾花数据集共有150个样本,分为三个类别,每个类别各50个样本;在每个样本中,有四个特征标示样本特征,根据这四个特征对鸢尾花进行分类。
# 高维数据的可视化
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
import pandas as pd
iris = load_iris()
x = iris.data # 特征矩阵
y = iris.target # 标签(三种鸢尾花的类别)
print('x:', x.shape) # (150, 4)
print('y:', y.shape) # (150,)
- 实例化PCA对象:
pca = PCA(n_components=2)
,参数n_components
表示指定要下降到多少维
pca = PCA(n_components=2) # 保留两个特征
x_dec = pca.fit_transform(x) # 拟合并导出新的特征矩阵
print('x_dec:', x_dec.shape) # (150, 2)
- 原始的鸢尾花数据集是四维的,基于PCA方法进行降维到2维后,就可以在二维平面进行数据的可视化
plt.scatter(x_dec[y == 0, 0], x_dec[y == 0, 1], label=iris.target_names[0])
plt.scatter(x_dec[y == 1, 0], x_dec[y == 1, 1], label=iris.target_names[1])
plt.scatter(x_dec[y == 2, 0], x_dec[y == 2, 1], label=iris.target_names[2])
plt.title("PCA OF IRIS")
plt.legend()
plt.show()
- 显然,簇的分布是很明显的。此时,不论使用SVM、KNN或随机森林都不容易分错,准确率基本都在95%以上,所以即使将数据从四维降到二维,对模型的分类效果影响甚微。
5.2 PCA方法属性
5.2.1 pca.explained_variance_
explained_variance_
表示降维后新特征上所带的信息量的大小,即可解释方差的大小
# 探索降维后的数据
# 表示降维后新特征上所带的信息量的大小,也就是可解释方差的大小
explained_var = pca.explained_variance_
print('explained_var:', explained_var) # [4.22824171 0.24267075]
5.2.2 pca.explained_variance_ratio_
explained_variance_ratio_
表示降维后,每个特征向量所包含的信息量,占原始数据总信息量的百分比
# 表示降维后每个新特征向量所包含的信息量,占原始数据总信息量的百分比
# 又称做可解释性方差贡献率
explained_var_radio = pca.explained_variance_ratio_
# 由输出结果可见,大部分信息都集中在第一个特征上 [0.92461872 0.05306648]
# 0.92461872+0.05306648=0.9776852,表明主成分分析之后保留了97.76%的原始数据特征
print('explained_var_radio:', explained_var_radio)
5.2.3 n_components
- 对于参数n_components,有多种类型取值,可以是整数,表示降维之后特征的数量;
pca = PCA(n_components=2) # 保留两个特征
x_dec = pca.fit_transform(x) # 拟合并导出新的特征矩阵
print('x_dec:', x_dec.shape) # (150, 2)
- 可以是[0,1]之间的小数,表示希望保留的信息量的百分比;
# 按照信息量占比选择超参数
pca = PCA(n_components=0.95)
x_radio = pca.fit_transform(x)
print(x_radio.shape) # (150, 2)
print(pca.explained_variance_) # [4.22824171 0.24267075]
print(pca.explained_variance_ratio_) # [0.92461872 0.05306648]
- 可以是字符类型mle,表示极大似然估计自选超参数,此时会自动选择整数值;
# 极大似然估计自选超参数,选择的新特征数量是3
pca = PCA(n_components='mle')
x_mle = pca.fit_transform(x)
print('x_mle:', x_mle.shape) # (150, 3)
print(pca.explained_variance_) # [4.22824171 0.24267075 0.0782095 ]
print(pca.explained_variance_ratio_) # [0.92461872 0.05306648 0.01710261]
- 可以直接使用PCA(k)的形式,甚至可以不填,默认是min(x.shape),由于一般特征数量小于样本数量,所以结果通常是特征数量。
# n_components不填,默认是min(x.shape),通常是特征数量
pca = PCA()
x_def = pca.fit_transform(x)
print('x_def:', x_def.shape) # (150, 4)
print(pca.explained_variance_) # [4.22824171 0.24267075 0.0782095 0.02383509]
print(pca.explained_variance_ratio_) # [0.92461872 0.05306648 0.01710261 0.00521218]
- 容易看出来第一个特征(向量)几乎包含所有的原始数据信息。如果原始数据维数较多,可以发现前几个特征几乎包含了所有的元素信息,所以通常取前K个特征就可以了。
5.3 主成分分析(PCA)与奇异值分解(SVD)
使用PCA进行降维的时候需要计算协方差矩阵 X X T XX^T XXT,其中 X = ( x i j ) m × n X=(x_{ij})_{m\times n} X=(xij)m×n表示特征矩阵,这个矩阵的计算量是非常大的,Sklearn中会使用SVD来帮助计算,大致的流程如下:
# SVD(奇异值分解)在fit中进行,分解结果除V(k,n)以外,其他的都被舍弃
# V(k,n)被保存在components_属性值中
pca = PCA(2)
pca.fit(x)
print('components_:', pca.components_)
print('shape:', pca.components_.shape)
输出结果
components_: [[ 0.36138659 -0.08452251 0.85667061 0.3582892 ]
[ 0.65658877 0.73016143 -0.17337266 -0.07548102]]
shape: (2, 4)
6 PCA人脸数据降维与还原
6.1 导入人脸识别数据
#人脸识别案例
from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import PCA
import numpy as np
import matplotlib.pyplot as plt
faces = fetch_lfw_people()
faces.data.shape,faces.images.shape #62*47=2924,像素 前者是2维数组后者是3维数组
输出:((13233, 2914), (13233, 62, 47))
figs,objs = plt.subplots(
3,5 # 3行5列
,figsize=(8,5) # 每个人脸图像的大小为8*5
,subplot_kw={"xticks":[],"yticks":[]} #不显示坐标轴
)
for i,obj in enumerate(objs.flat):#或者直接使用faces.images[i]
obj.imshow(faces.data[i].reshape(62,47),cmap="gray")
6.2 利用PCA对数据降维
现在我们进行降维,使用fit后得到的矩阵V来画图
#提取新特征空间 降维
x = faces.data
pca = PCA(200).fit(x)
V = pca.components_
#V.shape #输出(200, 2914) k=200,n=2914
figs,objs = plt.subplots(2,5,figsize=(8,5),subplot_kw={"xticks":[],"yticks":[]})
for i,obj in enumerate(objs.flat):
obj.imshow(V[i,:].reshape(62,47),cmap="gray")
比起降维前的数据,新特征空间可视化后的人脸非常模糊,这是因为原始数据还没有被映射到特征空间中。但是可以看出,整体比较亮的图片,获取的信息较多,整体比较暗的图片,却只能看见黑漆漆的一块。在比较亮的图片中,眼睛,鼻子,嘴巴,都相对清晰,脸的轮廓,头发之类的比较模糊。
这说明,新特征空间里的特征向量们,大部分是"五官"和"亮度"相关的向量,所以新特征向量上的信息肯定大部分是由原数据中和"五官"和"亮度"相关的特征中提取出来的。到这里,我们通过可视化新特征空间V,解释了一部分降维后的特征:虽然显示出来的数字看着不知所云,但画出来的图表示,这些特征是和”五官“以及”亮度“有关的。这也再次证明了,PCA能够将原始数据集中重要的数据进行聚集
6.3 pca.inverse_transform
pca.inverse_transform接口可以将归一化、标准化甚至做过哑变量的特征矩阵,还原到原始数据中的特征矩阵。
#人脸识别案例
from sklearn.decomposition import PCA
from sklearn.datasets import fetch_lfw_people
import numpy as np
import matplotlib.pyplot as plt
faces = fetch_lfw_people()
x = faces.data
pca = PCA(200)
x_face = pca.fit_transform(x)
print(x_face.shape) # (13233, 200)
x_inverse = pca.inverse_transform(x_face)
print(x_inverse.shape) # (13233, 2914)
figs, objs = plt.subplots(2,10,figsize=(10,2.5),subplot_kw={"xticks":[],"yticks":[]})
for i in range(10):
objs[0,i].imshow(x[i].reshape(62,47),cmap="gray")
objs[1,i].imshow(x_inverse[i].reshape(62,47),cmap="gray")
-
对比一下,一个是原始数据得到的人脸,一个是降维后使用接口inverse_transform还原回去的数据,得到的人脸是非常相似的,虽然后者有点模糊。
-
这说明,inverse_transform并没有实现数据的完全逆转。这是因为,在降维的时候,部分信息已经被舍弃了,X_face中往往不会包含原数据100%的信息,所以在逆转的时候,即便维度升高,原数据中已经被舍弃的信息也不可能再回来了。
-
所以,降维不是完全可逆的,但是同时也说明了,使用200维度,的确保留了原数据的大部分信息,所以图像看起来,才会和原数据高度相似,只是稍稍模糊罢了。
7 使用PCA进行降噪
- 降维的目的之一就是希望抛弃对模型带来负面影响的特征,而且含有效信息的特征的方差应该是远大于噪声的,所以相比于噪声,有效的特征所带来的信息应该不会在PCA过程中被大量抛弃。
- inverse_transform能够在不恢复原始数据的情况下,将降维后的数据返回到原本的高维空间,即能够实现保证维度,但去掉方差很小特征所带来的信息。利用inverse_transform这个性质,能够实现噪音过滤。
# 用PCA做噪声过滤
from sklearn.datasets import load_digits
dig=load_digits()
dig.data.shape,dig.images.shape
((1797, 64), (1797, 8, 8))
# 定义画图的方法
%matplotlib inline
import matplotlib.pyplot as plt
def draw_img(data):
figs,objs=plt.subplots(2,10,figsize=(10,2.5),subplot_kw={'xticks':[],'yticks':[]})
for i,obj in enumerate(objs.flat):
obj.imshow(data[i].reshape(8,8),cmap='binary')
draw_img(dig.data)
plt.show()
给数据加上噪声
# 在指定数据集中,随机抽取服从正太分布的数据
# 两个参数,分别是指定的数据集和抽取出来的正太分布的方差
import numpy as np
noisy=np.random.normal(dig.data,2)
draw_img(noisy)
对含有噪声的数据进行降维,然后还原
# 先降维,再还原
from sklearn.decomposition import PCA
pca=PCA(n_components=0.9)
x_dr=pca.fit_transform(noisy)
x_inverse=pca.inverse_transform(x_dr)
draw_img(x_inverse)
参考文献
- 李航《统计学习方法》第二版
- https://www.bilibili.com/video/BV1Rt411q7WJ
- https://blog.csdn.net/weixin_38748717/article/details/78847452
- https://blog.csdn.net/qq_37334135/article/details/87026462

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐
所有评论(0)