常用机器学习实践技巧

常用机器学习实践技巧

我们知道在机器学习的实践中有很多技巧是可以通用和流程化的,在这里我们通过一个简单的数据集来演示在数据的使用和处理过程中常用的实践技巧,内容主要包含了:

  • 数据预览
  • 数据可视化
  • 查找最优模型
  • Pipeline的使用
  • 模型调节

我们使用的数据集可以通过scikit-learn进行导入

from sklearn import datasets
data = datasets.load_iris()
col_name = data.feature_names
X = data.data
y = data.target

数据预览

当我们拿到数据的时候,首先需要对我们的数据有一个大致的了解,比如数据的分布,数据类型,数据维度等等,只有当我们对自己的数据结构有一个大体的印象之后,才能进一步进行深入的数据分析。

首先是两种最常用的数据预览方式:

X.head(n=10)
X.sample(n=10)

它们的区别是,前者为输出全部数据中排在前十个数据,后者是从全部数据中随机抽取十个进行输出,效果如下:

顺序抽取的前十个数据
随机抽取的十个数据

查看数据维度:

X.shape

查看数据各特征的类型:

X.dtypes

查看数据统计摘要:

X.describe()
数据统计摘要

这些信息会被经常使用到,让我们对被分析的数据有一个整体的了解非常有帮助。

数据可视化

数据预览让我们对被分析数据有一个更深入的理解,我们就可以通过数据的可视化发现数据中的异常值或者数据特征之间的联系以及数据分布规律。

首先我们可以绘制箱型图:

X.plot(kind="box",subplots=True,layout=(1,4),figsize=(12,5))
plt.show()
箱型图

通过箱型图我们很容易能够发现数据中隐藏的异常值。

绘制条形图:

X.hist(figsize=(12,5),xlabelsize=1,ylabelsize=1)
plt.show()
条形图

通过条形图我们可以很清楚的看到数据的分布结构,是否为存在正态分布等等。

绘制密度图:

X.plot(kind="density",subplots=True,layout=(1,4),figsize=(12,5))
plt.show()
密度图

密度图让我们知道数据值大小的密度分布情况。

绘制特征相关图:

scatter_matrix(X,figsize=(10,10))
plt.show()
特征相关图

通过特征相关图我们能够知道哪些特征是存在明显的相关性的。

绘制特征相关性的热力图:

fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111)
cax = ax.matshow(X.corr(),vmin=-1,vmax=1,interpolation="none")
fig.colorbar(cax)
ticks = np.arange(0,4,1)
ax.set_xticks(ticks)
ax.set_yticks(ticks)
ax.set_xticklabels(col_name)
ax.set_yticklabels(col_name)
plt.show()
特征相关性热力图

其实这个热力图和之前的特征相关图非常相似的,区别是热力图更加一目了然,将结果进行了量化。

查找最优模型

当我们一开始不知道使用什么模型来进行预测的时候,一个最简单的思路就是使用默认参数的多个模型开始我们的尝试。如基于决策树的集成模型、SVM、逻辑回归等等进一轮训练和预测,然后选取最好的模型进行调优。

代码如下:

from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

models = []
models.append(("AB",AdaBoostClassifier()))
models.append(("GBM",GradientBoostingClassifier()))
models.append(("RF",RandomForestClassifier()))
models.append(("ET",ExtraTreesClassifier()))
models.append(("SVC",SVC()))
models.append(("KNN",KNeighborsClassifier()))
models.append(("LR",LogisticRegression()))
models.append(("GNB",GaussianNB()))
models.append(("LDA",LinearDiscriminantAnalysis()))

names = []
results = []

for name,model in models:
    kfold = KFold(n_splits=5,random_state=42)
    result = cross_val_score(model,X,y,scoring="accuracy",cv=kfold)
    names.append(name)
    results.append(result)
    print("{}  Mean:{:.4f}(Std{:.4f})".format(name,result.mean(),result.std()))

最后的结果如下:

AB  Mean:0.9133(Std0.0980)
GBM  Mean:0.9133(Std0.0980)
RF  Mean:0.9067(Std0.0998)
ET  Mean:0.8933(Std0.1083)
SVC  Mean:0.9333(Std0.0699)
KNN  Mean:0.9133(Std0.0833)
LR  Mean:0.7533(Std0.2621)
GNB  Mean:0.9467(Std0.0340)
LDA  Mean:0.9600(Std0.0490)

在这里可以看到线性判别分析模型的分类准确率最高,如果面对的是真实问题,很大可能性我们会选取这个模型进行下一步的调优。

Pipeline的使用

需要补充说明一下的是在这里我们使用数据的数值范围相对来说比较规范,假如我们问题中的数据需要先进行标准缩放来达到归一化的目的,那么就可以使用scikit-learn中的Pipeline方法来进行操作。

代码如下:

pipeline = []
pipeline.append(("ScalerET", Pipeline([("Scaler",StandardScaler()),
                                     ("ET",ExtraTreesClassifier())])))
pipeline.append(("ScalerGBM", Pipeline([("Scaler",StandardScaler()),
                                       ("GBM",GradientBoostingClassifier())])))
pipeline.append(("ScalerRF", Pipeline([("Scaler",StandardScaler()),
                                     ("RF",RandomForestClassifier())])))

names = []
results = []
for name,model in pipeline:
    kfold = KFold(n_splits=5,random_state=42)
    result = cross_val_score(model, X, y, cv=kfold, scoring="accuracy")
    results.append(result)
    names.append(name)
    print("{}:  Error Mean:{:.4f} (Error Std:{:.4f})".format(
        name,result.mean(),result.std()))

