使用sklearn中preprocessing.Imputer实现对缺失值的处理。Imputer Class提供了补全缺失值的基本策略:使用一行或一列的均值,中值,出现次数最多的值,该类也允许不同缺失值的编码。
imp = Imputer(missing_values='NaN', strategy='mean', axis=0)
imp.transform(X)
在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布的需求,这种需求统称为将数据“无量纲化”。
在许多机器学习执行前,需要对数据集进行标准化处理。因为很多算法假设数据的特征服从标准正态分布。所以如果不对数据标准化,那么算法的效果会很差。
from sklearn import preprocessing
X_scaled = preprocessing.scale(X)
scaler = preprocessing.StandardScaler().fit(X)
scaler.transform(X)
对不同特征维度的数据做伸缩变换,其目的是使得各个特征维度对目标函数的影响权重是一致的。
min_max_scaler = preprocessing.MinMaxScaler(feature_range=(0,1))
X_train_minmax = min_max_scaler.fit_transform(X)
#上面的X上训练好的MinMaxScaler就可以通过transform函数被用到新的数据上
X_test_minmax = min_max_scaler.transform(X_test)
max_abs_scaler=preprocessing.MaxAbsScaler()
X_train_maxabs=max_abs_scaler.fit_transform(X)
X_test_maxabs=max_abs_scaler.transform(X_test)
正则化是将单个样本缩放为单位范数的过程。当你要使用二次形式如点积或核变换运算来度量任意一对样本的相似性的时候,数据的规范化非常有用。这个步骤是向量空间模型的基础,常被用于文本分类和聚类中。
normalize方法提供了快速简单的方法来对单个array数据集进行归一化,可以选择L1或者L2范数。
preprocessing.normalize(X, norm='l2')
preprocessing模块还提供了类Normalizer,通过方法Transformer API对另一数据集执行同样的操作。
normalizer = preprocessing.Normalizer().fit(X)
normalizer.transform(X)
注:normalize和Normalizer同样适用于类似array的稠密的或者稀疏的矩阵。
(1)如果对输出结果范围有要求,用归一化。
(2)如果数据较为稳定,不存在极端的最大最小值,用归一化。
(3)如果数据存在异常值和较多噪音,用标准化,可以间接通过中心化避免异常值和极端值的影响。
一般来说,建议优先使用标准化。对于输出有要求时再尝试别的方法,如归一化或者更加复杂的方法。很多方法都可以将输出范围调整到[0, 1],如果我们对于数据的分布有假设的话,更加有效的方法是使用相对应的概率密度函数来转换。
特征二值化是对数值特征进行阈值化以得到布尔值的过程,这一过程主要是概率型的学习器提供数据预处理机制。大于阈值的值映射为1,而小于或等于阈值的值映射为0。
binarizer=preprocessing.Binarizer(threshold=10).fit(x)
binarizer.transform(x)
在很多情况下,特征值不是连续的值而是种类。例如,一个人可能的特征是[male, female]等等,这些特征可以用整数值来进行编码。
在scikit-learn中,将种类特征用1-of-k或者one-hot编码。预处理模块中有OneHotEncoder来对种类特征编码,通常是m个可能的种类用m个值来表示。
X_onehot = preprocessing.OneHotEncoder().fit_transform(X).toarray()
通常,通过考虑输入数据的非线性特征来增加模型的复杂度是很有用的。一个简单常用的方法是多项式特征,它可以得到特征的高阶和相互作用项。
PolynomialFeatures类可以用来生成多项式特征。
poly = PolynomialFeatures(2)
poly.fit_transform(X)
上述将(X1, X2)转化为(1, X1, X2, X12, X1X2, X22)
应用范围:多样式特征常用于核方法中(SVM, 核PCA)
注:
可参考https://www.cnblogs.com/nolonely/p/7002168.html
Expected 2D array错误https://blog.csdn.net/flizhn/article/details/79252421
feature_selection.VarianceThreshold
这是通过特征本身的方差来筛选特征的类。比如一个特征本身的方差很小,就表示样本在这个特征上基本没有差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区分没有什么作用。
所以无论接下来的特征工程要做什么,都要优先消除方差为0的特征。VarianceThreshold有重要参数threshold,表示方差的阈值,表示舍弃所有方差小于threshold的特征,不填默认为0,即删除所有的记录都相同的特征。
from sklearn.feature_selection import VarianceThreshold
selector = VarianceThreshold()
x_var = selector.fit_transform(x) #得到除去部分方差为0后的新的特征矩阵
x_var.shape
# 取方差中位数作为阈值,看模型效果
x_var = VarianceThreshold(threshold=np.median(x.var().values)).fit_transform(x)
rfc = RandomForestClassifier(n_estimators=10,random_state=20)
cross_val_score(rfc,x_var,y,cv=5).mean()
卡方过滤是专门针对离散型标签(即分类问题)的相关性过滤。卡方检验类feature_selection.chi2计算每个非负特征和标签之间的卡方统计量,并依照卡方统计量由高到低为特征排名。再结合feature_selection.SelectKBest这个可以输入”评分标准“的类来选出前K个分数最高的特征的类,我们可以借此除去最可能独立于标签,与我们分类目的无关的特征。
#相关性检验 卡方检验 用于分类,直接选取相关性较大的前300个特征
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
chi_x=SelectKBest(chi2,k=300).fit_transform(x_var,y)
chi_x.shape
#通过学习曲线来确定最佳的K值
import matplotlib.pyplot as plt
list = []
for i in range(100,390,10):
chi_x = SelectKBest(chi2,k=i).fit_transform(x_var,y)
me = cross_val_score(RandomForestClassifier(n_estimators=100,random_state=20),chi_x,y,cv=5).mean()
list.append(me)
plt.plot(range(100,390,10),list)
plt.show()
# https://www.jianshu.com/p/586ba8c96a3d
从特征工程的角度,我们希望选取卡方值很大,p值小于0.05的特征,即和标签是相关联的特征。而调用SelectKBest之前,我们可以直接从chi2实例化后的模型中获得各个特征所对应的卡方值和P值
chi_val,p_val = chi2(x_var,y) #得到卡方值,和p值
k_val = x_var.shape[1]-(p_val>0.05).sum()
x_var.shape[1],k_val #输出:(392, 392)
是用来捕捉每个特征与标签之间的线性关系的过滤方法。它即可以做回归也可以做分类,因此包含feature_selection.f_classif(F检验分类)和feature_selection.f_regression(F检验回归)两个类。其中F检验分类用于标签是离散型变量的数据,而F检验回归用于标签是连续型变量的数据。
和卡方检验一样,这两个类需要和类SelectKBest连用,并且我们也可以直接通过输出的统计量来判断我们到底要设置一个什么样的K。需要注意的是,F检验在数据服从正态分布时效果会非常稳定,因此如果使用F检验过滤,我们会先将数据转换成服从正态分布的方式。
F检验的本质是寻找两组数据之间的线性关系,其原假设是”数据不存在显著的线性关系“。它返回F值和p值两个统计量。和卡方过滤一样,我们希望选取p值小于0.05或0.01的特征,这些特征与标签时显著线性相关的,而p值大于0.05或0.01的特征则被我们认为是和标签没有显著线性关系的特征,应该被删除。
#F检验 用于分类或者回归
from sklearn.feature_selection import f_classif
f_val,p_val = f_classif(x_var,y)
k_val = x_var.shape[1] - (p_val > 0.05).sum()
k_val #输出 392 特征数量没变
互信息法是用来捕捉每个特征与标签之间的任意关系(包括线性和非线性关系)的过滤方法。和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
x_mic = mutual_info_classif(x_var,y)
x_mic
常用的基于过滤法的特征选择,包括方差过滤,基于卡方,F检验和互信息的相关性过滤,讲解了各个过滤的原理和面临的问题,以及怎样调这些过滤类的超参数。通常来说,建议先使用方差过滤,然后使用互信息法来捕捉相关性,不过了解各种各样的过滤方式也是必要的
嵌入法是一种让算法自己决定使用哪些特征的方法,即特征选择和算法训练同时进行。在使用嵌入法时,我们先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据权值系数从大到小选择特征。这些权值系数往往代表了特征对于模型的某种贡献或某种重要性,比如决策树和树的集成模型中的feature_importances_属性,可以列出各个特征对树的建立的贡献,我们就可以基于这种贡献的评估,找出对模型建立最有用的特征。因此相比于过滤法,嵌入法的结果会更加精确到模型的效用本身,对于提高模型效力有更好的效果。并且,由于考虑特征对模型的贡献,因此无关的特征(需要相关性过滤的特征)和无区分度的特征(需要方差过滤的特征)都会因为缺乏对模型的贡献而被删除掉,可谓是过滤法的进化版。
过滤法中使用的统计量可以使用统计知识和常识来查找范围(如p值应当低于显著性水平0.05),而嵌入法中使用的权值系数却没有这样的范围可找——我们可以说,权值系数为0的特征对模型丝毫没有作用,但当大量特征都对模型有贡献且贡献不一时,我们就很难去界定一个有效的临界值。这种情况下,模型权值系数就是我们的超参数,我们或许需要学习曲线,或者根据模型本身的某些性质去判断这个超参数的最佳值究竟应该是多少。
#画学习曲线
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
from sklearn.feature_selection import SelectFromModel
data = pd.read_csv("D:/digit recognizor.csv")
x = data.iloc[:,1:]
y = data.iloc[:,0]
rfc = RandomForestClassifier(n_estimators=100,random_state=20)
rfc.fit(x,y)
thresholds = np.linspace(0,(rfc.feature_importances_).max(),20)
scores = []
for i in thresholds:
x_emb = SelectFromModel(rfc,threshold=i).fit_transform(x,y)
score = cross_val_score(rfc,x_emb,y,cv=5).mean()
scores.append(score)
plt.plot(thresholds,scores)
plt.show()
与嵌入法十分相似,它也是依赖于算法自身的选择,比如coef_属性或feature_importances_属性来完成特征选择。但不同的是,我们往往使用一个目标函数作为黑盒来帮助我们选取特征,而不是自己输入某个评估指标或统计量的阈值。包装法在初始特征集上训练评估器,并且通过coef_属性或通过feature_importances_属性获得每个特征的重要性。然后,从当前的一组特征中修剪最不重要的特征。在修剪的集合上递归地重复该过程,直到最终到达所需数量的要选择的特征。区别于过滤法和嵌入法的一次训练解决所有问题,包装法要使用特征子集进行多次训练,因此它所需要的计算成本是最高的。
# Wrapper包装法
from sklearn.feature_selection import RFE
rfc = RandomForestClassifier(n_estimators=10,random_state=20)
x_wra = RFE(rfc,n_features_to_select=300,step=50).fit_transform(x,y)
cross_val_score(rfc,x_wra,y,cv=5).mean()
参考文档:http://www.pianshen.com/article/2556225859/
在得到训练数据集时,通常我们经常会把训练数据集进一步拆分成训练集和验证集,这样有助于我们模型参数的选取。
# 作用:将数据集划分为 训练集和测试集
# 格式:train_test_split(*arrays, **options)
from sklearn.mode_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
"""
参数
---
arrays:样本数组,包含特征向量和标签
test_size:
float-获得多大比重的测试样本 (默认:0.25)
int - 获得多少个测试样本
train_size: 同test_size
random_state:
int - 随机种子(种子固定,实验可复现)
shuffle - 是否在分割之前对数据进行洗牌(默认True)
返回
---
分割后的列表,长度=2*len(arrays),
(train-test split)
"""
常用的回归:线性、决策树、SVM、KNN ;集成回归:随机森林、Adaboost、GradientBoosting、Bagging、ExtraTrees
常用的分类:线性、决策树、SVM、KNN,朴素贝叶斯;集成分类:随机森林、Adaboost、GradientBoosting、Bagging、ExtraTrees
常用聚类:k均值(K-means)、层次聚类(Hierarchical clustering)、DBSCAN
模型的常用属性和功能如下:
# 拟合模型
model.fit(X_train, y_train)
# 模型预测
model.predict(X_test)
# 获得这个模型的参数
model.get_params()
# 为模型进行打分
model.score(data_X, data_y) # 线性回归:R square; 分类问题: acc
from sklearn.linear_model import LinearRegression
# 定义线性回归模型
model = LinearRegression(fit_intercept=True, normalize=False,
copy_X=True, n_jobs=1)
"""
参数
---
fit_intercept:是否计算截距。False-模型没有截距
normalize: 当fit_intercept设置为False时,该参数将被忽略。 如果为真,则回归前的回归系数X将通过减去平均值并除以l2-范数而归一化。
n_jobs:指定线程数
"""
from sklearn.linear_model import LogisticRegression
# 定义逻辑回归模型
model = LogisticRegression(penalty=’l2’, dual=False, tol=0.0001, C=1.0,
fit_intercept=True, intercept_scaling=1, class_weight=None,
random_state=None, solver=’liblinear’, max_iter=100, multi_class=’ovr’,
verbose=0, warm_start=False, n_jobs=1)
"""参数
---
penalty:使用指定正则化项(默认:l2)
dual: n_samples > n_features取False(默认)
C:正则化强度的反,值越小正则化强度越大
n_jobs: 指定线程数
random_state:随机数生成器
fit_intercept: 是否需要常量
"""
from sklearn import naive_bayes
model = naive_bayes.GaussianNB() # 高斯贝叶斯
model = naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)
model = naive_bayes.BernoulliNB(alpha=1.0, binarize=0.0, fit_prior=True, class_prior=None)
"""
文本分类问题常用MultinomialNB
参数
---
alpha:平滑参数
fit_prior:是否要学习类的先验概率;false-使用统一的先验概率
class_prior: 是否指定类的先验概率;若指定则不能根据参数调整
binarize: 二值化的阈值,若为None,则假设输入由二进制向量组成
"""
from sklearn import tree
model = tree.DecisionTreeClassifier(criterion=’gini’, max_depth=None,
min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0,
max_features=None, random_state=None, max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
class_weight=None, presort=False)
"""参数
---
criterion :特征选择准则gini/entropy
max_depth:树的最大深度,None-尽量下分
min_samples_split:分裂内部节点,所需要的最小样本树
min_samples_leaf:叶子节点所需要的最小样本数
max_features: 寻找最优分割点时的最大特征数
max_leaf_nodes:优先增长到最大叶子节点数
min_impurity_decrease:如果这种分离导致杂质的减少大于或等于这个值,则节点将被拆分。
"""
from sklearn.svm import SVC
model = SVC(C=1.0, kernel=’rbf’, gamma=’auto’)
"""参数
---
C:误差项的惩罚参数C
gamma: 核相关系数。浮点数,If gamma is ‘auto’ then 1/n_features will be used instead.
"""
from sklearn import neighbors
#定义kNN分类模型
model = neighbors.KNeighborsClassifier(n_neighbors=5, n_jobs=1) # 分类
model = neighbors.KNeighborsRegressor(n_neighbors=5, n_jobs=1) # 回归
"""参数
---
n_neighbors: 使用邻居的数目
n_jobs:并行任务数
"""
from sklearn.neural_network import MLPClassifier
# 定义多层感知机分类算法
model = MLPClassifier(activation='relu', solver='adam', alpha=0.0001)
"""参数
---
hidden_layer_sizes: 元祖
activation:激活函数
solver :优化算法{‘lbfgs’, ‘sgd’, ‘adam’}
alpha:L2惩罚(正则化项)参数。
"""
from sklearn.model_selection import cross_val_score
cross_val_score(model, X, y=None, scoring=None, cv=None, n_jobs=1)
"""参数
---
model:拟合数据的模型
cv : k-fold
scoring: 打分参数-‘accuracy’、‘f1’、‘precision’、‘recall’ 、‘roc_auc’、'neg_log_loss'等等
"""
使用检验曲线,我们可以更加方便的改变模型参数,获取模型表现。
from sklearn.model_selection import validation_curve
train_score, test_score = validation_curve(model, X, y, param_name, param_range, cv=None, scoring=None, n_jobs=1)
"""参数
---
model:用于fit和predict的对象
X, y: 训练集的特征和标签
param_name:将被改变的参数的名字
param_range: 参数的改变范围
cv:k-fold
返回值
---
train_score: 训练集得分(array)
test_score: 验证集得分(array)
"""
我们可以将我们训练好的model保存到本地,或者放到线上供用户使用,那么如何保存训练好的model呢?主要有下面两种方式:
import pickle
# 保存模型
with open('model.pickle', 'wb') as f:
pickle.dump(model, f)
# 读取模型
with open('model.pickle', 'rb') as f:
model = pickle.load(f)
model.predict(X_test)
from sklearn.externals import joblib
# 保存模型
joblib.dump(model, 'model.pickle')
#载入模型
model = joblib.load('model.pickle')