TASK1
1 报名比赛
随着全球经济的快速发展和城市化进程的加速,电力系统面临着越来越大的挑战。电力需求的准确预测对于电网的稳定运行、能源的有效管理以及可再生能源的整合至关重要。然而,电力需求受到多种因素的影响,为了提高电力需求预测的准确性和可靠性,推动智能电网和可持续能源系统的发展,本场以“电力需求预测”为赛题的数据算法挑战赛。选手需要根据历史数据构建有效的模型,能够准确的预测未来电力需求。(2024 iFLYTEK A.I.开发者大赛-讯飞开放平台 (xfyun.cn))
2 下载数据并配置环境
从赛题数据中下载文件“电力需求预测挑战赛数据集.zip”,解压缩至桌面的文件夹“电力需求预测挑战赛”,在当前目录下运行jupyter notebook平台。
3 baseline
3.1 导入需要用到的相关库
# 导入 pandas 库,用于数据处理和分析
import pandas as pd
# 导入 numpy 库,用于科学计算和多维数组操作
import numpy as np
3.2 读取训练集和测试集
# 使用 read_csv() 函数从文件中读取训练集数据,文件名为 'train.csv'
train = pd.read_csv('dataset/train.csv')
train
id | dt | type | target | |
---|---|---|---|---|
0 | 00037f39cf | 11 | 2 | 44.050 |
1 | 00037f39cf | 12 | 2 | 50.672 |
2 | 00037f39cf | 13 | 2 | 39.042 |
3 | 00037f39cf | 14 | 2 | 35.900 |
4 | 00037f39cf | 15 | 2 | 53.888 |
... | ... | ... | ... | ... |
2877300 | fff81139a7 | 502 | 5 | 28.552 |
2877301 | fff81139a7 | 503 | 5 | 22.818 |
2877302 | fff81139a7 | 504 | 5 | 21.282 |
2877303 | fff81139a7 | 505 | 5 | 22.021 |
2877304 | fff81139a7 | 506 | 5 | 18.145 |
2877305 rows × 4 columns
# 使用 read_csv() 函数从文件中读取测试集数据,文件名为 'train.csv'
test = pd.read_csv('dataset/test.csv')
test
id | dt | type | |
---|---|---|---|
0 | 00037f39cf | 1 | 2 |
1 | 00037f39cf | 2 | 2 |
2 | 00037f39cf | 3 | 2 |
3 | 00037f39cf | 4 | 2 |
4 | 00037f39cf | 5 | 2 |
... | ... | ... | ... |
58315 | fff81139a7 | 6 | 5 |
58316 | fff81139a7 | 7 | 5 |
58317 | fff81139a7 | 8 | 5 |
58318 | fff81139a7 | 9 | 5 |
58319 | fff81139a7 | 10 | 5 |
58320 rows × 3 columns
3.3 计算训练数据最近11-20单位时间内对应id的目标均值
target_mean = train[train['dt']<=20].groupby(['id'])['target'].mean().reset_index()
target_mean
id | target | |
---|---|---|
0 | 00037f39cf | 39.6543 |
1 | 00039a1517 | 49.1805 |
2 | 000c15d0ea | 26.7723 |
3 | 00150bc11a | 30.7137 |
4 | 0038d86077 | 10.7277 |
... | ... | ... |
5827 | ffe1c50bbb | 9.7590 |
5828 | ffe8cdb524 | 23.7121 |
5829 | fff62c78fb | 39.3930 |
5830 | fff6d685ea | 40.7109 |
5831 | fff81139a7 | 30.0622 |
5832 rows × 2 columns
3.4 将target_mean作为测试集结果进行合并
test = test.merge(target_mean, on=['id'], how='left')
test
id | dt | type | target | |
---|---|---|---|---|
0 | 00037f39cf | 1 | 2 | 39.6543 |
1 | 00037f39cf | 2 | 2 | 39.6543 |
2 | 00037f39cf | 3 | 2 | 39.6543 |
3 | 00037f39cf | 4 | 2 | 39.6543 |
4 | 00037f39cf | 5 | 2 | 39.6543 |
... | ... | ... | ... | ... |
58315 | fff81139a7 | 6 | 5 | 30.0622 |
58316 | fff81139a7 | 7 | 5 | 30.0622 |
58317 | fff81139a7 | 8 | 5 | 30.0622 |
58318 | fff81139a7 | 9 | 5 | 30.0622 |
58319 | fff81139a7 | 10 | 5 | 30.0622 |
58320 rows × 4 columns
3.5 保存结果文件到本地
test[['id','dt','target']].to_csv('submit.csv', index=None, encoding='utf-8')
4 第一阶段总结
在本次电力需求预测挑战赛中,我们首先导入了所需的相关库,包括pandas和numpy。
然后,我们读取了训练集和测试集的数据。训练集包含了id、dt(时间)、type(类型)和target(目标值)等列,而测试集只包含了id、dt和type列。
接下来,我们计算了训练数据最近11-20单位时间内对应id的目标均值。这是通过将训练数据按照id进行分组,并计算每个分组内的target列的平均值来实现的。
计算得到的目标均值被存储在target_mean变量中,然后我们将target_mean与测试集进行合并,以便在测试集中使用这些均值作为预测结果。
之后,我们将合并后的测试集保存到本地文件submit.csv中。这个文件包含了id、dt和target列,其中target列是我们根据训练数据计算出的预测结果。
最后,在整个第一阶段过程中,我们主要使用了pandas库进行数据处理和分析。通过分组、计算均值和合并等操作,我们成功地生成了预测结果,并将其保存到本地文件中。这种基于历史数据的预测方法可以作为一种基线模型,为后续更复杂的预测模型提供一个参考。
TASK2
5 导入模块
import numpy as np
import pandas as pd
import lightgbm as lgb
from sklearn.metrics import mean_squared_log_error, mean_absolute_error, mean_squared_error
import tqdm
import sys
import os
import gc
import argparse
import warnings
warnings.filterwarnings('ignore')
import matplotlib.pyplot as plt
lightgbm使用3.3.0老版本
pip install lightgbm==3.3.0
6 探索性数据分析(EDA)
字段 | 含义 | 备注 |
---|---|---|
id | 房屋id | |
dt | 日标识 | 训练数据dt最小为11,不同id对应序列长度不同 |
type | 房屋类型 | 通常而言不同类型的房屋整体消耗存在比较大的差异 |
target | 实际电力消耗 | 本次比赛的预测目标 |
train = pd.read_csv('dataset/train.csv')
train
id | dt | type | target | |
---|---|---|---|---|
0 | 00037f39cf | 11 | 2 | 44.050 |
1 | 00037f39cf | 12 | 2 | 50.672 |
2 | 00037f39cf | 13 | 2 | 39.042 |
3 | 00037f39cf | 14 | 2 | 35.900 |
4 | 00037f39cf | 15 | 2 | 53.888 |
... | ... | ... | ... | ... |
2877300 | fff81139a7 | 502 | 5 | 28.552 |
2877301 | fff81139a7 | 503 | 5 | 22.818 |
2877302 | fff81139a7 | 504 | 5 | 21.282 |
2877303 | fff81139a7 | 505 | 5 | 22.021 |
2877304 | fff81139a7 | 506 | 5 | 18.145 |
2877305 rows × 4 columns
test = pd.read_csv('dataset/test.csv')
test
id | dt | type | |
---|---|---|---|
0 | 00037f39cf | 1 | 2 |
1 | 00037f39cf | 2 | 2 |
2 | 00037f39cf | 3 | 2 |
3 | 00037f39cf | 4 | 2 |
4 | 00037f39cf | 5 | 2 |
... | ... | ... | ... |
58315 | fff81139a7 | 6 | 5 |
58316 | fff81139a7 | 7 | 5 |
58317 | fff81139a7 | 8 | 5 |
58318 | fff81139a7 | 9 | 5 |
58319 | fff81139a7 | 10 | 5 |
58320 rows × 3 columns
6.1 不同type类型对应target的柱状图
# 不同type类型对应target的柱状图
type_target_df = train.groupby('type')['target'].mean().reset_index()
plt.figure(figsize=(8, 4))
plt.bar(type_target_df['type'], type_target_df['target'], color=['blue', 'green'])
plt.xlabel('Type')
plt.ylabel('Average Target Value')
plt.title('Bar Chart of Target by Type')
plt.show()
不同类型对应的目标值的平均值可以用于比较和分析不同类型的性能或效果。例如,在机器学习中,我们可能会对不同类型的模型进行训练和测试,然后计算每个类型的平均预测准确率。这样可以帮助我们了解哪种类型的模型在这个问题上表现最好。
6.2 id为00037f39cf的按dt为序列关于target的折线图
specific_id_df = train[train['id'] == '00037f39cf']
plt.figure(figsize=(10, 5))
plt.plot(specific_id_df['dt'], specific_id_df['target'], marker='o', linestyle='-')
plt.xlabel('DateTime')
plt.ylabel('Target Value')
plt.title("Line Chart of Target for ID '00037f39cf'")
plt.show()
绘制一个特定ID的目标值随时间变化的折线图可以帮助我们观察该ID在不同时间点上的目标值的变化趋势。这有助于我们了解目标值是否稳定,是否有上升或下降的趋势,以及是否存在周期性变化等。通过观察折线图,我们可以更好地理解数据的特征和模式,从而做出更准确的分析和决策。
7 特征工程
# 合并训练数据和测试数据,并进行排序
data = pd.concat([test, train], axis=0, ignore_index=True)
data = data.sort_values(['id','dt'], ascending=False).reset_index(drop=True)
data
id | dt | type | target | |
---|---|---|---|---|
0 | fff81139a7 | 506 | 5 | 18.145 |
1 | fff81139a7 | 505 | 5 | 22.021 |
2 | fff81139a7 | 504 | 5 | 21.282 |
3 | fff81139a7 | 503 | 5 | 22.818 |
4 | fff81139a7 | 502 | 5 | 28.552 |
... | ... | ... | ... | ... |
2935620 | 00037f39cf | 5 | 2 | NaN |
2935621 | 00037f39cf | 4 | 2 | NaN |
2935622 | 00037f39cf | 3 | 2 | NaN |
2935623 | 00037f39cf | 2 | 2 | NaN |
2935624 | 00037f39cf | 1 | 2 | NaN |
2935625 rows × 4 columns
合并训练数据和测试数据到新数据框data。
7.1 历史平移
历史平移特征:通过历史平移获取上个阶段的信息;如下图所示,可以将d-1时间的信息给到d时间,d时间信息给到d+1时间,这样就实现了平移一个单位的特征构建。
for i in range(10,30):
data[f'last{i}_target'] = data.groupby(['id'])['target'].shift(i)
-
提供历史信息:通过将过去一段时间内的数据作为新的特征,可以让模型在预测时考虑到过去的数据变化情况,从而更好地理解数据的趋势和周期性。
-
增加特征维度:历史平移可以生成大量的新特征,从而增加模型的输入维度,有助于提高模型的表达能力和预测准确性。
-
捕捉时间依赖性:对于具有明显时间依赖性的数据集(如股票价格、天气预报等),历史平移特征可以帮助模型捕捉到这种依赖关系,从而提高预测的准确性。
-
简化模型结构:通过引入历史平移特征,可以将复杂的时间序列问题转化为常规的回归或分类问题,从而简化模型的结构。
7.2 窗口统计
窗口统计特征:窗口统计可以构建不同的窗口大小,然后基于窗口范围进统计均值、最大值、最小值、中位数、方差的信息,可以反映最近阶段数据的变化情况。如下图所示,可以将d时刻之前的三个时间单位的信息进行统计构建特征给我d时刻。
data[f'win3_mean_target'] = (data['last10_target'] + data['last11_target'] + data['last12_target']) / 3
data[f'win3_mean_target']
0 NaN 1 NaN 2 NaN 3 NaN 4 NaN ... 2935620 43.567333 2935621 41.774000 2935622 42.943333 2935623 41.871333 2935624 44.588000 Name: win3_mean_target, Length: 2935625, dtype: float64
-
提供局部信息:通过将过去一段时间内的数据进行统计,可以让模型在预测时考虑到数据的局部变化情况,从而更好地理解数据的波动性和异常值。
-
增加特征维度:窗口统计可以生成大量的新特征,从而增加模型的输入维度,有助于提高模型的表达能力和预测准确性。
-
捕捉局部依赖性:对于具有明显局部依赖性的数据集(如股票价格、天气预报等),窗口统计特征可以帮助模型捕捉到这种依赖关系,从而提高预测的准确性。
-
简化模型结构:通过引入窗口统计特征,可以将复杂的时间序列问题转化为常规的回归或分类问题,从而简化模型的结构。
7.3 进行数据切分
train = data[data.target.notnull()].reset_index(drop=True)
train
id | dt | type | target | last10_target | last11_target | last12_target | last13_target | last14_target | last15_target | ... | last21_target | last22_target | last23_target | last24_target | last25_target | last26_target | last27_target | last28_target | last29_target | win3_mean_target | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | fff81139a7 | 506 | 5 | 18.145 | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1 | fff81139a7 | 505 | 5 | 22.021 | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2 | fff81139a7 | 504 | 5 | 21.282 | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
3 | fff81139a7 | 503 | 5 | 22.818 | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
4 | fff81139a7 | 502 | 5 | 28.552 | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2877300 | 00037f39cf | 15 | 2 | 53.888 | 42.801 | 29.319 | 43.427 | 36.989 | 44.566 | 38.876 | ... | 34.351 | 37.134 | 27.813 | 41.049 | 34.641 | 33.598 | 40.543 | 29.830 | 39.202 | 38.515667 |
2877301 | 00037f39cf | 14 | 2 | 35.900 | 38.814 | 42.801 | 29.319 | 43.427 | 36.989 | 44.566 | ... | 35.731 | 34.351 | 37.134 | 27.813 | 41.049 | 34.641 | 33.598 | 40.543 | 29.830 | 36.978000 |
2877302 | 00037f39cf | 13 | 2 | 39.042 | 37.267 | 38.814 | 42.801 | 29.319 | 43.427 | 36.989 | ... | 35.945 | 35.731 | 34.351 | 37.134 | 27.813 | 41.049 | 34.641 | 33.598 | 40.543 | 39.627333 |
2877303 | 00037f39cf | 12 | 2 | 50.672 | 34.662 | 37.267 | 38.814 | 42.801 | 29.319 | 43.427 | ... | 46.938 | 35.945 | 35.731 | 34.351 | 37.134 | 27.813 | 41.049 | 34.641 | 33.598 | 36.914333 |
2877304 | 00037f39cf | 11 | 2 | 44.050 | 50.395 | 34.662 | 37.267 | 38.814 | 42.801 | 29.319 | ... | 57.527 | 46.938 | 35.945 | 35.731 | 34.351 | 37.134 | 27.813 | 41.049 | 34.641 | 40.774667 |
2877305 rows × 25 columns
test = data[data.target.isnull()].reset_index(drop=True)
test
id | dt | type | target | last10_target | last11_target | last12_target | last13_target | last14_target | last15_target | ... | last21_target | last22_target | last23_target | last24_target | last25_target | last26_target | last27_target | last28_target | last29_target | win3_mean_target | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | fff81139a7 | 10 | 5 | NaN | 29.571 | 33.691 | 27.034 | 33.063 | 30.109 | 36.227 | ... | 32.513 | 32.984 | 31.413 | 34.685 | 23.518 | 29.392 | 31.081 | 29.185 | 30.631 | 30.098667 |
1 | fff81139a7 | 9 | 5 | NaN | 28.677 | 29.571 | 33.691 | 27.034 | 33.063 | 30.109 | ... | 28.664 | 32.513 | 32.984 | 31.413 | 34.685 | 23.518 | 29.392 | 31.081 | 29.185 | 30.646333 |
2 | fff81139a7 | 8 | 5 | NaN | 21.925 | 28.677 | 29.571 | 33.691 | 27.034 | 33.063 | ... | 26.588 | 28.664 | 32.513 | 32.984 | 31.413 | 34.685 | 23.518 | 29.392 | 31.081 | 26.724333 |
3 | fff81139a7 | 7 | 5 | NaN | 29.603 | 21.925 | 28.677 | 29.571 | 33.691 | 27.034 | ... | 33.816 | 26.588 | 28.664 | 32.513 | 32.984 | 31.413 | 34.685 | 23.518 | 29.392 | 26.735000 |
4 | fff81139a7 | 6 | 5 | NaN | 30.279 | 29.603 | 21.925 | 28.677 | 29.571 | 33.691 | ... | 37.080 | 33.816 | 26.588 | 28.664 | 32.513 | 32.984 | 31.413 | 34.685 | 23.518 | 27.269000 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
58315 | 00037f39cf | 5 | 2 | NaN | 53.888 | 35.534 | 41.280 | 26.114 | 25.612 | 44.451 | ... | 29.319 | 43.427 | 36.989 | 44.566 | 38.876 | 22.631 | 57.527 | 46.938 | 35.945 | 43.567333 |
58316 | 00037f39cf | 4 | 2 | NaN | 35.900 | 53.888 | 35.534 | 41.280 | 26.114 | 25.612 | ... | 42.801 | 29.319 | 43.427 | 36.989 | 44.566 | 38.876 | 22.631 | 57.527 | 46.938 | 41.774000 |
58317 | 00037f39cf | 3 | 2 | NaN | 39.042 | 35.900 | 53.888 | 35.534 | 41.280 | 26.114 | ... | 38.814 | 42.801 | 29.319 | 43.427 | 36.989 | 44.566 | 38.876 | 22.631 | 57.527 | 42.943333 |
58318 | 00037f39cf | 2 | 2 | NaN | 50.672 | 39.042 | 35.900 | 53.888 | 35.534 | 41.280 | ... | 37.267 | 38.814 | 42.801 | 29.319 | 43.427 | 36.989 | 44.566 | 38.876 | 22.631 | 41.871333 |
58319 | 00037f39cf | 1 | 2 | NaN | 44.050 | 50.672 | 39.042 | 35.900 | 53.888 | 35.534 | ... | 34.662 | 37.267 | 38.814 | 42.801 | 29.319 | 43.427 | 36.989 | 44.566 | 38.876 | 44.588000 |
58320 rows × 25 columns
- 提高模型泛化能力:数据切分是确保模型能在未见数据上表现良好的关键步骤。通过保留一部分数据作为测试集,可以用来估计模型在实际应用中的表现,这是模型泛化能力的重要指标。如果在全部数据上训练并评估模型,很可能会出现过拟合现象,即模型在这些数据上表现优异,但在新数据上效果较差。
- 避免信息泄露:数据切分避免了训练过程中使用到测试数据,从而防止了信息泄露的问题。例如,在分类任务中,如果测试集的数据被用于训练,那么模型在测试集上的准确性将会被人为地提高,从而误导模型的实际表现。通过将数据分为训练集和测试集,可以确保评估过程的公正性和准确性。
- 减少过拟合风险:在模型训练过程中,使用训练集进行模型的构建,而保留测试集用于最终的模型评估。这样,通过对比训练误差和测试误差,可以检测模型是否过拟合或欠拟合。过拟合是指模型在训练集上表现很好,但在测试集上表现差;而欠拟合则是指在两个集合上的表现都较差。通过适当的数据切分和模型调整,可以找到一个平衡点,使模型具有最佳的泛化能力。
- 提供可靠性能估计:数据切分允许使用独立的测试集对模型进行多次评估,这样可以提供更可靠的性能估计。在多次运行实验中,使用不同的训练集和测试集划分方式,可以获得模型性能的平均值和方差,从而更全面地了解模型的稳定性和可靠性。
- 支持交叉验证:数据切分方法之一是交叉验证,特别是k折交叉验证。这种方法通过将数据分成k个子集,每个子集轮流作为测试集,其余作为训练集,从而能更全面地利用数据进行模型训练和评估。这种方法可以进一步提高模型评估的稳定性和准确性。
7.4 确定输入特征
train_cols = [f for f in data.columns if f not in ['id','target']]
train_cols
['dt', 'type', 'last10_target', 'last11_target', 'last12_target', 'last13_target', 'last14_target', 'last15_target', 'last16_target', 'last17_target', 'last18_target', 'last19_target', 'last20_target', 'last21_target', 'last22_target', 'last23_target', 'last24_target', 'last25_target', 'last26_target', 'last27_target', 'last28_target', 'last29_target', 'win3_mean_target']
8 模型训练与测试集预测(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, 50000, valid_sets=[train_matrix, valid_matrix],
categorical_feature=[], verbose_eval=500, early_stopping_rounds=500)
# 验证集和测试集结果预测
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('submit2.csv', index=None)
Training until validation scores don't improve for 500 rounds [500] training's l2: 181.756 valid_1's l2: 185.823 [1000] training's l2: 170.758 valid_1's l2: 183.92 Early stopping, best iteration is: [956] training's l2: 171.445 valid_1's l2: 183.573 183.57327141293402
9 完整代码
#!/usr/bin/env python
# coding: utf-8
# # 1 导入模块
# In[1]:
import numpy as np
import pandas as pd
import lightgbm as lgb # 3.3.0老版本
from sklearn.metrics import mean_squared_log_error, mean_absolute_error, mean_squared_error
import tqdm
import sys
import os
import gc
import argparse
import warnings
warnings.filterwarnings('ignore') # 将所有的警告设置为忽略状态
import matplotlib.pyplot as plt
# # 2 探索性数据分析(EDA)
# 字段|含义|备注
# ----|----|----
# id|房屋id|
# dt|日标识|训练数据dt最小为11,不同id对应序列长度不同
# type|房屋类型|通常而言不同类型的房屋整体消耗存在比较大的差异
# target|实际电力消耗|也是我们的本次比赛的预测目标
# In[3]:
train = pd.read_csv('dataset/train.csv')
train
# In[4]:
test = pd.read_csv('dataset/test.csv')
test
# ## 2.1 不同type类型对应target的柱状图
# In[5]:
# 不同type类型对应target的柱状图
type_target_df = train.groupby('type')['target'].mean().reset_index() # 对数据集train按照'type'列进行分组,并计算每个类型的目标值(target)的平均值。然后将结果重置索引
plt.figure(figsize=(8, 4))
plt.bar(type_target_df['type'], type_target_df['target'], color=['blue', 'green'])
plt.xlabel('Type') # 设置横坐标的标签为'Type'
plt.ylabel('Average Target Value') # 设置纵坐标的标签为'Average Target Value'
plt.title('Bar Chart of Target by Type')
plt.show()
# ## 2.2 id为00037f39cf的按dt为序列关于target的折线图
# In[6]:
specific_id_df = train[train['id'] == '00037f39cf'] # 从train数据集中筛选出ID为'00037f39cf'的行,将其存储
plt.figure(figsize=(10, 5))
plt.plot(specific_id_df['dt'], specific_id_df['target'], marker='o', linestyle='-')
plt.xlabel('DateTime')
plt.ylabel('Target Value')
plt.title("Line Chart of Target for ID '00037f39cf'")
plt.show() # 特定ID目标值随时间变化的折线图
# # 3 特征工程
# In[7]:
# 合并训练数据和测试数据,并进行排序
data = pd.concat([test, train], axis=0, ignore_index=True)
data = data.sort_values(['id','dt'], ascending=False).reset_index(drop=True)
data
# ## 3.1 历史平移
# 历史平移特征:通过历史平移获取上个阶段的信息;如下图所示,可以将d-1时间的信息给到d时间,d时间信息给到d+1时间,这样就实现了平移一个单位的特征构建。
# In[8]:
for i in range(10,30):
data[f'last{i}_target'] = data.groupby(['id'])['target'].shift(i)
# ## 3.2 窗口统计
# 窗口统计特征:窗口统计可以构建不同的窗口大小,然后基于窗口范围进统计均值、最大值、最小值、中位数、方差的信息,可以反映最近阶段数据的变化情况。如下图所示,可以将d时刻之前的三个时间单位的信息进行统计构建特征给我d时刻。
# In[9]:
data[f'win3_mean_target'] = (data['last10_target'] + data['last11_target'] + data['last12_target']) / 3
data[f'win3_mean_target']
# ## 3.3 进行数据切分
# In[10]:
train = data[data.target.notnull()].reset_index(drop=True) # 将数据集data中的目标变量(target)不为空的行筛选出来,并将结果存储在名为train的新数据框中。
train
# In[11]:
test = data[data.target.isnull()].reset_index(drop=True) # 从为"data"数据框中筛选出所有目标变量(target)为空值的行,并将结果存储在名为"test"的新数据框中。
test
# ## 3.4 确定输入特征
# In[12]:
train_cols = [f for f in data.columns if f not in ['id','target']]
train_cols
# # 4 模型训练与测试集预测(Lightgbm模型)
# In[13]:
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, 50000, valid_sets=[train_matrix, valid_matrix],
categorical_feature=[], verbose_eval=500, early_stopping_rounds=500)
# 验证集和测试集结果预测
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('submit2.csv', index=None)