使用XGBoost和交叉验证探索能源消耗的时间序列预测

2024年01月26日 由 alex 发表 461 0

在这个项目中,我们利用从 Kaggle 获得的十多年来每小时能源消耗的综合数据集。我们的目标是利用强大的 XGBoost 模型并实施交叉验证技术来对未来能源消耗进行准确的时间序列预测。


数据分析设置


为了开始我们的分析,我们导入了用于数据操作和可视化的基本Python库。这包括用于数据处理的pandas,用于数值运算的numpy,用于增强可视化的seaborn,以及用于可定制绘图的matplotlib。此外,我们结合了用于预测分析的XGBoost模型和用于评估模型性能的均方误差指标。


import pandas as pd
import numpy as np 
import seaborn as sns
color_pal = sns.color_palette()
import matplotlib.pyplot as plt
plt.style.use('fivethirtyeight')
import xgboost as xgb
from sklearn.metrics import mean_squared_error


数据加载和索引


下一步是从CSV文件加载数据集。我们将索引设置为“日期时间”列,这是时间序列预测一致性的关键步骤。以下代码片段说明了这些操作:


df = pd.read_csv('PJME_hourly.csv')
### Set Index as Datetime
df = df.set_index('Datetime')
Change Datetime Datatype to Datetime
#df.index = pd.to_datetime(df.index)


探索时间序列模式


在进入建模阶段之前,必须检查时间序列数据中固有的各种模式。时间序列模型通常表现出不同的模式,这些模式会显著影响预测准确性。通过深入了解这些模式,我们可以更好地调整我们的建模方法,以进行有效的能耗预测。


了解时间序列组件和数据可视化


了解时间序列组件


在许多情况下,时间序列数据表现出各种模式的组合。彻底理解时间序列的组成部分是至关重要的。在接下来,我们将深入研究这些组件的细节,重点关注它们的复杂性和对准确时间序列预测的影响。


7


时间序列中的季节模式


我们后来的分析表明,我们的模型中存在的模式属于季节性模式的范畴。这意味着我们的数据会根据一年中的时间发生趋势变化,我们将在预测模型中仔细考虑这一因素。


数据可视化


接下来,我们将注意力转向可视化数据,以便进行深入分析。绘制一个简单的图表,以观察随时间变化的趋势,并识别数据集中的任何异常值。下面的代码片段生成图形:


df.plot(style = '.', 
        figsize = (15, 5), 
        color = color_pal[0], 
        title = 'PJME ENery Use in MW');


这种可视化是理解时间序列数据的基本模式和特征的基础步骤,为后续建模和分析铺平了道路。


8


离群点分析和数据分布探索


在查看说明能源消耗随时间变化的图表时,2012年至2013年期间的一个值得注意的区域显示出极低的数值。这些异常可能意味着我们数据中的异常值,可能是由熔毁、停电或传感器故障等异常事件造成的。解决异常值是至关重要的,因为我们的模型可能会从这些数据点中学习,这可能会影响预测的准确性。


直方图分析


更进一步,我们的目标是通过直方图分析将20,000 MW以下的值归类为异常值。为了创建直方图,我们计算平均能耗(“mean_MW ”)并使用以下代码绘制分布图:


mean_MW = df['PJME_MW'].mean()
mean_MW
df['PJME_MW'].plot(figsize = (15,5), kind = 'hist', bins = 500)
plt.title('Distribution Energy Consumed in MW', fontsize=18)
plt.xlabel('MW', fontsize=12)
plt.ylabel('Frequency', fontsize=12)
plt.axvline(x=mean_MW, color='r', linestyle = '--', label = 'mean')
plt.legend(bbox_to_anchor=(1.04,1));


9


直方图观察


直方图显示,大多数值落在20,000至55,000mW的范围内。因此,低于20,000MW的值被确定为异常值。为了查明这些低值出现的时间,使用了“查询”方法:


df.query('PJME_MW < 20000').plot(figsize = (15,5), style = '.')
plt.legend(bbox_to_anchor=(1.04,1));


10


深入的离群点分析和数据清理


持续异常值的识别


图表中有一个明显的时期,由一条一致的直线标记,其中能耗值骤降至15,000 MW。为了更深入地研究,我们利用“ query()”方法来查明这些离群值发生的具体日期和时间。代码片段如下:


