写点什么

主成分分析 PCA 与奇异值分解 SVD-PCA 对手写数据集的降维 & 用 PCA 做噪音过滤

  • 2022-11-21
    山东
  • 本文字数:2175 字

    阅读完需:约 7 分钟

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


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


from sklearn.decomposition import PCAfrom sklearn.ensemble import RandomForestClassifier as RFCfrom sklearn.model_selection import cross_val_scoreimport matplotlib.pyplot as pltimport pandas as pdimport 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()
复制代码



继续缩小最佳维度的范围


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维左右,并将数据导入随机森林将有最佳效果
复制代码



再次缩小


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()
复制代码



查看模型效果


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 KNNcross_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()
复制代码



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


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

用 PCA 做噪音过滤

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


from sklearn.datasets import load_digitsfrom sklearn.decomposition import PCAimport matplotlib.pyplot as pltimport 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)
复制代码



为数据加上噪音


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 = 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)
复制代码


总结


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


发布于: 刚刚阅读数: 3
用户头像

跃入人海 2022-09-14 加入

还未添加个人简介

评论

发布
暂无评论
主成分分析PCA与奇异值分解SVD-PCA对手写数据集的降维 & 用PCA做噪音过滤_Python_烧灯续昼2002_InfoQ写作社区