**模块preprocessing:**几乎包含数据预处理的所有内容
**模块lmpute:**填补缺失值专用
模块feature_ selection: 包含特征选择的各种方法的实践
**模块decomposition:**包含降维算法
将不同规格的数据转换为同一规则,或不同分布的数据转换到某个特定分布的需求。
以梯度和矩阵为核心的算法中,无量纲化可以加快求解速度;如逻辑回归、支持向量机、神经网络
**以距离为核心的模型,**无量纲化可以帮助我们提升模型精度,避免某一个取值范围特别大的特征对距离计算造成影响;如K近邻、K-Means聚类
决策树和树的集成算法,可以不“无量纲化”,树模型也可以将数据处理好;
数据的无量纲化,可以时线性或非线性的。
线性包括中心化和缩放处理。
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
data=[[-1,2],[-0.5,6],[0,10],[1,18]]
scaler=MinMaxScaler()
scaler.fit(data)
result=scaler.transform(data)
'''array([[0. , 0. ],
[0.25, 0.25],
[0.5 , 0.5 ],
[1. , 1. ]])'''
result=scaler.fit_transform(data)
'''array([[0. , 0. ],
[0.25, 0.25],
[0.5 , 0.5 ],
[1. , 1. ]])'''
scaler.inverse_transform(result)
'''array([[-1. , 2. ],
[-0.5, 6. ],
[ 0. , 10. ],
[ 1. , 18. ]])'''
scaler2=MinMaxScaler(feature_range=[5,10])
result2=scaler2.fit_transform(data)
result2
'''
array([[ 5. , 5. ],
[ 6.25, 6.25],
[ 7.5 , 7.5 ],
[10. , 10. ]])'''
#当x中的特征数量太多时,fit会报错,因为数据量太大了计算不了
#可以使用partial_fit作为训练接口
scaler3=MinMaxScaler()
scaler3.partial_fit(data)
result3=scaler3.transform(data)
result3
'''
array([[0. , 0. ],
[0.25, 0.25],
[0.5 , 0.5 ],
[1. , 1. ]])'''
from sklearn.preprocessing import StandardScaler
data=[[-1,2],[-0.5,6],[0,10],[1,18]]
scaler=StandardScaler()
scaler.fit(data)
scaler.mean_#查看原始数据均值
# array([-0.125, 9. ])
scaler.var_#查看原始数据方差
# array([ 0.546875, 35. ])
x_std=scaler.transform(data)
'''
array([[-1.18321596, -1.18321596],
[-0.50709255, -0.50709255],
[ 0.16903085, 0.16903085],
[ 1.52127766, 1.52127766]])'''
x_std.mean()#0.0
x_std.std()#1.0
scaler.inverse_transform(x_std)#逆转
'''array([[-1. , 2. ],
[-0.5, 6. ],
[ 0. , 10. ],
[ 1. , 18. ]])'''
对于StandardScaler和MinMaxScaler来说,空值NaN会被当做是缺失值,在fit的时候忽略,在transform的时候保持缺失NaN的状态显示。
在fit接口中,只允许导入至少二维数组,一维数组导入会报错。
大多数机器学习算法中,会选择StandardScaler来进行特征缩放
MinMaxScaler对异常值非常敏感。
在PCA,聚类,逻辑回归,支持向量机,神经网络这些算法中,StandardScaler往往是最好的选择。
MinMaxScaler在不涉及距离度量、梯度、协方差计算以及数据需要被压缩到特定区间时使用广泛,比如数字图像处理中量化像素强度时,都会使用MinMaxScaler将数据压缩于[0,1]区间之中。
建议先试试看StandardScaler,效果不好换MinMaxScaler。
参数 | 含义 |
---|---|
missing_values | 告诉SimpleImputer,数据中的缺失值长什么样,默认空值np.nan |
strategy | 我们填补缺失值的策略,默认均值。 输入“mean”使用均值填补(仅对数值型特征可用) 输入“median"用中值填补(仅对数值型特征可用) 输入"most_frequent”用众数填补(对数值型和字符型特征都可用) 输入“constant"表示请参考参数“fill_value"中的值(对数值型和字符型特征都可用) |
fill_value | 当参数startegy为”constant"的时候可用,可输入字符串或数字表示要填充的值,常用0 |
copy | 默认为True,将创建特征矩阵的副本,反之则会将缺失值填补到原本的特征矩阵中去。 |
import pandas as pd
data = pd.read_csv("Narrativedata.csv",index_col=0)
data.info()
'''
----------------填补之前---------------
Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Age 714 non-null float64
1 Sex 891 non-null object
2 Embarked 889 non-null object
3 Survived 891 non-null object
dtypes: float64(1), object(3)
memory usage: 34.8+ KB
'''
#填补年龄
Age=data.loc[:,'Age'].values.reshape(-1,1)
# Dataframe无法直接reshape
# data.loc[:,'Age'].values的类型是numpy.ndarray
from sklearn.impute import SimpleImputer
imp_mean=SimpleImputer()#实例化,默认为均值填补
imp_median=SimpleImputer(strategy='median')
imp_0=SimpleImputer(strategy='constant',fill_value=0)
imp_mean=imp_mean.fit_transform(Age)
imp_median=imp_median.fit_transform(Age)
imp_0=imp_0.fit_transform(Age)
#这里我们用中位数填补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)
data.info()
'''
----------------填补之后---------------
Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Age 891 non-null float64
1 Sex 891 non-null object
2 Embarked 891 non-null object
3 Survived 891 non-null object
dtypes: float64(1), object(3)
memory usage: 34.8+ KB'''
data.loc[:,"Age"]=data.loc[:,"Age"].fillna(data.loc[:,"Age"].median())
#EM=data.loc[:,"Embarked"].fillna(data.loc[:,"Embarked"].mode())
data.dropna(axis=0,inplace=True)#axis等于0,删除行;=1,删除列
data.info()
'''
----------填充之后-------------
Int64Index: 889 entries, 0 to 890
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Age 889 non-null float64
1 Sex 889 non-null object
2 Embarked 889 non-null object
3 Survived 889 non-null object
dtypes: float64(1), object(3)
memory usage: 34.7+ KB'''
标签专用,能够将分类转换为分类数值
from sklearn.preprocessing import LabelEncoder
data.iloc[:,-1]=LabelEncoder().fit_transform(data.iloc[:,-1])
data.head()
''' Age Sex Embarked Survived
0 22.0 male S 0
1 38.0 female C 2
2 26.0 female S 2
3 35.0 female S 2
4 35.0 male S 0'''
特征专用,与LabelEncoder用法类似
from sklearn.preprocessing import OrdinalEncoder
OrdinalEncoder().fit(data.iloc[:,1:-1]).categories_
#[array(['female', 'male'], dtype=object), array(['C', 'Q', 'S'], dtype=object)]
from sklearn.preprocessing import OneHotEncoder
X=data.iloc[:,1:-1]
enc=OneHotEncoder(categories='auto').fit(X)
# pd.DataFrame(enc.inverse_transform(result)) #逆转,返回原始数据
enc.get_feature_names()#返回每一列的名字
# array(['x0_female', 'x0_male', 'x1_C', 'x1_Q', 'x1_S'], dtype=object)
result=OneHotEncoder(categories='auto').fit_transform(X).toarray()
#要转成数组,.fit_transform(X)之后得到的是一个稀疏矩阵对象
axis=1
将特征值化成0和1
from sklearn.preprocessing import Binarizer
X = data.iloc[:,0].values.reshape(-1,1)
#类为特征专用,所以不能使用一维数组
transformer = Binarizer(threshold=30).fit_transform(X)
transformer
参数 | 含义&输入 |
---|---|
n_bins | 每个特征中分箱的个数,默认5,一次会被运用到所有导入的特征 |
encode | 编码的方式,默认“onehot” “onehot”:做哑变量,之后返回一个稀疏矩阵,每一列是一个特征中的一个类别,含有该类别的样本表示为1,不含的表示为0 “ordinal”:每个特征的每个箱都被编码为一个整数,返回每一列是一个特征.类似OrdinalEncoder每个特征下含有不同整数编码的箱的矩阵"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())#{0.0, 1.0, 2.0}
est = KBinsDiscretizer(n_bins=3, encode='onehot',strategy='uniform')
#查看转换后分的箱:变成了哑变量
est.fit_transform(X).toarray()
'''array([[1., 0., 0.],
[0., 1., 0.],
[1., 0., 0.],
...,
[0., 1., 0.],
[1., 0., 0.],
[0., 1., 0.]])'''
也可以用pandas中的qcut\cut
通常用于预处理,过滤法是独立于机器学习算法的,依据各种统计检验中的分数以及相关性的各种指标来选择特征。
即通过特征本身的方差来选择特征,方差特别小的特征对于样本区分没有什么作用。
sklearn.feature_selection.VarianceThreshold
#导入数据
import pandas as pd
data=pd.read_csv('digit recognizor.csv')
X=data.iloc[:,1:]
y=data.iloc[:,0]
X.shape#(42000, 784)
#本质是维度太高
#如果用支持向量机和神经网络,可能直接跑不出来,(这两个特征本质是升维)
#阈值为0
from sklearn.feature_selection import VarianceThreshold
selector=VarianceThreshold()#默认为零,删除方差为0的特征
X_var0=selector.fit_transform(X)
X_var0.shape#(42000, 708)
#阈值设为所有方差中位数
import numpy as np
# X.var()#查看方差的中位数,得到的是pandas.core.series.Series类型
# np.median(X.var().values)所有特征方差的中值1352.286703180131
X_fsvar=VarianceThreshold(np.median(X.var().values)).fit_transform(X)
X_fsvar.shape#(42000, 392)
#当特征式二分类问题时,方差=p(1-p); 若特征是伯努利随机变量,假设p=0.8,即二分类特种中某种分类占到80%以上时删除特征
X_vbar=VarianceThreshold(0.8*0.2).fit_transform(X)#删除特征中,某一分类占到0.8以上的
X_vbar.shape#(42000, 685)
方差过滤前后模型效果对比
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score
X=data.iloc[:,1:]
y=data.iloc[:,0]
X_fsvar=VarianceThreshold(np.median(X.var().values)).fit_transform(X)#默
#KNN_方差过滤前
cross_val_score(KNeighborsClassifier(),X,y,cv=5).mean()
# 0.965857142857143
#KNN_方差过滤后
cross_val_score(KNeighborsClassifier(),X_fsvar,y,cv=5).mean()
#0.966
#随机森林-方差过滤前
cross_val_score(RandomForestClassifier(n_estimators=100,random_state=0),X,y,cv=5).mean()
#0.9642142857142856
#随机森林-方差过滤后
cross_val_score(RandomForestClassifier(n_estimators=100,random_state=0),X_fsvar,y,cv=5).mean()
#0.9637142857142857
方差过滤后,删除了一半的特征(392),KNN效果提高了0.0002,随机森林效果降低了0.0005;
对于KNN、单棵决策树、SVM、神经网络、回归算法,需要遍历特征或升维进行计算。本身的计算量很大,方差过滤这样的特征选择的效果比较好
对于随机森林,它随机选取特征进行分枝,本身速度较快(n_estimators不高的情况),方差过滤对其影响不大。
虽然随机森林和单棵决策树都是随机选择特征,但是决策树选的特征要比随机森林中每棵树随机选的特征多得多,所以特征数量对决策树运行快慢也有一定影响。
如果过滤后,结果变好了,说明对于该模型,方差过滤舍弃的特征是噪音;否之,舍弃的特征中含有有效特征。
过滤法的主要对象是:需要遍历特征或升维的算法
过滤法的主要目的是:在维持算法表现的前提下,降低计算成本。
一般过滤法用于预处理,我们会先用阈值为0或很小的的方差过滤,再用更优的特征选择模仿继续削减特征数量。
这里我们用轻量级(n_estimators=10)的随机森林来实践。
#随机森林-方差过滤前
cross_val_score(RandomForestClassifier(c,random_state=0),X,y,cv=5).mean()
#0.9373571428571429
#随机森林-方差过滤后
cross_val_score(RandomForestClassifier(n_estimators=10,random_state=0),X_fsvar,y,cv=5).mean()
#0.9390476190476191
#由于方差过滤后的效果变好了,就直接用方差过滤后的数据
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
from sklearn.feature_selection import SelectKBest,chi2
x_fschi=SelectKBest(chi2,k=300).fit_transform(X_fsvar,y)
x_fschi.shape#(42000, 300)
cross_val_score(RandomForestClassifier(n_estimators=10,random_state=0),X_fsvar,y,cv=5).mean()#0.9390476190476191
这里的k要根据实际情况来做调整。k值可以通过学习曲线或者p值来确定
import matplotlib.pyplot as plt
score=[]
for i in range(350,200,-10):
x_fschi =SelectKBest(chi2,k=i).fit_transform(X_fsvar,y)
once=cross_val_score(RandomForestClassifier(n_estimators=10,random_state=0),x_fschi,y,cv=5).mean()
score.append(once)
plt.plot(range(350,200,-10),score)
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iR6ygd7S-1660645683500)(C:\Users\章ky\AppData\Roaming\Typora\typora-user-images\image-20220814142027328.png)]
卡方检验的本质是推测两组数据之间的差异,原假设是“两组数据是相互独立的”。
- p值<=0.05或0.01:拒绝原假设,两组数据是相关的
- p值<=0.05或0.01:接受原假设,两组数据不相关。
#看p值
chivalue,pvalue_chi=chi2(X_fsvar,y)
chivalue#返回所有特征对标签的卡方值
k=chivalue.shape[0]-(pvalue_chi>0.05).sum()#392,与标签相关的特征数量
#也就是(pvalue_chi<=0.05).sum()
F检验的本质是寻找两组数据之间的线性关系,原假设是“数据不存在线性的线性关系”。
- p值<=0.05或0.01:拒绝原假设,两组数据显著线性相关
- p值<=0.05或0.01:接受原假设,两组数据没有显著线性相关。
from sklearn.feature_selection import f_classif
F,pvalues_f=f_classif(X_fsvar,y)
k=(pvalues_f<=0.5).sum()
k#392
from sklearn.feature_selection import mutual_info_classif as MIC
result=MIC(X_fsvar,y)
k=(result>=0).sum()
k#392
class sklearn.feature_selection.SelectFromModel (estimator, threshold=None, prefifit=False, norm_order=1,max_features=None)
SelectFromModel是一个元变换器,可以与任何在拟合后具有coef_,feature_importances_属性或参数中可选惩罚项的评估器一起使用(比如随机森林和树模型就具有属性feature_importances_,逻辑回归就带有l1和l2惩罚项,线性支持向量机也支持l2惩罚项)。
参数 | 解释 |
---|---|
estimator | 使用的模型评估器,只要是带feature_importances_或者coef_属性,或带有l1和l2惩罚项的模型都可以使用 |
threshold | 特征重要性的阈值,重要性低于这个阈值的特征都将被删除 |
prefit | 默认False,判断是否将实例化后的模型直接传递给构造函数。如果为True,则必须直接调用fit和transform,不能使用fit_transform,并且SelectFromModel不能与cross_val_score,GridSearchCV和克隆估计器的类似实用程序一起使用。 |
norm_order | k可输入非零整数,正无穷,负无穷,默认值为1 在评估器的coef_属性高于一维的情况下,用于过滤低于阈值的系数的向量的范数的阶数。 |
max_features | 在阈值设定下,要选择的最大特征数。要禁用阈值并仅根据max_features选择,请设置threshold = -np.inf |
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.00067).fit_transform(X,y) #具体K值,可以通过学习曲线来查找
X_embedded.shape#(42000, 324)
cross_val_score(RFC_,X_embedded,y,cv=5).mean()#0.9391190476190475
包装法与嵌入法类似,不同的是
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)
X_wrapper=selector.transform(X)
cross_val_score(RFC_,X_wrapper,y,cv=5).mean()#0.9379761904761905
#selector.support_#返回所有的特征的是否最后被选中的布尔矩阵
#selector.ranking_#返回特征的按数次迭代中综合重要性的排名。
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)
X_wrapper=selector.transform(X)
cross_val_score(RFC_,X_wrapper,y,cv=5).mean()#0.9379761904761905
#selector.support_#返回所有的特征的是否最后被选中的布尔矩阵
#selector.ranking_#返回特征的按数次迭代中综合重要性的排名。
注:本文内容是本人在学习“菜菜的机器学习课程”网课过程中的记录、总结和整理,将重点部分整理出来的笔记。侵删。