文章目录
一、超参数
优化可以分为参数优化和超参数优化。其中,可学习的参数通过优化算法可以进行优化;还有一类参数是用来定义模型结构或优化策略的,这类参数称为超参数(hyper-parameter)
超参数优化(Hyperparameter Optimization)主要存在两方面的困难。
- 超参数优化是一个组合优化问题,无法像一般参数那样通过梯度下降方法来优化,也没有一种通用有效的优化方法。
- 评估一组超参数配置(Configuration)的时间代价非常高,从而导致一些优化方法(比如演化算法(Evolution Algorithm))在超参数优化中难以应用。
对于超参数的设置,比较简单的方法有人工搜索、 网格搜索和随机搜索。
1、网格搜索
网格搜索(grid search) 是一种通过尝试所有超参数的组合来寻址合适一组超参数配置的方法。
假设总共有 K K K 个超参数,第 k k k 个超参数的可以取 m k m_k mk 个值。那么总共的配置组合数量为 m 1 × m 2 × . . . × m K m_1 ×m_2 ×...× m_K m1×m2×...×mK。如果超参数是连续的,需要根据超参数自身的特点进行离散化。
实现:sklearn.model_selection.GridSearchCV 官网文档链接
class sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, fit_params=None, n_jobs=None, iid=’warn’, refit=True, cv=’warn’, verbose=0, pre_dispatch=‘2*n_jobs’, error_score=’raise-deprecating’, return_train_score=’warn’)
实际当中有用的参数,以clf表示我们的GridSearchCV对象
clf.best_params_
返回最好的参数clf.best_score_
返回最好的测试分数,它的值和clf.cv_results_['mean_test_score'][dt_grid.best_index_]
是相同的。clf.best_index_
返回列表中分数最好的下表clf.best_estimator_
返回最好的模型clf.cv_results_
返回使用交叉验证进行搜索的结果,它本身又是一个字典,里面又有很多内容。
2、随机搜索
对超参数进行随机组合,然后选取一个性能最好的配置,这就是随机搜索(Random Search)。随机搜索在实践中更容易实现,一般会比网格搜索更加有效。
3、贝叶斯优化
贝叶斯优化(Bayesian optimization)是一种自适应的超参数搜索方法,根据当前已经试验的超参数组合,来预测下一个可能带来最大收益的组合。
常用的贝叶斯优化方法:时序模型优化(Sequential Model-Based Optimization,SMBO)
二、Stacking
概述:将个体机器学习器的结果结合在一起,即对学习器的结果再加上一层学习器。将训练集学习器的学习结果作为输入,将训练集的输出作为输出,重新训练一个学习器来得到最终结果。(也就是常说的两层)
术语:
- 弱学习器称为初级学习器,将用于结合的学习器称为次级学习器;
- 对于测试集,我们首先用初级学习器预测一次,得到次级学习器的输入样本,再用次级学习器预测一次,得到最终的预测结果。
1、核心图解
对于每一轮的 5-fold,Model 1都要做满5次的训练和预测。
(1)构建新的训练集
- 先将训练集 D ( T r a i n i n g D a t a ) D(Training Data) D(TrainingData) 拆成 k k k 个大小相似但互不相交的子集 D 1 , D 2 , … , D k D_1,D_2,…,D_k D1,D2,…,Dk;
- 令 D j ′ = D − D j D_j'= D - D_j Dj′=D−Dj,在 D j ′ D_j' Dj′ 上训练一个弱学习器 L j L_j Lj 。将 D j D_j Dj 作为测试集,获得 L j L_j Lj 在 D j D_j Dj 上的输出 D j ′ ′ D_j'' Dj′′ ;
- 步骤2可以得到 k k k 个弱学习器以及 k k k 个相应的输出 D j ′ ′ D_j'' Dj′′ ,这个 k k k 个输出加上原本的类标构成新的训练集 D n D_n Dn ;
- 在 D n D_n Dn 训练次学习器 L L L , L L L 即为最后的学习器。
(2)构建新的测试集
- 对于每个训练好的一个弱学习器 L j L_j Lj,在测试集(Test Data,图中所示绿色部分,不要与上面的“测试集”混淆。注意:此处是测试集的全部)进行预测,将 k k k 次的预测结果取平均作为新的预测集。
(3)最终的训练与预测
- 训练集为构建新的训练集步骤得到的训练集,测试集为构建新的测试集得到的测试集
- 训练分类器并预测。
2、示例
(1)构建新的训练集
Train Data有890行。(请对应图中的上层部分)
每1次的fold,都会生成 713行 小train, 178行 小test。我们用Model 1来训练 713行的小train,然后预测 178行 小test。预测的结果是长度为 178 的预测值。
这样的动作走5次! 长度为178 的预测值 X 5 = 890 预测值,刚好和Train data长度吻合。这个890预测值是Model 1产生的,我们先存着,因为,一会让它将是第二层模型的训练来源。
重点:这一步产生的预测值我们可以转成 890 X 1 (890 行,1列),记作 P1 (大写P)
(2)构建新的测试集
Test Data 有 418 行。(请对应图中的下层部分,对对对,绿绿的那些框框)
每1次的fold,713行 小train训练出来的Model 1要去预测我们全部的Test Data(全部!因为Test Data没有加入5-fold,所以每次都是全部!)。此时,Model 1的预测结果是长度为418的预测值。
这样的动作走5次!我们可以得到一个 5 X 418 的预测值矩阵。然后我们根据行来就平均值,最后得到一个 1 X 418 的平均预测值。
重点:这一步产生的预测值我们可以转成 418 X 1 (418行,1列),记作 p1 (小写p)
(3)多模型的处理
走到这里,你的第一层的Model 1完成了它的使命。
第一层还会有其他Model的,比如Model 2,同样的走一遍, 我们有可以得到 890 X 1 (P2) 和 418 X 1 (p2) 列预测值。
这样吧,假设你第一层有3个模型,这样你就会得到:
来自5-fold的预测值矩阵 890 X 3,(P1,P2, P3) 和 来自Test Data预测值矩阵 418 X 3, (p1, p2, p3)。
(4)最终的训练与预测
来自5-fold的预测值矩阵 890 X 3 作为你的Train Data,训练第二层的模型
来自Test Data预测值矩阵 418 X 3 就是你的Test Data,用训练好的模型来预测他们吧。
三、实现
1、超参数调参
# -*- coding: utf-8 -*-
import pandas as pd
import pickle
import lightgbm as lgb
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model.logistic import LogisticRegression
from sklearn.svm import LinearSVC
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
fp = open('./features/data_tfidf_train.pkl', 'rb')
x_train,y_train = pickle.load(fp)
x_train, x_test, y_train, y_test = train_test_split(x_train[:5000], y_train[:5000], test_size=0.3, random_state=2019)
print('Start Training:Logistic Regression...')
lr_grid={'C':list((100,120,140))}
lr = GridSearchCV(LogisticRegression(),param_grid = lr_grid, cv = 5)
lr.fit(x_train, y_train)
print('Best param is ', lr.best_params_)
print('The best score is ', lr.best_score_)
print('Start Training:SVM...')
svm_grid={'C':list((1, 5, 10))}
svm = GridSearchCV(LinearSVC(),param_grid = svm_grid, cv = 5)
svm.fit(x_train, y_train)
print('Best param is ', svm.best_params_)
print('The best score is ', svm.best_score_)
print('Start Training:LightGBM...')
lgbm_grid={'num_leaves':list((25, 30, 35)), 'learning_rate':list((0.2, 0.1, 0.005)), 'n_estimators':list((10, 20, 50))}
lgbm = GridSearchCV(lgb.sklearn.LGBMClassifier(),param_grid = lgbm_grid, cv = 5)
lgbm.fit(x_train, y_train)
print('Best param is ', lgbm.best_params_)
print('The best score is ', lgbm.best_score_)
输出结果
结果后续补上,运行时间太长。。。。
2、模型融合
## 使用多模型实现
from mlxtend.classifier import StackingClassifier
lr_model = LogisticRegression()
svm_model = LinearSVC()
lgbm_model = lgb.sklearn.LGBMClassifier()
dt_model = DecisionTreeClassifier()
sclf = StackingClassifier(classifiers=[lr_model,svm_model,lgbm_model],meta_classifier=dt_model)
sclf.fit(x_train,y_train)
for clf,label in zip([lr_model,svm_model,lgbm_model,sclf],['逻辑回归','SVM','LightGBM','StackingClassifier']):
scores = cross_val_score(clf,x_train,y_train,cv = 5,scoring='accuracy')
print("Accuracy: %0.2f (+/- %0.2f) [%s]"% (scores.mean(), scores.std(), label))
结果输出
Accuracy: 0.77 (+/- 0.01) [逻辑回归]
Accuracy: 0.80 (+/- 0.00) [SVM]
Accuracy: 0.79 (+/- 0.01) [LightGBM]
Accuracy: 0.78 (+/- 0.01) [StackingClassifier]