一、赛题描述
赛题:电力需求预测挑战赛
主办方:科大讯飞xDatawhale
主页:https://challenge.xfyun.cn/topic/info?type=electricity-demand&option=ssgy
背景
随着全球经济的快速发展和城市化进程的加速,电力系统面临着越来越大的挑战。电力需求的准确预测对于电网的稳定运行、能源的有效管理以及可再生能源的整合至关重要。
然而,电力需求受到多种因素的影响,为了提高电力需求预测的准确性和可靠性,推动智能电网和可持续能源系统的发展,本场以“电力需求预测”为赛题的数据算法挑战赛。选手需要根据历史数据构建有效的模型,能够准确的预测未来电力需求。
任务
给定多个房屋对应电力消耗历史N天的相关序列数据等信息,预测房屋对应电力的消耗。
二、数据集说明
赛题数据由训练集、测试集、事件数据组成。总设备id超过2w,包含设备信息、APP信息和事件信息,其中device_id为用户的唯一标识符,gender为用户性别,age为用户年龄。
为了保证比赛的公平性,将会从中抽取2w条设备id为训练集,3千多个设备id作为测试集,同时会对部分字段信息进行脱敏。
特征字段 | 字段描述 |
---|---|
device_id | 用户对应设备号,唯一表示,无重复 |
gender | 用户性别,0为男性,1为女性 |
age | 用户年龄 |
phone_brand | 手机品牌 |
device_model | 手机型号 |
event_id | 事件id |
app_id | 应用程序id |
is_installed | 是否安装 |
is_active | 是否激活 |
tag_list | 应用程序的标签列表 |
date | 事件发生日期 |
数据集版权许可协议
BY-NC-SA 4.0
https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh-hans
三、解决方案样例
导入相关系统库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import gc
import seaborn as sns
from sklearn.model_selection import KFold
from sklearn.metrics import mean_absolute_error
import lightgbm as lgbm
【本样例运行环境的关键版本信息】
python 3.12.3
lightgbm 3.3.0
seaborn 0.13.2
读入数据集
data_path = './data/'
df_tr = pd.read_csv(data_path + 'train.csv')
df_tr_app_events = pd.read_csv(data_path + 'train_app_events.csv')
df_te = pd.read_csv(data_path + 'test.csv')
df_te_app_events = pd.read_csv(data_path + 'test_app_events.csv')
分析数据
df_tr_te_app_events.head()
df_tr['gender'].value_counts().plot(kind = 'bar')
特征工程
df_tr_te_app_events['tag_list_len'] = df_tr_te_app_events['tag_list'].apply(lambda x: x.count(',') + 1)
agg_dic = {
"event_id": ['count', 'nunique'],
"app_id": ['nunique'],
"is_installed": ['mean', 'sum'],
"is_active": ['mean', 'sum'],
"date": ['max', 'nunique'],
"tag_list_len": ['mean', 'std']
}
df_device_features = df_tr_te_app_events.groupby('device_id').agg(agg_dic).reset_index()
fea_names = ['_'.join(c) for c in df_device_features.columns]
df_device_features.columns = fea_names
df_device_features.rename(columns = {'device_id_':'device_id'}, inplace = True)
LighGBM 模型训练和预测
# gender 模型
lgb_params = {
"objective": "binary", # 定义学习任务和相应的学习目标。"binary" 表示这是一个二分类任务
"metric": "auc", # 评估模型性能的指标。"auc": 曲线下面积,衡量模型的区分能力
"boosting_type": "gbdt", # 定义提升类型。"gbdt" 是梯度提升决策树的默认类型,适用于大多数情况
"early_stopping_rounds": 50, # 在验证集上监控模型的性能,如果在指定的轮数内性能没有提升,则提前停止训练,防止过拟合
"learning_rate": 0.05, # 控制每一步的步长,较小的学习率需要更多的迭代次数
"colsample_bytree": 0.8, # 每棵树随机采样的列数比例。0.8 表示每棵树使用 80% 的特征
"max_depth": 7, # 控制每棵树的最大深度,防止过拟合
"num_leaves": 63, # 调整为 2^max_depth - 1 或其他合适的值
"lambda_l1": 0.1, # L1 正则化参数,用于控制模型的稀疏性,促使部分特征的权重降为零
"lambda_l2": 0.1, # L2 正则化参数,用于防止模型权重过大,减少过拟合
"force_col_wise": True # 强制使用按列(特征)的多线程方式,提升并行计算的效率
}
X_tr_val = df_tr[tr_features + [label_gender]]
X_te = df_te[tr_features]
kf = KFold(n_splits=5)
lgb_gender_models = []
y_pred = 0
for f, (tr_ind,val_ind) in enumerate(kf.split(X_tr_val)):
X_train, X_valid = X_tr_val.iloc[tr_ind][tr_features], X_tr_val.iloc[val_ind][tr_features]
y_train, y_valid = X_tr_val.iloc[tr_ind][label_gender], X_tr_val.iloc[val_ind][label_gender]
lgbm_train = lgbm.Dataset(X_train, y_train)
lgbm_valid = lgbm.Dataset(X_valid, y_valid)
model_binary = lgbm.train(params = lgb_params,
train_set = lgbm_train,
valid_sets = [lgbm_train, lgbm_valid],
num_boost_round = 100000)
y_pred += model_binary.predict(X_te[tr_features]) / 5.0
lgb_gender_models.append(model_binary)
# age 模型
def feval_lgb_Age(preds, lgbm_train):
labels = lgbm_train.get_label()
return 'Age Error', round(1.0 / (1.0 + mean_absolute_error(y_true = labels, y_pred = preds)), 7), True
lgb_params = {
"objective": "mae", # 指定回归任务的目标函数为平均绝对误差 (Mean Absolute Error, MAE)
"metric": ["mae", "mse"], # 在训练过程中监控多个评估指标。MAE 作为主要指标,MSE 作为辅助指标
"boosting_type": "gbdt", # 使用梯度提升决策树 (Gradient Boosting Decision Tree, GBDT) 作为提升类型
"learning_rate": 0.05, # 控制每一步的步长,较小的学习率需要更多的树
"max_depth": 7, # 控制每棵树的最大深度,防止过拟合
"num_leaves": 63, # 调整为 2^max_depth - 1 或其他合适的值
"subsample": 0.8, # 每棵树使用的样本比例,防止过拟合
"colsample_bytree": 0.9, # 每棵树使用的特征比例,防止过拟合
"min_child_samples": 20, # 每个叶子节点最少需要的样本数,控制树的复杂度
"reg_alpha": 0.1, # L1 正则化参数,促使部分特征权重为零,实现特征选择
"reg_lambda": 0.1, # L2 正则化参数,防止特征权重过大,减少过拟合
"early_stopping_rounds": 50, # 在验证集上监控性能,若在连续 50 轮内性能未提升,则提前停止训练
"force_col_wise": True, # 强制使用按列(特征)的多线程方式,提升并行计算效率
"random_state": 42, # 设置随机种子以确保可重复性
}
X_tr_val = df_tr[tr_features + [label_age]]
X_te = df_te[tr_features]
kf = KFold(n_splits=5)
lgb_age_models = []
y_pred = 0
for f, (tr_ind, val_ind) in enumerate(kf.split(X_tr_val)):
X_train, X_valid = X_tr_val.iloc[tr_ind][tr_features], X_tr_val.iloc[val_ind][tr_features]
y_train, y_valid = X_tr_val.iloc[tr_ind][label_age], X_tr_val.iloc[val_ind][label_age]
lgbm_train = lgbm.Dataset(X_train, y_train)
lgbm_valid = lgbm.Dataset(X_valid, y_valid)
model_mae = lgbm.train(params = lgb_params,
train_set = lgbm_train,
valid_sets = [lgbm_train, lgbm_valid],
num_boost_round = 100000,
feval = feval_lgb_Age)
y_pred += model_mae.predict(X_te[tr_features]) / 5.0
lgb_age_models.append(model_mae)
提交预测数据
df_submit.to_csv('Fold5_LightGBM_Prediction.csv', index = None)
源码开源协议
GPL-v3
https://zhuanlan.zhihu.com/p/608456168