当前位置:   article > 正文

机器学习实战(LightGBM)_lightgbm实战

lightgbm实战

LightGBM

介绍

LightGBM(Light Gradient Boosting Machine):一个实现GBDT算法的框架,解决GBDT在海量数据遇到的问题。

两大技术:

(1)GOSS(Gradient-based One-Side Sampling):减少样本数

(2)EFB (Exclusive Feature Bundling ):减少特征数

XGBoost的缺点:先预排序再找分割点,空间消耗大

XGBoost与LightGBM的区别:

lightGBMXGBoost
分裂方式leaft-wise选择分裂收益最大的节点,要限制深度容易过拟合level-wise无差别分裂
输入lightgbm支持直接输入categorical 的feature需要one-hot编码
时间复杂度基于直方图的决策树算法,直方图的优化算法只需要计算K次,时间复杂度为O(Kfeature)基于预排序的决策树算法,每遍历一个特征就需要计算一次特征的增益,时间复杂度为O(datafeature)
特征捆绑转化为图着色问题,减少特征数量

两种使用形式

sklearn接口形式

导包

import lightgbm as lgb
from sklearn.metrics import mean_squared_error
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
  • 1
  • 2
  • 3
  • 4
gbm = lgb.LGBMRegressor(objective='regression', num_leaves=31, learning_rate=0.05, n_estimators=20)
gbm.fit(X_train, y_train, eval_set=[(X_test, y_test)], eval_metric='l1', early_stopping_rounds=5)
  • 1
  • 2
原生形式

数据集切分与转换

lgb_train = lgb.Dataset(X_train, y_train)
#If this is Dataset for validation, training data should be used as reference.
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train) 
  • 1
  • 2
  • 3

将参数写为字典形式

params = {
    'task': 'train',
    'boosting_type': 'gbdt',  # 设置提升类型
    'objective': 'regression',  # 目标函数
    'metric': {'l2', 'auc'},  # 评估函数
    'num_leaves': 31,  # 叶子节点数
    'learning_rate': 0.05,  # 学习速率
    'feature_fraction': 0.9,  # 建树的特征选择比例
    'bagging_fraction': 0.8,  # 建树的样本采样比例
    'bagging_freq': 5,  # k 意味着每 k 次迭代执行bagging
    'verbose': 1  # <0 显示致命的, =0 显示错误 (警告), >0 显示信息
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

交叉验证与预测评估

gbm = lgb.train(params, lgb_train, num_boost_round=20, valid_sets=lgb_eval, early_stopping_rounds=5)
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration)
  • 1
  • 2

Epoch、Iteration、Batchsize相关理解

Epoch

一个完整的数据集通过了神经网络一次并且返回了一次。梯度下降的方法来优化学习过程,随着epoch

Iteration

batch需要完成一个epoch的次数

一个迭代=一个正向通过+一个反向通过。

Batchsize

不能将数据一次性通过神经网络的时候,就需要将数据集分成几个batch。

batchsize的选择:Batch:数据集较小选择全批次

mini batch:选定后以batch的大小输入网络,计算这个batch的所有样本的平均损失,即代价函数是所有样本的平均

stochastic:每次修正方向以各自样本的梯度方向修正,难收敛

如果batchsize过小,训练数据难以收敛容易欠拟合,增加batchsize相对处理速度加快但是占用内存增加

参数调整

预先固定的参数调整策略
learning_rate0.05~0.1 学习率较小比较稳定。默认0.1
n_estimators100~1000。可以设置一个较大的值配合early_stopping_round来让模型根据性能自动选择最好的迭代次数。默认100
min_split_gain执行节点分裂的最小增益。默认为0。不建议去调整。增大这个数值会得到相对浅的树深。可调整其他参数得到类似效果。
min_child_sample一个叶子上的最小数据量。默认设置为20.数据量大适当增加
min_child_weight一个叶子上的最小hessian和。默认设置为0.001,一般设置为1。不建议调整,增大数值会得到较浅的树深
通过算法来搜索的参数调整策略
max_depth3,4,5(过大容易过拟合)
num_leaves小于2^max_depth-1
subsample大致的搜索范围[0.8, 0.9, 1.0]
colsample_bytree大致的搜索范围[0.8, 0.9, 1.0]
reg_alpha服务于L1正则化,一般取0-1000的范围。通过特征筛选该数值由大变小可以增加模型信心
reg_lambda服务于L2正则化,一般0-1000的范围。如果有非常强势的特征,可以人为加大一些reg_lambda使得整体特征效果平均一些,一般会比reg_alpha的数值略大一些,但如果这个参数大的夸张也需要再查看一遍特征是否合理

代码实例

训练模型并求最优参数的函数定义
import lightgbm as lgb
def cv_model(clf, train_x, train_y, test_x, clf_name):
  • 1
  • 2

划分100折并进行数据打乱

folds = 10
seed = 2022
kf = KFold(n_splits=folds, shuffle=True, random_state=seed)
  • 1
  • 2
  • 3

​ 设置测试集的输出矩阵。每一组数据输出:[0,0,0,0]以概率值填入

test = np.zeros((test_x.shape[0],4))

#交叉验证分数
cv_scores = []
onehot_encoder = OneHotEncoder(sparse=False)
  • 1
  • 2
  • 3
  • 4
  • 5

根据折数进行划分,i值代表第(i+1)折。每一个K折都进行「数据混乱:随机」操作
train_index:10折里9折在train_index
valid_index:剩下1折样本索引值,作为验证集用于给出「训练误差」

for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
if i < 9:
    #打印第(i+1)个模型结果
    print('模型:'i+1)
    
    #将训练集分为:真正训练的数据(K-1折),和 训练集中的测试数据(1折)
    trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y.iloc[train_index], train_x.iloc[valid_index], train_y.iloc[valid_index]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
模型的设置和调用
 #LGB模型
        if clf_name == "lgb":            
            #训练样本
            train_matrix = clf.Dataset(trn_x, label=trn_y)
            #训练集中测试样本
            valid_matrix = clf.Dataset(val_x, label=val_y) 
            #参数设置
            params = {
                'boosting_type': 'gbdt',          #boosting方式
                'objective': 'multiclass',        #任务类型为「多分类」
                'num_class': 4,                   #类别个数
                'num_leaves': 2 ** 5,             #最大的叶子数,树模型的复杂度
                'feature_fraction': 0.8,          #每次迭代中随机选择特征的比例(0.5-0.9之间调整)
                'bagging_fraction': 0.8,          #不进行重采样的情况下随机选择部分数据(0.5-0.9之间调整)
                'bagging_freq': 5,                #每5次迭代,进行一次bagging(3-5之间调整)
                'learning_rate': 0.05,            #学习率
                'seed': seed,                     #seed值,保证模型复现
                'nthread': 28,                    
                'n_jobs':24,                      #多线程
                'verbose': 1,
                'lambda_l1': 0.4,                 # L1正则化
                'lambda_l2': 0.5,                 #L2正则化
                'min_data_in_leaf':100,           #叶子可能具有的最小记录数
            }
            
            #模型
            model = clf.train(params, 
                      train_set=train_matrix,     #训练样本
                      valid_sets=valid_matrix,    #测试样本 
                      num_boost_round=2000,      #迭代次数
                      verbose_eval=100,           
                      early_stopping_rounds=200)  #如果数据在200次内没有提高,停止计算
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

            val_pred = model.predict(val_x, num_iteration=model.best_iteration)
            test_pred = model.predict(test_x, num_iteration=model.best_iteration) 

        val_y = np.array(val_y).reshape(-1, 1)
        val_y = onehot_encoder.fit_transform(val_y)
        print('预测的概率矩阵:')
        print(test_pred)
        test += test_pred
        #验证集计算训练误差
        score = loss(val_y, val_pred)
        cv_scores.append(score)
        print(cv_scores)
    
print("%s_scotrainre_list:" % clf_name, cv_scores)
print("%s_score_mean:" % clf_name, np.mean(cv_scores))
print("%s_score_std:" % clf_name, np.std(cv_scores))

#i个模型输出结果的平均值。
test = test / 10
return test
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
调用模型的函数定义
def lgb_model(x_train, y_train, x_test):
    lgb_test = cv_model(lgb, x_train, y_train, x_test, "lgb")
    return lgb_test

def loss(y_p,y_t):
	y_p=np.array(y_p)
    y_t=np.array(y_t)
    loss=sum(sum(abs(y_p-y_t)))
    return loss
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
lgb_test = lgb_model(X_train, y_train, X_test)
  • 1
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号