视频作者:[菜菜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()
继续缩小最佳维度的范围
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 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()
在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)
为数据加上噪音
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)