数据预处理
数据无量纲化
在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布的需求,这种需求统称为将数据“无量纲化”。比如梯度和矩阵为核心的算法中,对于逻辑回归,支持向量机,神经网络等,无量纲化可以加快求解速度;而在距离类模型,比如K近邻,K-Means聚类中,无量纲化可以帮我们提升模型精度,避免某一个取值范围特别大的特征对距离计算造成影响。一个特例是决策树和树的集成算法们,对决策树我们不需要无量纲化,决策树可以把任意数据都处理得很好。
线性的无量纲化包括中心化处理和缩放处理。中心化的本质是让所有记录减去一个固定值,即让样本数据平移到某个位置。缩放的本质是通过除以一个固定值,让数据固定在某个范围之中,取对数也算是一种缩放处理。
数据归一化
当数据(x)按照最小值中心化后,再按极差(最大值-最小值)缩放,数据移动了最小值个单位,并且会被收敛到[0,1]之间,这个过程就叫做数据归一化。
data=[[-1,2],[-0.5,6],[0,10],[1,18]]
import numpy as np
X=np.array(data)
X
#使用numpy来实现归一化
X_nor=(X-X.min(axis=0))/(X.max(axis=0)-X.min(axis=0))
X_nor
import pandas as pd
x=pd.DataFrame(data)
x_nor=(x-x.min())/(x.max()-x.min())
from sklearn.preprocessing import MinMaxScaler
scaler=MinMaxScaler()
scaler=scaler.fit(data) #fit,在这里本质是生成min(x)和max(x)
result=scaler.transform(data)
result_=scaler.fit_transform(data)
scaler.inverse_transform(result)
#使用MinMaxScaler的参数feature_range实现将数据归一化到[0,1]以外的范围中
scaler=MinMaxScaler(feature_range=[5,10])
result=scaler.fit_transform(data)
result
#当X中的特征数量非常多的时候,fit会报错并表示,数据量太大了计算不了,此时使用partial_fit作为训练接口
scaler=scaler.partial_fit(data)
数据标准化
当数据(x)按均值(μ)中心化后,再按标准差(σ)缩放,数据就变成满足均值为0,方差为1的分布,而这个过程,就叫做数据标准化。
from sklearn.preprocessing import StandardScaler
data=[[-1,2],[-0.5,6],[0,10],[1,18]]
scaler=StandardScaler() #实例化
scaler.fit(data) #fit,本质是生成均值和方差
scaler.mean_ #查看均值的属性mean_
scaler.var_ #查看方差的属性var_
x_std=scaler.transform(data) #通过接口到处结果
x_std.mean() #导出的结果时一个数组,用mean()查看均值
x_std.std() #用std()查看方差
scaler.fit_transform(data)
scaler.inverse_transform(x_std)
对于StandardScaler和MinMaxScaler来说,空值NaN会被当做是缺失值,在fit的时候忽略,在transform的时候保持缺失NaN的状态显示。并且,尽管去量纲化过程不是具体的算法,但在fit接口中,依然只允许导入至少二维数组,一维数组导入会报错。
大多数机器学习算法中,会选择StandardScaler来进行特征缩放,因为MinMaxScaler对异常值非常敏感。在PCA,聚类,逻辑回归,支持向量机,神经网络这些算法中,StandardScaler往往是最好的选择。
MinMaxScaler在不涉及距离度量、梯度、协方差计算以及数据需要被压缩到特定区间时使用广泛,比如数字图像处理中量化像素强度时,都会使用MinMaxScaler将数据压缩于[0,1]区间之中。
缺失值
impute.SimpleImputer
class sklearn.impute.SimpleImputer(missing_values=nan,strategy='mean',fill_value=None,verbose=0,copy=True)
import pandas as pd
data=pd.read_csv('Narrativedata.csv')
data.head()
data.isnull().sum()
Age=data.loc[:,'Age'].values.reshape(-1,1)
Age[:20]
from sklearn.impute import SimpleImputer
imp_mean=SimpleImputer() #实例化,默认均值填补
imp_median=SimpleImputer(strategy='median') #用中位数填补
imp_0=SimpleImputer(strategy='constant',fill_value=0)
#fit_transform 一步完成调取结果
imp_mean=imp_mean.fit_transform(Age)
imp_median=imp_median.fit_transform(Age)
imp_0=imp_0.fit_transform(Age)
imp_mean[:20]
imp_median[:20]
imp_0[:20]
#在这里我们使用中位数填补Age
data.loc[:,'Age']=imp_median
#使用众数填补Embarked
Embarked=data.loc[:,'Embarked'].values.reshape(-1,1)
imp_mode=SimpleImputer(strategy='most_frequent')
data.loc[:,'Embarked']=imp_mode.fit_transform(Embarked)
#用Pandas和Numpy进行填补其实更加简单
import pandas as pd
data=pd.read_csv('Narrativedata.csv')
data.head()
data.loc[:,'Age']=data.loc[:,'Age'].fillna(data.loc[:,'Age'].median())
data.dropna(axis=0,inplace=True)
#.dropna(axis=0)删除所有有缺失值的行,.dropna(axis=1)删除所有有缺失值的列
#参数inplace,为True表示在原数据集上进行修改,为False表示生成一个复制对象,不修改原数据,默认为False
处理分类型特征:编码与哑变量
将数据进行编码,即是说,将文字性数据转换为数值型。
from sklearn.preprocessing import LabelEncoder
y=data.iloc[:,-1] #要输入的是标签,不是特征矩阵,所以允许一维
le=LabelEncoder() #实例化
le=le.fit(y) #导入数据
label=le.transform(y) #transform接口调取结果
data.iloc[:,-1]=label
data.head()
#查看相关属性
le.classes_ #属性.classes_查看标签中究竟有多少类别
le.fit_transform(y)
le.inverse_transform(label)
preprocessing.OrdinalEncoder:特征专用,能够将分类特征转换为分类数值
from sklearn.preprocessing import OrdinalEncoder
data_=data.copy()
data_.iloc[:,1:-1]=OrdinalEncoder().fit_transform(data_.iloc[:,1:-1])
OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_
data_.head()
preprocessing.OneHotEncoder:独热编码,创建哑变量
变量分为名义变量(相互独立,彼此之间完全没有联系)、有序变量(三种取值不是完全独立,但取值之间却不可以计算)
类别OrdinalEncoder可以用来处理有序变量,但对于名义变量,我们只有使用哑变量的方式来处理,才能够尽量想算法传达最准确的信息。
from sklearn.preprocessing import OneHotEncoder
X=data.iloc[:,1:-1]
result=OneHotEncoder(categories='auto').fit_transform(X).toarray() #进行独热编码
newdata=pd.concat([data,pd.DataFrame(result)],axis=1)
newdata.drop(['Sex','Embarked'],axis=1,inplace=True)
newdata.columns=['Age','Survived','Female','Male','Embarked_C','Embarked_Q','Embarked_S']
newdata.head()
#获取模型特征名
enc=OneHotEncoder(categories='auto').fit(X)
re=enc.transform(X).toarray()
pd.DataFrame(enc.inverse_transform(re))
#获取模型特征名
enc.get_feature_names()
#合并原数据和独热编码
df=pd.concat([data,pd.DataFrame(re)],axis=1) #axis=1,表示跨行进行合并,也就是将量表左右相连,如果是axis=0,就是将量表上下相连
df.head()
特征可以做哑变量,标签类可以使用类sklearn.preprocessing.LabelBinarizer做标签哑变量。
处理连续型特征:二值化与分段
preprocessing.Binarizer
根据阈值将数据二值化(将特征值设置为0或1),用于处理连续型变量。大于阈值的值映射为1,而小于或等于阈值的值映射为0。默认阈值为0时,特征中所有的正值都映射到1。二值化是对文本计数数据的常见操作,分析人员可以决定仅考虑某种现象的存在与否。它还可以用作考虑布尔随机变量的估计器的预处理步骤(例如,使用贝叶斯设置中的伯努利分布建模)。
#将年龄二值化
data_2=data.copy()
from sklearn.preprocessing import Binarizer
X=data_2.iloc[:,0].values.reshape(-1,1) #类为特征专用,所以不能使用一维数组
transformer=Binarizer(threshold=30).fit_transform(X)
preprocessing.KBinsDiscretizer
这是将连续型变量划分为分类变量的类,能否将连续变量排序后按顺序分箱后编码。总共包含三个重要参数。
n_bins:每个特征中分箱的个数,默认5,一次会被运用到所有导入的特征。
encode:编码的方式,默认'onehot'
‘onehot':做哑变量,之后返回一个稀疏矩阵,每一列是一个特征中得一个类别,含有该类别的样本表示为1,不含的表示为0。
'ordinal':每个特征的每个箱都被编码为一个整数,返回每一列是一个特征,每个特征下含有不同整数编码的箱的矩阵。
‘onehot-dense’:做哑变量,之后返回一个密集数组。
strategy:用来定义箱宽的方式,默认‘quantile’
'uniform':表示等宽分箱,即每个特征中的每个箱的最大值之间的差为 (特征.max()-特征.min())/(n_bins)
'quantile':表示等位分箱,即每个特征中的每个箱内的样本数量都相同
‘kmeans’:表示按聚类分箱,每个箱中的值到最近的一维k均值聚类的簇心的距离都相同
from sklearn.preprocessing import KBinsDiscretizer
X=data.iloc[:,0].values.reshape(-1,1)
est=KBinsDiscretizer(n_bins=3,encode='ordinal',strategy='uniform')
est.fit_transform(X)
#查看转化后分的箱:变成了一列中的三箱
set(est.fit_transform(X).ravel())
est=KBinsDiscretizer(n_bins=3,encode='onehot',strategy='uniform')
est.fit_transform(X).toarray().sum(0)
特征选择
当数据处理完成后,我们就要开始进行特征工程了。
特征提取:从文字、图像、声音等其他非结构化信息中提取新信息作为特征。比如说,从淘宝宝贝的名称中提取出产品类别,产品颜色,是否是网红产品等。
特征选择:从所有的特征中,选择出有意义,对模型有帮助的特征,以避免必须将所有特征都导入模型中去训练的情况。
特征创造:把现有特征进行组合,或相互计算,得出新的特征。如果我们有一列特征是距离,一列特征是速度,我们就可以通过让两列相除,创造新的特征:通过距离所花的时间。其实,大多数的降维算法都是在做特征创造
特征工程第一步是理解业务,那如果遇到极端情况,我们无法依赖对业务的理解来选择特征,有四种方法可以用来选择特征:过滤法,嵌入法,包装法和降维法
#导入数据,让我们使用digit recognizor数据来一展身手
import pandas as pd
data=pd.read_csv(r'D:\CDA\机器学习2\辅助资料\digit recognizor.csv')
data.shape
X=data.iloc[:,1:]
y=data.iloc[:,0]
X.shape
Filter过滤法:过滤方法通常用作预处理步骤,特征选择完全独立于任何机器学习算法。它是根据各种统计检验中的分数以及相关性的各项指标来选择特征。
全部特征——>最佳特征子集——>算法——>模型评估
1.1方差过滤
VarianceThreshold
fit(X):用特征矩阵X训练模型
transform(X):将挑选出满足要求的特征矩阵
fit_transform(X):用原特征矩阵训练模型,然后保留满足要求的特征并返回
get_params():返回模型中的参数值
get_support(indices=False):-indices=False,返回长度与X特征数相同的布尔数组,满足要求的为True;-indices=True,返回满足要求的特征的索引
inverse_transform(X):逆转训练结果
这是通过特征本身的方差来筛选特征的类。比如一个特征本身的方差很小,就表示样本你在这个特征上没有差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区别没有什么作用,所以要优先消除方差为0的特征。VarianceThreshold有重要参数threshold,表示方差的阈值,表示舍弃所有方差小于threshold的特征,不填默认为0,即删除所有记录都相同的特征。
from sklearn.feature_selection import VarianceThreshold
VTS=VarianceThreshold() #实例化,不填参数默认方差为0
X_var0=VTS.fit_transform(X) #获取删除不合格之后的新特征矩阵
X_var0.shape
如果我们知道我们需要多少个特征,方差也可以帮助我们将特征选择一步到位。比如说,我们希望留下一半的特征,那可以设定一个让特征总数减半的方差阈值,只要找到特征方差的中位数,再将这个中位数作为参数threshol的值输入就好:
import numpy as np
X_fsvar=VarianceThreshold(np.median(X.var().values)).fit_transform(X)
X_fsvar.shape
查看哪些特征被保留下来
from sklearn.feature_selection import VarianceThreshold
#训练模型
VTS=VarianceThreshold(np.median(X.var().values)) #实例化
VTS=VTS.fit(X) #训练模型
X_fsvar=VTS.transform(X) #将X降维,只保留需要的特征
#查看模型相关接口
VTS.get_support(indices=False)
VTS.get_support(indices=True) #返回被留下的特征的索引
#提取出满足要求的特征矩阵
#以下两种表达都可以
X.columns[VTS.get_support(indices=False)]
X.columns[VTS.get_support(indices=True)]
X.iloc[:,VTS.get_support(indices=True)]
X.iloc[:,VTS.get_support()]
小结:过滤法的主要对象是:需要遍历特征或升维的算法们,主要目的是,在维持算法表现的前提下,帮助算法们降低计算成本。
1.2.相关性过滤
我们希望选出与标签相关且有意义的特征,因为这样的特征能够为我们提供大量信息,如果特征与标签无关,只会浪费计算内存,还会给模型带来噪音。在sklearn中,我们有三种常用的方法来评判特征与标签之间的相关性:卡方、F检验、互信息
卡方过滤
卡方过滤是专门针对离散型标签(即分类问题)的相关性过滤。卡方检验类feature_selection.chi2计算每个非负特征和标签之间的卡方统计量,并按照卡方统计量由高到低为特征排名。再结合feature_selection.SelectKBest这个可以输入‘评分标准’来选出前K个分数最高的特征的类,我们可以借此除去最可能独立于标签,与我们分类目的无关的特征。
from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.model_selection import cross_val_score
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
X_fschi=SelectKBest(chi2,k=300).fit_transform(X_fsvar,y)
X_fschi.shape
cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()
chi2val,pval=chi2(X_fsvar,y)
chi2val
pval
#在卡方检验结果中,卡方值越大,P值越小,原假设H0的拒绝程度越大,也就是特征与标签无关的概率越低
k=chi2val.shape[0]-(pval>0.05).sum()
F检验
F检验,又称ANOVA,方差齐性检验,是用来捕捉每个特征与标签之间的线性关系的过滤方法。它即可以做回归也可以做分类,因此包含feature_selection.f_classif(F检验分类)和feature_selection.f_regression(F检验回归)两个类。其中F检验分类用于标签是离散型变量的数据,而F检验回归用于标签是连续型变量的数据
需要注意的是,F检验在数据服从正态分布时效果会非常稳定,因此如果使用F检验过滤,我们会先将数据转换成服从正态分布的方式
from sklearn.feature_selection import f_classif
F,pval_f=f_classif(X_fsvar,y)
F
pval_f
k=F.shape[0]-(pval_f>0.05).sum()
互信息法
互信息法是用来捕捉每个特征与标签之间的任意关系(包括线性和非线性关系)的过滤方法。和F检验相似,它既可以做回归也可以做分类,并且包含两个类feature_selection.mutual_info_classif(互信息分类)和feature_selection.mutual_info_regression(互信息回归)。这两个类的用法和参数都和F检验一模一样,不过互信息法比F检验更加强大,F检验只能够找出线性关系,而互信息法可以找出任意关系。
互信息法不返回p值或F值类似的统计量,它返回‘每个特征与目标之间的互信息量的估计’,这个估计量在[0,1]之间取值,为0则表示两个变量独立,为1则表示两个变量完全相关。
from sklearn.feature_selection import mutual_info_classif as MIC
result=MIC(X_fsvar,y)
k=result.shape[0]-sum(result<=0)
2.2 Embedded嵌入法
嵌入法是一种让算法自己决定使用哪些特征的方法,即特征选择和算法训练同时进行。在使用嵌入法时,我们先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据权值系数从大到小选择特征。这些权值系数往往代表了特征对于模型的某种贡献或某种重要性,比如决策树和树的集成模型中的feature_importances_属性,可以列出各个特征对树的建立的贡献,我们就可以基于这种贡献的评估,找出对模型建立最有用的特征。
feature_selection.SelectFromModel
class sklearn.feature_selection.SelectFromModel(estimator,threshold=None,prefit=False,norm_order=1,max_feature=None)
SelectFromModel是一个元变换器,可以与任何在拟合后具有coef_,feature_importances_属性或参数中可选惩罚项的评估器一起使用(比如随机森林和树模型就具有属性feature_importances_,逻辑回归就带有l1和l2惩罚项,线性支持向量机也支持l2惩罚项)
对于有feature_importances_的模型来说,若重要性低于提供的阈值参数,则认为这些特征不重要并被移除。
使用惩罚项的模型的嵌入法
而对于使用惩罚项的模型来说,正则化惩罚项越大,特征在模型中对应的系数就会越小,当正则化惩罚项大到一定的程度的时候,部分特征系数就会变成0,当正则化惩罚项继续增大到一定程度时,所有的特征系数都会趋于0。但是我们会发现一部分特征系数会更容易先变成0,这部分系数是可以筛掉的,也就是说,我们选择特征系数较大的特征。
另外,支持向量机和逻辑回归使用参数C来控制返回的特征矩阵的稀疏性,参数C越小,返回特征越少。Lasso回归,用alpha参数来控制返回的特征矩阵,alpha的值越大,返回的特征越少。
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier as RFC
RFC_=RFC(n_estimators=10,random_state=0)
X_embedded=SelectFromModel(RFC_,threshold=0.005).fit_transform(X,y)
X_embedded.shape
#模型的维度明显被降低了
#同样的,我们也可以画学习曲线来找最佳阈值
import numpy as np
import matplotlib.pyplot as plt
RFC_.fit(X,y).feature_importances_
threshold=np.linspace(0,(RFC_.fit(X,y).feature_importances_).max(),20)
score=[]
for i in threshold:
X_embedded=SelectFromModel(RFC_,threshold=i).fit_transform(X,y)
once=cross_val_score(RFC_,X_embedded,y,cv=5).mean()
score.append(once)
plt.plot(threshold,score)
plt.show()
在嵌入法下,我们很容易就能够实现特征选择的目标:减少计算量,提升模型表现,然而在算法本身很复杂的时候,过滤法的计算远远比嵌入法要快,所以大型数据中,我们还是会优先考虑过滤法。
Wrapper包装法
包装法也是一个特征选择和算法训练同时进行的方法,与嵌入法十分相似,但不同的是,我们往往使用一个目标函数作为黑盒来帮助我们选取特征,而不是自己输入某个评估指标或统计量的阈值。包装法在初始特征集上训练评估器,并且通过coef_属性或通过feature_importances_属性获得每个特征的重要性。然后,从当前的一组特征中修建最不重要的特征。在修剪的集合上递归地重复该过程,直到最终到达所需数量的要选择的特征。区别于过滤法和嵌入法的一次训练解决所有问题,包装法要使用特征子集进行多次训练,因此它需要的计算成本是最高的。
最典型的目标函数是递归特征消除法。它是一种贪婪的优化算法,旨在找到性能最佳的特征子集。它反复创建模型,每次迭代时保留最佳特征或剔除最差特征,下一次迭代时,它会使用上一次建模中没有被选中的特征来构建下一个模型,直到所有特征都耗尽为止。然后,它根据自己保留或剔除特征顺序来对特征进行排名,最终选出一个最佳子集。包装法的效果是所有特征选择方法中最利于提升模型表现的,它可以使用很少的特征达到很优秀的效果。除此之外,在特征数目相同时,包装法和嵌入法的效果能够匹敌,不过它比嵌入法算得更缓慢,所以也不适用于太大型的数据,相比之下,包装法是最能保证模型效果的特征选择方法。
feature_selection.RFE
class sklearn.feature_selection.RFE(estimator,n_features_to_select=None,step=1,verbose=0)
参数estimator是需要填写的实例化的评估器,n_features_to_select是想要选择的特征个数,step表示每次迭代中希望移除的特征个数。除此之外,RFE类有两个很重要的属性:
.support_:返回所有的特征是否最后被选中的布尔矩阵
.ranking_:返回特征的按迭代中综合重要性的排名
类feature_selection.RFECV会在交叉验证循环中执行RFE以找到最佳数量的特征,增加参数cv,其他用法和RFE一模一样
from sklearn.feature_selection import RFE
RFC_=RFC(n_estimators=10,random_state=0)
selector=RFE(RFC_,n_features_to_select=340,step=50).fit(X,y)
selector.support_.sum()
selector.ranking_
X_wrapper=selector.transform(X)
cross_val_score(RFC_,X_wrapper,y,cv=5).mean()
score=[]
for i in range(1,751,50):
X_wrapper=RFE(RFC_,n_features_to_select=i,step=50).fit_transform(X,y)
once=cross_val_score(RFC_,X_wrapper,y,cv=5).mean()
score.append(once)
plt.figure(figsize=[20,5])
plt.plot(range(1,751,50),score)
plt.xticks(range(1,751,50))
plt.show()
小结:当数据量很大的时候,优先使用方差过滤和互信息法调整,再上其他特征选择方法。使用逻辑回归时,优先使用嵌入法。使用支持向量机时,优先使用包装法。迷茫的时候,从过滤法走起,看具体数据具体分析。
3.降维算法
在新的特征矩阵生成之前,我们无法知晓PCA都建立了怎样的特征向量,新特征矩阵生成之后也不具有可读性,PCA一般不适用于探索特征和标签之间的关系的模型(如线性回归),因为无法解释的新特征和标签之间的关系不具有意义。在线性回归模型中,我们使用特征选择。
class sklearn.decomposition.PCA(n_components=None,copy=True,whiten=False,svd_solver='auto',tol=0.0,iterated_power='auto',random_state=None)
重要参数n_components
n_components是我们降维后需要的维度,即降维后需要保留的特征数量,如果我们希望可视化一组数据来观察数据分布,我们往往将数据降到三维以下,很多时候是二维,即n_components的取值为2。
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
iris=load_iris()
y=iris.target
X=iris.data
pca=PCA(n_components=2) #实例化
pca=pca.fit(X) #拟合模型
X_dr=pca.tranform(X) #获取新矩阵
X_dr[y==0,0] #这里是布尔索引
'''
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()
'''
可以预见,KNN、随机森林、神经网络、朴素贝叶斯、Adaboost这些分类器在鸢尾花数集上,未调整的时候都可以有95%上下的准确率。
#属性explained_variance_,查看降低后每个新特征向量上所带的信息量大小(可解释性方差的大小)
pca.explained_variance_
#属性explained_variance_ratio,查看降维后每个新特征向量所占的信息量占原始数据总信息量的百分比,又叫做可解释方差贡献率
pca.explained_variance_ratio_
#大部分信息都被有效地集中在了第一个特征上
pca.explained_variance_ratio_sum()
3.1 选出最好的n_components
累积可解释方差贡献率曲线
当参数n_components中不填写任何值,则默认返回min(X.shape)个特征。我们可以使用这种输入方式来画出累计可解释方差贡献率曲线,以此选择最好的n_components的整数取值。
累积可解释方差贡献率曲线是一条以降维后保留的特征个数为横坐标,降维后新特征矩阵捕捉到的可解释方差贡献率为纵坐标的曲线,能够帮助我们决定n_components最好的取值。
import numpy as np
pca_line=PCA().fit(X)
plt.plot([1,2,3,4],np.cumsum(pca_line.explained_variance_ratio_))
plt.xticks([1,2,3,4])
plt.xlabel('number of components after dimension reduction')
plt.ylabel('cumulative explained variance ratio')
plt.show()
最大似然估计自选超参数
输入‘mle’作为n_components的参数输入,可以让PCA用最大似然估计自选超参数的方法。
pca_mle=PCA(n_components='mle')
pca_mle=pca_mle.fit(X)
X_mle=pca_mle.transform(X)
X_mle
pca_mle.explained_variance_ratio_.sum()
#得到了比设定2个特征时更高的信息含量,对于鸢尾花这个很小的数据集来说,3个特征对应这么高的信息含量,并不需要去纠结于只保留2个特征,毕竟3个特征也可以可视化。
按信息量占比选超参数
输入[0,1]之间的浮点数,并且让参数svd_solver=='full',表示希望降维后的总解释性方差占比大于n_components指定的百分比,即是说,希望保留百分之多少的信息量。比如说,如果我们希望保留97%的信息量,就可以输入n_components=0.97,PCA会自动选出能够让保留的信息量超过97%的特征数量。
pca_f=PCA(n_components=0.97,svd_solver='full')
pca_f=pca_f.fit(X)
X_f=pca_f.transform(X)
pca_f.explained_variance_ratio_
案例:PCA对手写数字数据集的降维
1)导入需要的模块和库
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
2)导入数据,探索数据
data=pd.read_csv(r'D:\CDA\机器学习2\辅助资料\digit recognizor.csv')
X=data[:,1:]
y=data[:,0]
X
y
3)画累计方差贡献率曲线,找最佳降维后维度的范围
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 ratio')
plt.show()
4)降维后维度的学习曲线,继续缩小最佳维度的范围
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()
5)细化学习曲线,找出降维后的最佳维度
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()
6)导入找出的最佳维度进行降维,查看模型效果
X_dr=PCA(23).fit_transform()
cross_val_score(RFC(n_estimators=100,random_state=0),X_dr,y,cv=5).mean()
7)突发奇想,特征数量已经不足原来的3%,换模型怎么样?
from sklearn.neighbors import KNeighborsClassifier as KNN
cross_val_score(KNN(),X_dr,y,cv=5).mean()
8)KNN的k值学习曲线
score=[]
for i in range(10):
X_dr=PCA(23).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()
9)定下超参数后,模型效果如何,模型运行时间如何?
cross_val_score(KNN(4),X_dr,y,cv=5).mean()
%%timeit
cross_val_score(KNN(4),X_dr,y,cv=5).mean()








暂无数据