df.query('PJME_MW < 19000')['PJME_MW']


11


异常发生分析


根据表输出,异常值出现在2012年10月29日夜间,一直持续到第二天上午9点。此外,10月31日凌晨还出现了其他异常值。为了直观显示并更详细地了解这些事件,我们使用以下代码:


df.query('PJME_MW < 19000').plot(figsize = (15,5), style = '.')
plt.legend(bbox_to_anchor=(1.04,1));


12


生成的图表显示了发生日期(10月30日)和这些异常值发生的相应时间。


数据清理


在离群值分析的最后阶段,我们使用“ copy()”方法创建当前数据帧的副本。然后,我们通过删除小于19,000 MW的值来更新我们的数据帧(“ DF ”)。此数据清理步骤的代码如下:


df = df[df['PJME_MW'] > 19000].copy()


这种细致的离群值分析和数据清理过程确保了我们数据集的完整性,为更准确可靠的时间序列预测铺平了道路。


稳健模型评估的时间序列交叉验证


时间序列分割简介


时间序列拆分是为时间序列数据设计的专用交叉验证器,确保在拆分过程中保持数据的时间顺序。该方法对于时间序列分析中模型性能的实际评估至关重要。通过将数据集分为训练集和测试集,同时考虑时间顺序,时间序列分割提供了对模型预测能力的更准确的评估。


时间序列拆分配置


要实现时间序列拆分,请使用以下代码:


tss = TimeSeriesSplit(n_splits = 5, test_size = 24*365*1, gap = 24)
df = df.sort_index()


对索引进行排序


使用“sort_index()”方法按升序对数据帧的索引进行排序,这是时间序列分割分析中的一种常见做法,可确保数据按时间顺序排列。


用于生成交叉验证拆分的For循环


为了生成交叉验证分割,for循环在数据帧上迭代以创建训练和验证索引。下面的代码片段举例说明了这个过程:


for train_index, val_index in tss.split(df):
    break


该循环生成训练和验证指数,这些指数将循环五次,以产生跨越不同年份的五个不同的交叉验证分割。


交叉验证分割的可视化


使用具有以下代码的子图图形可视化创建的交叉验证拆分:


fig, axs = plt.subplots(5, 1,figsize = (15,15), sharex=True)
fold = 0
for train_index, val_index in tss.split(df):
    train =df.iloc[train_index]
    test = df.iloc[val_index]
    train['PJME_MW'].plot(ax = axs[fold],
                         label = 'Training Set',
                         title = f'Data Train/Test split Fold {fold}')
    test['PJME_MW'].plot(ax = axs[fold], label = 'Test Set')
    
    axs[fold].axvline(test.index.min(), color = 'black', ls = '--')
    fold += 1


13


此图直观地表示每个交叉验证拆分的训练集和测试集,有助于理解数据如何随时间划分。在我们的时间序列分析之旅中,请继续关注对特征工程和模型训练的进一步探索。


上图可视化了时间序列交叉验证的结果,说明了五个不同年份的独立测试。该方法用于确保稳健的模型评估,并且在处理大型数据集时特别有益。通过对不同的年度细分市场进行测试,我们对模型在不同时间背景下的表现有了全面的了解。


在五个不同年份进行独立测试的决定是一种战略选择,可以最大限度地发挥大型数据集的效用。当我们进行特征工程和模型训练时,这种方法确保了全面的评估,并增强了模型对不同时间模式的适应性。请继续关注我们的时间序列分析之旅的进一步发展。


用于增强时间序列分析的特征工程


为了增强我们的时间序列分析和捕获能量消耗模式,我们采用了一个特征创建功能,该功能将几个与时间相关的特征添加到我们的数据帧中。这些特征来源于时间序列索引,包括 Hour、Day_of_Week、Quarter、Month、Year、Day_of_Year、Day_of_Month 和 Week_of_Year。这种丰富有助于更深入地理解我们数据的时间方面,帮助我们的模型识别模式和季节性。


特征创建功能


特征创建功能名为“create_features”,其实现方式如下:


def create_features(df):
    """
    Create time series features based on time series index. 
    """
    df.copy()
    df['Hour'] = df.index.hour
    df['Day_of_Week'] = df.index.dayofweek


