前言
PCA(Principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据降维算法。PCA的主要思想是将n维特征映射到k维上,这k维是全新的正交特征也被称为主成分,是在原有n维特征的基础上重新构造出来的k维特征。 降维的方法有很多,包括:奇异值分解(SVD)、主成分分析(PCA)、因子分析(FA)、独立成分分析(ICA)等等。 在 PCA 中,数据从原来的坐标系转换到新的坐标系下,新的坐标系的选择与数据本身是密切相关的。其中,第一个新坐标轴选择的是原始数据中方差最大的方向,第二个新坐标轴选取的是与第一个坐标轴正交且具有最大方差的方向,依次类推,我们可以取到这样的个坐标轴。 正交属性空间中的样本点,若存在一个超平面,可能具有两个性质: 1. 最近重构性:样本点到这个超平面的距离都足够近;2. 最大可分性:样本点在这个超平面上的投影能尽可能分开。读书是爱读,会读,想方设法去读。
一、PCA是什么?
PCA是一种常用的降维方法。
为什么要降维?
在高维情况下出现的数据样本稀疏、距离计算困难等问题,被称为“维数灾难”(curse of dimensionality)。
降维(dimension reduction),通过某种数学变换将原始高维属性空间转变为一个低维“子空间”(subspace),在这个子空间中样本密度大幅提高,距离计算也变得更为容易。因此,原始高维空间的样本点,在低维嵌入子空间中更容易进行学习。
PCA的操作流程大致如下:
(1)去平均值(去中心化),即每一位特征减去各自的平均值
(2)计算协方差矩阵
(3)利用特征值分解的方法计算协方差矩阵的特征值与特征向量
(4)对特征值从大到小排序
(5)保留最大的k个特征向量
(6)将数据转换到k个特征向量构建的新空间中。
二、代码实践
sklearn库中decomposition模块的PCA()函数:
class sklearn.decomposition.PCA(n_components=None, *, copy=True, whiten=False, svd_solver='auto', tol=0.0, iterated_power='auto', random_state=None)
使用数据的奇异值分解SVD(Singular Value Decomposition)将其投影到较低维空间的线性降维。在应用 SVD 之前,输入数据已居中但未针对每个特征进行缩放。
参数:
- n_components: n_components是>=1的整数时,表示期望PCA降维后的特征维度;n_components是[0,1]的数时,表示主成分的方差和所占的最小比例阈值,PCA类自己去根据样本特征方差来决定降维到的维度。默认值是n_components=min(样本数,特征数)。
- copy:如果为 False,则传递给 fit 的数据将被覆盖。
- whiten:判断是否进行白化。所谓白化,就是对降维后的数据的每个特征进行归一化,让方差都为1。当为 True(默认为 False)时,components_向量乘以 n_samples 的平方根,然后除以奇异值以确保不相关的输出具有单位分量方差。
- svd_solver:求解器,即指定奇异值分解SVD的方法。4个值:{‘auto’, ‘full’, ‘arpack’, ‘randomized’}。
- tol:由 svd_solver == ‘arpack’ 计算的奇异值的容差。
- iterated_power:由 svd_solver == ‘randomized’ 计算的幂方法的迭代次数。
- random_state:在使用“arpack”或“randomized”求解器时使用。
属性:
- components_ :特征空间中的主轴,表示数据中最大方差的方向。
- n_features_:训练数据中的特征数。
- n_samples_:训练数据中的样本数。
fit_transform(X):用X拟合模型并对X进行降维。
inverse_transform(X):将数据转换回原始空间。
explained_variance_:代表降维后的各主成分的方差值。方差值越大,则说明越是重要的主成分。explained_variance_ratio_:代表降维后的各主成分的方差值占总方差值的比例,这个比例越大,则越是重要的主成分。
使用MNIST数据集实现sklearn库里的主成分分析方法
代码如下(示例):
import sys
from pathlib import Path
from torch.utils.data import DataLoader
from torchvision import datasets
import torchvision.transforms as transforms
from sklearn.decomposition import PCA # 导入PCA模型
import numpy as np
import matplotlib.pyplot as plt
# sklearn方法通过SVD(Singular Value Decomposition,奇异值分解)实现,使用SVD将其投影到较低维空间的线性降维。
curr_path = str(Path().absolute())
parent_path = str(Path().absolute().parent)
p_parent_path = str(Path().absolute().parent.parent)
sys.path.append(p_parent_path)
# print(f"主目录为:{p_parent_path}") # 获取项目所在位置根目录
# 从当前路径中获取MNIST数据集,已经提前下载好。如果没有下载,可将download设为True。
train_dataset = datasets.MNIST(root = p_parent_path+'2021pycharmprojects\\datasets\\', train = True,transform = transforms.ToTensor(), download = False)
test_dataset = datasets.MNIST(root = p_parent_path+'2021pycharmprojects\\datasets\\', train = False, transform = transforms.ToTensor(), download = False)
batch_size = len(train_dataset)
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)
X_train,y_train = next(iter(train_loader))
X_test,y_test = next(iter(test_loader))
X_train,y_train = X_train.cpu().numpy(),y_train.cpu().numpy() # tensor转为array形式)
X_test,y_test = X_test.cpu().numpy(),y_test.cpu().numpy() # tensor转为array形式)
X_train = X_train.reshape(X_train.shape[0],784)
X_test = X_test.reshape(X_test.shape[0],784)
m , p = X_train.shape # m:训练集数量,p:特征维度数
print(f"原本特征维度数:{p}") # 特征维度数为784
# 用方差来定义样本的间距,方差越大表示样本分布越稀疏,方差越小表示样本分布越密集。
# n_components是>=1的整数时,表示期望PCA降维后的特征维度数
# n_components是[0,1]的数时,表示主成分的方差和所占的最小比例阈值,PCA类自己去根据样本特征方差来决定降维到的维度
model = PCA(n_components=0.95) # n_components在(0,1)之间,表示主成分的方差和所占的最小比例阈值
lower_dimensional_data = model.fit_transform(X_train) # 通过fit_transform方法得到拟合降维模型
print(f"降维后的特征维度数:{model.n_components_}")
approximation = model.inverse_transform(lower_dimensional_data) # 降维后的数据还原
plt.figure(figsize=(8,4));
# 原始图片
plt.subplot(1, 2, 1);
plt.imshow(X_train[1].reshape(28,28),
cmap = plt.cm.gray, interpolation='nearest',
clim=(0, 1));
# interpolation='nearest' 最近邻插值,将目标图像各点的像素值设为源图像中与其最近的点。
plt.xlabel(f'{X_train.shape[1]} components', fontsize = 14)
plt.title('Original Image', fontsize = 20)
# 降维后的图片
plt.subplot(1, 2, 2);
plt.imshow(approximation[1].reshape(28, 28),
cmap = plt.cm.gray, interpolation='nearest',
clim=(0,1));
plt.xlabel(f'{model.n_components_} components', fontsize = 14)
plt.title('95% of Explained Variance', fontsize = 20) # 可解释方差
plt.show()
不同主成分个数对应的可解释方差分析(Explained Variance)
可解释方差(Explained Variance)指标衡量的是所有预测值和样本之间的差的分散程度与样本本身的分散程度的相近程度。
代码如下(示例):
import sys
from pathlib import Path
from torch.utils.data import DataLoader
from torchvision import datasets
import torchvision.transforms as transforms
from sklearn.decomposition import PCA # 导入PCA模型
import numpy as np
import matplotlib.pyplot as plt
curr_path = str(Path().absolute())
parent_path = str(Path().absolute().parent)
p_parent_path = str(Path().absolute().parent.parent)
sys.path.append(p_parent_path)
train_dataset = datasets.MNIST(root = p_parent_path+'2021pycharmprojects\\datasets\\', train = True,transform = transforms.ToTensor(), download = False)
test_dataset = datasets.MNIST(root = p_parent_path+'2021pycharmprojects\\datasets\\', train = False,
transform = transforms.ToTensor(), download = False)
batch_size = len(train_dataset)
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)
X_train,y_train = next(iter(train_loader))
X_test,y_test = next(iter(test_loader))
X_train,y_train = X_train.cpu().numpy(),y_train.cpu().numpy() # tensor转为array形式)
X_test,y_test = X_test.cpu().numpy(),y_test.cpu().numpy() # tensor转为array形式)
X_train = X_train.reshape(X_train.shape[0],784)
X_test = X_test.reshape(X_test.shape[0],784)
m , p = X_train.shape # m:训练集数量,p:特征维度数
# print(f"原本特征维度数:{p}") # 特征维度数为784
# 可解释方差
def explained_variance(percentage, images):
'''
:param: percentage [float]: 降维的百分比
:return: approx_original: 降维后还原的图片
:return: model.n_components_: 降维后的主成分个数
'''
model = PCA(percentage)
model.fit(images)
components = model.transform(images)
approx_original = model.inverse_transform(components)
return approx_original,model.n_components_
plt.figure(figsize=(8,10));
percentages = [784,0.99,0.95,0.90]
for i in range(1,5):
plt.subplot(2,2,i)
im, n_components = explained_variance(percentages[i-1], X_train)
im = im[5].reshape(28, 28) # 重建成图片
plt.imshow(im,cmap = plt.cm.gray, interpolation='nearest',clim=(0,1))
plt.xlabel(f'{n_components} Components', fontsize = 12)
if i==1:
plt.title('Original Image', fontsize = 14)
else:
plt.title(f'{percentages[i-1]*100}% of Explained Variance', fontsize = 14)
plt.show()
总结
枯沙湮没不了芳华,且看为谁袖手天下。
以上就是今天要讲的内容,本文仅仅简单介绍了pca的使用,而sklearn库提供了大量能使我们快速便捷地应用函数和方法。
参考内容
主成分分析(PCA)原理详解
主成分分析
sklearn PCA
机器学习