我们早已经知道了内容参数和超参数的区别。内容参数是算法内部的权重和偏置,而超参数是算法的参数,例如逻辑回归中的C值、神经网络的层数和优化器、KNN中的K值,都是超参数。
算法的内部参数,是算法通过梯度下降自行优化,而超参数通常依据经验手工调整。
在第4课的学习中,我们手工调整过逻辑回归算法中的C值,那时小冰就提出过一个问题:为什么要手工调整,而不能由机器自动地选择最优的超参数?
而本次课程中,我们看到了同一个KNN算法,不同K值所带来的不同结果。因此,机器是可以通过某种方法自动找到最佳的K值的。
现在揭晓这个“秘密武器”:利用Sklearn的网格搜索(Grid Search)功能,可以为特定机器学习算法找到每一个超参数指定范围内的最佳值。
什么是指定范围内的最佳值呢?思路很简单,就是列举出一组组可选超参数值。网格搜索会遍历其中所有的可能组合,并根据指定的评估指标比较每一个超参数组合的性能。这个思路正如刚才在KNN算法中,选择1~15来逐个检查哪一个K值效果最好。当然,通常来说,超参数并不是一个,因此组合起来,可能的情况也多。
下面用网格搜索功能进一步优化随机森林算法的超参数,看看预测准确率还有没有能进一步提升的空间:
from sklearn.model_selection import Stratified KFold # 导入K折验证工具
from sklearn.model_selection import Grid Search CV # 导入网格搜索工具
kfold = Stratified KFold(n_splits=10) # 10折验证
rf = Random Forest Classifier() # 随机森林模型
# 对随机森林算法进行参数优化
rf_param_grid = {"max_depth": [None],
"max_features": [3, 5, 12],
"min_samples_split": [2, 5, 10],
"min_samples_leaf": [3, 5, 10],
"bootstrap": [False],
"n_estimators" :[100,300],
"criterion": ["gini"]}
rf_gs = Grid Search CV(rf,param_grid = rf_param_grid, cv=kfold,
scoring="accuracy", n_jobs= 10, verbose = 1)
rf_gs.fit(X_train, y_train) # 用优化后的参数拟合训练数据集
此处选择了准确率作为各个参数组合的评估指标,并且应用10折验证以提高准确率。程序开始运行之后,10个“后台工作者”开始分批同步对54种参数组合中的每一组参数,用10折验证的方式对训练集进行训练(因为是10折验证,所以共需训练540次)并比较,试图找到最佳参数。
咖哥发言
对于随机森林算法中每一个超参数的具体功能,请同学们自行查阅Sklearn文档。
输出结果如下:
Fitting 10 folds for each of 54 candidates, totalling 540 fits
[Parallel(n_jobs=10)]: Using backend Loky Backend with 10 concurrent workers.
[Parallel(n_jobs=10)]: Done 30 tasks | elapsed: 3.1s
[Parallel(n_jobs=10)]: Done 180 tasks | elapsed: 24.3s
[Parallel(n_jobs=10)]: Done 430 tasks | elapsed: 1.0min
[Parallel(n_jobs=10)]: Done 540 out of 540 | elapsed: 1.3min finished
在GPU的加持之下,整个540次拟合只用了1.3分钟(不是每一个训练集的训练速度都这么快,当参数组合数目很多、训练数据集很大时,网格搜索还是挺耗费资源的)。
下面使用找到的最佳参数进行预测:
from sklearn.metrics import (accuracy_score, confusion_matrix)
y_hat_rfgs = rf_gs.predict(X_test) # 用随机森林算法的最佳参数进行预测
print("参数优化后随机森林预测准确率:", accuracy_score(y_test.T, y_hat_rfgs))
在测试集上,对心脏病的预测准确率达到了90%以上,这是之前多种算法都没有达到过的最好成绩:
参数优化后随机森林测试准确率: 0.9016393442622951
显示一下混淆矩阵,发现 “假正”进一步下降为3人,也就是说测试集中仅有3个健康的人被误判为心脏病患者,同时仅有3个真正的心脏病患者成了漏网之鱼,被误判为健康的人:
cm_rfgs = confusion_matrix(y_test, y_had_rfgs) # 显示混淆矩阵
plt.figure(figsize=(4, 4))
plt.title("Random Forest (Best Score) Confusion Matrix")#随机森林(最优参数)混淆矩阵
sns.heatmap(cm_rfgs, annot=True, cmap="Blues", fmt="d", cbar=False)
参数优化后随机森林算法的混淆矩阵如下图所示。
参数优化后随机森林算法的混淆矩阵
那么,如果得到了好的结果,能把参数输出来,留着以后重用吗?
输出最优模型的best_params_属性就行!
示例代码如下:
print("最佳参数组合:", rf_gs.best_params_)
输出结果如下:
最佳参数:
{'bootstrap': False,
'criterion': 'gini',
'max_depth': None,
'max_features': 3,
'min_samples_leaf': 3,
'min_samples_split': 2,
'n_estimators': 100}
这就是网格搜索帮我们找到的随机森林算法的最佳参数组合。