详解主成分分析PCA与奇异值分解SVD-PCA对手写数据集的降维 & 用PCA做噪音过滤【菜菜的sklearn课堂笔记】

时间:2022-11-17 12:01:03

视频作者:[菜菜TsaiTsai] 链接:[【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili]

数据预处理章节一直用的这个数据集

在本个案例中,由于PCA也有random_state参数,而并未设置,因此结果可能有不同

from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

data = pd.read_csv(r"D:\ObsidianWorkSpace\SklearnData\digit recognizor.csv")
X = data.iloc[:,1:]
y = data.iloc[:,0]

X.shape
---
(42000, 784)

y.shape
---
(42000,)

画累计方差贡献率曲线,找最佳降维后维度的范围

pca_line = PCA().fit(X)

plt.figure(figsize=[20,5])
plt.plot(np.cumsum(pca_line.explained_variance_ratio_))
plt.xlabel('number of components after dimension reduction')
plt.ylabel('cumulative explained variance')
plt.show()

详解主成分分析PCA与奇异值分解SVD-PCA对手写数据集的降维 & 用PCA做噪音过滤【菜菜的sklearn课堂笔记】

继续缩小最佳维度的范围

score = []
for i in range(1,101,10):
    X_dr = PCA(i).fit_transform(X)
    once = cross_val_score(RFC(n_estimators=10,random_state=0)
                          ,X_dr,y,cv=5).mean()
    score.append(once)

plt.figure(figsize=[20,5])
plt.plot(range(1,101,10),score)
plt.xticks(range(1,101,10))
plt.show() # 降维到21维左右,并将数据导入随机森林将有最佳效果

详解主成分分析PCA与奇异值分解SVD-PCA对手写数据集的降维 & 用PCA做噪音过滤【菜菜的sklearn课堂笔记】

再次缩小

score = []
for i in range(11,25):
    X_dr = PCA(i).fit_transform(X)
    once = cross_val_score(RFC(n_estimators=10,random_state=0)
                          ,X_dr,y,cv=5).mean()
    score.append(once)

plt.figure(figsize=[20,5])
plt.plot(range(11,25),score)
plt.xticks(range(11,25))
plt.show()

详解主成分分析PCA与奇异值分解SVD-PCA对手写数据集的降维 & 用PCA做噪音过滤【菜菜的sklearn课堂笔记】

查看模型效果

X_dr = PCA(24).fit_transform(X)

cross_val_score(RFC(n_estimators=10,random_state=0),X_dr,y,cv=5).mean()
---
0.9170718423612418

cross_val_score(RFC(n_estimators=100,random_state=0),X_dr,y,cv=5).mean()
---
0.9471193590104136

在之前的建模过程中,因为计算量太大,所以我们一直使用随机森林,但事实上,对于这个数据集,KNN的效果比随机森林更好,KNN在未调参的状况下已经达到96%的准确率,而随机森林在未调参前只能达到93%,这是模型本身的限制带来的。现在我们的特征数量已经降到不足原来的3%,可以考虑使用KNN了

from sklearn.neighbors import KNeighborsClassifier as KNN
cross_val_score(KNN(),X_dr,y,cv=5).mean() # 默认k=5

score = []
for i in range(10):
    once = cross_val_score(KNN(i+1),X_dr,y,cv=5).mean()
    score.append(once)

plt.figure(figsize=[20,5])
plt.plot(range(10),score)
plt.xticks(range(10))
plt.show()

详解主成分分析PCA与奇异值分解SVD-PCA对手写数据集的降维 & 用PCA做噪音过滤【菜菜的sklearn课堂笔记】

在k=5是效果最好,上面我们也跑过交叉验证了,这里不再赘述

可以发现,原本785列的特征被我们缩减到23列之后,用KNN跑出了目前位置这个数据集上最好的结果。再进行更细致的调整,我们也许可以将KNN的效果调整到98%以上。PCA为我们提供了无限的可能,终于不用再因为数据量太庞大而*选择更加复杂的模型了!

用PCA做噪音过滤

降维的目的之一就是希望抛弃掉对模型带来负面影响的特征,而我们相信,带有效信息的特征的方差应该是远大于噪音的,所以相比噪音,有效的特征所带的信息应该不会在PCA过程中被大量抛弃inverse_transform能够在不恢复原始数据的情况下,将降维后的数据返回到原本的高维空间,即是说能够实现”保证维度,但去掉方差很小特征所带的信息“。利用inverse_transform的这个性质,我们能够实现噪音过滤。

from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np

digits = load_digits()
digits.data.shape
---
(1797, 64)

digits.images.shape
---
(1797, 8, 8)

set(digits.target)
---
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

def plot_digits(data):
# data的结构必须是(m,n),并且n要能够被分成(8,8)这样的结构
    fig, axes = plt.subplots(4,10,figsize=(10,4)
                            ,subplot_kw={'xticks':[],'yticks':[]}
                            )
    for i,ax in enumerate(axes.flat):
        ax.imshow(data[i].reshape(8,8),cmap='binary')

plot_digits(digits.data)

详解主成分分析PCA与奇异值分解SVD-PCA对手写数据集的降维 & 用PCA做噪音过滤【菜菜的sklearn课堂笔记】

为数据加上噪音

rng = np.random.RandomState(42)
noisy = rng.normal(digits.data,2) # 猜测应该是给每一列加上方差为2的高斯噪声,均值为该列的均值
# digits.data指定数据集
# 2:抽取出来正态分布的方差
noisy.shape
---
(1797, 64)

关于rng.normal(数据集,方差)

a = rng.randint(0,10,(4,5))
a.sum(axis=0)
---
array([15, 12, 15, 16, 28])

rng.normal(a,0).sum(axis=0) # 我们令方差为0,验证上面的想法
---
array([15., 12., 15., 16., 28.])
plot_digits(noisy)

详解主成分分析PCA与奇异值分解SVD-PCA对手写数据集的降维 & 用PCA做噪音过滤【菜菜的sklearn课堂笔记】

pca = PCA(0.5,svd_solver='full').fit(noisy)
# 0.5是指50%的数据,而不是50%的维度
X_dr = pca.transform(noisy)
X_dr.shape
---
(1797, 6)

pca.explained_variance_ratio_.sum()
---
0.5071198405440357

without_noisy = pca.inverse_transform(X_dr)
plot_digits(without_noisy)

详解主成分分析PCA与奇异值分解SVD-PCA对手写数据集的降维 & 用PCA做噪音过滤【菜菜的sklearn课堂笔记】

总结

详解主成分分析PCA与奇异值分解SVD-PCA对手写数据集的降维 & 用PCA做噪音过滤【菜菜的sklearn课堂笔记】