时间序列数据是许多现实世界问题的核心,例如预测能源消耗。传统上,我们使用专门的时间序列模型如Prophet来对此类数据进行建模和预测。然而,通过将时间序列数据转换为表格格式,我们可以利用更广泛的机器学习算法和技术,从而发现新的见解和改进预测性能。
在本文中,我们探索了如何使用开源库将日常能源消耗的时间序列数据集转换为表格形式。然后,我们尝试了多种机器学习模型,包括梯度提升决策树和自动机器学习(AutoML),将其与Prophet模型的性能进行对比。我们的发现显示:
使用梯度提升决策树对表格数据进行多类别分类,可将样本外预测误差降低67% (准确率提高38个百分点),优于Prophet模型。 与梯度提升相比,AutoML进一步将预测误差降低42% (准确率提高8个百分点)。 总的来说,AutoML相比Prophet可将预测误差降低高达81% (准确率提升46个百分点)。 这些发现说明,通过适当的特征工程和机器学习技术,我们能够从时间序列数据中挖掘出更多有价值的信息,显著提高预测准确性。在接下来的内容中,我们将详细介绍整个过程。
检查数据该数据表示 PJM 每小时的能源消耗量(以兆瓦为单位)。PJM Interconnection LLC(PJM)是美国的一个区域输电组织(RTO),是东部互联电网的一部分,为多州提供电力传输服务。
数据集包括日期列(object
类型)和兆瓦级能耗列(float64
类型)(对每小时能耗水平的四分位数)。目标是训练时间序列预测模型,预测明天的日能耗水平分为 4 个等级:low
、below average
、above average
和high
。这些等级根据整体日能耗分布的四分位数确定。
首先演示如何应用时间序列预测方法(如Prophet),但这些方法仅适用于时间序列数据的某些类型的 ML 模型。接下来,演示如何将问题重构为一个标准的多类分类问题,可以应用任何机器学习模型,并展示如何通过使用监督式 ML 获得出色的预测结果。
首先,我们将数据转换为日均能耗,并将列重命名为先知预测模型期望的格式。实际值的日能耗水平转换成四分位数,即预测的值。训练数据及每个日能耗水平对应的四分位数如下所示,四分位数是使用训练数据计算的,以防止数据泄露。
下面是我们用来拟合预测模型的训练数据。
包含每日能源消耗水平四分位数的训练数据 下面是测试数据,我们将根据这些数据来评估我们的预测结果。
包含每日能源消耗水平四分位数的测试数据 训练和评估Prophet预测模型根据上图显示,我们将使用 2015-04-09
作为训练数据范围的结束日期,并从 2015-04-10
开始进行测试数据。我们仅使用训练数据计算每日能耗的四分位阈值,以避免数据泄漏。
接下来,我们将预测测试数据期间 PJME 的日能耗水平(以兆瓦为单位),并将预测值表示为离散变量。该变量表示每日能源消耗水平的四分位数,可分为 1("低")、2("低于平均水平")、3("高于平均水平")或 4("高")。在评估方面,我们将使用 scikit-learn
中的 accuracy_score
函数来评估模型的性能。由于我们是以这种方式提出问题的,因此我们能够使用分类准确率来评估模型的次日预测(并比较未来的模型)。
import numpy as npfrom prophet import Prophetfrom sklearn.metrics import accuracy_score# 初始化模型并在训练数据上进行训练 model = Prophet() model.fit(train_df)
# 创建覆盖测试期的未来预测数据框 future = model.make_future_dataframe(periods=len(test_df), freq='D' ) 预测 = model.predict(future)# 根据阈值将预测的每日值分为四等分 forecast['quartile' ] = pd.cut(forecast['yhat' ], bins = [-np.inf] + list(quartiles) + [np.inf], labels=[1 , 2 , 3 , 4 ])# 提取测试期的预测四分位数 forecasted_quartiles = forecast.iloc[-len(test_df):]['quartile' ].astype(int)# 将测试集中的实际日值归类为四分位数 test_df['quartile' ] = pd.cut(test_df['y' ], bins=[-np.inf] + list(quartiles) + [np.inf], labels=[1 , 2 , 3 , 4 ]) actual_test_quartiles = test_df['quartile' ].astype(int)# 计算评估指标 accuracy = accuracy_score(actual_test_quartiles, forecasted_quartiles)# 打印评估指标 print(f'Accuracy: {accuracy:.4 f} ' )>>> 0.4249
样本外准确率很低,只有43%。建立时间序列模型时,只能使用时间序列预测模型(可能的ML模型的有限子集)。接下来,会探讨如何通过适当的特征化将时间序列转换为标准表格数据集,更灵活地对这些数据进行建模。转换为标准表格数据后,就可以使用任何有监督的ML模型来预测这些日能耗数据。
通过特征化将时间序列数据转换为表格数据我们将时间序列数据转换为表格格式,并使用开源库 sktime
、tsfresh
和 tsfel
对数据进行特征化处理。这些库可以提取大量的特征,包括统计特征、时间特征和可能的频谱特征,以捕捉时间序列数据的潜在模式和特征。通过将时间序列分解为单个特征,我们可以更容易地了解数据的不同方面是如何影响目标变量的。
TSFreshFeatureExtractor
是sktime
库中的一个特征提取工具,利用tsfresh
的功能从时间序列数据中提取相关特征。tsfresh
设计用于自动计算大量时间序列特征,对理解复杂的时间动态非常有益。在我们的用例中,我们使用TSFreshFeatureExtractor
中最小的基本特征集来对数据进行特征化。
tsfel
,即 "时间序列特征提取库",提供了一整套从时间序列数据中提取特征的工具。我们利用预定义配置,从能源消耗时间序列数据中构建了丰富的特征集(如统计、时间、频谱),捕捉了可能与我们的分类任务相关的各种特征。
import tsfelfrom sktime.transformations.panel.tsfresh import TSFreshFeatureExtractor# 定义 tsfresh 特征提取器 tsfresh_trafo = TSFreshFeatureExtractor(default_fc_parameters="minimal" )# 使用特征提取器转换训练数据 X_train_transformed = tsfresh_trafo.fit_transform(X_train)# 使用相同的特征提取器转换测试数据 X_test_transformed = tsfresh_trafo.transform(X_test)# 检索预定义的特征配置文件,提取所有可用特征 cfg = tsfel.get_features_by_domain()# 每天计算 tsfel 特征的函数 def compute_features (group) : # TSFEL expects a DataFrame with the data in columns, so we transpose the input group features = tsfel.time_series_features_extractor(cfg, group, fs=1 , verbose=0 ) return features# 按指数的 "日 "级分组,并进行特征计算 train_features_per_day = X_train.groupby(level='Date' ).apply(compute_features).reset_index(drop=True ) test_features_per_day = X_test.groupby(level='Date' ).apply(compute_features).reset_index(drop=True )# 将每个特征组合成一组组合特征,用于训练/测试数据 train_combined_df = pd.concat([X_train_transformed, train_features_per_day], axis=1 ) test_combined_df = pd.concat([X_test_transformed, test_features_per_day], axis=1 )
接下来,针对输入特征进行了精心的特征选择。首先剔除那些与目标变量"日均能耗水平"的相关性过高(相关系数绝对值超过0.8)的特征。这些高度相关的特征可能会导致模型过度拟合,即在训练数据上表现良好,但在新的未见数据上泛化能力差。
同时,我们也移除了那些与目标变量完全不相关(相关系数为0)的特征。毫无相关性的特征对预测目标没有任何贡献,保留它们不仅增加了模型复杂度,也可能引入无关的噪声信息,影响模型性能。
通过这一步筛选,我们保留了那些与目标变量有一定相关性、但又不至于过度相关的特征子集,为后续的机器学习建模打下基础。合理的特征工程有助于提升模型的估计质量和泛化能力。
# 滤出与目标变量高度相关的特征 column_of_interest = "PJME_MW__mean" train_corr_matrix = train_combined_df.corr() train_corr_with_interest = train_corr_matrix[column_of_interest] null_corrs = pd.Series(train_corr_with_interest.isnull()) false_features = null_corrs[null_corrs].index.tolist() columns_to_exclude = list(set(train_corr_with_interest[abs(train_corr_with_interest) > 0.8 ].index.tolist() + false_features)) columns_to_exclude.remove(column_of_interest)
# 过滤后的数据帧排除了与所关注列高度相关的列 X_train_transformed = train_combined_df.drop(columns=columns_to_exclude) X_test_transformed = test_combined_df.drop(columns=columns_to_exclude)
如果我们现在看一下训练数据的前几行,这就是它的一个快照。我们现在有 73 个特征,这些特征是从我们使用的时间序列特征库中添加的。根据这些特征,我们要预测的标签是第二天的能耗水平。
新特征化并以表格形式显示的前 5 行训练数据 我们最佳的做法是在训练数据和测试数据上分别应用特征化过程,以避免数据泄漏。测试数据是最近的观测数据。此外,我们使用以下代码计算离散四分位值,并获取训练/测试能量标签,也就是 y_labels
。
# 定义一个函数,将每个值划分为四分位数 def classify_into_quartile (value) : if value 0]: return 1 elif value 1]: return 2 elif value 2]: return 3 else : return 4 y_train = X_train_transformed["PJME_MW__mean" ].rename("daily_energy_level" ) X_train_transformed.drop("PJME_MW__mean" , inplace=True , axis=1 ) y_test = X_test_transformed["PJME_MW__mean" ].rename("daily_energy_level" ) X_test_transformed.drop("PJME_MW__mean" , inplace=True , axis=1 ) energy_levels_train = y_train.apply(classify_into_quartile) energy_levels_test = y_test.apply(classify_into_quartile)
在特征化表格数据上训练和评估GBC模型使用特征化表格数据集,我们可以应用任何有监督的 ML 模型来预测未来的能耗水平。在这里,我们将使用梯度提升分类器(GBC)模型,它是大多数数据科学家处理表格数据的首选武器。
我们的 GBC 模型由 sklearn.ensemble
模块实例化,并配置了特定的超参数,以优化其性能并避免过度拟合。
from sklearn.ensemble import GradientBoostingClassifier gbc = GradientBoostingClassifier( n_estimators=150 , learning_rate=0.1 , max_depth=4 , min_samples_leaf=20 , max_features='sqrt' , subsample=0.8 , random_state=42 ) gbc.fit(X_train_transformed, energy_levels_train) y_pred_gbc = gbc.predict(X_test_transformed) gbc_accuracy = accuracy_score(energy_levels_test, y_pred_gbc) print(f'Accuracy: {gbc_accuracy:.4 f} ' )>>> 0.8075
81% 的样本外准确率大大高于我们之前的prophet模型结果。
使用AutoML简化工作已了解如何特征化时间序列问题,以及应用梯度提升等强大 ML 模型的好处后,一个自然的问题就出现了:我们应该应用哪种有监督的 ML 模型呢?我们可以尝试多种模型,调整超参数,然后将它们集合在一起。另一个解决方案是让 AutoML 处理所有这些问题。
我们会使用 [Cleanlab Studio: https://cleanlab.ai/] 提供的 AutoML 解决方案,无需任何配置。只需提供表格数据集,平台将自动训练多种有监督 ML 模型(包括梯度提升等),并调整超参数,确定最适合组合成一个预测器的模型。以下是训练和部署 AutoML 监督分类器所需的全部代码:
from cleanlab_studio import Studio studio = Studio() studio.create_project( dataset_id=energy_forecasting_dataset, project_name="ENERGY-LEVEL-FORECASTING" , modality="tabular" , task_type="multi-class" , model_type="regular" , label_column="daily_energy_level" , ) model = studio.get_model(energy_forecasting_model) y_pred_automl = model.predict(test_data, return_pred_proba=True )
自动机器学习(AutoML)平台中展示了模型评估估计值,展示了所有不同类型的机器学习(ML)模型(包括多个梯度提升模型),以及通过优化组合这些模型的预测结果而构建的集合预测器。
不同类型模型的 AutoML 结果 在测试数据上运行推理以获得第二天的能耗水平预测结果后,我们发现测试准确率为 89%,与之前的梯度提升方法相比,原始准确率提高了 8%。
在我们的日常能耗水平数据上测试 AutoML 的准确率 结论在实际应用中,我们将此方法应用于预测 PJM 地区的日常能源消耗数据。首先使用专门的时间序列模型 Prophet 对原始数据进行建模,作为基准。然后,我们将数据转换为表格格式,提取出更多有用的特征,再使用通用的机器学习分类算法进行建模和预测。
结果显示,与基准的 Prophet 模型相比,表格数据加梯度提升树的方法可将预测误差降低 67%(准确率提高 38 个百分点)。进一步地,我们尝试了自动机器学习(AutoML)技术,对表格数据自动选择并调优最佳的分类算法。AutoML 模型不仅比梯度提升树表现更好,降低了 42%的预测误差(准确率提高 8 个百分点),而且比 Prophet 基准模型的表现出色得多,降低了高达 81% 的预测误差(准确率提高 46 个百分点)。
这些发现说明,通过将时间序列数据转化为更标准的表格形式,并结合适当的特征工程和机器学习算法,我们能够超越传统时间序列模型的性能,在能源消耗等许多现实预测问题上获得更准确的结果。总的来说,这种基于表格数据的通用建模方法,为时间序列预测问题提供了一种值得探索的新思路。