Datawhale AI 夏令营--电力需求预测

TASK1

 1 报名比赛

        随着全球经济的快速发展和城市化进程的加速,电力系统面临着越来越大的挑战。电力需求的准确预测对于电网的稳定运行、能源的有效管理以及可再生能源的整合至关重要。然而,电力需求受到多种因素的影响,为了提高电力需求预测的准确性和可靠性,推动智能电网和可持续能源系统的发展,本场以“电力需求预测”为赛题的数据算法挑战赛。选手需要根据历史数据构建有效的模型,能够准确的预测未来电力需求。(2024 iFLYTEK A.I.开发者大赛-讯飞开放平台 (xfyun.cn)

2 下载数据并配置环境

        从赛题数据中下载文件“电力需求预测挑战赛数据集.zip”,解压缩至桌面的文件夹“电力需求预测挑战赛”,在当前目录下运行jupyter notebook平台。

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
iddttypetarget
000037f39cf11244.050
100037f39cf12250.672
200037f39cf13239.042
300037f39cf14235.900
400037f39cf15253.888
...............
2877300fff81139a7502528.552
2877301fff81139a7503522.818
2877302fff81139a7504521.282
2877303fff81139a7505522.021
2877304fff81139a7506518.145

2877305 rows × 4 columns

# 使用 read_csv() 函数从文件中读取测试集数据,文件名为 'train.csv'
test = pd.read_csv('dataset/test.csv')
test
iddttype
000037f39cf12
100037f39cf22
200037f39cf32
300037f39cf42
400037f39cf52
............
58315fff81139a765
58316fff81139a775
58317fff81139a785
58318fff81139a795
58319fff81139a7105

58320 rows × 3 columns

3.3 计算训练数据最近11-20单位时间内对应id的目标均值

target_mean = train[train['dt']<=20].groupby(['id'])['target'].mean().reset_index()
target_mean
idtarget
000037f39cf39.6543
100039a151749.1805
2000c15d0ea26.7723
300150bc11a30.7137
40038d8607710.7277
.........
5827ffe1c50bbb9.7590
5828ffe8cdb52423.7121
5829fff62c78fb39.3930
5830fff6d685ea40.7109
5831fff81139a730.0622

5832 rows × 2 columns

3.4 将target_mean作为测试集结果进行合并

test = test.merge(target_mean, on=['id'], how='left')
test
iddttypetarget
000037f39cf1239.6543
100037f39cf2239.6543
200037f39cf3239.6543
300037f39cf4239.6543
400037f39cf5239.6543
...............
58315fff81139a76530.0622
58316fff81139a77530.0622
58317fff81139a78530.0622
58318fff81139a79530.0622
58319fff81139a710530.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
iddttypetarget
000037f39cf11244.050
100037f39cf12250.672
200037f39cf13239.042
300037f39cf14235.900
400037f39cf15253.888
...............
2877300fff81139a7502528.552
2877301fff81139a7503522.818
2877302fff81139a7504521.282
2877303fff81139a7505522.021
2877304fff81139a7506518.145

2877305 rows × 4 columns

test = pd.read_csv('dataset/test.csv')
test
iddttype
000037f39cf12
100037f39cf22
200037f39cf32
300037f39cf42
400037f39cf52
............
58315fff81139a765
58316fff81139a775
58317fff81139a785
58318fff81139a795
58319fff81139a7105

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
iddttypetarget
0fff81139a7506518.145
1fff81139a7505522.021
2fff81139a7504521.282
3fff81139a7503522.818
4fff81139a7502528.552
...............
293562000037f39cf52NaN
293562100037f39cf42NaN
293562200037f39cf32NaN
293562300037f39cf22NaN
293562400037f39cf12NaN

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
iddttypetargetlast10_targetlast11_targetlast12_targetlast13_targetlast14_targetlast15_target...last21_targetlast22_targetlast23_targetlast24_targetlast25_targetlast26_targetlast27_targetlast28_targetlast29_targetwin3_mean_target
0fff81139a7506518.145NaNNaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1fff81139a7505522.021NaNNaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2fff81139a7504521.282NaNNaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
3fff81139a7503522.818NaNNaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
4fff81139a7502528.552NaNNaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
..................................................................
287730000037f39cf15253.88842.80129.31943.42736.98944.56638.876...34.35137.13427.81341.04934.64133.59840.54329.83039.20238.515667
287730100037f39cf14235.90038.81442.80129.31943.42736.98944.566...35.73134.35137.13427.81341.04934.64133.59840.54329.83036.978000
287730200037f39cf13239.04237.26738.81442.80129.31943.42736.989...35.94535.73134.35137.13427.81341.04934.64133.59840.54339.627333
287730300037f39cf12250.67234.66237.26738.81442.80129.31943.427...46.93835.94535.73134.35137.13427.81341.04934.64133.59836.914333
287730400037f39cf11244.05050.39534.66237.26738.81442.80129.319...57.52746.93835.94535.73134.35137.13427.81341.04934.64140.774667

2877305 rows × 25 columns

test = data[data.target.isnull()].reset_index(drop=True)
test
iddttypetargetlast10_targetlast11_targetlast12_targetlast13_targetlast14_targetlast15_target...last21_targetlast22_targetlast23_targetlast24_targetlast25_targetlast26_targetlast27_targetlast28_targetlast29_targetwin3_mean_target
0fff81139a7105NaN29.57133.69127.03433.06330.10936.227...32.51332.98431.41334.68523.51829.39231.08129.18530.63130.098667
1fff81139a795NaN28.67729.57133.69127.03433.06330.109...28.66432.51332.98431.41334.68523.51829.39231.08129.18530.646333
2fff81139a785NaN21.92528.67729.57133.69127.03433.063...26.58828.66432.51332.98431.41334.68523.51829.39231.08126.724333
3fff81139a775NaN29.60321.92528.67729.57133.69127.034...33.81626.58828.66432.51332.98431.41334.68523.51829.39226.735000
4fff81139a765NaN30.27929.60321.92528.67729.57133.691...37.08033.81626.58828.66432.51332.98431.41334.68523.51827.269000
..................................................................
5831500037f39cf52NaN53.88835.53441.28026.11425.61244.451...29.31943.42736.98944.56638.87622.63157.52746.93835.94543.567333
5831600037f39cf42NaN35.90053.88835.53441.28026.11425.612...42.80129.31943.42736.98944.56638.87622.63157.52746.93841.774000
5831700037f39cf32NaN39.04235.90053.88835.53441.28026.114...38.81442.80129.31943.42736.98944.56638.87622.63157.52742.943333
5831800037f39cf22NaN50.67239.04235.90053.88835.53441.280...37.26738.81442.80129.31943.42736.98944.56638.87622.63141.871333
5831900037f39cf12NaN44.05050.67239.04235.90053.88835.534...34.66237.26738.81442.80129.31943.42736.98944.56638.87644.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)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值