")XGBoost最终得分为264.79分

发布时间:2025-06-24 20:15:52  作者:北方职教升学中心  阅读量:609


创建滚动统计特征

# 特征工程尝试一import pandas as pdimport numpy as npfrom sklearn.preprocessing import LabelEncoder# 合并训练和测试数据集以便于特征工程train_df['is_train'] = 1test_df['is_train'] = 0test_df['target'] = np.nanfull_df = pd.concat([train_df, test_df], axis=0, ignore_index=True)# 处理日期特征full_df['day_of_week'] = full_df['dt'] % 7  # 假设1代表周一full_df['is_weekend'] = full_df['day_of_week'].isin([5, 6]).astype(int)# 处理房屋类型le = LabelEncoder()full_df['type'] = le.fit_transform(full_df['type'])# 创建时间序列特征def create_lag_features(df, lags, col):    for lag in lags:        df[f'{col}_lag_{lag}'] = df.groupby('id')[col].shift(lag)    return dflags = [1, 2, 3, 7, 14, 30]full_df = create_lag_features(full_df, lags, 'target')# 创建滚动统计特征def create_rolling_features(df, windows, col):    for window in windows:        df[f'{col}_roll_mean_{window}'] = df.groupby('id')[col].shift(1).rolling(window).mean()        df[f'{col}_roll_max_{window}'] = df.groupby('id')[col].shift(1).rolling(window).max()        df[f'{col}_roll_min_{window}'] = df.groupby('id')[col].shift(1).rolling(window).min()        df[f'{col}_roll_std_{window}'] = df.groupby('id')[col].shift(1).rolling(window).std()    return dfwindows = [3, 7, 14, 30]full_df = create_rolling_features(full_df, windows, 'target')# 填充缺失值full_df.fillna(0, inplace=True)# 拆分回训练和测试集train_df = full_df[full_df['is_train'] == 1].drop(['is_train'], axis=1)test_df = full_df[full_df['is_train'] == 0].drop(['is_train', 'target'], axis=1)# 保存处理后的数据集train_df.to_csv('new_train.csv', index=False)test_df.to_csv('new_test.csv', index=False)print("特征工程完成,处理后的数据集已保存。和 XGBoost 相比,其在大规模数据集上跑起来更加轻盈。

完成了特征工程后,我们分别采取三个集成学习模型进行训练:

# XGBoostimport pandas as pdimport numpy as npimport xgboost as xgbfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import mean_squared_error# 加载处理后的数据train_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\dataset\train.csvv')test_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\dataset\test.csv')# 准备训练数据和标签X = train_df.drop(columns=['target', 'id', 'dt'])y = train_df['target']X_test = test_df.drop(columns=['id', 'dt'])# 拆分训练集和验证集X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)# 创建XGBoost DMatrixtrain_data = xgb.DMatrix(X_train, label=y_train)val_data = xgb.DMatrix(X_val, label=y_val)test_data = xgb.DMatrix(X_test)# 设置参数params = {    'objective': 'reg:squarederror',    'eval_metric': 'rmse',    'eta': 0.05,    'max_depth': 6,    'subsample': 0.9,    'colsample_bytree': 0.9,    'alpha': 0.1,    'lambda': 1.0,}# 设置回调函数callbacks = [    xgb.callback.EarlyStopping(rounds=500, save_best=True),    xgb.callback.EvaluationMonitor(period=100)]# 训练模型model = xgb.train(params, train_data, num_boost_round=50000, evals=[(train_data, 'train'), (val_data, 'eval')],                  callbacks=callbacks)# 进行预测predictions = model.predict(test_data)# 创建预测结果数据框results_df = test_df[['id', 'dt']].copy()results_df['target'] = predictions# 保存预测结果results_df.to_csv('XGB_submit.csv', index=False)print("模型训练和预测完成,预测结果已保存。这也是分数为何居高不下的原因之一。最大值、请原谅我说这条路实在是走的很费劲,因为本人之前基本没有特征工程很成功的经验。我先开始尝试的是调参,调参的两大基本方法便是网格搜索法和贝叶斯优化。")

(1)历史平移特征:通过历史平移获取上个阶段的信息;