可视化特征关系


为了确认我们的特征所捕获的模式和季节性,我们利用箱形图来可视化某些特征和目标变量(能源消耗)之间的关系。下面突出显示了两个特定的可视化效果。


1. 每小时消耗的箱形图:


fig, ax= plt.subplots(figsize=(10, 8))
sns.boxplot(data=df, x='Hour', y='PJME_MW')
ax.set_title('MW by Hour');


14


箱形图显示,清晨时段的能源消耗有所下降,从早上6点开始显著上升。


2、月消费箱形图


fig, ax= plt.subplots(figsize=(10, 8))
sns.boxplot(data=df, x='Month', y='PJME_MW', palette='Blues')
ax.set_title('MW by Month');


aaa


这张图表显示了夏季能源消耗的高峰,尤其是在7月,这表明与空调使用的增加有关。


结论


特征工程过程增强了我们对数据集中时间模式的理解,为改进时间序列分析铺平了道路。这些可视化证实了能源消耗季节性模式的存在,为后续建模和预测分析提供了有价值的见解。


时间序列分析中时态背景的滞后特征


滞后特性简介


滞后特征有助于为模型提供历史背景,使其在进行预测时能够考虑过去的数据。在我们的例子中,目标变量是' PJME_MW ',代表能耗。通过创建滞后特征,我们指示模型将过去指定天数的能耗值合并为新特征。


目标映射


为了便于创建滞后特征,我们创建一个字典(“target_map”),该字典将“ PJME_MW ”值映射到数据帧中的相应日期:


target_map = df['PJME_MW'].to_dict()


创建滞后特征


实现“add_lags”功能以向数据帧添加滞后特征。在此函数中,通过引用364、728和1092天前的目标变量,分别创建了三个滞后特征(' LAG1 '、' LAG2 '和' LAG3 '):


def add_lags(df): 
    df['lag1'] = (df.index - pd.Timedelta('364 days')).map(target_map)
    df['lag2'] = (df.index - pd.Timedelta('728 days')).map(target_map)
    df['lag3'] = (df.index - pd.Timedelta('1092 days')).map(target_map)
    return df


数据集转换


15


生成的DataFrame现在包括滞后特性,增强了模型捕获时间依赖关系的能力。需要注意的是,数据集的前几行包含滞后特征的NaN值,因为前几年的历史数据不可用。然而,在数据集的末尾,用有意义的值填充滞后特征。


结论


滞后特征的加入丰富了数据集,为模型提供了历史信息,以更好地理解和预测能源消耗模式。随着我们的进步,这些滞后特征将有助于我们的时间序列模型的准确性和有效性。


时间序列交叉验证与XGBoost回归


介绍


在时间序列分析的这一阶段,我们使用Scikit-Learn的“ TimeSeriesSplit ”方法进行时间序列交叉验证。目标是拟合XGBOOST回归量(' XGBRegressor ')以预测目标变量(' PJME_MW ')。这一过程确保了我们的模型在多个时间段的性能的稳健评估。


时间序列拆分配置


我们配置时间序列分割(' TSS ')以创建5个折叠,其中测试大小表示一年的数据,并且在训练集和测试集之间有24小时的间隔:


tss = TimeSeriesSplit(n_splits = 5, test_size = 24*365*1, gap = 24)
df = df.sort_index()
fold = 0
preds = []
scores = []
for train_index, val_index in tss.split(df):
    train =df.iloc[train_index]
    test = df.iloc[val_index]
    ###run the train and test sets through create fetures function 5 different times
    train = create_features(train)
    test = create_features(test)
    ### Define the features including the lags
    FEATURES = ['Hour', 'Day_of_Week', 'Quarter', 'Month', 'Year','Day_of_Year','lag1','lag2','lag3']
    TARGET = 'PJME_MW'
    
    
    X_train = train[FEATURES]
    y_train = train[TARGET]
    X_test = test[FEATURES]
        y_test = test[TARGET]
    
    reg = xgb.XGBRegressor(base_score = 0.5, booster = 'gbtree',
                           n_estimators = 1000, 
                           early_Stopping_rounds=50,
                           objective = 'reg:linear',
                           max_depth = 3,
                           learning_rate = 0.01)
    reg.fit(X_train, y_train,
           eval_set = [(X_train, y_train), (X_test, y_test)],
           verbose = 100)
    
    y_pred = reg.predict(X_test)
    preds.append(y_pred)
    # give score to the model
    score = np.sqrt(mean_squared_error(y_test, y_pred))
    #save the scores into list
    scores.append(score)


