LightGBMCV
使用 LightGBM 进行时间序列交叉验证。
源代码
LightGBMCV
创建 LightGBM CV 对象。
类型 | 默认值 | 详细信息 | |
---|---|---|---|
freq | Union | Pandas offset 别名,例如 ‘D’、‘W-THU’,或表示时间序列频率的整数。 | |
lags | 可选 | None | 用作特征的目标变量的滞后值。 |
lag_transforms | 可选 | None | 目标变量滞后值及其变换的映射。 |
date_features | 可选 | None | 根据日期计算的特征。可以是 pandas 日期属性,或将日期作为输入的函数。 |
num_threads | int | 1 | 计算特征时使用的线程数。 |
target_transforms | 可选 | None | 在计算特征之前应用于目标变量,并在预测步骤后恢复的变换。 |
示例
这里展示了 M4 数据集中仅 4 个时间序列的示例。如果您想在所有序列上自行运行,可以参考此 Notebook。
unique_id | ds | y | |
---|---|---|---|
86796 | H196 | 1 | 11.8 |
86797 | H196 | 2 | 11.4 |
86798 | H196 | 3 | 11.1 |
86799 | H196 | 4 | 10.8 |
86800 | H196 | 5 | 10.6 |
… | … | … | … |
325235 | H413 | 1004 | 99.0 |
325236 | H413 | 1005 | 88.0 |
325237 | H413 | 1006 | 47.0 |
325238 | H413 | 1007 | 41.0 |
325239 | H413 | 1008 | 34.0 |
LightGBMCV 的作用是模仿 LightGBM 的 cv 函数,在该函数中,多个 Booster 同时在数据的不同分区上进行训练,即每次对所有分区执行一次 boosting 迭代。这允许按迭代估算误差,因此如果我们将此与早期停止结合使用,我们可以找到使用所有数据训练最终模型的最佳迭代次数,甚至可以使用这些单独模型的预测来计算集成结果。
为了准确估算模型的预测性能,我们计算整个测试周期的预测值并计算相应的指标。由于此步骤可能会减慢训练速度,因此可以使用 `eval_every` 参数来控制此行为。例如,如果 `eval_every=10`(默认值),则每 10 次 boosting 迭代,我们将计算完整窗口的预测值并报告误差。
我们还有早期停止参数
early_stopping_evals
:在没有改进的情况下,应进行多少次完整窗口评估以停止训练?early_stopping_pct
:在这些early_stopping_evals
次评估中,我们希望达到的最小百分比改进是多少,以便继续训练?
这使得 LightGBMCV 类成为快速测试模型不同配置的好工具。考虑以下示例,我们将尝试找出哪些特征可以提高模型的性能。我们首先只使用滞后项。
源代码
LightGBMCV.fit
同时训练 Booster 并在完整的预测窗口上评估它们的性能。
类型 | 默认值 | 详细信息 | |
---|---|---|---|
df | DataFrame | 长格式的时间序列数据。 | |
n_windows | int | 要评估的窗口数。 | |
h | int | 预测范围。 | |
id_col | str | unique_id | 标识每个时间序列的列。 |
time_col | str | ds | 标识每个时间步长的列,其值可以是时间戳或整数。 |
target_col | str | y | 包含目标变量的列。 |
step_size | 可选 | None | 每个交叉验证窗口之间的步长。如果为 None,则等于 h 。 |
num_iterations | int | 100 | 要运行的最大 boosting 迭代次数。 |
params | 可选 | None | 传递给 LightGBM Booster 的参数。 |
static_features | 可选 | None | 静态特征的名称,预测时将重复使用。 |
dropna | bool | True | 丢弃由变换产生的包含缺失值的行。 |
keep_last_n | 可选 | None | 为预测步骤保留每个时间序列的最后这么多条记录。如果您的特征允许,可以节省时间和内存。 |
eval_every | int | 10 | 在完整预测窗口上评估之前,训练的 boosting 迭代次数。 |
weights | 可选 | None | 用于乘以每个窗口指标的权重。如果为 None,则所有窗口具有相同的权重。 |
metric | Union | mape | 用于评估模型性能和执行早期停止的指标。 |
verbose_eval | bool | True | 打印每次评估的指标。 |
early_stopping_evals | int | 2 | 在没有改进的情况下,运行的最大评估次数。 |
early_stopping_pct | float | 0.01 | 在 early_stopping_evals 次评估中,指标值的最小百分比改进。 |
compute_cv_preds | bool | False | 找到最佳迭代次数后,计算每个窗口的预测值。 |
before_predict_callback | 可选 | None | 在计算预测值之前对特征调用的函数。 此函数将接收传递给模型进行预测的输入 DataFrame,并应返回具有相同结构的 DataFrame。 时间序列标识符位于索引上。 |
after_predict_callback | 可选 | None | 在更新目标变量之前对预测值调用的函数。 此函数将接收包含预测值的 pandas Series,并应返回另一个具有相同结构的 Series。 时间序列标识符位于索引上。 |
input_size | 可选 | None | 每个窗口中每个时间序列的最大训练样本数。如果为 None,将使用扩展窗口。 |
返回值 | List | (boosting 轮次,指标值) 元组列表。 |
通过设置 compute_cv_preds
,我们可以获得每个模型在其对应验证折叠上的预测值。
unique_id | ds | y | Booster | 窗口 | |
---|---|---|---|---|---|
0 | H196 | 865 | 15.5 | 15.522924 | 0 |
1 | H196 | 866 | 15.1 | 14.985832 | 0 |
2 | H196 | 867 | 14.8 | 14.667901 | 0 |
3 | H196 | 868 | 14.4 | 14.514592 | 0 |
4 | H196 | 869 | 14.2 | 14.035793 | 0 |
… | … | … | … | … | … |
187 | H413 | 956 | 59.0 | 77.227905 | 1 |
188 | H413 | 957 | 58.0 | 80.589641 | 1 |
189 | H413 | 958 | 53.0 | 53.986834 | 1 |
190 | H413 | 959 | 38.0 | 36.749786 | 1 |
191 | H413 | 960 | 46.0 | 36.281225 | 1 |
我们训练的各个模型都已保存,因此调用 predict
会返回每个训练好的模型的预测值。
源代码
LightGBMCV.predict
使用每个训练好的 Booster 计算预测值。
类型 | 默认值 | 详细信息 | |
---|---|---|---|
h | int | 预测范围。 | |
before_predict_callback | 可选 | None | 在计算预测值之前对特征调用的函数。 此函数将接收传递给模型进行预测的输入 DataFrame,并应返回具有相同结构的 DataFrame。 时间序列标识符位于索引上。 |
after_predict_callback | 可选 | None | 在更新目标变量之前对预测值调用的函数。 此函数将接收包含预测值的 pandas Series,并应返回另一个具有相同结构的 Series。 时间序列标识符位于索引上。 |
X_df | 可选 | None | 包含未来外部特征的 DataFrame。应包含 id 列和时间列。 |
返回值 | DataFrame | 每个时间序列和时间步长的预测值,每个窗口一列。 |
unique_id | ds | Booster0 | Booster1 | |
---|---|---|---|---|
0 | H196 | 961 | 15.670252 | 15.848888 |
1 | H196 | 962 | 15.522924 | 15.697399 |
2 | H196 | 963 | 14.985832 | 15.166213 |
3 | H196 | 964 | 14.985832 | 14.723238 |
4 | H196 | 965 | 14.562152 | 14.451092 |
… | … | … | … | … |
187 | H413 | 1004 | 70.695242 | 65.917620 |
188 | H413 | 1005 | 66.216580 | 62.615788 |
189 | H413 | 1006 | 63.896573 | 67.848598 |
190 | H413 | 1007 | 46.922797 | 50.981950 |
191 | H413 | 1008 | 45.006541 | 42.752819 |
我们可以对这些预测值进行平均并进行评估。
现在,由于这些时间序列是按小时计算的,也许我们可以尝试通过计算第 168 (24 * 7) 个差分来去除每日季节性,即减去一周前同一时间的数值,因此我们的目标变量将是 。特征将从此目标变量计算,预测时将自动重新应用。
不错!我们在更少的迭代次数下获得了更好的分数。让我们看看这种改进是否也能体现在验证集上。
太好了!现在也许我们可以尝试一些滞后变换。我们将尝试季节性滚动平均值,它对“每个季节”的值进行平均,也就是说,如果我们设置 season_length=24
和 window_size=7
,那么我们将对每周同一小时的值进行平均。
看来这也有帮助!
这是否反映在验证集上?
不错!mlforecast 也支持日期特征,但在本例中,我们的时间列由整数构成,因此这里没有太多可能性。如您所见,这使您可以更快地迭代并更好地估算模型的预测性能。
如果您正在进行超参数调优,能够运行几次迭代、评估性能并确定特定配置是否有前景以及是否应丢弃,这将非常有用。例如,optuna 提供了剪枝器 (pruners),您可以根据当前分数调用它来决定是否应丢弃该试验。现在我们将展示如何做到这一点。
由于 CV 需要一些设置,例如 LightGBM 数据集和内部特征,因此我们提供了 setup
方法。
源代码
LightGBMCV.setup
初始化内部数据结构,以便迭代训练 Booster。在调用 partial_fit 之前使用此方法。
类型 | 默认值 | 详细信息 | |
---|---|---|---|
df | DataFrame | 长格式的时间序列数据。 | |
n_windows | int | 要评估的窗口数。 | |
h | int | 预测范围。 | |
id_col | str | unique_id | 标识每个时间序列的列。 |
time_col | str | ds | 标识每个时间步长的列,其值可以是时间戳或整数。 |
target_col | str | y | 包含目标变量的列。 |
step_size | 可选 | None | 每个交叉验证窗口之间的步长。如果为 None,则等于 h 。 |
params | 可选 | None | 传递给 LightGBM Booster 的参数。 |
static_features | 可选 | None | 静态特征的名称,预测时将重复使用。 |
dropna | bool | True | 丢弃由变换产生的包含缺失值的行。 |
keep_last_n | 可选 | None | 为预测步骤保留每个时间序列的最后这么多条记录。如果您的特征允许,可以节省时间和内存。 |
weights | 可选 | None | 用于乘以每个窗口指标的权重。如果为 None,则所有窗口具有相同的权重。 |
metric | Union | mape | 用于评估模型性能和执行早期停止的指标。 |
input_size | 可选 | None | 每个窗口中每个时间序列的最大训练样本数。如果为 None,将使用扩展窗口。 |
返回值 | LightGBMCV | 带有用于 partial_fit 的内部数据结构的 CV 对象。 |
拥有此对象后,我们可以调用 partial_fit
只训练一些迭代并返回预测窗口的分数。
源代码
LightGBMCV.partial_fit
训练 Booster 若干迭代次数。
类型 | 默认值 | 详细信息 | |
---|---|---|---|
num_iterations | int | 要运行的 boosting 迭代次数 | |
before_predict_callback | 可选 | None | 在计算预测值之前对特征调用的函数。 此函数将接收传递给模型进行预测的输入 DataFrame,并应返回具有相同结构的 DataFrame。 时间序列标识符位于索引上。 |
after_predict_callback | 可选 | None | 在更新目标变量之前对预测值调用的函数。 此函数将接收包含预测值的 pandas Series,并应返回另一个具有相同结构的 Series。 时间序列标识符位于索引上。 |
返回值 | float | 训练 num_iterations 次迭代后的加权指标。 |
这与我们第一个示例中的第一次评估结果相同。
现在我们可以使用此分数来决定此配置是否有前景。如果需要,我们可以再训练一些迭代。
这现在等于我们第一个示例中的第三个指标,因为这次我们训练了 20 次迭代。
使用自定义指标
内置指标是 MAPE 和 RMSE,它们按时间序列计算,然后对所有时间序列进行平均。如果您想做一些不同的事情或完全使用不同的指标,您可以定义自己的指标,如下所示