在实际操作数据集的过程中,难免会遇到很多高维特征的数据,计算量也会暴增。为了在减少计算量的同时提高算法准确率,可尝试降维。
PCA(Principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据降维算法。
下文将列出三个案例,分别是人脸识别、降噪和处理手写数据集。
案例一:人脸识别
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA
##########人脸识别########
from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import PCA
faces = fetch_lfw_people(min_faces_per_person=60) #每个人60张照片
print(faces.data.shape) #二维 1277*2914 2914=62*47
print(faces.images.shape) #三维:1277矩阵中图像个数,62每个图像的特征矩阵的行,47每个图像的特征矩阵的列
x1 = faces.data
#创建画布 subplots子图画布(4行5列)
fig, axes = plt.subplots(4,5
,figsize=(8,4) #画布大小
,subplot_kw= {'xticks':[],'yticks':[]}) #不要显示坐标轴
axes[0][0].imshow(faces.images[0,:,:]) #填图
#循环填补 由于4行5列 比较复杂,所以直接1-20,方法就是将axes降维至1维
[* axes.flat] #惰性对象
print(len([* axes.flat])) #列表没有shape
[*enumerate(axes.flat)] #索引加内容的元组
for i,ax in [*enumerate(axes.flat)]:
ax.imshow(faces.images[i, :, :],cmap='gray') #选择色彩模式,灰色
print(fig)
print(axes) #axes和fig相互对应,一个框fig对应一个axes
axes[0][0].imshow(faces.images[0,:,:])
####开始降维
pca_face = PCA(150).fit(x1)
v = pca_face.components_
print(v.shape)
#可视化v
fig,axes = plt.subplots(3,6
,figsize=(8,4)
,subplot_kw={'xticks':[],'yticks':[]})
for i,ax in enumerate(axes.flat):
ax.imshow(v[i,:].reshape(62,47),cmap='gray')
案例二:降噪
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np
digits = load_digits()
def plot(data):
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.data)
##为图像数据添加噪音
rng = np.random.RandomState(42) #规定numpy 中的随机模式
#在指定的数据集中,随机抽取服从正态分布的数据。两个参数分别是指定的数据集,和抽取的正态分布的方差
noisy = rng.normal(digits.data,2)#从原有的数据集中随机地抽取一个满足正态分布的数据集,第一个参数是数据集,第二个参数是方差,如果方差越大那么随机抽取的数据越凌乱,与原数据的结构一致
plot(noisy)
#降维50%
pca = PCA(0.5,svd_solver='full').fit(noisy)
x_dd = pca.transform(noisy)
x_dd.shape
#转回原来的维度,可视化
without_noise = pca.inverse_transform(x_dd) ##必须转回去,因为plot函数的(m,n),n必须是64
plot(without_noise)
案例三:手写数据集
from sklearn.decomposition import PCA
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier as RFC
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
####导入数据
data = pd.read_csv('digit.csv')
x = data.iloc[:,1:]
y = data.iloc[:,0]
print(x.shape)#(42000, 784)
####画累计方差贡献率曲线,找最佳降维后维度的范围u
pca = PCA().fit(x) #默认参数,什么都不填数据最小维度(行42000、列784)————》784
plt.figure(figsize=(20,5))
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.plot(np.cumsum(pca.explained_variance_ratio_))
plt.xlabel('降维后的特征数目')
plt.ylabel('累计可解释性方差比例之和')
plt.show()
#####由上图可知数据集大概在特征数量为1-100之间特征比较有用,拉出来专门绘制
#####降维后的学习曲线,继续缩小最佳维度的范围
# 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=42),x_dr,y,cv=5).mean()
# score.append(once)
# plt.figure(figsize=[20,5])
# plt.plot(range(1,101,10),score)
# plt.xlabel('特征数')
# plt.ylabel('随机森林交叉验证分数')
# plt.show()
#####在20左右达到最高,之后平稳,所以取10-25
# score = []
# for i in range(10,25):
# x_dr = PCA(i).fit_transform(x)
# once = cross_val_score(RFC(n_estimators=10,random_state=42),x_dr,y,cv=5).mean()
# score.append(once)
# plt.figure(figsize=[20,5])
# plt.plot(range(10,25),score)
# plt.xlabel('特征数')
# plt.ylabel('随机森林交叉验证分数')
# plt.show()
###降到21维
x_dr = PCA(22).fit_transform(x)
# once = cross_val_score(RFC(n_estimators=10,random_state=42),x_dr,y,cv=5).mean()
# print(once) #0.9161428571428571
# once1 = cross_val_score(RFC(n_estimators=100,random_state=42),x_dr,y,cv=5).mean()
# print(once1) #0.9444761904761905
#####此时分数已经很高了,但是相距原来的96点多,还差一些
#由于已经降维到22维,所以考虑一下换模型KNN
from sklearn.neighbors import KNeighborsClassifier as KNN
# score_knn = cross_val_score(KNN(),x_dr,y,cv=5).mean
# print(score_knn) #0.9676 这里打印出来
# 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.xlabel('特征数')
# plt.ylabel('KNN交叉验证分数')
# plt.show() #取3的时候最大
# %%timeit #jupyter里计算时间
import time
start = time.time()
sc = cross_val_score(KNN(3),x_dr,y,cv=5).mean()
end = time.time()
print(sc) #0.9686666666666668
print(end-start)