模型训练与评估


随后的循环通过由“ TSS.SPLIT(DF)”生成的折叠进行迭代。对于每个折叠:


-它将数据分为训练集(' train ')和测试集(' test ')。

-将“create_features”功能应用于训练集和测试集,以丰富特征。

-定义特征(' features ')和目标变量(' target ')。

-使用指定的超参数初始化XGBOOST回归器(`reg`)。

-在训练集上拟合模型,并使用均方根误差在测试集上进行评估。

-将预测(' Y_Pred ')和均方根误差(' Score ')分别附加到列表' Pred '和' Score '。


我们的5个交叉验证的分数是使用以下代码打印出来的,我们的总平均分数是3799.7874。


16


结论


使用XGBoost回归实现时间序列交叉验证增强了预测模型的稳健性。跨不同时间段的迭代评估提供了对模型性能的全面了解。随着我们的进展,将探索对结果的进一步分析和潜在的模型改进。


使用XGBoost预测未来:时间序列分析


介绍


随着时间序列分析进程的推进,下一步是使用XGBoost算法预测未来的能源消耗。最初,我们利用所有可用的历史数据,在整个数据集上优化和训练我们的模型。随后,我们将我们的数据帧扩展到未来,创建特征,并使用我们训练的模型每小时进行一次预测。


在整个数据集上训练模型


我们修改先前的代码以在整个数据集上训练XGBOOST回归量(' reg '),而不分成训练集和测试集:


## Retian on all data
df = create_features(df)
### Define the features including the lags
FEATURES = ['Hour', 'Day_of_Week', 'Quarter', 'Month', 'Year','Day_of_Year',
                'Day_of_Month','lag1','lag2','lag3']
TARGET = 'PJME_MW'
    
X_all = df[FEATURES]
y_all = df[TARGET]
    
reg = xgb.XGBRegressor(base_score = 0.5, 
                       booster = 'gbtree',
                       n_estimators = 1000, 
                       objective = 'reg:linear',
                       max_depth = 3,
                       learning_rate = 0.01)
reg.fit(X_all, y_all, 
        eval_set = [(X_all, y_all)],
        verbose = 100)


将DataFrame扩展到未来


为了预测未来,我们创建具有未来日期的新数据帧(“future_df ”),并引入列“ IsFuture ”来标识未来预测。然后,我们将其与现有的DataFrame连接,并添加功能和滞后值:


future = pd.date_range('2018-08-03','2019-08-01', freq = '1h')
future_df = pd.DataFrame(index = future)
future_df['isFuture'] = True
df['isFuture'] = False
df_and_future = pd.concat([df, future_df])
# add the features
df_and_future = create_features(df_and_future)
df_and_future = add_lags(df_and_future)


使用XGBoost预测未来


我们在未来数据集中创建一个新列“ pred ”,并使用经过训练的xgboost回归器来预测未来的能耗:


future_with_features = df_and_future.query('isFuture').copy()
future_with_features['pred'] = reg.predict(future_with_features[FEATURES])


未来预测的可视化


最后,我们绘制了一张图表,说明2018年8月至2019年8月每小时的预测未来值:


future_with_features['pred'].plot(figsize = (10,5),
                                 color = color_pal[1],
                                 ms=1,
                                 lw=1,
                                 title='Future Predictions');


17


结论


这张图是我们的XGBoost模型对未来能源消耗预测的直观表示。虽然XGBoost是一种功能强大的算法,但还有其他各种预测未来值的方法,掌握这些技术为更复杂的时间序列分析打开了大门。

总结

XGBoost 是一种强大且流行的机器学习算法,特别适用于回归和分类任务。然而,与任何其他算法一样,它在时间序列预测方面也有其局限性和考虑因素。

文章来源:https://medium.com/@ethannabatchian/exploring-time-series-prediction-of-energy-consumption-using-xgboost-and-cross-validation-5d299655bec6
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消