读书是爱读,会读,想方设法去读。
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 之前,输入数据已居中但未针对每个特征进行缩放。
参数:
属性:
fit_transform(X):用X拟合模型并对X进行降维。
inverse_transform(X):将数据转换回原始空间。
explained_variance_:代表降维后的各主成分的方差值。方差值越大,则说明越是重要的主成分。explained_variance_ratio_:代表降维后的各主成分的方差值占总方差值的比例,这个比例越大,则越是重要的主成分。
代码如下(示例):
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)指标衡量的是所有预测值和样本之间的差的分散程度与样本本身的分散程度的相近程度。
代码如下(示例):
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
机器学习