使用机器学习模型进行时间序列预测
在上一章中,我们开始将机器学习视为解决时间序列预测问题的工具。我们讨论了几种技术,如时间延迟嵌入和时间嵌入,这两种方法都将时间序列预测问题转化为机器学习范式中的经典回归问题。在本章中,我们将详细研究这些技术,并利用本书一直使用的伦敦智能电表数据集以实践方式对其进行探讨。
在本章中,我们将涵盖以下主题:
- 使用机器学习模型进行训练和预测
- 生成单步预测基线
- 用于训练和评估机器学习模型的标准化代码
- 训练和预测多个家庭
技术要求
你需要按照本书《前言》中的说明设置Anaconda环境,以获得一个包含本书代码所需所有库和数据集的可用环境。任何额外的库将在运行notebooks时安装。
在使用本章代码之前,你需要运行以下notebooks:
02-Preprocessing_London_Smart_Meter_Dataset.ipynb在Chapter0201-Setting_up_Experiment_Harness.ipynb在Chapter0401-Feature_Engineering.ipynb在Chapter0602-Dealing_with_Non-Stationarity.ipynb在Chapter0702a-Dealing_with_Non-Stationarity-Train+Val.ipynb在Chapter07
本章的代码可在 https://github.com/PacktPublishing/Modern-Time-Series-Forecasting-with-Python-/tree/main/notebooks/Chapter08 中找到。
使用机器学习模型进行训练和预测
在第5章《时间序列预测作为回归》中,我们讨论了有监督机器学习的示意图(图5.2)。在该示意图中,我们提到有监督学习问题的目的是找到一个函数 $\hat{y} = h(X, \phi)$,其中 $\hat{y}$ 是预测值,X 是作为输入的特征集,$\phi$ 是模型参数,h 是理想函数的近似。在本节中,我们将更详细地讨论 h,并了解如何使用不同的机器学习模型来估计它。
h 是任何近似理想函数的函数,但它可以被视为一个函数族中所有可能函数的一个元素。更正式地,我们可以表述如下:
$$\hat{y} = h(X, \phi), \quad \text{where } h \in H$$
这里,H 是一个函数族,我们也称之为模型。例如,线性回归是一种模型或一个函数族。对于系数的每个值,线性回归模型给出一个不同的函数,而 H 则成为线性回归模型所能产生的所有可能函数的集合。
有许多可用的函数族或模型。为了更全面地理解这一领域,我们需要参考其他机器学习资源。进一步阅读部分提供了一些资源,可能有助于你开始这段旅程。至于本书的范围,我们将其狭义地定义为机器学习模型在预测中的应用,而非一般的机器学习。尽管我们可以使用任何回归模型,但我们只会回顾几种流行且对时间序列预测有用的模型,并观察它们的实际应用。我们留给你自己去探索其他算法,以便也熟悉它们。但在我们查看不同模型之前,需要再次生成几个基线。
生成单步预测基线
我们在第4章《设定强基线预测》中回顾并生成了几个基线模型。但有一个小问题——预测范围。在第6章《时间序列预测的特征工程》中,我们讨论了机器学习模型一次只能预测一个目标,并且我们坚持使用单步预测。我们之前生成的基线不是单步的,而是多步的。为ARIMA或ETS等基线算法生成单步预测需要我们在历史数据上拟合,预测下一步,然后再使用多一天的数据重新拟合。以这种迭代方式对我们的测试或验证周期进行预测,需要执行约1,440次迭代(每天48个数据点,共30天),并对所选数据集中的所有家庭(本例中为150个)重复此过程。这将需要相当长的计算时间。
我们选择了朴素方法和季节朴素法(第4章《设定强基线预测》),这两种方法可以作为原生pandas方法实现,作为生成单步预测的两种基线方法。
朴素预测在单步预测中表现得出奇地好,可以被视为一个强基线。在 Chapter08 文件夹中,有一个名为 00-Single_Step_Backtesting_Baselines.ipynb 的笔记本,它生成这些基线并保存到磁盘。让我们现在运行这个笔记本。该笔记本为验证集和测试集生成基线,并将预测结果、指标和聚合指标保存到磁盘。测试周期的聚合指标如下:

图8.1:单步基线模型的聚合指标
为了使这些模型的训练和评估更简单,我们自始至终采用了一种标准结构。让我们也快速回顾一下这种结构,以便你能紧跟笔记本中的内容。
用于训练和评估机器学习模型的标准化代码
训练机器学习模型有两个主要成分——数据和模型本身。因此,为了使流程标准化,我们定义了三个配置类(FeatureConfig、MissingValueConfig和ModelConfig)以及另一个位于 scikit-learn 风格估计器 MLForecast 之上的包装类(.fit–.predict),以使过程更顺畅。让我们逐一查看它们。
笔记本提示:
若要跟随代码进行操作,请使用 01-Forecasting_with_ML.ipynb 文件夹中的 Chapter08 笔记本,以及 src 文件夹中的代码。
FeatureConfig
FeatureConfig 是一个 Python dataclass,它定义了处理数据时必要的几个关键属性和函数。例如,连续列、分类列和布尔列在输入机器学习模型之前需要不同类型的预处理。让我们看看 FeatureConfig 包含什么:
date:用于设置 DataFrame 日期时间索引的列名。target:包含预测目标的列名。original_target:如果target包含变换后的目标(如对数或差分),此项指定未经变换的目标列名,用于计算依赖训练历史的指标(如 MASE)。如果未指定,则假定target和original_target相同。continuous_features:连续特征列表。categorical_features:分类特征列表。boolean_features:布尔特征列表。布尔特征属于分类特征,但只有两个唯一值。index_cols:预处理时设置为 DataFrame 索引的列列表,通常包括日期时间列,有时还包括时间序列唯一 ID。exogenous_features:外生特征列表。它们可以来自特征工程(如滞后或滚动特征),也可以来自外部来源(如温度数据)。这是可选字段,用于将外生特征与其他特征分开;列表中的项目应是continuous_features、categorical_features或boolean_features的子集。
除了对输入进行一些验证外,该类中还有一个名为get_X_y的有用方法,其参数如下:
df: 一个包含所有必要列的DataFrame,包括目标变量(如果可用)。categorical: 一个布尔标志,用于指示是否包含类别特征。exogenous: 一个布尔标志,用于指示是否包含外生特征。
该函数返回一个(features, target, original_target)元组。
我们只需要像初始化其他类一样,将特征名称按照类的参数分开初始化该类即可。包含所有特征的完整代码可在随附的notebook中找到。
在设置FeatureConfig数据类之后,我们可以将任何包含已定义特征的DataFrame传递给get_X_y函数,以获取特征、目标变量和原始目标变量:
train_features, train_target, train_original_target = feat_config.get_X_y(
sample_train_df, categorical=False, exogenous=False
)
如您所见,这里我们没有使用类别特征或外生特征,因为我希望专注于核心算法,并展示它们如何作为我们之前看到的其他经典时间序列模型的即插即用替代方案。我们将在第15章 全局深度学习预测模型的策略中讨论如何处理类别特征。
缺失值配置
另一个关键设置是如何处理缺失值。我们在第3章《分析与可视化时间序列数据》中看到了一些在时间序列上下文中填充缺失值的方法,并且我们已经填充了缺失值并准备好了数据集。但在将时间序列转换为回归问题所需的特征工程中,会创建一些缺失值。例如,在创建滞后特征时,数据集中最早的日期没有足够的数据来创建滞后,将会留空。
最佳实践:
尽管用零或均值填充是大多数数据科学家社区的默认或首选方法,但我们应始终尽力智能化地填充缺失值。对于滞后特征而言,用零填充可能会扭曲特征。与其用零填充,不如采用后向填充(使用列中最早的值向后填充)可能更为合适。
一些机器学习模型自然处理空值或NaN特征,而对于其他机器学习模型,我们需要在训练前处理这些缺失值。如果我们能定义一个config,在其中为一些列设置我们期望的NaN填充信息,那将很有帮助。MissingValueConfig是一个Pythondataclass,正是用来做这件事的。让我们看看它包含什么:
bfill_columns:需要采用后向填充策略来填充缺失值的列名列表。ffill_columns:需要采用前向填充策略来填充缺失值的列名列表。如果一个列名同时出现在bfill_columns和ffill_columns中,则该列首先使用后向填充,剩余的缺失值使用前向填充策略填充。zero_fill_columns:需要用零填充的列名列表。
缺失值的填充顺序是:先bfill_columns,然后ffill_columns,最后zero_fill_columns。作为默认策略,数据类使用列均值来填充缺失值,因此即使你没有为某个列定义任何策略,缺失值也会使用列均值填充。有一个名为impute_missing_values的方法,它接收DataFrame并根据指定的策略填充空单元格。
模型配置
ModelConfig是一个Pythondataclass,它保存了有关建模过程的一些细节,例如是否归一化数据、是否填充缺失值等。让我们详细看看它包含什么:
model:这是一个强制参数,可以是任何scikit-learn风格的估计器。name: 模型的字符串名称或标识符。如果未使用,它将回退为model中传入的类的名称。normalize: 一个布尔标志,用于设置是否对输入应用StandardScaler。fill_missing: 一个布尔标志,用于设置是否在训练前填充空值。有些模型可以自然地处理NaN,而有些则不能。encode_categorical: 一个布尔标志,用于设置是否在拟合过程中对分类列进行编码。如果False,则期望单独进行分类编码并将其作为连续特征的一部分包含进来。categorical_encoder: 如果encode_categorical是True,则categorical_encoder是我们可以使用的scikit-learn风格的编码器。
让我们看看如何定义 ModelConfig 数据类:
model_config = ModelConfig(
model=LinearRegression(),
name="Linear Regression",
normalize=True,
fill_missing=True,
)
它只有一个方法 clone,该方法将估计器及其配置克隆到一个新实例中。
MLForecast
最后但同样重要的是,我们有一个围绕scikit-learn风格模型的包装类。它使用我们讨论过的不同配置来封装训练和预测函数。让我们看看初始化模型时可用的参数:
model_config: 我们在ModelConfig部分讨论过的ModelConfig类的实例。feature_config: 我们之前讨论过的FeatureConfig类的实例。missing_config: 我们之前讨论过的MissingValueConfig类的实例。target_transformer: 来自src.transforms的目标转换器实例。它应支持fit、transform和inverse_transform。它还应在使用 datetime 索引时返回pd.Series以避免错误。如果我们单独进行了目标转换,这也用于在预测期间执行inverse_transform。
MLForecast 有一些函数可以帮助我们管理模型的生命周期,一旦初始化后。让我们来看一下。
fit 函数
fit 函数在目的上与 scikit-learn 的 fit 函数类似,但额外处理了标准化、分类编码以及基于三个配置信息的目标转换。该函数的参数如下:
X: 这是 pandas DataFrame,其列是模型中要使用的特征。y: 这是目标变量,可以是 pandas DataFrame、pandas Series 或 numpy 数组。is_transformed: 这是一个布尔参数,用于指示目标是否已经转换。如果True,即使我们已用target_transformer初始化对象,fit方法也不会转换目标。fit_kwargs: 这是一个 Python 字典,包含需要传递给估计器fit函数的关键字参数。
predict 函数
predict 函数处理推理。它封装了 scikit-learn 估计器的 predict 函数,但与 fit 类似,它还执行其他操作,如标准化、分类编码和反转目标转换。此函数只有一个参数:
X: 这是 pandas DataFrame,其列是模型中要使用的特征。DataFrame 的索引会传递到预测结果中。
feature_importance 函数
feature_importance函数从模型中获取特征重要性(如果可用)。对于线性模型,它提取系数;而对于基于树的模型,它提取内置的重要性,并以排序后的DataFrame返回。
评估模型的辅助函数
虽然我们之前看到的其他函数处理核心训练和预测,但我们也希望评估模型、绘制结果等。我们已在笔记本或代码库中定义了这些函数。下面的函数用于在笔记本中评估模型:
def evaluate_model(
model_config,
feature_config,
missing_config,
train_features,
train_target,
test_features,
test_target,
):
ml_model = MLForecast(
model_config=model_config,
feature_config=feat_config,
missing_config=missing_value_config,
)
ml_model.fit(train_features, train_target)
y_pred = ml_model.predict(test_features)
feat_df = ml_model.feature_importance()
metrics = calculate_metrics(test_target, y_pred, model_config.name, train_target)
return y_pred, metrics, feat_df
这为我们提供了一种评估所有不同模型的标准方式,同时也实现了大规模自动化。我们还有一个计算指标的函数calculate_metrics,定义在src/forecasting/ml_forecasting.py中。
本书中提供的标准实现绝非万能方法,而是最适合本书流程和数据集的方式。请勿将其视为健壮的库,而应作为良好的起点和指南,帮助您开发自己的代码。
现在我们有了基线模型和应用不同模型的标准方法,让我们回到不同模型是什么。对于接下来的讨论,暂时把时间从脑海中移除,因为我们已将时间序列预测问题转换为回归问题,并将时间作为问题的一个特征(滞后和滚动特征)。
线性回归
线性回归是一族函数,形式如下:
$$\hat{y} = \beta_0 + \sum_{i=1}^{k} X_i \beta_i$$
这里,k是模型中的特征数量,$\beta$是模型的参数。每个特征对应一个$\beta$,以及一个$\beta_0$,我们称之为截距,它由数据估计得到。本质上,输出是特征向量Xi的线性组合。顾名思义,这是一个线性函数。
模型参数可以从数据D(Xi, yi)中通过优化方法和损失函数估计得到,但最流行的估计方法是使用普通最小二乘法(OLS)。这里,我们找到模型参数$\beta$,它最小化残差平方和(均方误差(MSE)):
$$RSS = \sum_{i=1}^{N} (y_i - \hat{y}_i)^2$$
这里的损失函数非常直观。我们实际上是在最小化训练样本与预测点之间的距离。平方项作为一种技术手段,可以避免正负误差相互抵消。除了损失函数的直观性外,最小二乘法被广泛采用的另一个原因是存在解析解,因此我们无需采用计算量更大的优化技术(如梯度下降)。
线性回归在统计学中根基深厚,在满足适当假设的前提下,它可以成为一种强大的工具。通常,线性回归有五个相关假设,如下所示:
- 自变量与因变量之间的关系是线性的。
- 误差服从正态分布。
- 误差的方差在所有自变量取值下保持恒定。
- 误差不存在自相关。
- 自变量之间几乎没有相关性(多重共线性)。
但除非你关心的是使用线性回归来得出预测区间(即预测值以一定概率所在的区间),否则除第一个假设外,其他假设我们在一定程度上都可以忽略。
线性假设(第一个假设)之所以重要,是因为如果变量之间不是线性关系,将导致欠拟合,从而性能不佳。我们可以在一定程度上通过将输入投影到更高维空间来解决这个问题。理论上,我们可以将一个非线性问题投影到一个更高维的空间,在该空间中问题变为线性。例如,考虑一个非线性函数 $y = 3x_1^2 + 2x_2^2 + 6x_1 x_2$。如果在输入空间 y 的函数将变成完美的线性拟合。
多重共线性假设(最后一个假设)与线性函数的拟合部分相关,因为当自变量高度相关时,估计的系数非常不稳定且难以解释。拟合的函数仍然可以正常工作,但由于存在多重共线性,即使输入发生微小变化,系数的量级和符号也会改变。如果使用纯线性回归,检查多重共线性是一种最佳实践。在时间序列中这通常是一个问题,因为我们提取的特征(如滞后特征和滚动特征)可能相互关联。因此,在时间序列数据上使用和解释线性回归时,我们必须小心谨慎。
现在,让我们看看如何使用线性回归并评估验证数据集中某个样本家庭的拟合效果:
from sklearn.linear_model import LinearRegression
model_config = ModelConfig(
model=LinearRegression(),
name="Linear Regression",
# LinearRegression is sensitive to normalized data
normalize=True,
# LinearRegression cannot handle missing values
fill_missing=True,
)
y_pred, metrics, feat_df = evaluate_model(
model_config,
feat_config,
missing_value_config,
train_features,
train_target,
test_features,
test_target,
)
单步预测看起来不错,并且已经优于朴素预测(MAE = 0.173):