输出结果:

ScalerET:  Error Mean:0.9133 (Error Std:0.0884)
ScalerGBM:  Error Mean:0.9133 (Error Std:0.0980)
ScalerRF:  Error Mean:0.9133 (Error Std:0.0884)

当然Pipeline的管道化功能不限于此,它不仅可以添加数据缩放的部分,其他的数据处理流程也可以一并引入。

模型调节

接着说我们的模型调节,也可以说是模型调优,假如我们获取到了最好的模型之后想要进一步提升模型的泛化能力,这是需要进行参数的调节,一个通用的方法就是网格搜索,网格搜索可以对模型参数进行批量调节,从而达到进一步提升模型的泛化性能的目的。我们以之前使用的SVM为例。

代码如下:

param_grid = {
    "C":[0.1, 0.3, 0.5, 0.7, 0.9, 1.0, 1.3, 1.5, 1.7, 2.0],
    "kernel":['linear', 'poly', 'rbf', 'sigmoid']
}
model = SVC()
kfold = KFold(n_splits=5, random_state=42)
grid = GridSearchCV(estimator=model, param_grid=param_grid, scoring="accuracy", cv=kfold)
grid_result = grid.fit(X, y)
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in zip(means, stds, params):
    print("%f (%f) with: %r" % (mean, stdev, param))

最后得到的结果:

Best: 0.946667 using {'C': 1.0, 'kernel': 'linear'}
0.886667 (0.125786) with: {'C': 0.1, 'kernel': 'linear'}
0.926667 (0.090431) with: {'C': 0.1, 'kernel': 'poly'}
0.660000 (0.337573) with: {'C': 0.1, 'kernel': 'rbf'}
0.000000 (0.000000) with: {'C': 0.1, 'kernel': 'sigmoid'}
0.926667 (0.067987) with: {'C': 0.3, 'kernel': 'linear'}
0.933333 (0.081650) with: {'C': 0.3, 'kernel': 'poly'}
0.893333 (0.114310) with: {'C': 0.3, 'kernel': 'rbf'}
0.000000 (0.000000) with: {'C': 0.3, 'kernel': 'sigmoid'}
0.933333 (0.069921) with: {'C': 0.5, 'kernel': 'linear'}
0.926667 (0.090431) with: {'C': 0.5, 'kernel': 'poly'}
0.906667 (0.099778) with: {'C': 0.5, 'kernel': 'rbf'}
0.000000 (0.000000) with: {'C': 0.5, 'kernel': 'sigmoid'}
0.933333 (0.069921) with: {'C': 0.7, 'kernel': 'linear'}
0.920000 (0.100222) with: {'C': 0.7, 'kernel': 'poly'}
0.933333 (0.069921) with: {'C': 0.7, 'kernel': 'rbf'}
0.000000 (0.000000) with: {'C': 0.7, 'kernel': 'sigmoid'}
0.940000 (0.061101) with: {'C': 0.9, 'kernel': 'linear'}
0.920000 (0.100222) with: {'C': 0.9, 'kernel': 'poly'}
0.933333 (0.069921) with: {'C': 0.9, 'kernel': 'rbf'}
0.000000 (0.000000) with: {'C': 0.9, 'kernel': 'sigmoid'}
0.946667 (0.065320) with: {'C': 1.0, 'kernel': 'linear'}
0.920000 (0.100222) with: {'C': 1.0, 'kernel': 'poly'}
0.933333 (0.069921) with: {'C': 1.0, 'kernel': 'rbf'}
0.000000 (0.000000) with: {'C': 1.0, 'kernel': 'sigmoid'}
0.946667 (0.065320) with: {'C': 1.3, 'kernel': 'linear'}
0.920000 (0.100222) with: {'C': 1.3, 'kernel': 'poly'}
0.933333 (0.069921) with: {'C': 1.3, 'kernel': 'rbf'}
0.000000 (0.000000) with: {'C': 1.3, 'kernel': 'sigmoid'}
0.940000 (0.074237) with: {'C': 1.5, 'kernel': 'linear'}
0.920000 (0.100222) with: {'C': 1.5, 'kernel': 'poly'}
0.933333 (0.069921) with: {'C': 1.5, 'kernel': 'rbf'}
0.000000 (0.000000) with: {'C': 1.5, 'kernel': 'sigmoid'}
0.933333 (0.069921) with: {'C': 1.7, 'kernel': 'linear'}
0.920000 (0.100222) with: {'C': 1.7, 'kernel': 'poly'}
0.933333 (0.069921) with: {'C': 1.7, 'kernel': 'rbf'}
0.000000 (0.000000) with: {'C': 1.7, 'kernel': 'sigmoid'}
0.940000 (0.074237) with: {'C': 2.0, 'kernel': 'linear'}
0.920000 (0.100222) with: {'C': 2.0, 'kernel': 'poly'}
0.933333 (0.069921) with: {'C': 2.0, 'kernel': 'rbf'}
0.000000 (0.000000) with: {'C': 2.0, 'kernel': 'sigmoid'}

比较之前使用SVM默认参数的模型,网格搜索调参后得到的模型进一步提升了准确性,如果时间和计算机算力充裕还可以尝试更多的组合方式。

总结

最后要说一下在机器学习的实践中其实还有两个非常重要的步骤,那就是特征工程模型融合,它们对最后模型泛化能力提升的极限有着最为紧密的联系,但是这两部分内容又不是三言两语能够讲清楚的,还需要自己大量的探索和经验的累积才能最后把握住“火候”。




微信公众号:PyMachine

编辑于 04-19

文章被以下专栏收录