数据挖掘--模型参数调优
模型评估
使用metric函数来进行评分
sklearn.metrics里面提供了一些函数来帮助我们进行评分。其中里面以_score结尾的函数的返回值越大,模型的性能越好。而以_error或_loss结尾的函数,返回值越小,表示模型性能越好。从命名上来看,这一点不难理解。
metrics里面的很多函数名不直接传入scoring后面,因为有一些函数需要传入特定的参数才能够使用。比如在使用fbeta_score的时候需要传入bata参数等。 在这个时候,我们的做法是把函数名和参数封装一下,封装成为一个新的函数,然后传入scoring后面。封装的方法是使用metrics的make_scorer方法。
from sklearn.metrics import make_scorer, fbeta_score #我们用make_scorer封装了fbeta_score,它需要传入一个参数 ftwo_score = make_scorer(fbeta_score, beta=2) from sklearn.model_selection import GridSearchCV from sklearn.svm import LinearSVC grid = GridSearchCV(LinearSVC(), param_grid={‘C‘:[1, 10]}, scoring=ftwo_score)
使用metrics的make_score方法,我们可以制定出我们自己的方法,这个方法需要满足下面一些条件:
- 需要传入一个我们自定义的函数的名称
- 需说明greater_is_better的值是True还是False。 当值为正的时候,返回的是score的值,值越高性能越好。当为False的时候,返回的为score的负值,值越低越好。
- 是否是针对分类问题的。 传入needs_threshold=True来说明是针对分类问题的,默认情况为False。
- 其余的参数。如在f1_score中的bata,labels。
import numpy as np from sklearn.metrics import make_scorer def my_custom_loss_func(ground_truth, predictions): diff = np.abs(ground_truth - predictions).max() return np.log(1 + diff) loss = make_scorer(my_custom_loss_func, greater_is_better=False) score = make_scorer(my_custom_loss_func, greater_is_better=True) ground_truth = [[1], [1]] predictions = [0, 1] from sklearn.dummy import DummyClassifier clf = DummyClassifier(strategy=‘most_frequent‘, random_state=0) clf = clf.fit(ground_truth, predictions) #这段代码的原理是这样的,我们的clf使用ground_truth 和predictions进行训练 #使用clf.predict(ground_truth) 进行预测以后的结果为[0,0], #my_custom_loss_func(np.array([0,0], np.array[0,1]) 最后得到log(2) = 0.69314 print(score(clf, ground_truth, predictions)) print(loss(clf, ground_truth, predictions))
我们还可以实现我们自己的评分对象.为了实现更高的自由度,我们可以不使用上述的make_scorer方法,完全定制出来我们自己的评分对象,这需要遵循两点
- 能够调用(estimater, X, y)参数,estimater是我们的模型,X为数据集, y为X数据集的真实结果。
- 需要返回一个分数作为评分的结果。该分数能够从某个方面反映出我们模型的好坏。
模型调参
1.贪心调参
采用贪心算法选取局部最优的思想,每次选择一个参数(其他参数为默认或者为已经调至最优的参数)调至最优。代码如下:
## LGB的参数集合: objective = ['regression', 'regression_l1', 'mape', 'huber', 'fair'] num_leaves = [3,5,10,15,20,40, 55] max_depth = [3,5,10,15,20,40, 55] bagging_fraction = [] feature_fraction = [] drop_rate = [] # 贪心调参 每一轮针对某个特征找到最优的值, # key-参数名字 value为对应的参数值 best_obj = dict() for obj in objective: model = LGBMRegressor(objective=obj) score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error))) best_obj[obj] = score best_leaves = dict() for leaves in num_leaves: model = LGBMRegressor(objective=min(best_obj.items(), key=lambda x:x[1])[0], num_leaves=leaves) score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error))) best_leaves[leaves] = score best_depth = dict() for depth in max_depth: model = LGBMRegressor(objective=min(best_obj.items(), key=lambda x:x[1])[0], num_leaves=min(best_leaves.items(), key=lambda x:x[1])[0], max_depth=depth) score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error))) best_depth[depth] = score sns.lineplot(x=['0_initial','1_turning_obj','2_turning_leaves','3_turning_depth'], y=[0.143 ,min(best_obj.values()), min(best_leaves.values()), min(best_depth.values())])
2.网格调参(Grid Search)
Sklearn-GridSearchCV:一种调参的方法,当你算法模型效果不是很好时,可以通过该方法来调整参数,通过循环遍历,尝试每一种参数组合,返回最好的得分值的参数组合。由于遍历的组合较多,在算力条件一般的情况下,适用于小数据集。代码如下:
# grid search 网格搜索调参 遍历所有给定的值进行调参 适用于小数据集 # 原来的数据集分割为训练集和测试集之后,其中测试集起到的作用有两个,一个是用来调整参数,一个是用来评价模型的好坏,这样会导致评分值会比实际效果要好。(因为我们将测试集送到了模型里面去测试模型的好坏,而我们目的是要将训练模型应用在没使用过的数据上。) from sklearn.model_selection import GridSearchCV parameters = {'objective': objective , 'num_leaves': num_leaves, 'max_depth': max_depth} model = LGBMRegressor() # 交叉验证~ clf = GridSearchCV(model, parameters, cv=5) clf = clf.fit(train_X, train_y) clf.best_params_
3.贝叶斯调参:
在搜索空间过大的时候,网格搜索的速度实在不太能让人接受,贝叶斯调参相对于网格搜索的优势如下
- 贝叶斯调参采用高斯过程,会考虑到之前的参数信息,不断地更新先验;网格搜索则不会考虑先验信息。
- 贝叶斯调参迭代次数少,速度快;网格搜索会遍历所有的可能的参数组合,所以速度慢,参数多时易导致维度爆炸
- 贝叶斯调参针对非凸问题依然稳健;网格搜索针对非凸问题易得到局部最优。
# 贝叶斯调参 from bayes_opt import BayesianOptimization from sklearn.metrics import mean_absolute_error, make_scorer # 用 make_scorer封装metrics中的评分函数供scoring使用 def rf_cv(num_leaves, max_depth, subsample, min_child_samples): val = cross_val_score( LGBMRegressor(objective = 'regression_l1', num_leaves=int(num_leaves), max_depth=int(max_depth), subsample = subsample, min_child_samples = int(min_child_samples) ), X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error) ).mean() return 1 - val # 核心三个部分 目标函数的设计:rf_cv,域空间的设定(参数范围),最优化search rf_bo = BayesianOptimization( rf_cv, { 'num_leaves': (2, 100), 'max_depth': (2, 100), 'subsample': (0.1, 1), 'min_child_samples' : (2, 100) } ) rf_bo.maximize() # 输出最优参数组合 print(rf_bo.max)
https://github.com/fmfn/BayesianOptimization 有贝叶斯调参代码更加详细的一个介绍
附录:
常用模型的链接一个记录回头整理一下: