赞
踩
LightGBM(Light Gradient Boosting Machine)是一款基于决策树算法的分布式梯度提升框架,旨在提供快速高效、低内存占用、高准确率的模型训练工具。它通过多种优化手段,解决了传统GBDT在面对海量数据时遇到的效率和内存瓶颈问题,使其更适用于工业级应用。
基于直方图的决策树算法:LightGBM使用直方图优化技术,将连续的特征值离散化成特定的bin(即直方图的桶),减少了在节点分裂时需要计算的数据量。这种方法可以在减少内存使用的同时,提高计算速度。
带深度限制的leaf-wise树生长策略:与传统的水平分割不同,leaf-wise的生长策略是每次从当前所有叶子节点中选择分裂收益最大的节点进行分裂。这种策略可以使得决策树更加侧重于数据中的异常部分,通常可以得到更好的精度。
单边梯度采样:对于数据集中的大梯度样本,只保留数据的一部分(通常是大梯度的样本),减少计算量同时保证不会损失太多的信息。这种方法可以在不显著损失精度的情况下加快训练速度。
互斥特征捆绑:EFB是一种减少特征数量、提高计算效率的技术,它将互斥的特征进行合并,以减少特征维度。
优点:
高效性:通过直方图优化和leaf-wise生长策略,LightGBM在保证精度的同时大幅提升了训练速度。
内存使用少:相比于其他GBM实现,LightGBM需要的内存更少,这使得它能够处理更大的数据集。
可扩展性:支持多线程和分布式计算,可以利用现代硬件的计算能力。
易用性:提供了丰富的参数选项,方便用户根据具体问题进行调整。
缺点:
对噪声敏感:leaf-wise的生长策略容易受到数据中噪声的影响,可能导致过拟合。
调参复杂:虽然LightGBM提供了丰富的参数选项,但这也使得模型调参变得相对复杂,需要一定的经验和实验来确定最优参数。
- import numpy as np
- import pandas as pd
- import lightgbm as lgb
- from sklearn.metrics import mean_squared_error
- import sys
- import os
- import gc
- import argparse
- import warnings
- train = pd.read_csv('../data/train.csv')
- test = pd.read_csv('../data/test.csv')
历史平移特征是一种在时间序列分析中常用的特征工程方法,它通过将历史数据作为新特征加入模型中,以提升模型的预测能力。主要作用是捕捉时间序列数据中的历史信息,这些信息对于预测未来的值可能具有重要作用。在时间序列分析中,一个观测点的值往往与其历史上的值密切相关。例如,在金融市场中,股票的今日价格往往与昨天、上周甚至是去年同一天的价格有关;在销售预测中,本月的销售额往往受到前几个月销售情况的影响。因此,通过在模型中加入这些历史数据作为特征,可以帮助模型学习到数据中的时间依赖关系,从而提高预测的准确性。
相关代码如下:
- # 历史平移
- for i in range(10, 30):
- data[f'last{i}_target'] = data.groupby(['id'])['target'].shift(i)
窗口统计特征是基于时间序列数据在滑动窗口内计算的一系列统计量,用于捕捉数据的局部行为和动态变化。这些统计量通常包括平均值、中位数、标准偏差、最小值和最大值等,有助于揭示时间序列在不同时间段内的行为变化。其主要目的是通过在数据上滑动固定大小的窗口并计算该窗口内数据的统计量,从而提取有意义的信息。这种方法特别适用于那些具有局部相似性和时间依赖性的数据。例如,在金融市场分析中,股票价格的移动平均线可以通过计算特定时间窗口内的平均值来得到,这有助于平滑短期波动并突出长期趋势。
相关代码如下:
- # 窗口统计
- data[f'win3_mean_target'] = (data['last10_target'] + data['last11_target'] + data['last12_target']) / 3
在正式开始模型训练与测试集预测前,我们需要对数据进行切分和对特征的确认。这两个步骤在机器学习和数据分析中至关重要,因为它们直接影响模型的训练效果和预测能力。
数据集切分的目的是将原始数据分为不同的子集,以便在不同的阶段使用。训练集用于模型学习,测试集用于初步评估模型性能,而验证集则用于优化模型超参数。特征确认旨在识别和选择对模型预测最有用和最具代表性的特征,以提高模型的性能和泛化能力。
- # 进行数据切分
- train = data[data.target.notnull()].reset_index(drop=True)
- test = data[data.target.isnull()].reset_index(drop=True)
-
- # 确定输入特征
- train_cols = [f for f in data.columns if f not in ['id', 'target']]
使用训练数据集对模型进行训练。这一过程中,LightGBM会自动进行多线程或分布式计算,大幅度提高训练速度。
- def time_model(lgb,train_df, test_df, cols):
- # 训练集和验证集切分
- trn_x, trn_y = train_df[train_df.dt >= 31][cols], train_df[train_df.dt >= 31]['target']
- val_x, val_y = train_df[train_df.dt <= 30][cols], train_df[train_df.dt <= 30]['target']
- # 构建模型输入数据
- train_matrix = lgb.Dataset(trn_x, label=trn_y)
- valid_matrix = lgb.Dataset(val_x, label=val_y)
- # lightgbm参数
- lgb_params = {
- 'boosting_type': 'gbdt',
- 'objective': 'regression',
- 'metric': 'mse',
- 'min_child_weight': 5,
- 'num_leaves': 2 ** 5,
- 'lambda_l2': 10,
- 'feature_fraction': 0.8,
- 'bagging_fraction': 0.8,
- 'bagging_freq': 4,
- 'learning_rate': 0.05,
- 'seed': 2024,
- 'nthread': 16,
- 'verbose': -1,
- }
- # 训练模型
- model = lgb.train(lgb_params, train_matrix, 10000, valid_sets=[train_matrix, valid_matrix],
- categorical_feature=[])
- # 验证集和测试集结果预测
- val_pred = model.predict(val_x, num_iteration=model.best_iteration)
- test_pred = model.predict(test_df[cols], num_iteration=model.best_iteration)
- # 离线分数评估
- score = mean_squared_error(val_pred, val_y)
- print(score)
-
- return val_pred, test_pred
-
-
- lgb_oof, lgb_test = time_model(lgb, train, test, train_cols)
-
- # 保存结果文件到本地
- test['target'] = lgb_test
- test[['id', 'dt', 'target']].to_csv('../data/submit.csv', index=None)
首先,我们需要导入所需的库,并定义一个函数cv_model
,该函数将根据传入的参数选择使用lightgbm、xgboost或catboost模型。然后,我们将使用K折交叉验证方法对每个模型进行评估,并将三个模型的结果取平均进行融合。
- import numpy as np
- import pandas as pd
- import lightgbm as lgb
- from sklearn.linear_model import Ridge
- from sklearn.metrics import mean_squared_log_error, mean_absolute_error, mean_squared_error
- from sklearn.model_selection import StratifiedKFold, KFold, GroupKFold
- import xgboost as xgb
- from catboost import CatBoostRegressor
- import warnings
- def cv_model(clf, train_x, train_y, test_x, clf_name, seed=2024):
- """
- clf:调用模型
- train_x:训练数据
- train_y:训练数据对应标签
- test_x:测试数据
- clf_name:选择使用模型名
- seed:随机种子
- """
- folds = 5
- kf = KFold(n_splits=folds, shuffle=True, random_state=seed)
- oof = np.zeros(train_x.shape[0])
- test_predict = np.zeros(test_x.shape[0])
- cv_scores = []
-
- for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
- print('************************************ {} ************************************'.format(str(i + 1)))
- trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], \
- train_y[valid_index]
-
- 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',
- 'objective': 'regression',
- 'metric': 'mae',
- 'min_child_weight': 6,
- 'num_leaves': 2 ** 6,
- 'lambda_l2': 10,
- 'feature_fraction': 0.8,
- 'bagging_fraction': 0.8,
- 'bagging_freq': 4,
- 'learning_rate': 0.1,
- 'seed': 2023,
- 'nthread': 16,
- 'verbose': -1,
- }
- model = clf.train(params, train_matrix, 1000, valid_sets=[train_matrix, valid_matrix],categorical_feature=[])
- val_pred = model.predict(val_x, num_iteration=model.best_iteration)
- test_pred = model.predict(test_x, num_iteration=model.best_iteration)
-
- if clf_name == "xgb":
- xgb_params = {
- 'booster': 'gbtree',
- 'objective': 'reg:squarederror',
- 'eval_metric': 'mae',
- 'max_depth': 5,
- 'lambda': 10,
- 'subsample': 0.7,
- 'colsample_bytree': 0.7,
- 'colsample_bylevel': 0.7,
- 'eta': 0.1,
- 'tree_method': 'hist',
- 'seed': 520,
- 'nthread': 16
- }
- train_matrix = clf.DMatrix(trn_x, label=trn_y)
- valid_matrix = clf.DMatrix(val_x, label=val_y)
- test_matrix = clf.DMatrix(test_x)
-
- watchlist = [(train_matrix, 'train'), (valid_matrix, 'eval')]
-
- model = clf.train(xgb_params, train_matrix, num_boost_round=1000, evals=watchlist)
- val_pred = model.predict(valid_matrix)
- test_pred = model.predict(test_matrix)
-
- if clf_name == "cat":
- params = {'learning_rate': 0.1, 'depth': 5, 'bootstrap_type': 'Bernoulli', 'random_seed': 2023,
- 'od_type': 'Iter', 'od_wait': 100,'allow_writing_files': False}
-
- model = clf(iterations=1000, **params)
- model.fit(trn_x, trn_y, eval_set=(val_x, val_y),
- metric_period=200,
- use_best_model=True,
- cat_features=[],
- verbose=1)
-
- val_pred = model.predict(val_x)
- test_pred = model.predict(test_x)
-
- oof[valid_index] = val_pred
- test_predict += test_pred / kf.n_splits
-
- score = mean_absolute_error(val_y, val_pred)
- cv_scores.append(score)
- print(cv_scores)
-
- return oof, test_predict
这里使用了lightgbm、xgboost和catboost三个模型,并使用K折交叉验证来评估模型的性能。 函数首先初始化K折交叉验证,对于每个交叉验证的循环,将训练数据划分为训练集和验证集;再根据选择的模型名,使用相应的库(lightgbm、xgboost或catboost)来训练模型,使用训练好的模型对验证集进行预测,并将预测结果保存到oof数组中,再将预测结果累加到test_predict数组中,以计算测试数据的平均预测结果;然后将计算验证集的均方误差(mean absolute error,mae),并将结果保存到cv_scores列表中;最后打印和返回相关数据。
- # 选择lightgbm模型
- lgb_oof, lgb_test = cv_model(lgb, train[train_cols], train['target'], test[train_cols], 'lgb')
- # 选择xgboost模型
- xgb_oof, xgb_test = cv_model(xgb, train[train_cols], train['target'], test[train_cols], 'xgb')
- # 选择catboost模型
- cat_oof, cat_test = cv_model(CatBoostRegressor, train[train_cols], train['target'], test[train_cols], 'cat')
-
- # 进行取平均融合
- final_test = (lgb_test + xgb_test + cat_test) / 3
另外需要注意的是虽然模型融合能显著提高预测性能,但会增加计算复杂度。需要权衡模型复杂度和准确度,避免过度堆砌模型。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。