目录
一.维度
二.sklearn中的降维算法
三.PCA与SVD
四.降维的实现
五.重要参数n_components
1.累积可解释方差贡献率曲线选择n_components
2.最大似然估计自选超参数
3.按信息量占比选超参数
六.PCA中的SVD
七.重要参数svd_solver 与 random_state
八.重要属性components_
九.重要接口inverse_transform
十.重要接口,参数和属性总结
1.pca参数列表
2.pca属性列表
3.PCA接口列表
十一.pca代码实现
十二.PCA对手写数字数据集的降维
对于数组和Series来说,维度就是功能shape返回的结果,shape中返回了几个数字,就是几维。
针对每一张表,维度指的是样本的数量或特征的数量,一般无特别说明,指的都是特征的数量。除了索引之外,一个特征是一维,两个特征是二维,n个特征是n维。
对图像来说,维度就是图像中特征向量的数量。
降维算法中的”降维“,指的是降低特征矩阵中特征的数量。降维的目的是为了让算法运算更快,效果更好,但其实还有另一种需求:数据可视化。
sklearn中降维算法都被包括在模块decomposition中,这个模块本质是一个矩阵分解模块。在过去的十年中,如果要讨论算法进步的先锋,矩阵分解可以说是独树一帜。矩阵分解可以用在降维,深度学习,聚类分析,数据预处理,低纬度特征学习,推荐系统,大数据分析等领域。
SVD和主成分分析PCA都属于矩阵分解算法中的入门算法,都是通过分解特征矩阵来进行降维.
在降维过程中,我们会减少特征的数量,这意味着删除数据,数据量变少则表示模型可以获取的信息会变少,模型的表现可能会因此受影响。同时,在高维数据中,必然有一些特征是不带有有效的信息的(比如噪音),或者有一些特征带有的信息和其他一些特征是重复的(比如一些特征可能会线性相关)。我们希望能够找出一种办法来帮助我们衡量特征上所带的信息量,让我们在降维的过程中,能够即减少特征的数量,又保留大部分有效信息——将那些带有重复信息的特征合并,并删除那些带无效信息的特征等等——逐渐创造出能够代表原特征矩阵大部分信息的,特征更少的,新特征矩阵。
在降维中,PCA使用的信息量衡量指标,就是样本方差,又称可解释性方差,方差越大,特征所带的信息量越多。
在步骤3当中,我们用来找出n个新特征向量,让数据能够被压缩到少数特征上并且总信息量不损失太多的技术就是矩阵分解。
PCA和SVD是两种不同的降维算法,但他们都遵从上面的过程来实现降维,只是两种算法中矩阵分解的方法不同,信息量的衡量指标不同罢了。PCA使用方差作为信息量的衡量指标,并且特征值分解来找出空间V。降维完成之后,PCA找到的每个新特征向量就叫做“主成分”,而被丢弃的特征向量被认为信息量很少,这些信息很可能就是噪音。
而SVD使用奇异值分解来找出空间V,其中Σ也是一个对角矩阵,不过它对角线上的元素是奇异值,这也是SVD中用来衡量特征上的信息量的指标。U和V^{T}分别是左奇异矩阵和右奇异矩阵,也都是辅助矩阵。
PCA和特征选择技术都是特征工程的一部分,它们有什么不同?
特征选择是从已存在的特征中选取携带信息最多的,选完之后的特征依然具有可解释性,我们依然知道这个特征在原数据的哪个位置,代表着原数据上的什么含义。
而PCA,是将已存在的特征进行压缩,降维完毕后的特征不是原本的特征矩阵中的任何一个特征,而是通过某些方式组合起来的新特征。通常来说,在新的特征矩阵生成之前,我们无法知晓PCA都建立了怎样的新特征向量,新特征矩阵生成之后也不具有可读性,我们无法判断新特征矩阵的特征是从原数据中的什么特征组合而来,新特征虽然带有原始数据的信息,却已经不是原数据上代表着的含义了。以PCA为代表的降维算法因此是特征创造(feature creation,或feature construction)的一种。
可以想见,PCA一般不适用于探索特征和标签之间的关系的模型(如线性回归),因为无法解释的新特征和标签之间的关系不具有意义。在线性回归模型中,我们使用特征选择。
n_components是我们降维后需要的维度,即降维后需要保留的特征数量,降维流程中第二步里需要确认的k值,一般输入[0, min(X.shape)]范围中的整数。一说到K,大家可能都会想到,类似于KNN中的K和随机森林中的
n_estimators,这是一个需要我们人为去确认的超参数,并且我们设定的数字会影响到模型的表现。如果留下的特征太多,就达不到降维的效果,如果留下的特征太少,那新特征向量可能无法容纳原始数据集中的大部分信息,因此,n_components既不能太大也不能太小。那怎么办呢?
可以先从我们的降维目标说起:如果我们希望可视化一组数据来观察数据分布,我们往往将数据降到三维以下,很多时候是二维,即n_components的取值为2。
当参数n_components中不填写任何值,则默认返回min(X.shape)个特征,一般来说,样本量都会大于特征数目,所以什么都不填就相当于转换了新特征空间,但没有减少特征的个数。一般来说,不会使用这种输入方式。但我们却可以使用这种输入方式来画出累计可解释方差贡献率曲线,以此选择最好的n_components的整数取值。
累积可解释方差贡献率曲线是一条以降维后保留的特征个数为横坐标,降维后新特征矩阵捕捉到的可解释方差贡献率为纵坐标的曲线,能够帮助我们决定n_components最好的取值。
除了输入整数,n_components还有哪些选择呢?之前我们提到过,矩阵分解的理论发展在业界独树一帜,勤奋智慧的数学大神Minka, T.P.在麻省理工学院媒体实验室做研究时找出了让PCA用最大似然估计(maximum likelihood estimation)自选超参数的方法,输入“mle”作为n_components的参数输入,就可以调用这种方法。
输入[0,1]之间的浮点数,并且让参数svd_solver =='full',表示希望降维后的总解释性方差占比大于n_components 指定的百分比,即是说,希望保留百分之多少的信息量。比如说,如果我们希望保留97%的信息量,就可以输入n_components = 0.97,PCA会自动选出能够让保留的信息量超过97%的特征数量。
细心的小伙伴可能注意到了,svd_solver是奇异值分解器的意思,为什么PCA算法下面会有有关奇异值分解的参数?不是两种算法么?我们之前曾经提到过,PCA和SVD涉及了大量的矩阵计算,两者都是运算量很大的模型,但其实,SVD有一种惊人的数学性质,即是它可以跳过数学神秘的宇宙,不计算协方差矩阵,直接找出一个新特征向量组成的n维空间,而这个n维空间就是奇异值分解后的右矩阵.
右奇异矩阵有着如下性质:
就是n_components,是我们降维后希望得到的维度。若X为(m,n)的特征矩阵,vt就是结构为(n,n)的矩阵,取这个矩阵的前k行(进行切片),即将V转换为结构为(k,n)的矩阵。而$V_{(k,n)}^T$与原特征矩阵X相乘,即可得到降维后的特征矩阵X_dr。这是说,奇异值分解可以不计算协方差矩阵等等结构复杂计算冗长的矩阵,就直接求出新特征空间和降维后的特征矩阵。
简而言之,SVD在矩阵分解中的过程比PCA简单快速,虽然两个算法都走一样的分解流程,但SVD可以作弊耍赖直接算出V。但是遗憾的是,SVD的信息量衡量指标比较复杂,要理解”奇异值“远不如理解”方差“来得容易,因此,sklearn将降维流程拆成了两部分:一部分是计算特征空间V,由奇异值分解完成,另一部分是映射数据和求解新特征矩阵,由主成分分析完成,实现了用SVD的性质减少计算量,却让信息量的评估指标是方差,具体流程如下图:
通过SVD和PCA的合作,sklearn实现了一种计算更快更简单,但效果却很好的“合作降维“。很多人理解SVD,是把SVD当作PCA的一种求解方法,其实指的就是在矩阵分解时不使用PCA本身的特征值分解,而使用奇异值分解来减少计算量。这种方法确实存在,但在sklearn中,矩阵U和Σ虽然会被计算出来(同样也是一种比起PCA来说简化非常多的数学过程,不产生协方差矩阵),但完全不会被用到,也无法调取查看或者使用,因此我们可以认为,U和Σ在fit过后就被遗弃了。奇异值分解追求的仅仅是V,只要有了V,就可以计算出降维后的特征矩阵。在transform过程之后,fit中奇异值分解的结果除了V(k,n)以外,就会被舍弃,而V(k,n)会被保存在属性components_ 当中,可以调用查看。
svd_solver是在降维过程中,用来控制矩阵分解的一些细节的参数。有四种模式可选:"auto", "full", "arpack", "randomized",默认”auto"。
"auto":基于X.shape和n_components的默认策略来选择分解器:如果输入数据的尺寸大于500x500且要提取的特征数小于数据最小维度min(X.shape)的80%,就启用效率更高的”randomized“方法。否则,精确完整的SVD将被计算,截断将会在矩阵被分解完成后有选择地发生
"full":从scipy.linalg.svd中调用标准的LAPACK分解器来生成精确完整的SVD,适合数据量比较适中,计算时间充足的情况,生成的精确完整的SVD的结构为:
"arpack":从scipy.sparse.linalg.svds调用ARPACK分解器来运行截断奇异值分解(SVD truncated),分解时就将特征数量降到n_components中输入的数值k,可以加快运算速度,适合特征矩阵很大的时候,但一般用于特征矩阵为稀疏矩阵的情况,此过程包含一定的随机性。截断后的SVD分解出的结构为:
"randomized",通过Halko等人的随机方法进行随机SVD。在"full"方法中,分解器会根据原始数据和输入的n_components值去计算和寻找符合需求的新特征向量,但是在"randomized"方法中,分解器会先生成多个随机向量,然后一一去检测这些随机向量中是否有任何一个符合我们的分解需求,如果符合,就保留这个随机向量,并基于这个随机向量来构建后续的向量空间。这个方法已经被Halko等人证明,比"full"模式下计算快很多,并且还能够保证模型运行效果。适合特征矩阵巨大,计算量庞大的情况。
而参数random_state在参数svd_solver的值为"arpack" or "randomized"的时候生效,可以控制这两种SVD模式中的随机模式。通常我们就选用”auto“,不必对这个参数纠结太多。
现在我们了解了,V(k,n)是新特征空间,是我们要将原始数据进行映射的那些新特征向量组成的矩阵。我们用它来计算新的特征矩阵,但我们希望获取的毕竟是X_dr,为什么我们要把V(k,n)这个矩阵保存在n_components这个属性当中来让大家调取查看呢?
我们之前谈到过PCA与特征选择的区别,即特征选择后的特征矩阵是可解读的,而PCA降维后的特征矩阵式不可解读的:PCA是将已存在的特征进行压缩,降维完毕后的特征不是原本的特征矩阵中的任何一个特征,而是通过某些方式组合起来的新特征。通常来说,在新的特征矩阵生成之前,我们无法知晓PCA都建立了怎样的新特征向量,新特征矩阵生成之后也不具有可读性,我们无法判断新特征矩阵的特征是从原数据中的什么特征组合而来,新特征虽然带有原始数据的信息,却已经不是原数据上代表着的含义了。
但是其实,在矩阵分解时,PCA是有目标的:在原有特征的基础上,找出能够让信息尽量聚集的新特征向量。在sklearn使用的PCA和SVD联合的降维方法中,这些新特征向量组成的新特征空间其实就是V(k,n)。当V(k,n)是数字时,我们无法判断V(k,n)和原有的特征究竟有着怎样千丝万缕的数学联系。但是,如果原特征矩阵是图像,V(k,n)这个空间矩阵也可以被可视化的话,我们就可以通过两张图来比较,就可以看出新特征空间究竟从原始数据里提取了什么重要的信息。
inverse_transform,可以将我们归一化,标准化,甚至做过哑变量的特征矩阵还原回原始数据中的特征矩阵,这几乎在向我们暗示,任何有inverse_transform这个接口的过程都是可逆的。PCA应该也是如此。
人脸识别是最容易的,用来探索inverse_transform功能的数据。我们先调用一组人脸数据X(m,n),对人脸图像进行绘制,然后我们对人脸数据进行降维得到X_dr,之后再使用inverse_transform(X_dr)返回一个X_inverse(m,n),并对这个新矩阵中的人脸图像也进行绘制。如果PCA的降维过程是可逆的,我们应当期待X(m,n)和X_inverse(m,n) 返回一模一样的图像,即携带一模一样的信息。
由降维后再通过inverse_transform转换回原维度的数据画出的图像和原数据画的图像大致相似,但原数据的图像明显更加清晰。这说明,inverse_transform并没有实现数据的完全逆转。这是因为,在降维的时候,部分信息已经被舍弃了,X_dr中往往不会包含原数据100%的信息,所以在逆转的时候,即便维度升高,原数据中已经被舍弃的信息也不可能再回来了。所以,降维不是完全可逆的。
Inverse_transform的功能,是基于X_dr中的数据进行升维,将数据重新映射到原数据所在的特征空间中,而并非恢复所有原有的数据。
降维的目的之一就是希望抛弃掉对模型带来负面影响的特征,而我们相信,带有效信息的特征的方差应该是远大于噪音的,所以相比噪音,有效的特征所带的信息应该不会在PCA过程中被大量抛弃。inverse_transform能够在不恢复原始数据的情况下,将降维后的数据返回到原本的高维空间,即是说能够实现”保证维度,但去掉方差很小特征所带的信息“。利用inverse_transform的这个性质,我们能够实现噪音过滤。
重要参数参数n_components,svd_solver,random_state,三个重要属性:components_, explained_variance_以及explained_variance_ratio_,无数次用到了接口fit,transform,fit_transform,与众不同的重要接口inverse_transform。
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
iris = load_iris()
y = iris.target
X = iris.data
#作为数组,X是几维?
print(X.shape)#(150, 4)
#作为数据表或特征矩阵,X是几维?
import pandas as pd
print(pd.DataFrame(X).head())
# 调用PCA
pca = PCA(n_components=2) # 实例化,n_components指定降为几维
pca = pca.fit(X) # 拟合模型
X_dr = pca.transform(X) # 获取新矩阵
print(X_dr)
# 也可以fit_transform一步到位
# X_dr = PCA(2).fit_transform(X)
# plt.figure()
# plt.scatter(X_dr[y==0, 0], X_dr[y==0, 1], c="red", label=iris.target_names[0])#散点图
# plt.scatter(X_dr[y==1, 0], X_dr[y==1, 1], c="black", label=iris.target_names[1])
# plt.scatter(X_dr[y==2, 0], X_dr[y==2, 1], c="orange", label=iris.target_names[2])
# plt.legend()
# plt.title('PCA of IRIS dataset')
# plt.show()
# colors = ['red', 'black', 'orange']
# print(iris.target_names)
# plt.figure()
# for i in [0, 1, 2]:
# plt.scatter(X_dr[y == i, 0]
# , X_dr[y == i, 1]
# , alpha=.7 # 指画出的图像的透明度
# , c=colors[i]
# , label=iris.target_names[i]
# )
# plt.legend() # 图例
# plt.title('PCA of IRIS dataset')
# plt.show()
# print(pca.explained_variance_)#查看方差是否从大到小排列,第一个最大,依次减小 array([4.22824171, 0.24267075]),属性explained_variance_,查看降维后每个新特征向量上所带的信息量大小(可解释性方差的大小)
# print(pca.explained_variance_ratio_) # array([0.92461872, 0.05306648]),属性explained_variance_ratio,查看降维后每个新特征向量所占的信息量占原始数据总信息量的百分比,又叫做可解释方差贡献率,大部分信息都被有效地集中在了第一个特征上
# print(pca.explained_variance_ratio_.sum()) # 0.977685206318795
# import numpy as np
# pca_line = PCA().fit(X)
# # pca_line.explained_variance_ratio_#array([0.92461872, 0.05306648, 0.01710261, 0.00521218])
# plt.plot([1,2,3,4],np.cumsum(pca_line.explained_variance_ratio_))#np.cumsum能对数据进行累加
# plt.xticks([1,2,3,4]) #这是为了限制坐标轴显示为整数
# plt.xlabel("number of components after dimension reduction")
# plt.ylabel("cumulative explained variance ratio")
# plt.show()
# pca_mle = PCA(n_components="mle") # mle缺点计算量大
# pca_mle = pca_mle.fit(X)
# X_mle = pca_mle.transform(X)
# print(X_mle) # 3列的数组,可以发现,mle为我们自动选择了3个特征
# print(pca_mle.explained_variance_ratio_.sum()) # 0.9947878161267247
# # 得到了比设定2个特征时更高的信息含量,对于鸢尾花这个很小的数据集来说,3个特征对应这么高的信息含量,并不需要去纠结于只保留2个特征,毕竟三个特征也可以可视化
# pca_f = PCA(n_components=0.97,svd_solver="full")#svd_solver="full"不能省略,svd_solver是奇异值分解器,使用了奇异值分解
# pca_f = pca_f.fit(X)
# X_f = pca_f.transform(X)
# print(X_f)
# print(pca_f.explained_variance_ratio_)#array([0.92461872, 0.05306648])
# #X.shape()#(m,n)
# print(PCA(2).fit(X).components_.shape)#(2, 4)
# print(PCA(2).fit(X).components_)#新特征空间V(k,n)
# # array([[ 0.36138659, -0.08452251, 0.85667061, 0.3582892 ],
# # [ 0.65658877, 0.73016143, -0.17337266, -0.07548102]])
from sklearn.datasets import fetch_lfw_people#7个人的1000多张人脸图片组成的一组人脸数据
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np
faces = fetch_lfw_people(min_faces_per_person=60)#实例化 min_faces_per_person=60:每个人取出60张脸图
print(faces)#一个字典形式的数据
print(faces.images.shape)#(1277,62,47) 1277是矩阵中图像的个数,62是每个图像的特征矩阵的行,47是每个图像的特征矩阵的列
#怎样理解这个数据的维度?
print(faces.data.shape)#(1277,2914) 行是样本,列是样本相关的所有特征:2914 = 62 * 47
#换成特征矩阵之后,这个矩阵是什么样?
X = faces.data
# 数据本身是图像,和数据本身只是数字,使用的可视化方法不同
# 创建画布和子图对象
# fig, axes = plt.subplots(4, 5 # 4行5列个图,subplots是专门用来画子图的
# , figsize=(8, 4) # figsize指的是图的尺寸,横向是8,纵向是4
# , subplot_kw={"xticks": [], "yticks": []} # 不要显示坐标轴,xticks表示横坐标,yticks表示纵坐标
# )
# print(fig) # 指的是画布
# print(axes)
# 不难发现,axes中的一个对象对应fig中的一个空格
# 我们希望,在每一个子图对象中填充图像(共24张图),因此我们需要写一个在子图对象中遍历的循环
# print(axes.shape) # (4,5)
# 二维结构,可以有两种循环方式,一种是使用索引,循环一次同时生成一列上的四个图
# 另一种是把数据拉成一维,循环一次只生成一个图
# 在这里,究竟使用哪一种循环方式,是要看我们要画的图的信息,储存在一个怎样的结构里
# 我们使用 子图对象.imshow 来将图像填充到空白画布上
# 而imshow要求的数据格式必须是一个(m,n)格式的矩阵,即每个数据都是一张单独的图
# 因此我们需要遍历的是faces.images,其结构是(1277, 62, 47)
# 要从一个数据集中取出24个图,明显是一次性的循环切片[i,:,:]来得便利
# 因此我们要把axes的结构拉成一维来循环
# print([*axes.flat]) # 降低一个维度
# [*axes.flat] #1维
# print(enumerate(axes.flat))#enumerate将数字和对象组成一个个元组
# 填充图像
# for i, ax in enumerate(axes.flat):#画图,填充对象
# ax.imshow(faces.images[i, :, :]#画图的时候用faces.images
# , cmap="gray" # 选择色彩的模式
# )
# plt.show()
# cmap参数取值选择各种颜色:https://matplotlib.org/tutorials/colors/colormaps.html
# #原本有2900维,我们现在来降到150维
# pca = PCA(150).fit(X)#这里X = faces.data,不是faces.images.shape ,因为sklearn只接受2维数组降,不接受高维数组降
# # x_dr = pca.transform(X)
# # x_dr.shape#(1277,150)
# V = pca.components_#新特征空间
# print(V.shape)#V(k,n) (150, 2914)
# fig, axes = plt.subplots(3, 8, figsize=(8, 4), subplot_kw={"xticks": [], "yticks": []})#创建画布和子图对象
# for i, ax in enumerate(axes.flat):#填充对象
# ax.imshow(V[i, :].reshape(62, 47), cmap="gray")
# plt.show()
# from sklearn.datasets import fetch_lfw_people
# from sklearn.decomposition import PCA
# import matplotlib.pyplot as plt
# import numpy as np
# faces = fetch_lfw_people(min_faces_per_person=60)
# print(faces.images.shape)
# #怎样理解这个数据的维度?
# print(faces.data.shape)
# #换成特征矩阵之后,这个矩阵是什么样?
# X = faces.data
# pca = PCA(150)#实例化
# X_dr = pca.fit_transform(X)#拟合+提取结果,传入的是二维的,不能传入三维的
# print(X_dr.shape)
# X_inverse = pca.inverse_transform(X_dr)
# print(X_inverse.shape) # (1348, 2914)
# print(faces.images.shape) # (1348, 62, 47)
# fig, ax = plt.subplots(2, 10, figsize=(10, 2.5)#建画布,ax是对象,fig是画布,填充用对象
# , subplot_kw={"xticks": [], "yticks": []}
# )
# # 和2.3.3节中的案例一样,我们需要对子图对象进行遍历的循环,来将图像填入子图中
# # 那在这里,我们使用怎样的循环?
# # 现在我们的ax中是2行10列,第一行是原数据,第二行是inverse_transform后返回的数据
# # 所以我们需要同时循环两份数据,即一次循环画一列上的两张图,而不是把ax拉平
# for i in range(10):#填充图像
# ax[0, i].imshow(faces.images[i, :, :], cmap="binary_r")
# ax[1, i].imshow(X_inverse[i].reshape(62, 47), cmap="binary_r")#还是会损失掉一些数据量的
# plt.show()
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np
digits = load_digits()
print(digits.data.shape)#(1797, 64)
print(set(digits.target.tolist()))#查看target有哪几个数 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
print(digits.images.shape)#(1797, 8, 8)
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)
# plt.show()
rng = np.random.RandomState(42)#规定numpy中的随机模式
# 在指定的数据集中,随机抽取服从正态分布的数据
# 两个参数,分别是指定的数据集,和抽取出来的正太分布的方差
noisy = rng.normal(digits.data, 2) # np.random.normal(digits.data,2),制造噪音
# plot_digits(noisy)
# plt.show()
pca = PCA(0.5,svd_solver='full').fit(noisy)#降噪
X_dr = pca.transform(noisy)
print(X_dr.shape)#(1797, 6)
without_noise = pca.inverse_transform(X_dr)
plot_digits(without_noise)
plt.show()
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"./digit recognizor.csv")
X = data.iloc[:, 1:]
y = data.iloc[:, 0]
print(X.shape) # (42000, 784)
# pca_line = PCA().fit(X)#n_edtimators默认为784
# 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 ratio")
# plt.show()
# ======【TIME WARNING:2mins 30s】======#
# 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.show()
# score = []
# for i in range(10,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(10,25),score)
# plt.show()
#
X_dr = PCA(22).fit_transform(X)
# # ======【TIME WARNING:1mins 30s】======#
# cross_val_score(RFC(n_estimators=100, random_state=0), X_dr, y, cv=5).mean() # 0.946524472295366
from sklearn.neighbors import KNeighborsClassifier as KNN
print(cross_val_score(KNN(),X_dr,y,cv=5).mean())#KNN()的值不填写默认=5 0.9698566872605972
#======【TIME WARNING: 】======#
score = []
for i in range(10):
X_dr = PCA(22).fit_transform(X)
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.show()
cross_val_score(KNN(4), X_dr, y, cv=5).mean() # KNN()的值不填写默认=5
# =======【TIME WARNING: 3mins】======#
# %%timeit
cross_val_score(KNN(4), X_dr, y, cv=5).mean()