调整超参数:决定模型是“金子”还是“垃圾”!
数据清洗以后,你也许会困惑应该从哪里开始建模。一般情况下它的下一步应该是特征选择,但特征工程和模型训练是相互影响的。好的特征选择可以使模型得到好的效果,而不同的模型又对数据有不同的要求。
因此,特征工程和模型训练是两个不可分割的部分。由于模型的选择会对特征的选择造成影响,因此,在特征工程开始前,至少应该尝试训练一些可能的模型,查看当前的特征是否适合可能的模型。如下图是建模流程的循环,特征工程和训练模型是两个动态过程。
通过特征工程,选择可能的重要特征。通过参数调整,尝试训练可能的模型,从中选择最佳的模型并调试参数。
除了特征工程以外,超参数的选择也十分重要,它决定你的模型是“金子”还是“垃圾”,以及模型是否处于最优的表现并得到好的结果。本文着重介绍三种超参数调节的方法,分别为:手动调节(manual tuning),网格搜索(grid search),随机搜索(randomized search),贝叶斯搜索(Bayesian Search)。 详见链接。
图片来源:https://towardsdatascience.com/what-is-the-best-starter-model-in-table-data-ml-lessons-from-a-high-rank-kagglers-new-book-f08b821db797
在开始介绍超参数前,首先要明确参数与超参数的区别:
参数:是模型内部的配置变量,在机器学习中生成的。
超参数:超参数是在机器学习前由用户基于以往的经验填入的实体,它不能通过机器学习自动生成,而必须由外部进行指定。
例如逻辑回归,假设y=ax+b,其中x是输入数据,sigmoid函数是$f(x) = {1 \over {1 + e^{-(ax+b)}}}$,模型的输出值为0或1。 对于任意给定的数据X,模型都会返回一个a和b与之匹配,其中的a和b就是模型的参数。由于模型的输出值是0或1,因此,决定模型何时输出为1,何时输出为0,需要外部设置一个阈值,这个阈值(threshold)即为模型的超参数。 对于模型的参数,是通过在训练模型或者机器学习中生成的,而超参数是需要外部设置,可以用过学习曲线或者网格搜索等方法进行调节,以使模型表现最佳。
1. 超参数的调整概述
在scikit-learn中提供很多不同的机器学习模型,并且提供了各模型超参数的初始值设置,这些初始值的搭配仅是针对解决某些问题的可能的最优搭配,并不是针对解决所有问题的最优搭配,因此,当使用scikit-learn中的模型进行建模时,调整超参数仍是必要的。
1.1 伴随特征工程的三个调参过程
比较常见的步骤可以如下:
- 初始阶段:以基准参数和基准特征工程为开始,
- 重要参数调节阶段:通过选择一些参数候选和特征工程,手动调参或者网格搜索一些重要特征 ,
- 剩余参数调节阶段:对于其它参数和最后的特征工程,使用随机搜索。
1.2 了解模型超参数
数据科学家的工作之一就是找到模型的最佳超参数。由于每个模型的超参数都不尽相同,很难对所有模型的超参数进行概括性总结。因此,在调节超参数前,应对可能用到的模型及其超参数设置有一个全面概括的了解。下面为几个关于不同集成算法的各参数总结网站,可以收藏,以备不时之需。
(1)介绍xgboost和lightGBM超参数的网站。
(2)在Analytic Vidhya网站上也提供关于GBDT模型的超参数的丰富资料:
- xgboost: "Complete Guide to Parameter Tuning in XGBoost with codes in Python"
- lightgbm: "Which algorithm takes the crown: Light GBM vs XGBOOST?"
(3)XGBoost,LightGBM和CatBoost超参数的优化:
- "An Example of Hyperparameter Optimization on XGBoost, LightGBM and CatBoost using Hyperopt"
下表展示了根据不同分级的重要性,参数不同重要性的总结:
图片来源 https://towardsdatascience.com/hyperparameter-tuning-explained-d0ebb2ba1d35
2. 四个调节超参数的基本方法
2.1 手动调节
手动参数调节更多的是基于建模者对以往经验的总结,通过修改模型的部分参数,了解模型分数对模型参数变化的敏感性。
手动调节参数的优势:
- 应用以往构建模型的经验,选择可能的最佳模型参数。在调参过程中至少可以手动尝试调节模型参数;较为快速。
手动调节参数的劣势:
- 缺少对模型参数与相应得分变化的宏观把握。
比如,当你发现在训练模型的时候,很多不用的特征被“味”到模型中,你可以手动增加正则参数的权重进行特征选择。手动调节参数可以让建模者快速掌握模型对参数变化的敏感度,以备后续提供更好的模型调参范围。
2.2 网格搜索
又名穷尽的网格搜索(Exhaustive Grid Search)。网格搜索方法是通过设置可能的各超参数集合,将所有集合中可能的组合作为超参数,对模型进行一次训练。n个可能的超参数组合意味着n次模型训练。最后,网格搜索的返回值是n次模型训练中模型表现最好的超参数组合。因此,网格搜索随设置的超参数个数和集合的提高,呈时间和空间的复杂性。 网格搜索的评分标准可以由用户来指定,例如准确率,精确率,召回率等。
参数设置和模型评估可以使用sklearn中的GridSearchCV进行调用。
网格搜索的优势:
- 可以选用任何你认为可能是最佳参数范围的超参数集合进行模型训练。
网格搜索的劣势:
- 网格搜索较为耗时,因为要运行给定的每一个超参数集。所以,如果参数集较大,则网格搜索的运行成本较高。实际上,网格搜索的参数范围是需要被限制的,即不能无限大。
以LGBMRegressor模型为例,分别设置了“max_depth”,“subsample”,“colsample_bytree”,“min_child_weight”超参数,它的评分器是“r2”,可能的组合个数是3*2*2*3=36,即需要训练36次LGBMRegressor模型,如下是代码示例:
# 导入lightgbm库 from lightgbm import LGBMRegressor # 导入网格搜索 from sklearn.model_selection import train_test_split, GridSearchCV import pandas as pd import numpy as np # 导入数据并拆分训练集 df = pd.read_csv('test.csv',index_col=0) y = df['Target'] X = df.drop(['Targe'],axis=1) X_train0, X_test, y_train0, y_test = train_test_split(X,y,test_size=0.2, random_state= 2) # 定义验证集比例 r = 0.1 trainLen = round(len(X_train0)*(1-r)) # 拆分训练集和验证集 X_train = X_train0.iloc[:trainLen,:] y_train = y_train0[:trainLen] X_val = X_train0.iloc[trainLen:,:] y_val = y_train0[trainLen:] # 定义网格搜索参数 gridParams = { 'max_depth': [3, 5, 7], 'subsample': [0.8, 1.0], 'colsample_bytree': [0.8, 1.0], 'min_child_weight': [0.1, 1.0, 2.0], } # 定义lightgbm网格搜索 reg = LGBMRegressor(learning_rate=0.1, n_estimators=1000, random_state=1000) reg_gridsearch = GridSearchCV(reg, gridParams, cv=5, scoring='r2', n_jobs=-1) # 训练模型 reg_gridsearch.fit(X_train, y_train, early_stopping_rounds=100, eval_set=(X_val,y_val)) # 返回最佳参数 reg_gridsearch.best_params_
代码参考:https://gist.githubusercontent.com/daydreamersjp/0e588d805be6d6b755c68fa1e8095fc4/raw/e0eb0af142db38fb3ceb48b1f37e2a22671afd0a/gistfile2019120801.py
2.3 随机搜索
随机搜索是基于网格搜索的延伸,它与网格搜索一样,需要预先指定超参数的候选集。随机搜索会随机的从参数候选集中选取参数,训练模型。随机搜索从由所有可能的超参数组合中随机抽取“组合”以训练模型,使用者可以通过设置最大迭代次数,来调节模型的运行次数。相对网格搜索而言,随机搜索的计算成本更低,结果精度相对较低,它返回一个比较general的模型可能实现的水平。随机搜索与网格搜索的返回值相同,均是各自策略下模型的最佳超参数。
随机搜索还可以设置参数的密度函数,例如:均匀分布或者正态分布。
可以在如下库中实现上述操作,如:sklearn中的RandomizedSearchCV。
随机搜索的优势:
- 你可以通过控制参数搜索的次数,控制随机搜索的运行成本。
随机搜索的劣势:
- 它是一种“权衡”策略,运行成本和搜索精度的“权衡”。随机搜索返回的最佳参数可能不是模型实际的最佳参数。
- 由于设置最大搜索次数,因此,一些参数可能被遍历的次数有限。
- 随机搜索不提供随机抽取超参数的方法。
以LGBMRegressor模型为例,分别设置了“max_depth”,“subsample”,“colsample_bytree”,“min_child_weight”,它的评分器为“r2”,最大迭代次数为20,代码示例如下:
# 导入LGBMRegressor from lightgbm import LGBMRegressor # 导入网格搜索 from sklearn.model_selection import train_test_split, RandomizedSearchCV # 可用于声明参数分布 import scipy.stats as stats import pandas as pd import numpy as np # 导入数据集,将数据集拆分为训练/测试集 df = pd.read_csv('test.csv',index_col=0) y = df['Target'] X = df.drop(['Target'],axis=1) X_train0, X_test, y_train0, y_test = train_test_split(X,y,test_size=0.2, random_state= 2) # 训练集的比例 r = 0.1 trainLen = round(len(X_train0)*(1-r)) # 拆分训练集和验证集 X_train = X_train0.iloc[:trainLen,:] y_train = y_train0[:trainLen] X_val = X_train0.iloc[trainLen:,:] y_val = y_train0[trainLen:] # 定义网格搜索空间 randParams = { 'max_depth': stats.randint(1,10), # 介于1到10的整数 'subsample': stats.uniform(0.6,1.0-0.6), # 介于0.6到1的值 'colsample_bytree': stats.uniform(0.6,1.0-0.6), # 介于0.6到1的值 'min_child_weight': stats.uniform(0.1,10.0-0.1), # 介于0.6到1的值 } # 定义lightgbm和网格搜索 reg = LGBMRegressor(learning_rate=0.1, n_estimators=1000, random_state=1000) reg_randsearch = RandomizedSearchCV(reg, randParams, cv=5, n_iter=20, scoring='r2', n_jobs=-1, random_state=2222) # 训练模型 reg_randsearch.fit(X_train, y_train, early_stopping_rounds=100, eval_set=(X_val,y_val)) ## Final l2 was l2: 0.0212662. # 返回最佳参数 reg_randsearch.best_params_
代码参考:https://gist.githubusercontent.com/daydreamersjp/d3e60e613f51bd223f8f153dca2ccb12/raw/8a2f28858a07e0f3e5878d2d3375780a63a80df4/gistfile2019120802.py
2.4 贝叶斯搜索
贝叶斯搜索又名贝叶斯优化。它是基于贝叶斯规则(如下图所示),贝叶斯搜索是从随机搜索开始,基于贝叶斯理论逐渐缩小搜索空间,即通过随机搜索将可能超参数的先验分布更新为后验分布。在考虑已知信息下帮助缩小“好的”超参数组合的搜索空间。 相较随机搜索而言,贝叶斯搜索会花费更多时间,但仍比网格搜索花费更多时间。原理详见如下链接。
图片来源:luminousmen
贝叶斯搜索的优势:
- 搜索的效率较高。
贝叶斯搜索的劣势:
- 可能会落入局布最优化陷阱。
scikit-learn不提供贝叶斯随机搜索的模块,因此,此处代码略。
(1)获取更多优质内容及精彩资讯,可前往:https://www.cda.cn/?seo
(2)了解更多数据领域的优质课程: