前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >独家 | 将时间信息编码用于机器学习模型的三种编码时间信息作为特征的三种方法

独家 | 将时间信息编码用于机器学习模型的三种编码时间信息作为特征的三种方法

作者头像
数据派THU
发布2022-03-24 16:43:05
1.7K0
发布2022-03-24 16:43:05
举报
文章被收录于专栏:数据派THU

代码语言:javascript
复制
作者:Eryk Lewinson
翻译:汪桉旭校对:zrx
本文约4400字,建议阅读5分钟本文研究了三种使用日期相关的信息如何创造有意义特征的方法。

标签:时间帧,机器学习,Python,技术演示

想象一下,你刚开始一个新的数据科学项目。目标是建立一个预测目标变量Y的模型。你已经收到了来自利益相关者/数据工程师的一些数据,进行了彻底的EDA并且选择了一些你认为和手头上问题有关的变量。然后你终于建立了你的第一个模型。得分是可以接受的,但是你相信你可以做得更好。你应该怎么做呢?

这里你可以通过许多方式跟进。一种可能性是增加你使用的机器学习模型的复杂度。或者,你可以尝试提出一些更有意义的特征并且继续使用现在的模型(至少暂时是这样)。

对于许多项目,企业数据科学家和Kaggle等数据科学竞赛的参与者都认为,后者——从数据中辨别更多有意义的特征——通常可以在最少的尝试下最大程度地提升模型的精度。

你正有效地将复杂度从模型转移到了特征。特征不一定要非常复杂,但是,理想的情况下,我们会找到与目标变量具有强烈而简单关系的特征。

许多数据科学项目包含了一些关于时间变化的信息,这不仅限于时序预测问题。例如,你经常会在传统的回归或者分类问题中发现这些特征。这篇文章研究了使用日期相关的信息如何创造有意义的特征。我们提出三种方法,但是我们需要先做一些准备。

设置和数据

在这篇文章中,我们更多时候会使用一些有名的Python包,但我们同时也使用了一个相对不出名的包,scikit-lego。它是一个包含大量有用功能的的库,这些功能扩展了scikit-learn’s的功能。我们输入需要的库:

为了简单起见,我们自己生成数据。在此示例中,我们使用人工的时间序列。首先,我们要创建一个索引跨越四个日历年的空DataFrame(我们使用pd.date_range)。然后,我们创建两列:

  • day_nr – 表示时间流逝的数字索引;
  • day_of_year – 一年中的第几天;

最后,我们需要创建时间序列本身。为此,我们结合了两条变换后的正弦曲线和一些随机噪声。用于生成数据的代码是基于 scikit-lego的文档中包含的代码写下的。https://scikit-lego.readthedocs.io/en/latest/

图1:生成的时间序列

然后,我们创建一个新的DataFrame,用来存储生成的时间序列。该DataFrame 将用于使用不同的特征工程方法比较模型的性能。

创建与时间相关的特征

在本节中,我们描述了生成时间相关特征的三种方法。

在深入研究之前,应该定义一个评估框架。模拟数据包含了四年期间的观察结果。我们使用前 3 年生成的数据作为训练集,并在第四年进行评估。在这个过程中,平均绝对误差 (MAE)将作为评估指标。

下面我们定义一个变量来分出这两个集合:

方法#1:虚拟变量

我们将从你可能已经熟悉的内容开始。对时间相关信息进行编码的最简单方法是使用虚拟变量https://en.wikipedia.org/wiki/Dummy_variable_(statistics)(也称为 one-hot 编码)。让我们看一个例子。下面你可以看到我们操作的输出。

表格1:带有月份虚拟变量的 DataFrame

首先,我们从DatetimeIndex中提取了有关月份的信息(编码为 1 到 12范围内的整数)。然后,我们使用pd.get_dummies函数来创建虚拟变量。每列包含有关观察(行)是否来自给定月份的信息。

你可能注意到,我们已经丢弃了一层,现在只有 11 列。这样做是为了避免熟知的虚拟变量陷阱(完美多重共线性)。

在我们的示例中,我们使用虚拟变量方法来捕获记录观察的月份。同样的方法可用于指示来自DatetimeIndex的一系列其他信息。例如,一年中的天/周/季度,给定日期是否是周末的标志,周期的第一天/最后一天等等。你可以在 pandas.pydata.org 上找到一个列表,列表包含了我们可以从pandashttps://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#time-date-components文档索引中提取的所有可能的特性。

温馨提示:这超出了简单练习的范围,但在现实生活场景中,我们还可以使用有关特殊日子(例如国定假日、圣诞节、黑色星期五等)的信息来创建特征。holidays 是一个不错的 Python 库,其中包含有关每个国家/地区特殊日子的过去和未来信息。

如引言所述,特征工程的目标是将复杂性从模型端转移到特征端。这就是为什么我们将使用最简单的 ML 模型之一“线性回归”来查看仅使用创建的虚拟模型来拟合时间序列的效果有多好。

图2: 使用月份虚拟变量进行拟合。垂直线将训练集和测试集分开

我们可以看到,拟合线已经很好地遵循了时间序列,尽管它有点锯齿状(阶梯状)——这是由于虚拟特征的不连续性造成的。我们将尝试用下列两种方法解决问题。

值得一提的是,当使用决策树(或其集合)等非线性模型时,我们不会将月份数或一年中的某一天等特征明确编码为虚拟模型。这些模型能够学习序数输入特征和目标之间的非单调关系。

方法 #2:使用正弦/余弦变换进行循环编码

正如我们之前所见,拟合线类似于台阶。那是因为每个虚拟变量都是单独处理的,没有连续性。然而,时间等变量存在明显的周期性连续性。

想象一下,我们正在处理能源消耗数据。当我们将观察到的消费月份的信息包括在内时,连续两个月之间存在更强的联系是有道理的。按照这个逻辑,12 月和 1 月之间以及 1 月和 2 月之间的联系很强。相比之下,1月和7月之间的联系并不那么紧密。这同样适用于其他与时间相关的信息。

那么我们如何将这些知识融入到特征工程中呢?三角函数是一种办法。

我们可以使用以下正弦/余弦变换将循环时间特征编码为两个特征。

在下面的代码片段中,我们复制初始DataFrame,添加带有月份编号的列,然后使用正弦/余弦变换对月份和 day_of_year 列进行编码。接着,我们绘制两对曲线。

图3:基于月份和每日序列的正/余弦转换

如图 3 所示,我们可以从转换后的数据中得出两点结论:其一,我们可以看到,当使用月份进行编码时,曲线是逐步的,但是当使用每日频率时,曲线更平滑;其二,我们也可以看到,我们必须使用两条曲线而不是一条曲线。由于曲线的重复性,如果你在一年内画一条水平直线,你会在两个地方穿过曲线。这不足以让模型理解观察的时间点。但有了这两条曲线,就不存在这样的问题,使用者可以识别每一个时间点。当我们在散点图上绘制正弦/余弦函数的值时,这一点清晰可见。在图 4 中,可以看到没有重叠值的圆形图案。

图4:正余弦转换的散点图

仅使用来自每日频率的新创建的特征来拟合相同的线性回归模型。

图5:使用正弦/余弦变换拟合。垂直线将训练集和测试集分开

图 5 显示该模型能够捕捉数据的总体趋势,识别具有较高和较低值的时期。然而,预测的幅度似乎不太准确,乍一看,这种拟合似乎比使用虚拟变量实现的拟合更差(图 2)。

在我们讨论第三种特征工程技术之前,值得一提的是,这种方法有一个严重的缺点,这在使用基于树的模型时很明显。根据设计,基于树的模型当时基于单个特征进行拆分。正如我们之前提到的,应该同时考虑正弦/余弦特征,以便正确识别一段时间内的时间点。

方法#3:径向基函数

最后一种方法使用径向基函数。我们不会详细介绍它们的实际含义,但是您可以在此处https://en.wikipedia.org/wiki/Radial_basis_function阅读有关该主题的更多信息。本质上,我们再次想解决我们在第一种方法中遇到的问题,即时间特征具有连续性。

我们使用方便的scikit-lego库,它提供了RepeatingBasisFunction类,并指定以下参数:

  • 我们想要创建的基函数的数量(我们选择了 12 个)。
  • 用于索引 RBF 的列。在我们的例子中,这是包含给定观察来自一年中哪一天的信息的列。
  • 输入的范围——在我们的例子中,范围是从 1 到 365。
  • 如何处理我们将用于拟合估计器的 DataFrame 的剩余列。“drop”将只保留创建的 RBF 特征,“passthrough”将保留新旧特征。

图6:12个径向基函数

图 6 显示了使用天数作为输入创建的 12 个径向基函数。每条曲线都包含有关我们与一年中某一天的接近程度的信息(因为我们选择了该列)。例如,第一条曲线测量的是从 1 月 1 日开始的距离,因此它在每年的第一天达到峰值,并随着我们远离该日期而对称地减小。

根据设计,基函数在输入范围内等距分布。我们选择12是因为我们希望RBF类似于月份。这样,每个函数都会大致显示(由于月份的长度不等)到该月第一天的距离。

与之前的方法类似,让我们使用 12 个 RBF 特征拟合线性回归模型。

图7:使用径向基函数拟合。垂直线将训练集和测试集分开

图 7 显示该模型在使用 RBF 特征时能够准确地捕获真实数据。

使用径向基函数时,我们可以调整两个关键参数:

  • 径向基函数的数量;
  • 钟形曲线的形状——可以使用RepeatingBasisFunction的width参数进行修改。

调整这些参数值的一种方法是使用网格搜索来识别给定数据集的最佳值。

最终比较

我们可以执行以下代码段来生成数值,比较对时间相关信息编码的不同方法。

图8:使用不同的基于时间的特征获得的模型拟合比较。垂直线将训练集和测试集分开

图 8 说明径向基函数与所考虑的方法最接近。正弦/余弦特征使模型能够拾取主要模式,但不足以完全捕捉系列的动态。

使用下面的代码片段,我们在训练集和测试集上计算每个模型的平均绝对误差。我们希望训练集和测试集之间的分数非常相似,因为生成的系列几乎是完全周期性的——年份之间的唯一区别是随机部分。

当然,在现实生活中情况并非如此,随着时间的推移,我们会在相同时期间遇到更多的可变性。然而,我们也会使用许多其他特征(例如,某种趋势或时间流逝的度量)来解释这些变化。

和以前一样,我们可以看到使用 RBF 特征的模型得到了最佳拟合,而正弦/余弦特征的拟合效果最差。我们关于训练集和测试集之间分数相似性的假设也得到了证实。

表格2:来自训练/测试集的分数(MAE)的比较

关键点

  • 我们展示了三种将时间相关信息编码为机器学习模型特征的方法。
  • 除了最流行的虚拟编码之外,还有一些更适合编码时间循环性质的方法。
  • 使用这些方法时,时间间隔的粒度对新创建的特征的形状非常重要。
  • 使用径向基函数,我们可以决定要使用的函数数量以及钟形曲线的宽度。

您可以在我的 GitHub https://github.com/erykml/nvidia_articles/blob/main/three_approaches_to_encoding_time_information_as_features_for_ml_models.ipynb上找到本文使用的代码。

参考:

https://scikit-learn.org/stable/auto_examples/applications/plot_cyclical_feature_engineering.html

https://scikit-lego.readthedocs.io/en/latest/preprocessing.html

https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#time-date-components

原文标题:

Three Approaches to Encoding Time Informationas Features for ML Models

原文链接:

https://developer.nvidia.com/blog/three-approaches-to-encoding-time-information-as-features-for-ml-models/

编辑:黄继彦

译者简介

汪桉旭,南京航空航天大学研究生。对数据科学充满兴趣,热衷于在分享中提高自己,在实践中学习新知识。休闲时间喜欢看电影看小说。乐于结交新朋友、一起探索新爱好。

翻译组招募信息

工作内容:需要一颗细致的心,将选取好的外文文章翻译成流畅的中文。如果你是数据科学/统计学/计算机类的留学生,或在海外从事相关工作,或对自己外语水平有信心的朋友欢迎加入翻译小组。

你能得到:定期的翻译培训提高志愿者的翻译水平,提高对于数据科学前沿的认知,海外的朋友可以和国内技术应用发展保持联系,THU数据派产学研的背景为志愿者带来好的发展机遇。

其他福利:来自于名企的数据科学工作者,北大清华以及海外等名校学生他们都将成为你在翻译小组的伙伴。

点击文末“阅读原文”加入数据派团队~

转载须知

如需转载,请在开篇显著位置注明作者和出处(转自:数据派ID:DatapiTHU),并在文章结尾放置数据派醒目二维码。有原创标识文章,请发送【文章名称-待授权公众号名称及ID】至联系邮箱,申请白名单授权并按要求编辑。

发布后请将链接反馈至联系邮箱(见下方)。未经许可的转载以及改编者,我们将依法追究其法律责任。

点击“阅读原文”拥抱组织

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据派THU 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 设置和数据
    • 方法#1:虚拟变量
      • 方法 #2:使用正弦/余弦变换进行循环编码
        • 方法#3:径向基函数
        • 最终比较
        • 关键点
        • 参考:
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档