图8.2:线性回归预测
模型的系数$\beta$(可以通过训练好的scikit-learn模型的coef_属性访问)显示了每个特征对输出的影响程度。因此,提取并绘制它们可以让我们对模型有第一层级的认识。让我们来看一下模型的系数:

图8.3:线性回归的特征重要性(前15项)
如果我们查看特征重要性图中的Y轴,可以看到数值在数十亿量级,因为几个特征的系数数量级达到数十亿。我们还可以看到这些特征是基于傅里叶级数的特征,它们彼此相关。尽管我们有很多系数达到数十亿,但它们在零的两侧都有分布,因此它们会在函数中基本相互抵消。这就是我们之前讨论的多重共线性问题。我们可以移除多重共线性的特征,然后进行某种特征选择(前向选择或后向消除),以进一步改善线性模型。
但是,与其那样做,不如让我们看看可以对线性模型进行的一些修改,这些修改对多重共线性和特征选择更加稳健。
正则化线性回归
我们在第5章《时间序列预测作为回归》中简要讨论过正则化,并提到正则化,在一般意义上,是我们对学习过程施加的任何约束,以降低学习函数的复杂性。线性模型变得更复杂的方式之一是系数幅度很大。例如,在线性拟合中,我们有一个200亿的系数。该特征的任何微小变化都会导致预测结果产生巨大波动。直观地说,如果有一个大系数,函数就会变得更灵活和复杂。解决这个问题的一种方法是应用权重衰减形式的正则化。权重衰减是我们在损失函数中添加一个惩罚系数幅度的项。损失函数,即残差平方和,现在变为如下形式:
$$RSS = \sum_{i=1}^{N} (y_i - \hat{y}_i)^2 + \lambda \mathcal{W}$$
这里,W是权重衰减,$\lambda \lt 0$是正则化强度。
W通常是权重矩阵的范数。在线性代数中,矩阵的范数是衡量其元素大小的度量。矩阵有许多种范数,但用于正则化的两种最常见范数是L1和L2范数。当我们使用L1范数正则化线性回归时,我们称之为lasso回归;而当我们使用L2范数时,我们称之为ridge回归。当我们应用权重衰减正则化时,我们迫使系数变小,这意味着它也起到了内部特征选择的作用,因为那些不带来很多价值的特征将获得非常低或为零(取决于正则化类型)的系数,这意味着它们在最终函数中贡献很少或没有贡献。
L1范数定义为矩阵绝对值之和。对于权重衰减正则化,L1范数如下所示:
$$W = \sum_{i=1}^{k} |\beta_i|$$
L2范数定义为矩阵平方值之和。对于权重衰减正则化,L2范数如下所示:
$$W = \sum_{i=1}^{k} |\beta_i^2|$$
通过将这一项添加到线性回归的损失函数中,我们强制系数变小,因为优化器在减小RSS的同时,也会被激励减小W。
另一种理解正则化的方式是从线性代数和几何的角度。
下一节讨论正则化的几何直觉。虽然这会让您对正则化的理解更加扎实,但对于理解本书后续内容并非必需。因此,如果您时间紧迫,或者想稍后再看,可以随意跳过下一节,只阅读要点标注。
正则化——一个几何视角
如果我们从稍微不同的角度来看L1和L2范数,就会发现它们是距离的度量。
令B为所有系数的向量,$\beta$,在线性回归中。向量是一个数字数组,但从几何上看,它也是从原点到n维坐标空间中某一点的有向线段。现在,L2范数不过是该向量定义的空间中从原点到该点的欧几里得距离。L1范数是该向量定义的空间中从原点到该点的曼哈顿距离或出租车距离。让我们通过图表来看这一点:

图8.4:欧几里得距离与曼哈顿距离
欧氏距离是从原点到点的直线路径长度。但如果只能平行于两个轴移动,则必须首先沿一个轴移动 $\beta_0$ 的距离,然后再沿另一个轴移动 $\beta_1$ 的距离。这就是曼哈顿距离。
假设我们在一个城市(例如曼哈顿),建筑物以方形街区排列,笔直的街道以直角相交,我们想从A点旅行到B点。欧氏距离是A点到B点的直接距离,实际上只有当我们沿着建筑物顶部跑酷时才可能。另一方面,曼哈顿距离是出租车沿着直角道路从A点到B点行驶的实际距离。
为了进一步建立关于L1和L2范数的几何直觉,让我们做一个思想实验。如果我们在二维空间中移动点 $(\beta_0, \beta_1)$ ,同时保持欧氏距离或L2范数不变,我们将得到一个以原点为中心的圆。这在三维空间中变成一个球体,在 n 维空间中变成一个超球体。如果我们画出相同的轨迹但保持L1范数不变,我们将得到一个以原点为中心的菱形。这在三维空间中变成一个立方体,在 n 维空间中变成一个超立方体。
现在,当我们优化权重时,除了减少损失函数的主要目标外,我们还鼓励系数保持在距离原点(范数)的限定范围内。几何上,这意味着我们要求优化过程找到一个向量 $\beta$ ,使其最小化损失函数并保持在由范数定义的几何形状(圆或正方形)内。我们可以在下图中看到这一点:

图8.5:使用L1范数(套索回归)与L2范数(岭回归)的正则化
图中的同心圆是损失函数的等高线,最内层是最低点。向外移动时,损失增加。因此,正则化回归不会选择 $\beta_{\text{opt}}$ ,而是选择一个与范数几何形状相交的 $\beta$ 。
这种几何解释也使理解岭回归和套索回归之间的另一个关键区别变得更容易。套索回归由于L1范数,产生稀疏解。之前,我们提到权重衰减正则化会进行隐式特征选择。但根据应用L1还是L2范数,隐式特征选择的类型有所不同。
关键点:
对于L2范数,不重要特征的系数被推向接近零,但不完全为零。该特征仍会在最终函数中发挥作用,但其影响将很小。而L1范数则将这些特征的系数完全推向零,产生稀疏解。因此,L1正则化促进稀疏性和特征选择,而L2正则化通过将系数向零收缩来降低模型复杂度,但不一定消除任何特征。
这可以通过正则化的几何解释更好地理解。在优化中,有趣的点通常位于形状的极值点或 角点 上。圆没有角点,因此L2范数创建时,最小值可以位于圆的边缘上的任何位置。但对于菱形,我们有四个角点,最小值会位于这些角点上。因此,使用L2范数时,解可以非常接近零,但不一定为零。然而,使用L1范数时,解将位于角点上,此时系数可以被推向绝对零。
现在,让我们看看如何使用岭回归并评估对验证数据集中一个样本家庭的拟合效果:
from sklearn.linear_model import RidgeCV
model_config = ModelConfig(
model=RidgeCV(),
name="Ridge Regression",
# RidgeCV is sensitive to normalized data
normalize=True,
# RidgeCV does not handle missing values
fill_missing=True
)
y_pred, metrics, feat_df = evaluate_model(
model_config,
feat_config,
missing_value_config,
train_features,
train_target,
test_features,
test_target,
)
让我们看一下来自RidgeCV的单步超前预测。它看起来与线性回归非常相似。甚至这个家庭的MAE也是相同的:

图8.6:岭回归预测
但有趣的是查看L2正则化模型的系数。我们来看一下模型的系数:

图8.7:岭回归的特征重要性(前15个)
现在,Y轴看起来合理且数值较小。多重共线性特征的系数已经收缩到更合理的水平。像滞后特征这样本应具有高度影响力的特征占据了前几位。你可能还记得,在线性回归(图8.3)中,这些特征被傅里叶特征的大系数所掩盖。我们这里只绘制了前15个特征,但如果你查看整个列表,会发现许多特征的系数接近于零。
现在,让我们尝试对样本家庭进行套索回归:
from sklearn.linear_model import LassoCV
model_config = ModelConfig(
model=LassoCV(),
name="Lasso Regression",
# LassoCV is sensitive to normalized data
normalize=True,
# LassoCV does not handle missing values
fill_missing=True
)
y_pred, metrics, feat_df = evaluate_model(
model_config,
feat_config,
missing_value_config,
train_features,
train_target,
test_features,
test_target,
)
让我们看一下来自LassoCV的单步超前预测。与岭回归一样,与线性回归几乎没有任何视觉差异:

图8.8:套索回归预测
让我们看一下模型的系数:

图8.9:套索回归的特征重要性(前15个)
系数与岭回归非常相似,但如果你查看完整系数列表(在笔记本中),你会看到很多特征的系数为零。
即使MAE、MSE等相同,岭回归或套索回归也比线性回归更受青睐,因为正则化回归带来了额外的稳定性和鲁棒性,尤其是在多重共线性几乎总是存在的预测中。但我们需要记住,所有线性回归模型仍然只捕捉线性关系。如果数据集具有非线性关系,线性回归的拟合结果就不会那么好,有时甚至会非常糟糕。
现在,我们切换方向,来看另一类模型——决策树。
决策树
决策树是另一类函数族,其表达能力远强于线性函数。决策树将特征空间划分为不同的子空间,并对每个子空间拟合一个非常简单的模型(例如平均值)。让我们通过一个示例来理解这种划分的工作原理。考虑一个回归问题,用单一特征X预测Y,如下图所示:

图8.10:决策树划分的特征空间
我们立刻可以看到,拟合线性函数会导致欠拟合。但决策树所做的是将特征空间(这里只是X)划分为目标Y相似的不同区域,然后拟合一个简单函数,如平均值(因为这是一个回归问题)。在这种情况下,决策树将特征空间划分为分区——A、B和C。现在,对于落入分区A的任何X,预测函数将返回分区A中所有点的平均值。
这些分区是通过使用数据创建决策树而形成的。直观地说,决策树创建一组if-else条件,并尝试找到最佳方式划分特征空间,以最大化分区内目标变量的同质性。理解决策树工作原理的一个有用方式是将数据点想象成沿着树流下的珠子,根据其特征选择路径,最终到达一个最终位置。在我们讨论如何从数据创建决策树之前,让我们先看看它的组成部分并了解相关术语:

图8.11:决策树的结构
决策树中有两种节点——决策节点和叶节点。决策节点就是我们之前提到的if-else语句。该节点有一个条件,依据流经树的数据点选择左侧还是右侧分支。位于最顶部的决策节点有一个特殊的名称——根节点。最后,根据条件划分数据点并将其导向右侧或左侧分支的过程称为分裂。叶节点是下面没有任何其他分支的节点。它们是"珠子沿树流下"比喻中的最终停留点,也就是我们在本节前面讨论过的划分。
形式上,我们可以定义由具有M个划分P1, P2, …, PM的决策树生成的函数如下:
$$\hat{y} = \sum_{m=1}^{M} c_m I(x \in P_m)$$
这里,x是输入,cm是区域Pm的常数响应,I是一个函数,如果$(x \in P_m)$则取值为1,否则为0。
对于回归树,我们通常采用平方损失作为损失函数。在这种情况下,cm通常设置为所有落在Pm划分中的x对应的y的平均值。
既然我们知道了决策树的工作原理,唯一需要理解的是如何决定对哪个特征进行分裂以及在何处分裂该特征。
多年来,人们提出了许多从数据创建决策树的算法,如ID3、C4.5、CART等。使用分类与回归树(CART)是其中最流行的方法之一,并且也支持回归。因此,我们在本书中只使用CART。分类树用于目标变量为类别型(例如,预测类别标签)的情况。回归树用于目标变量为连续型(例如,预测数值)的情况。
能够全局最小化平方和的最优二元划分集合通常是难以处理的。因此,我们采用一种贪婪算法来创建决策树。贪婪优化是一种启发式方法,它逐步构建解,在每个阶段选择局部最优。因此,我们不会全局寻找最佳特征分裂,而是逐决策节点创建决策树,在每个阶段选择最优特征分裂。对于回归树,我们选择一个分裂特征f和分裂点s,使其创建两个划分P1和P2,并最小化如下表达式:
$$\sum_{x_i \in P_1} (y_i - c_1)^2 + \sum_{x_i \in P_2} (y_i - c_2)^2$$
这里,c1和c2分别是所有落在P1和P2中的x对应的y的平均值。
因此,通过使用这个标准,我们可以不断进一步划分区域。每进行一次分裂,树的深度就增加一层。在某个时刻,我们开始对数据集过拟合。但如果分裂不够,又可能对数据欠拟合。一种策略是在达到预设深度时停止进一步分裂。在scikit-learn的DecisionTreeRegressor实现中,这对应于max_depth参数。这是一个需要使用验证数据集估计的超参数。还有其他停止分裂的策略,例如设置分裂所需的最小样本数(min_samples_split),或进行分裂所需的最小成本下降(min_impurity_decrease)。有关DecisionTreeRegressor参数的完整列表,请参阅文档https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeRegressor.html。
现在,让我们看看如何使用决策树并在验证数据集中的一个样本家庭上评估拟合效果:
from sklearn.tree import DecisionTreeRegressor
model_config = ModelConfig(
model=DecisionTreeRegressor(max_depth=4, random_state=42),
name="Decision Tree",
# Decision Tree is not affected by normalization
normalize=False,
# Decision Tree in scikit-learn does not handle missing values
fill_missing=True,
)
y_pred, metrics, feat_df = evaluate_model(
model_config,
feat_config,
missing_value_config,
train_features,
train_target,
test_features,
test_target,
)
让我们看看来自 DecisionTreeRegressor 的单步预测。它的表现不如我们迄今运行的线性或正则化线性回归模型:

图8.12:决策树预测
对于线性模型,一些系数帮助我们理解每个特征对预测函数的重要性。在决策树中,我们没有系数,但特征重要性仍然通过树构建过程中归因于每个特征的损失函数均值减少来估计。这可以通过使用训练模型的 feature_importance_ 属性在 scikit-learn 模型中访问。让我们看看这个特征重要性:

图8.13:决策树的特征重要性(前15个)
最佳实践:
尽管默认的特征重要性是一种快速简便地检查不同特征使用情况的方法,但在将其用于其他目的(如特征选择或业务决策)之前,应进行尽职调查。这种评估特征重要性的方式会为某些连续特征和高基数分类特征给出误导性的高值。建议使用排列重要性(sklearn.inspection.permutation_importance)进行简单但更好的特征重要性评估。进一步阅读部分包含一些关于模型可解释性的资源,可以作为理解模型影响因素的起点。
在这里,我们可以看到重要的特征如滞后和季节性滚动特征排在前列。
我们在第5章中讨论了过拟合和欠拟合,时间序列预测作为回归。在机器学习术语中,这些也被称为高偏差(欠拟合)和高方差(过拟合)(进一步阅读部分包含一些链接,如果你想了解更多关于偏差和方差及其权衡的知识)。
决策树是一种高度容易过拟合或高方差的算法,因为与线性函数不同,如果有足够的表达能力,它可以通过划分特征空间来记忆训练数据集。另一个关键缺点是决策树无法进行外推。考虑一个特征 f,它线性地增加我们的目标变量 y。我们拥有的训练数据具有 fmax 作为 f 的最大值,以及 ymax 作为 y 的最大值。由于决策树划分特征空间并为每个分区分配一个常数值,即使我们提供 f > fmax,我们仍然只会得到预测值 $\hat{y} \leq y_{\max}$。
现在,我们来关注一个使用决策树但采用集成方式且不容易过拟合的模型。
随机森林
随机森林是一种集成学习方法,它在训练时构建多个决策树,并通过合并其结果来提高准确性和稳健性。通过装袋(bagging)和特征随机性减少过拟合并增强预测性能,它在分类和回归任务中均表现出色。
集成学习是一种利用多个模型(或称专家)并以某种方式组合它们以解决当前问题的过程。它借鉴了“群体智慧”方法,该方法认为一群人的决策通常优于该群体中的任何个体。在机器学习背景下,这些单独模型被称为基学习器。单个模型可能表现不佳,因为它对数据集过拟合,但当我们组合多个这样的模型时,它们可以形成一个强学习器。
装袋(Bagging)是一种集成学习形式,我们使用自助采样(从总体中重复有放回地采样)来抽取数据集的不同子集,在每个子集上训练弱学习器,并通过平均或投票(分别用于回归和分类)组合它们。装袋最适合高方差、低偏差的弱学习器,而决策树是装袋成功的主要候选。理论上,装袋保持弱学习器相同的偏差水平,但降低了方差,从而得到更好的模型。但如果弱学习器之间相互关联,装袋的好处将受限。
2001年,Leo Brieman提出了随机森林,它通过构建大量去相关树对标准装袋进行了重大改进。他提议稍微修改建树过程,以确保在自助采样数据集上生长的所有树彼此不相关。
参考文献检查:
随机森林的原始研究论文在参考文献部分中被引用为参考文献1。
在随机森林算法中,我们决定要构建多少棵树。设其为M棵树。现在,对于每棵树,重复以下步骤:
- 从训练数据集中抽取一个自助样本。
- 从所有特征中随机选择f个特征。
- 仅使用这f个特征选择最佳分裂点,并将节点分裂为两个子节点。
- 重复步骤2和3,直到达到任何定义的停止准则。
这组M棵树就是随机森林。与常规树的关键区别在于每次分裂时随机采样特征,这增加了随机性并降低了不同树输出之间的相关性。在预测时,我们使用这M棵树中的每一棵来获得预测。对于回归问题,我们取平均;对于分类问题,我们取多数投票。随机森林用于回归的最终预测函数如下:
$$\hat{y} = \frac{1}{M} \sum_{t=1}^{M} T_t(x)$$
这里,Tt((x) 是随机森林中第 tth 棵树的输出。棵树的输出。
我们用来控制决策树复杂度的所有超参数在此同样适用(scikit-learn 中的 RandomForestRegressor)。除此之外,我们还有两个重要的参数——集成中要构建的树的个数(n_estimators)以及每次分裂时随机选择的特征数量(max_features)。
现在,让我们看看如何使用随机森林并评估对一个来自验证数据集的样本家庭的拟合效果:
from sklearn.ensemble import RandomForestRegressor
model_config = ModelConfig(
model=RandomForestRegressor(random_state=42, max_depth=4),
name="Random Forest",
# RandomForest is not affected by normalization
normalize=False,
# RandomForest in scikit-learn does not handle missing values
fill_missing=True,
)
y_pred, metrics, feat_df = evaluate_model(
model_config,
feat_config,
missing_value_config,
train_features,
train_target,
test_features,
test_target,
)
让我们看看来自 RandomForestRegressor 的单步预测。它比决策树好,但不如线性模型。然而,我们应该记住我们还没有调优模型,通过设置正确的超参数也许能得到更好的结果。
现在,让我们看看使用随机森林生成的预测:

图8.14: 随机森林预测
就像决策树中的特征重要性一样,随机森林也有一个非常相似的机制来估计特征重要性。由于随机森林中有很多棵树,我们累积所有树中分裂准则的减少量,从而得到随机森林的单一特征重要性。这可以通过已训练模型的 feature_importance_ 属性在 scikit-learn 模型中访问。让我们看看特征重要性:

图8.15:决策树的特征重要性(前15个)
在这里,我们可以看到特征重要性与决策树非常相似。关于这类特征重要性的同样注意事项在这里也适用。这只是查看模型内部使用内容的一种快速且粗略的方法。
通常,随机森林在几乎没有调优的情况下就能在许多数据集上取得良好的性能,因此随机森林是机器学习中非常流行的选择。随机森林难以过拟合这一事实也增加了它的吸引力。但由于随机森林使用决策树作为弱学习器,决策树无法外推的特性也遗传给了随机森林。
Scikit-learn 中随机森林的实现对于大量树和数据规模可能会有些慢。来自 XGBoost 库的 XGBRFRegressor 提供了另一种随机森林的实现,由于 XGBoost 的优化算法和并行化能力,它在更大数据集上可以更快,尤其是在更大数据集上。此外,XGBRFRegressor 使用的超参数与 scikit-learn 随机森林中的超参数类似,因此在调优模型时在不同实现之间切换相对直接。大多数情况下,这是一个即插即用的替代品,并且给出几乎相同的结果。细微差异是由于实现细节上的小差别。我们也在笔记本中使用了这个变体。由于明显的运行时考虑,今后更推荐使用这个变体。它还原生处理缺失值,省去了额外的预处理步骤。关于实现及其使用方法的更多详情,请参见 https://xgboost.readthedocs.io/en/latest/tutorials/rf.html。
现在,让我们看最后一类函数,它是最强大的学习方法之一,并且在各种数据集上已被证明极其有效——梯度提升。
梯度提升决策树
提升,就像装袋一样,是另一种集成方法,使用少量弱学习器来生成一个强大的模型委员会。装袋和提升之间的关键区别在于弱学习器的组合方式。提升不像装袋那样在自助采样数据集上并行构建不同的模型,而是以顺序方式使用弱学习器,每个弱学习器应用于数据的重复修改版本。
为了理解加法函数形式,让我们考虑这个函数:
$$F(x) = 25 + x^2 + \cos(x)$$
我们可以将这个函数分解为 f1(x) = 25,f2(x) = x2,f3(x) = cos(x) 并重写 F(x) 如下:
F(x) = f1(x) + f2(x) + f3(x)
这就是我们在提升中学习的加法集成函数类型。虽然理论上我们可以使用任何弱学习器,但决策树是最流行的选择。因此,让我们使用决策树来探索梯度提升的工作原理。
之前讨论决策树时我们看到,一个具有 M 个划分,划分区域 P1, P2, …, PM 的决策树如下所示:
$$T(x) = \sum_{m=1}^{M} c_m I(x \epsilon P_m)$$
这里,x 是输入,Cm 是该区域的常数响应,Pm,且 I 是一个函数,当 $x \epsilon P_m$ 时其值为 1,否则为 0。梯度提升决策树模型是此类树的加和:
$$\hat{y} = \sum_{k=1}^{M} T_k(x)$$
由于为集成中所有树找到最优划分 P 和常数 c 是一个非常困难的优化问题,我们通常采用一种次优的逐阶段(stagewise)解法,在构建集成时逐步优化每一步。在梯度提升中,我们使用损失函数的梯度来指导优化,因此得名。
设训练中使用的损失函数为 $L(\hat{y}, y)$。由于我们考虑的是逐阶段加性函数形式,我们可以将 $\hat{y}_k$ 替换为 $\hat{y}_{k-1} + T_k(x)$,其中 $\hat{y}_{k-1}$ 是直到第 k-1 步所有树的预测之和,而 Tk(x) 是第 k 步树的预测。来看看对训练数据 D(含 N 个样本)的梯度提升学习过程:
- 通过最小化损失函数,用常数初始化模型:
$$F_{0(x)} = \underset{b_0}{\operatorname{argmin}} \sum_{i=1}^{N} L(y_i, b_0)$$
- b0 是在第 0 次迭代时最小化损失函数的模型预测。在此迭代中,我们还没有任何弱学习器,且此优化与任何特征无关。
- 对于平方误差损失,这等于所有训练样本的平均值;而对于绝对误差损失,则是中位数。
- 现在有了初始解,我们可以开始建树过程。对于 k=1 到 M,我们必须执行以下步骤:
- 对所有训练样本计算 $r_k = -\left[ \frac{\delta L(y, F_{k-1}(x))}{\delta F_{k-1}(x)} \right]$:
- rk 是损失函数对上一次迭代的 F(x) 的导数,也称为伪残差。
- 对于平方误差损失,这就是残差,即 ($\hat{y} - y$)。
- 构建一个普通的回归树来拟合 rk 值,该树有 Mk 个划分或叶节点 Pmk。
- 计算 $\rho_t = \underset{\rho}{\operatorname{arg\,min}} \sum_{i=1}^{N} L(y_i, F_{k-1}(x_i) + \rho T_k(x_i))$:
- $\rho_k$ 是当前阶段叶节点或划分值的缩放因子。
- $T_k(x_i)$ 是当前阶段决策树学到的函数。
- 更新 $F_k(x) = F_{k-1}(x) + \eta + \rho_k \times T_k(x_i)$:
- $\eta$ 是收缩参数或学习率。
- 对所有训练样本计算 $r_k = -\left[ \frac{\delta L(y, F_{k-1}(x))}{\delta F_{k-1}(x)} \right]$:
这种“提升”前一个弱模型误差的过程赋予了算法其名称——梯度提升,其中梯度在此处指前一个弱模型上的残差。
Boosting通常是高方差算法,这意味着过拟合训练数据集的风险相当高,需要采取足够措施确保不发生。梯度提升树中有多种实现正则化和容量约束的方式。一如既往,决策树用于减少容量以拟合数据的所有关键参数在这里都有效,因为弱学习器是决策树。除此之外,还有两个其他关键参数——树的数量M(scikit-learn中的n_estimators)和学习率(scikit-learn中的$\eta$,即learning_rate)。
在加法模型中应用学习率时,本质上是收缩每个弱学习器,从而减少任何单个弱学习器对整体函数的影响。这最初被称为收缩,但现在在梯度提升树的所有流行实现中,它被称为学习率。树的数量和学习率高度相互依赖。对于相同问题,如果降低学习率,将需要更多数量的树。经验表明,较低的学习率能改善泛化误差。因此,一种非常有效且便捷的方式是:将学习率设为非常低的值(<0.1),将树的数量设为非常高的值(>5,000),并使用早停法训练梯度提升树。早停法是指在训练模型时使用验证数据集监控样本外性能,当样本外误差停止减少时,停止向集成中添加更多树。
许多实现采用的另一个关键技术是子采样。子采样可以在行和列上进行。行子采样类似于自助法,集成中的每个候选者在数据集的一个子样本上训练。列子采样类似于随机森林中的随机特征选择。这两种技术都为集成引入了正则化效果,有助于减少泛化误差。一些梯度提升树的实现,如XGBoost和LightGBM,也在目标函数中直接实现了L1和L2正则化。
回归梯度提升树有多种实现。一些流行的实现如下:
- scikit-learn中的
GradientBoostingRegressor和HistGradientBoostingRegressor - T Chen的XGBoost
- 微软的LightGBM
- Yandex的CatBoost
每种实现相对于标准梯度提升算法都提供了从细微到非常根本的变化。我们在扩展阅读部分包含了一些资源,以便您了解这些差异并熟悉它们支持的不同参数。
在我们的练习中,我们将使用微软研究院的LightGBM,因为它是最快且性能最好的实现之一。LightGBM和CatBoost还原生支持类别特征并处理缺失值。
参考文献检查:
XGBoost、LightGBM和CatBoost的原始研究论文在参考文献部分分别引用为2、3和4。
现在,让我们看看如何使用 LightGBM,并在验证数据集中的一个样本住户上评估拟合效果:
from lightgbm import LGBMRegressor
model_config = ModelConfig(
model=LGBMRegressor(random_state=42),
name="LightGBM",
# LightGBM is not affected by normalization
normalize=False,
# LightGBM handles missing values
fill_missing=False,
)
y_pred, metrics, feat_df = evaluate_model(
model_config,
feat_config,
missing_value_config,
train_features,
train_target,
test_features,
test_target,
)
让我们看看来自 LGBMRegressor 的单步预测。它已经显著优于我们目前尝试过的所有其他模型:

图8.16:LightGBM 预测
与决策树中的特征重要性类似,梯度提升实现也有一个非常相似的机制来估计特征重要性。集成模型的特征重要性由所有树中归因于每个特征的分裂准则减少量的平均值给出。在 scikit-learn API 中,可以通过训练后模型的 feature_importance_ 属性来访问。让我们看看特征重要性:

图8.17:LightGBM 的特征重要性(前15个)
从模型中获取特征重要性有多种方法,每种实现的计算方式略有不同。这由参数控制。最常用的提取方式(沿用 LightGBM 术语)是 split 和 gain。如果我们选择 split,特征重要性是特征在树中用于分裂节点的次数。另一方面,gain 是分裂准则的总减少量,可归因于任何特征。图8.17 显示了 split,这是 LightGBM 中的默认值。我们可以看到,特征重要性的顺序与决策树或随机森林非常相似,几乎相同的特征占据前三位。
梯度提升决策树(GBDTs)通常在表格数据和时间序列上表现出色,回归也不例外。这个非常强大的模型在最近几乎所有的 Kaggle 时间序列预测竞赛获奖作品中都有出现。虽然它是最优秀的机器学习模型家族之一,但仍有一些缺点:
- GBDTs 是高方差算法,因此容易过拟合。这就是为什么在大多数成功的 GBDT 实现中,以不同方式应用了各种正则化方法。
- GBDTs 通常需要更长的训练时间(尽管许多现代实现已使其更快),并且不像随机森林那样容易并行化。在随机森林中,我们可以并行训练所有树,因为它们相互独立。但在 GBDTs 中,算法的顺序性限制了并行化。所有成功的实现都有巧妙的方法在创建决策树时实现并行化。LightGBM 有许多并行化策略,例如特征并行、数据并行和投票并行。有关这些的详细信息可以在 https://lightgbm.readthedocs.io/en/latest/Features.html#optimization-in-distributed-learning 找到,并且值得理解。该库的文档还包含一个有用的表格,用于在这些并行化策略之间进行选择:

图8.18:LightGBM 中的并行化策略
- 外推对于GBDT来说是一个问题,就像对所有基于树的模型一样。GBDT具有非常微弱的外推潜力,但无法解决这个问题。因此,如果你的时间序列存在强趋势,基于树的方法很可能无法捕捉到趋势。要么对去趋势后的数据进行模型训练,要么切换到另一类模型。一个简单的去趋势方法是使用
AutoStationaryTransformer,我们在第6章《时间序列预测特征工程》中讨论过。
总结一下,让我们看看这些机器学习模型所取得的指标和运行时间。如果你与本章一起运行了笔记本,那么你会在其中找到以下汇总表:

图8.18:样本家庭的指标和运行时间汇总
首先,我们可以看到,除了预测偏差外,我们尝试的所有机器学习模型在所有指标上都优于基线。三个线性回归模型表现良好,在MAE、MASE和MSE上表现几乎相同,正则化模型的运行时间略有增加。决策树表现不佳,但这通常是预期的。决策树需要更好地调整以减少过拟合。随机森林(包括scikit-learn和XGBoost实现)提高了决策树的性能,这正是我们所期望的。这里需要注意的一点是,XGBoost的随机森林实现几乎比scikit-learn的快六倍。最后,LightGWM在所有指标上表现最佳,且运行时间更快。
现在,这只是所有选定家庭中的一个。为了了解这些模型的表现,我们需要对所有选定的家庭进行评估。
训练和预测多个家庭
我们选择了几个模型(LassoCV、XGBRFRegressor和LGBMRegressor),它们在指标和运行时间上表现更好,以便在我们的验证数据集中的所有选定家庭上运行。过程很简单:遍历所有唯一组合,内层循环遍历要运行的不同模型,然后训练、预测和评估。代码可在01-Forecasting_with_ML.ipynb笔记本中的“为所有消费者运行ML预测”标题下找到,位于Chapter08中。你可以运行代码并休息一下,因为这将花费不到一个小时。笔记本还会计算指标,并包含一个汇总表,在你回来时已经准备就绪。
现在让我们看一下汇总:

图8.19:验证数据集中所有家庭的聚合指标
在这里,我们可以看到,即使在聚合层面上,我们使用的不同模型也如预期般表现。笔记本还将验证集的预测结果保存到磁盘上。
笔记本提示:
我们还需要运行另一个笔记本,名为 01a-Forecasting_with_ML_for_Test_Dataset.ipynb,在 Chapter08 中。该笔记本遵循相同的过程,生成预测,并计算测试数据集上的指标。
测试数据集的汇总指标如下(来自笔记本):

图8.20:测试数据集中所有家庭的汇总指标
在第6章《时间序列预测的特征工程》中,我们在所有家庭上使用了 AutoStationaryTransformer(而不是我们将在第14章中学习的 Transformer 模型)并保存了变换后的数据集。
使用AutoStationaryTransformer
该过程与本章前面所做的非常相似,但有一些小改动。我们读取变换后的目标,并将其连接到常规数据集,使得原始目标命名为 energy_consumption,变换后的目标命名为 energy_consumption_auto_stat:
#Reading the missing value imputed and train test split data
train_df = pd.read_parquet(preprocessed/"block_0-7_train_missing_imputed_feature_engg.parquet")
auto_stat_target = pd.read_parquet(preprocessed/"block_0-7_train_auto_stat_target.parquet")
transformer_pipelines = joblib.load(preprocessed/"auto_transformer_pipelines_train.pkl")
#Reading in validation as test
test_df = pd.read_parquet(preprocessed/"block_0-7_val_missing_imputed_feature_engg.parquet")
# Joining the transformed target
train_df = train_df.set_index(['LCLid','timestamp']).join(auto_stat_target).reset_index()
在定义 FeatureConfig 时,我们使用 energy_consumption_auto_stat 作为 target,使用 energy_consumption 作为 original_target。
笔记本提示:
02-Forecasting_with_ML_and_Target_Transformation.ipynb 和 02a-Forecasting_with_ML_and_Target_Transformation_for_Test_Dataset.ipynb 笔记本分别使用这些变换后的目标来生成验证集和测试集的预测。
让我们看看这些笔记本在变换后的数据上生成的汇总指标:

图8.21: 验证数据集中所有经目标变换的家庭的聚合指标
目标变换模型的表现不如原始模型。这可能是因为数据集没有任何强劲趋势。转换后的模型
恭喜您完成了这一章理论充实、实践丰富的学习。我们希望这增强了您对机器学习的理解以及将这些现代技术应用于时间序列数据的能力。
小结
这是一章非常实用的动手章节,我们开发了一些标准代码来训练和评估多个机器学习模型。然后,我们回顾了几个关键的机器学习模型,如岭回归、套索回归、决策树、随机森林和梯度提升树,以及它们在幕后是如何工作的。为了巩固所学,我们将学到的机器学习模型应用于伦敦智能电表数据集,并观察了它们的表现。这一章为您后续章节的学习奠定了基础,在后续章节中,我们将使用标准化代码和这些模型更深入地探讨基于机器学习的预测。
在下一章中,我们将开始将不同的预测组合成一个单一的预测,并探索组合优化和堆叠等概念,以实现最先进的结果。
参考文献
本章提供了以下参考文献:
- Breiman, L. Random Forests, Machine Learning 45, 5–32 (2001): https://doi.org/10.1023/A:1010933404324..
- Chen, Tianqi and Guestrin, Carlos. (2016). XGBoost: A Scalable Tree Boosting System. Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD ‘16). Association for Computing Machinery, New York, NY, USA, 785–794: https://doi.org/10.1145/2939672.2939785..
- Ke, Guolin et.al. (2017), LightGBM: A Highly Efficient Gradient Boosting Decision Tree. Advances in Neural Information Processing Systems, pages 3149-3157: https://dl.acm.org/doi/pdf/10.5555/3294996.3295074..
- Prokhorenkova, Liudmila 等 (2018),CatBoost: 使用类别特征的无偏提升. 第32届国际神经信息处理系统会议论文集 (NIPS'18): https://dl.acm.org/doi/abs/10.5555/3327757.3327770.
延伸阅读
要了解更多关于本章涉及的主题,请参阅以下资源:
- L1和L2正则化的区别,作者 Terrence Parr:https://explained.ai/regularization/L1vsL2.html
- L1范数对比L2范数,作者 Aleksey Bilogur:https://www.kaggle.com/residentmario/l1-norms-versus-l2-norms
- 可解释性——打开黑箱,作者 Manu Joseph:https://deep-and-shallow.com/2019/11/13/interpretability-cracking-open-the-black-box-part-ii/
- 梯度提升器——第三部分:XGBoost,作者 Manu Joseph:https://deep-and-shallow.com/2020/02/12/the-gradient-boosters-iii-xgboost/
- 梯度提升器——第四部分:LightGBM,作者 Manu Joseph:https://deep-and-shallow.com/2020/02/21/the-gradient-boosters-iii-lightgbm/
- 梯度提升器——第五部分:CatBoost,作者 Manu Joseph:https://deep-and-shallow.com/2020/02/29/the-gradient-boosters-v-catboost/
- 梯度提升器——第二部分:正则化贪心森林,作者 Manu Joseph:https://deep-and-shallow.com/2020/02/09/the-gradient-boosters-ii-regularized-greedy-forest/
- LightGBM分布式学习指南:https://lightgbm.readthedocs.io/en/latest/Parallel-Learning-Guide.html