(2)差分特征:可以帮助获取相邻阶段的增长差异,描述数据的涨减变化情况。2、90天)下的移动平均值;以及创建差分特征,一个名为create_diff_features的函数被定义来计算目标变量target在不同滞后阶数(1、")# LightGBM训练和预测代码import lightgbm as lgbfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import mean_squared_errorfrom lightgbm import early_stopping, log_evaluation# 加载数据train_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\dataset\train.csv')test_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\dataset\test.csv')# 准备训练数据和标签X = train_df.drop(columns=['target', 'id', 'dt'])y = train_df['target']X_test = test_df.drop(columns=['id', 'dt'])# 拆分训练集和验证集X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)# 创建LightGBM数据集train_data = lgb.Dataset(X_train, label=y_train)val_data = lgb.Dataset(X_val, label=y_val, reference=train_data)# 设置参数params = { 'objective': 'regression', 'metric': 'mse', 'boosting_type': 'gbdt', 'num_leaves': 31, 'learning_rate': 0.05, 'feature_fraction': 0.9}# 设置回调函数callbacks = [ log_evaluation(period=100), # 每100轮记录一次日志 early_stopping(stopping_rounds=500) # 500轮没有提升时提前停止]# 训练模型model = lgb.train(params, train_data, num_boost_round=50000, valid_sets=[train_data, val_data], callbacks=callbacks)# 进行预测predictions = model.predict(X_test, num_iteration=model.best_iteration)# 创建预测结果数据框results_df = test_df[['id', 'dt']].copy()results_df['target'] = predictions# 保存预测结果results_df.to_csv('submit7.csv', index=False)print("模型训练和预测完成,预测结果已保存。到这里,我突然意识到了一个问题,特征工程并不是各种花里胡哨的堆砌,简单的也许能直击要害。嗯,不错,算是努力没有白费,这也算是日拱一卒,功不唐捐嘛。

learning_rate: 0.2

max_depth: 12.75(向下取整为12)

min_child_samples: 20

num_leaves: 86

然后,我将上述参数组合用在了LightGBM中,确实上了一点分,达到了251.22分。中位数、

解决时间序列问题的方法有很多,本次,我主要采用的是机器学习中的Boosting提升树家族的模型。轻量梯度提升机(LightGBM)以及CatBoost。

上图是我的代码输出日志,详细的反映了每一次迭代贝叶斯优化的过程。7、

本次笔记就到此为止了,也算是记录了我这三天来的所有学习和尝试吧。和窗口统计特征

# 尝试三import pandas as pdimport numpy as npfrom sklearn.preprocessing import LabelEncoder# 合并训练数据和测试数据train_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\dataset\train.csv')test_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\dataset\test.csv')data = pd.concat([train_df, test_df], axis=0).reset_index(drop=True)data = data.sort_values(['id', 'dt'], ascending=False).reset_index(drop=True)# 历史平移特征for i in range(10, 51, 5):    data[f'target_shift{i}'] = data.groupby('id')['target'].shift(i)# 历史平移 + 差分特征for i in range(1, 4):    for j in range(10, 51, 5):        data[f'target_shift{j}_diff{i}'] = data.groupby('id')[f'target_shift{j}'].diff(i)# 增加二阶差分特征for i in range(10, 51, 5):    data[f'target_shift{i}_diff2'] = data.groupby('id')[f'target_shift{i}'].diff(2)# 窗口统计特征for win in [15, 30, 50, 70]:    data[f'target_win{win}_mean'] = data.groupby('id')['target'].rolling(window=win, min_periods=3, closed='left').mean().values    data[f'target_win{win}_max'] = data.groupby('id')['target'].rolling(window=win, min_periods=3, closed='left').max().values    data[f'target_win{win}_min'] = data.groupby('id')['target'].rolling(window=win, min_periods=3, closed='left').min().values    data[f'target_win{win}_std'] = data.groupby('id')['target'].rolling(window=win, min_periods=3, closed='left').std().values# 历史平移 + 窗口统计特征for win in [7, 14, 28, 35, 50, 70]:    for j in range(10, 51, 5):        data[f'target_shift{j}_win{win}_mean'] = data.groupby('id')[f'target_shift{j}'].rolling(window=win, min_periods=3, closed='left').mean().values        data[f'target_shift{j}_win{win}_max'] = data.groupby('id')[f'target_shift{j}'].rolling(window=win, min_periods=3, closed='left').max().values        data[f'target_shift{j}_win{win}_min'] = data.groupby('id')[f'target_shift{j}'].rolling(window=win, min_periods=3, closed='left').min().values        data[f'target_shift{j}_win{win}_std'] = data.groupby('id')[f'target_shift{j}'].rolling(window=win, min_periods=3, closed='left').std().values# 填充缺失值data.fillna(0, inplace=True)# 拆分回训练和测试集train_df = data[data['target'].notna()]test_df = data[data['target'].isna()].drop(['target'], axis=1)# 保存处理后的数据集train_df.to_csv('1_train_optimized.csv', index=False)test_df.to_csv('1_test_optimized.csv', index=False)print("优化后的特征工程完成,处理后的数据集已保存。季度等;

(2)移动平均:计算更长时间范围内的移动平均;

(3)差分特征:计算电力消耗的差分;

(4)交互特征:构建不同特征之间的交互特征;

(5)聚合特征:对每个房屋类型计算全局的统计量,例如均值、60天、

这就有了尝试三:主要构建了历史平移特征、中位数、

# 特征工程尝试二import pandas as pdimport numpy as npfrom sklearn.preprocessing import LabelEncoderimport lightgbm as lgbfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import mean_squared_errorfrom lightgbm import early_stopping, log_evaluation# 加载数据train_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\dataset\train.csv')test_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\dataset\test.csv')# 合并训练和测试数据集以便于特征工程train_df['is_train'] = 1test_df['is_train'] = 0test_df['target'] = np.nanfull_df = pd.concat([train_df, test_df], axis=0, ignore_index=True)# 处理日期特征full_df['day_of_week'] = full_df['dt'] % 7  # 假设1代表周一full_df['is_weekend'] = full_df['day_of_week'].isin([5, 6]).astype(int)full_df['month'] = (full_df['dt'] // 30) % 12  # 假设每月30天full_df['quarter'] = (full_df['dt'] // 90) % 4  # 假设每季度90天# 处理房屋类型le = LabelEncoder()full_df['type'] = le.fit_transform(full_df['type'])# 创建移动平均特征def create_moving_average_features(df, windows, col):    for window in windows:        df[f'{col}_ma_{window}'] = df.groupby('id')[col].transform(lambda x: x.rolling(window).mean())    return dfwindows = [7, 30, 60, 90]full_df = create_moving_average_features(full_df, windows, 'target')# 创建差分特征def create_diff_features(df, lags, col):    for lag in lags:        df[f'{col}_diff_{lag}'] = df.groupby('id')[col].diff(lag)    return dflags = [1, 2, 3, 7, 14, 30]full_df = create_diff_features(full_df, lags, 'target')# 填充缺失值full_df.fillna(0, inplace=True)# 拆分回训练和测试集train_df = full_df[full_df['is_train'] == 1].drop(['is_train'], axis=1)test_df = full_df[full_df['is_train'] == 0].drop(['is_train', 'target'], axis=1)# 保存处理后的数据集train_df.to_csv('processed_train.csv', index=False)test_df.to_csv('processed_test.csv', index=False)print("特征工程完成,处理后的数据集已保存。过程很辛苦,也很有趣,感谢Datawhale这个用心的开源组织!我们第三期见!

不过不能就此放弃,我继续进行了尝试二:在尝试一的基础上,我增加了创建移动平均特征,在不同窗口大小(7天、")

CatBoost最终得分为276.98分

# LightGBMdef 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,    }    # 训练模型        callbacks = [log_evaluation(period=100), early_stopping(stopping_rounds=500)]    model = lgb.train(lgb_params, train_matrix, 50000, valid_sets=[train_matrix, valid_matrix],                       categorical_feature=[],callbacks=callbacks)    # 验证集和测试集结果预测    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_testtest[['id','dt','target']].to_csv('submit1.csv', index=None)

LightGBM的最终得分为259.97分。我当时的思考方向无非就两个,要么继续思考特征工程,要么就尝试调参呗。

必须引起关注的是,特征工程将直接决定预测结果的好坏,这也是我打本次比赛总结的经验教训之一,后文会再说道的。")

XGBoost最终得分为264.79分。

本次打卡,主要是来按照教程和自己的思考,完成的一次上分之旅。

这个尝试应该是我最英明的尝试了,达到了233.33分(历史最高分,大赛30名左右)。

基于此,我进行了以下尝试:

尝试一:处理日期特征、

针对时间序列问题,我查阅了相关资料,一般的特征工程有以下几种:

(1)日期特征:考虑更丰富的日期特征,例如月、于是,我逐步将上述特征工程进行了删减,并去除了处理房屋类型这致命的一步(我后来才发现,这一步会将原有的id打乱,最终不好恢复,直接影响了最终提交的csv文件,造成大面积错误。最终,得出最佳的参数组合如下:Best Params: {'learning_rate': 0.2, 'max_depth': 12.753964325020366, 'min_child_samples': 20.0, 'num_leaves': 86.1360835609615}。按照官方教程,模型皆是基于梯度提升决策树(GBDT)作为基学习器的集成学习模型。

这里顺带提一嘴LightGBM,可以看成是 XGBoost 的升级加强版本,2017 年经微软推出后,便成为各种数据竞赛中刷分拿奖的神兵利器。

我们暂时根据官方教程完成特征工程:

# 合并训练数据和测试数据,并进行排序data = pd.concat([test, train], axis=0, ignore_index=True)data = data.sort_values(['id','dt'], ascending=False).reset_index(drop=True)# 历史平移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']]

这段特征工程主要实现了三点:

(1)将数据合并,并按照 id和时间 dt进行排序,确保数据按时间降序排列;

(2)历史平移:对每个 id组进行平移操作,将 target列进行10到30步的历史平移,生成新的特征列;

(3)窗口平移:计算最近三次历史平移的目标值的均值,并生成一个新的特征。创建时间序列特征、

继续,我就开始走上了另外一条路,那就是做特征工程。

由此可见,LightGBM更胜一筹。")

效果惊人的差,分数达到了四位数,我真的裂开。")

结果比上次的好了点,但是也有1111.12分。

min_child_samples: 20到100之间。

# CatBoostimport pandas as pdimport numpy as npfrom catboost import CatBoostRegressor, Poolfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import mean_squared_error# 加载处理后的数据train_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\dataset\train.csv')test_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\dataset\test.csv')# 准备训练数据和标签X = train_df.drop(columns=['target', 'id', 'dt'])y = train_df['target']X_test = test_df.drop(columns=['id', 'dt'])# 拆分训练集和验证集X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)# 创建CatBoost Pooltrain_pool = Pool(X_train, y_train)val_pool = Pool(X_val, y_val)test_pool = Pool(X_test)# 设置参数params = {    'iterations': 50000,    'learning_rate': 0.05,    'depth': 6,    'loss_function': 'RMSE',    'eval_metric': 'RMSE',    'random_seed': 42,    'logging_level': 'Verbose',    'od_type': 'Iter',    'od_wait': 500  # 提前停止轮数}# 训练模型model = CatBoostRegressor(**params)model.fit(train_pool, eval_set=val_pool, verbose=100, early_stopping_rounds=500)# 进行预测predictions = model.predict(test_pool)# 创建预测结果数据框results_df = test_df[['id', 'dt']].copy()results_df['target'] = predictions# 保存预测结果results_df.to_csv('C_submit.csv', index=False, float_format='%.6f')print("模型训练和预测完成,预测结果已保存。在各大机器学习领域的比赛中使用量最大,效果普遍较好的便是极端梯度提升树(XGBoost)、六百、特征工程三个部分来尝试。方差的信息,可以反映最近阶段数据的变化情况。

learning_rate: 0.05到0.2之间。30天、差分特征、五百到298.63分就下不去了。3、在此基础上还可以构建相邻数据比值变化、

我们可以用以下公式来浅显的揭示二者之间的关系:
LightGBM =XGBoost +Histogram +GOSS +EFB

对机器学习原理感兴趣的同学也可以来看看我写的机器学习方法课堂系列,链接放在这里了,欢迎前来交流!https://mp.weixin.qq.com/mp/appmsgalbum?__biz=Mzk0ODI1MzMwNg==&action=getalbum&album_id=3315279070611619844#wechat_redirect

接下来,我就尝试基于LightGBM的基础上,进行了优化思考。标准差等;

(6)周期特征:一般采用傅里叶。

max_depth: 5到15之间。我试着动手做了做贝叶斯优化:

# Bayes优化# 定义贝叶斯优化对象lgb_bo = BayesianOptimization(    lgb_cv,    {        'num_leaves': (30, 100),        'max_depth': (5, 15),        'learning_rate': (0.05, 0.2),        'min_child_samples': (20, 100),    },    random_state=2024)# 开始优化lgb_bo.maximize(init_points=5, n_iter=10)# 获取最佳参数best_params = lgb_bo.max['params']print("Best Params:", best_params)# 使用最佳参数重新训练模型,并预测测试集best_params['num_leaves'] = int(best_params['num_leaves'])best_params['max_depth'] = int(best_params['max_depth'])best_params['min_child_samples'] = int(best_params['min_child_samples'])lgb_model = lgb.LGBMRegressor(**best_params)lgb_oof, lgb_test = cv_model(lgb, train[train_cols], train['target'], test[train_cols], 'lgb')# 保存输出结果final_test = lgb_testsubmission = pd.DataFrame({'id': test['id'], 'dt': test['dt'], 'target': final_test})submission.to_csv('Bayes_LightGBM_submit4.csv', index=False)

首先,我定义了贝叶斯优化搜索最佳参数的范围(即在我定的范围里,找到一个最合适的参数):

num_leaves: 30到100之间。

随机种子随便设一个,今年2024年,那就2024吧哈哈哈。30天)下的差分。调参、我再进行慢慢的尝试,分数在逐步下降,八百、二阶差分等;

(3)窗口统计特征:窗口统计可以构建不同的窗口大小,然后基于窗口范围进统计均值、然后,启动贝叶斯优化器,迭代10次。 与XGBoost对比以下几点:

(1)模型精度:XGBoost LightGBM 相当;

(2)训练速度:LightGBM 远快于 XGBoost

(3)内存消耗:LightGBM 远小于 XGBoost

(4)缺失值特征:XGBoost LightGBM 都可以自动处理特征缺失值;

(5)分类特征:XGBoost不支持类别特征,需要 OneHot编码预处理,LightGBM 直接支持类别特征。")# 加载处理后的数据train_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\new_train.csv')test_df = pd.read_csv(r'D:\数学建模竞赛\2024DW夏令营2机器学习\new_test.csv')# 准备训练数据和标签X = train_df.drop(columns=['target', 'id', 'dt'])y = train_df['target']X_test = test_df.drop(columns=['id', 'dt'])# 拆分训练集和验证集X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)# 创建LightGBM数据集train_data = lgb.Dataset(X_train, label=y_train)val_data = lgb.Dataset(X_val, label=y_val, reference=train_data)# 设置参数params = { 'objective': 'regression', 'metric': 'mse', 'boosting_type': 'gbdt', 'num_leaves': 31, 'learning_rate': 0.05, 'feature_fraction': 0.9}# 训练模型# 设置回调函数callbacks = [ log_evaluation(period=100), # 每100轮记录一次日志 early_stopping(stopping_rounds=500) # 500轮没有提升时提前停止]# 训练模型model = lgb.train(params, train_data, num_boost_round=50000, valid_sets=[train_data, val_data], callbacks=callbacks)# 进行预测predictions = model.predict(X_test, num_iteration=model.best_iteration)# 创建预测结果数据框results_df = test_df[['id', 'dt']].copy()results_df['target'] = predictions# 保存预测结果results_df.to_csv('Newnew_L_submit5.csv', index=False)print("模型训练和预测完成,预测结果已保存。这时,我决定换方法。

本次笔记,我将分为选择模型、14、最小值、