LightGBM模型与数据处理策略
关键要点
- 竞赛目标是预测10个新能源电站的功率输出,基于气象和历史数据,研究表明这对能源管理至关重要。
- 数据包括气象变量(如风速、辐射)和功率输出,证据显示这些数据需处理以提高预测准确性。
- baseline使用LightGBM模型,数据处理涉及空间平均和时间序列整合,研究表明其效率高但有优化空间。
- 评估指标为RMSE和相关性系数(C_r),似乎是衡量预测性能的标准方法。
竞赛简介
第三届世界科学智力竞赛的新能源赛道聚焦于预测5个风电场和5个光伏电站的功率输出。这对构建现代电力系统、提升能源安全和促进可持续性有重要意义。竞赛从2025年2月持续到7月,分为初赛、半决赛和决赛,鼓励全球人才创新。
数据概述
竞赛提供气象数据(NWP_1、NWP_2、NWP_3),包括8个变量如风速(u100、v100)、温度(t2m)、辐射(ghi、poai)等,以NetCDF格式存储,每小时一次。功率数据为10个电站的实际输出,每15分钟一次,可能含缺失值需处理。
baseline解读
baseline是一个Python脚本,使用LightGBM进行回归预测,涉及:
- 数据提取:从NetCDF文件计算空间平均值。
- 数据预处理:整合气象和功率数据,按小时采样。
- 模型训练:5折交叉验证,参数如学习率0.1、特征比例0.9。
- 输出:生成10个CSV文件,匹配15分钟粒度。
LightGBM因其高效性和处理大规模数据的优势被选用,支持自动特征选择和缺失值处理。
评估与优化
评估指标为RMSE(均方根误差)和(C_r)(相关性系数),baseline通过(1/(1+\text{RMSE}))转换分数。优化方向包括特征工程(如风速幅值)、时间序列模型和模型融合。
详细报告
竞赛背景与目标
第三届世界科学智力竞赛由上海科学智力研究院和复旦大学主办,旨在通过科学和技术手段解决实际问题。新能源赛道特别聚焦于新能源发电功率预测,目标是预测10个新能源电站(5个风电场和5个光伏电站)的功率输出,基于气象数据和历史功率数据。竞赛从2025年2月持续到7月,分为注册、初赛、半决赛和决赛,团队可由1-3人组成,需通过上海智研院平台注册,强调公平性,禁止代码共享和使用外部数据。竞赛与南方电网调度控制中心合作,旨在提升预测准确性,构建灵活开放的新能源预测生态系统,对能源安全、经济效益和环境可持续性至关重要。
数据描述与处理
竞赛提供两种主要数据类型:
- 气象数据:包括三个来源(NWP_1、NWP_2、NWP_3),包含8个变量:u100、v100(100米高度风速分量)、t2m(2米温度)、tcc(总云量)、tp(总降水量)、sp(地表压力)、ghi(全球水平辐射)、poai(阵面辐射)。数据以NetCDF格式存储,每小时一次,覆盖24小时,适合处理多维科学数据。
- 功率数据:为10个电站的实际功率输出,每15分钟一次,数据已归一化,可能包含缺失值、异常值或负值,需参赛者处理。
baseline的处理步骤包括:
- 数据提取:从NetCDF文件中提取气象数据,计算每个特征的11x11网格空间平均值,使用
np.mean
简化维度。 - 数据预处理:将气象数据(每小时)和功率数据(每15分钟)整合,功率数据按小时采样,只保留每小时第一个数据点(“00:00”),确保时间序列一致。
- 特征工程:baseline通过空间平均处理数据,但可进一步优化,如计算风速幅值(
u
10
0
2
+
v
10
0
2
\sqrt{u100^2 + v100^2}
u1002+v1002)、辐射比值(如
ghi/poai
),或加入时间特征(如小时、日期)。
baseline模型与实现
baseline是一个Python脚本,使用LightGBM进行回归预测,采用5折交叉验证。LightGBM参数设置如下:
参数名 | 值 |
---|---|
boosting_type | ‘gbdt’ |
objective | ‘regression’ |
metric | ‘rmse’ |
num_leaves | 256 |
learning_rate | 0.1 |
feature_fraction | 0.9 |
bagging_fraction | 0.8 |
bagging_freq | 5 |
verbose | 100 |
num_threads | 8 |
LightGBM因其高效性被选用,训练速度快、内存占用低,适合处理大规模数据,支持自动特征选择和缺失值处理。模型训练后,预测结果重复四次以匹配15分钟粒度,生成10个CSV文件(output1.csv到output10.csv),对应10个电站。
评估指标与性能
竞赛评估指标包括:
- RMSE:均方根误差,公式为 1 n ∑ i = 1 n ( P M , i − P P , i ) 2 \sqrt{\frac{1}{n} \sum_{i=1}^n (P_{M,i} - P_{P,i})^2} n1∑i=1n(PM,i−PP,i)2,衡量预测值与实际值的差异。
- (C_r):相关性系数,公式为 ( 1 − 1 n ∑ i = 1 n ( P M , i − P P , i ) 2 max ( P M , i , 0.2 ) ) × 100 % \left(1 - \sqrt{\frac{1}{n} \sum_{i=1}^n \frac{(P_{M,i} - P_{P,i})^2}{\max(P_{M,i}, 0.2)}}\right) \times 100\% (1−n1∑i=1nmax(PM,i,0.2)(PM,i−PP,i)2)×100%,评估预测与实际值的相关性。
baseline的RMSE得分通过公式 1 / ( 1 + RMSE ) 1/(1+\text{RMSE}) 1/(1+RMSE)转换,确保分数越高表示性能越好。
深入分析与优化方向
baseline提供了一个高效起点,但有优化空间:
- 特征工程:可提取更多特征,如风速幅值、辐射比值,或分析气象变量间的关系(如ghi与poai的正比性)。
- 时间序列处理:数据具有时间序列特性,可考虑ARIMA、LSTM等模型,或加入时间窗口特征。
- 模型融合:结合LightGBM、XGBoost、CatBoost的预测结果,可能提高性能。
- 异常值处理:baseline仅删除含缺失值的行,可进一步使用插值或异常值检测提升数据质量。
总结与展望
通过对baseline的解读,我们了解了竞赛数据的结构、baseline的实现方式及其潜在优化方向。baseline为参赛者提供了一个高效且易于理解的起点,但要取得更好成绩,需对数据进行更深入分析和处理。希望本文能为参赛者提供有价值的insights,帮助大家在竞赛中取得佳绩。
第二部分:代码详细解读
关键要点
- 以下是baseline代码的逐段详细解读,涵盖数据解压、库安装、数据处理、模型训练和结果保存。
- 解读基于提供的baseline代码,重点解释每段代码的功能和逻辑。
- 研究表明,baseline使用LightGBM模型,数据处理涉及空间平均和时间序列整合,适合新能源功率预测任务。
解压缩和准备
baseline代码首先通过 unzip
命令解压比赛数据集,包括测试集、训练集和输出示例文件,解压到 data
目录,确保数据文件准备就绪。
库安装和导入
然后,安装必要的Python库(如numpy、pandas、netCDF4、lightgbm、scikit-learn),并导入这些库,用于后续数据处理和模型训练。
数据读取和预处理
代码读取NetCDF格式的气象数据,提取通道信息和气象数据,计算每个气象要素的空间平均值,并转换为DataFrame格式。训练和测试数据分别按日期范围生成,功率数据处理只保留整点数据。
模型训练和预测
使用LightGBM模型进行5折交叉验证训练,设置参数如学习率0.1、特征抽样比例0.8等。预测结果重复4次以匹配15分钟粒度,最终生成10个CSV文件。
结果保存和打包
预测结果保存为CSV文件,生成10个输出文件,并打包为zip格式,方便提交。
详细报告
引言
本文详细解读第三届世界科学智力竞赛新能源赛道baseline代码,代码基于Python实现,涵盖数据解压、预处理、模型训练和结果生成。baseline使用LightGBM模型,数据处理涉及空间平均和时间序列整合,适合新能源发电功率预测任务。以下按代码段逐一分析,帮助参赛者理解其逻辑和优化方向。
代码逐段解读
1. 解压缩比赛数据集文件
# 解压缩比赛数据集文件
!unzip -d data data/初赛测试集.zip # 解压测试集数据到data目录
!unzip -d data data/初赛训练集.zip # 解压训练集数据到data目录
!unzip -d data data/output.zip # 解压输出示例文件到data目录
- 功能: 使用
unzip
命令解压比赛提供的三个zip文件,包括测试集、训练集和输出示例文件,解压到data
目录。 - 解释: 这一步确保所有数据文件(如NetCDF格式的气象数据和CSV格式的功率数据)都已准备好,方便后续读取和处理。
2. 安装必要的Python库
# 安装必要的Python库
%pip install numpy==2.2.4 pandas==2.2.3 netCDF4==1.7.2 lightgbm==4.6.0 scikit-learn==1.6.1
- 功能: 安装特定版本的Python库,包括
numpy
、pandas
、netCDF4
、lightgbm
和scikit-learn
。 - 解释: 这些库分别用于数值计算、数据操作、读取NetCDF文件、机器学习建模和评估。版本固定确保环境一致性。
3. 导入所需的库
# 导入所需的库
from netCDF4 import Dataset # 用于读取NC格式的气象数据
import numpy as np
import pandas as pd
- 功能: 导入
netCDF4
的Dataset
类用于读取NetCDF文件,numpy
和pandas
用于数据处理。 - 解释: 这些库是后续数据读取和处理的基石,
netCDF4
特别适合处理气象数据。
4. 读取示例NC文件,了解数据结构
# 读取示例NC文件,了解数据结构
nc_path = "data/初赛训练集/nwp_data_train/1/NWP_1/20240101.nc" # 指定NC文件路径
dataset = Dataset(nc_path, mode='r') # 以只读模式打开NC文件
dataset.variables.keys() # 查看NC文件中的变量名
- 功能: 打开一个示例NetCDF文件,查看其变量名。
- 解释: 这一步帮助理解数据结构,通常包含 “channel”(气象要素)和 “data”(气象数据)等变量。
5. 获取通道信息(气象要素)
# 获取通道信息(气象要素)
channel = dataset.variables["channel"][:] # 提取通道变量
channel # 显示通道信息
- 功能: 提取 “channel” 变量,通常包含8个气象要素的名称。
- 解释: 这些要素如风速、温度、辐射等,是后续特征工程的基础。
6. 获取气象数据
# 获取气象数据
data = dataset.variables["data"][:] # 提取数据变量
data.shape # 显示数据形状,了解数据维度
- 功能: 提取 “data” 变量,查看其形状。
- 解释: 数据维度可能包括时间、高度、纬度、经度和通道,形状信息帮助理解数据结构。
7. 计算每个通道的平均值
# 计算每个通道的平均值
# 对每个气象要素(8个通道),计算其在空间维度上的平均值
mean_values = np.array([np.mean(data[:, :, i, :, :][0], axis=(1, 2)) for i in range(8)]).T
mean_values.shape # 显示处理后的数据形状
- 功能: 计算8个气象要素的空间平均值。
- 解释: 使用
np.mean
对空间维度(纬度、经度)求平均,简化数据为每个要素的单值,.T
转置数组以便后续处理。
8. 将平均值数据转换为DataFrame格式
# 将平均值数据转换为DataFrame格式
df_day = pd.DataFrame(mean_values, columns=channel)
df_day # 显示DataFrame,每列对应一个气象要素
- 功能: 将numpy数组转换为pandas DataFrame。
- 解释: 每列对应一个气象要素,方便后续数据合并和分析。
9. 生成日期范围,用于读取训练数据
# 生成日期范围,用于读取训练数据
date_range = pd.date_range(start='2024-01-01', end='2024-12-30') # 创建从2024-01-01到2024-12-30的日期范围
date = [date.strftime('%Y%m%d') for date in date_range] # 将日期格式化为'YYYYMMDD'格式
date[:5] # 显示前5个日期,检查格式
- 功能: 生成训练数据的日期范围。
- 解释: 从2024年1月1日到12月30日,格式化为 ‘YYYYMMDD’,如 ‘20240101’,用于后续文件路径。
10. 定义函数,用于从NC文件中提取数据并计算平均值
# 定义函数,用于从NC文件中提取数据并计算平均值
def get_data(path_template, date):
dataset = Dataset(path_template.format(date), mode='r') # 打开指定日期的NC文件
channel = dataset.variables["channel"][:] # 获取通道信息
data = dataset.variables["data"][:] # 获取数据
mean_values = np.array([np.mean(data[:, :, i, :, :][0], axis=(1, 2)) for i in range(8)]).T # 计算平均值
return pd.DataFrame(mean_values, columns=channel) # 返回DataFrame格式的数据
- 功能: 定义函数
get_data
,读取指定日期的NetCDF文件,计算平均值。 - 解释: 这一函数封装了数据读取和预处理的逻辑,方便批量处理多个日期。
11. 读取所有训练日期的数据
# 读取所有训练日期的数据
train_path_template = "data/初赛训练集/nwp_data_train/1/NWP_1/{}.nc" # 训练数据路径模板
data = [get_data(train_path_template, i) for i in date] # 对每个日期应用get_data函数
train = pd.concat(data, axis=0).reset_index(drop=True) # 将所有日期的数据合并为一个DataFrame
train.shape # 显示训练数据的形状
- 功能: 读取所有训练数据,合并为一个DataFrame。
- 解释: 使用列表推导式批量处理,
pd.concat
纵向合并,reset_index
重置索引,shape
查看维度。
12. 读取目标变量(功率数据)
# 读取目标变量(功率数据)
target = pd.read_csv("data/初赛训练集/fact_data/1_normalization_train.csv")
target = target[96:] # 跳过前96行数据
# 功率数据中每四条数据取一条(只保留整点数据)
target = target[target['时间'].str.endswith('00:00')]
target = target.reset_index(drop=True) # 重置索引
target.head() # 显示前几行数据
- 功能: 读取功率数据,处理时间序列。
- 解释: 跳过前96行,筛选整点数据(‘00:00’),确保与气象数据的时间粒度一致。
13. 读取测试数据
# 读取测试数据
test_path_template = "data/初赛测试集/nwp_data_test/1/NWP_1/{}.nc" # 测试数据路径模板
# 生成测试日期范围
date_range = pd.date_range(start='2024-12-31', end='2025-02-27')
date = [date.strftime('%Y%m%d') for date in date_range]
date[:5] # 显示前5个测试日期
- 功能: 生成测试数据的日期范围。
- 解释: 测试数据从2024年12月31日到2025年2月27日,格式化为 ‘YYYYMMDD’。
14. 读取所有测试日期的数据
# 读取所有测试日期的数据
data = [get_data(test_path_template, i) for i in date] # 对每个测试日期应用get_data函数
test = pd.concat(data, axis=0).reset_index(drop=True) # 将所有测试日期的数据合并
test.shape # 显示测试数据的形状
- 功能: 读取所有测试数据,合并为DataFrame。
- 解释: 与训练数据处理类似,确保测试数据格式一致。
15. 导入模型训练和评估所需的库
# 导入模型训练和评估所需的库
from sklearn.model_selection import KFold # 用于交叉验证
from sklearn.metrics import mean_squared_error # 用于计算均方误差
import lightgbm as lgb # 使用LightGBM模型
- 功能: 导入交叉验证、评估和建模所需的库。
- 解释:
KFold
用于5折交叉验证,mean_squared_error
计算RMSE,lightgbm
是核心模型。
16. 定义交叉验证模型训练函数
# 定义交叉验证模型训练函数
def cv_model(clf, train_x, train_y, test_x, seed):
# 5折交叉验证
folds = 5
kf = KFold(n_splits=folds, shuffle=True, random_state=seed) # 创建K折交叉验证对象
oof = np.zeros(train_x.shape[0]) # 存储训练集上的预测结果
test_predict = np.zeros(test_x.shape[0]) # 存储测试集上的预测结果
cv_scores = [] # 存储每折的评分
# 进行K折交叉验证
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]
# 创建LightGBM数据集
train_matrix = clf.Dataset(trn_x, label=trn_y)
valid_matrix = clf.Dataset(val_x, label=val_y)
# 设置LightGBM模型参数
params = {
'boosting_type': 'gbdt', # 使用梯度提升决策树
'objective': 'regression', # 回归任务
'metric': 'rmse', # 使用均方根误差作为评估指标
'min_child_weight': 5, # 最小叶子节点样本权重和
'num_leaves': 256, # 叶子节点数量
'lambda_l2': 10, # L2正则化系数
'feature_fraction': 0.8, # 特征抽样比例
'bagging_fraction': 0.8, # 样本抽样比例
'bagging_freq': 4, # 抽样频率
'learning_rate': 0.1, # 学习率
'nthread' : 16, # 使用的线程数
'verbose' : -1, # 不显示训练信息
}
# 训练模型
model = clf.train(params, train_matrix, 3000, valid_sets=[train_matrix, valid_matrix])
# 预测验证集和测试集
val_pred = model.predict(val_x, num_iteration=model.best_iteration)
test_pred = model.predict(test_x, num_iteration=model.best_iteration)
# 存储预测结果
oof[valid_index] = val_pred
# 将每个模型结果加权并相加
test_predict += test_pred / kf.n_splits
# 计算评分(1/(1+RMSE))
score = 1/(1+np.sqrt(mean_squared_error(val_pred, val_y)))
cv_scores.append(score)
print(cv_scores)
return oof, test_predict
- 功能: 定义
cv_model
函数,使用5折交叉验证训练LightGBM模型。 - 解释: 参数包括学习率0.1、特征抽样比例0.8等,评估指标为1/(1+RMSE),适合竞赛的评分规则。
17. 训练模型并生成预测结果
# 设置随机种子并训练模型
seed = np.random.randint(0, 10000) # 随机生成种子
lgb_oof, lgb_test = cv_model(lgb, train, target['功率(MW)'], test, seed) # 训练模型并获取预测结果
# 将测试集预测结果重复4次(恢复到原始时间粒度)
lgb_test = [item for item in lgb_test for _ in range(4)]
- 功能: 训练模型,生成预测结果,并调整时间粒度。
- 解释: 预测结果重复4次以匹配15分钟粒度,符合功率数据的原始格式。
18. 保存预测结果
# 保存预测结果
import os
if not os.path.exists("output"): # 如果output目录不存在,则创建
os.makedirs("output")
# 读取输出模板文件
output = pd.read_csv("data/output/output1.csv").reset_index(drop=True)
output["power"] = lgb_test # 将预测结果填入power列
output.rename(columns={'Unnamed: 0': ''}, inplace=True) # 重命名列
output.set_index(output.iloc[:, 0], inplace=True) # 设置索引
output = output.drop(columns=["0", ""]) # 删除不需要的列
# 生成10个输出文件(比赛要求)
for i in range(1, 11):
output.to_csv('output/output'+ str(i) + '.csv')
- 功能: 保存预测结果为CSV文件,生成10个输出文件。
- 解释: 符合比赛要求,每个文件对应一个电站的预测结果。
19. 将输出文件打包为zip格式
# 将输出文件打包为zip格式,用于提交
!zip -r output.zip output
- 功能: 将输出文件打包为zip格式。
- 解释: 方便参赛者提交结果,符合比赛提交规范。
总结与优化建议
baseline代码实现了从数据读取到结果生成的完整流程,核心使用LightGBM模型,数据处理包括空间平均和时间序列整合。优化方向包括:
- 特征工程:提取风速幅值、辐射比值等。
- 时间序列模型:尝试ARIMA、LSTM等。
有关深度学习,baseline创建者建议“深度学习问题 :因训练集数据量少(单个场站 8760 条,深度学习小模型最好需 10 万条以上数据),使用深度学习可能过拟合,做好数据工程机器学习表现不次于深度学习。” - 模型融合:结合XGBoost、CatBoost提升性能。
关键参数表
以下是LightGBM模型的部分关键参数:
参数名 | 值 | 说明 |
---|---|---|
boosting_type | ‘gbdt’ | 使用梯度提升决策树 |
objective | ‘regression’ | 回归任务 |
metric | ‘rmse’ | 均方根误差 |
learning_rate | 0.1 | 学习率 |
feature_fraction | 0.8 | 特征抽样比例 |
结论
通过对baseline代码的详细解读,参赛者可以理解其实现逻辑,并在此基础上进行优化。希望本文能为参赛者提供有价值的参考。