时间序列数据在很多领域都是重要的结构化数据形式,例如金融、经济、生态学、神经科学和物理学。在多个时间点观测或测量的数据形成了时间序列。许多时间序列是固定频率的,也就是说数据是根据相同的规则定期出现的,例如每15秒、每5分钟或每月1次。时间序列也可以是不规则的,没有固定的时间单位或单位间的偏移量
时间序列数据中通常隐藏着以下几个特征,我们可以对分析场景进行深入分析挖掘后,提取能反映时间序列数据信息的特征,作为建模的特征输入
-
日期特征:提取与日期相关的信息,如年、月、日、星期等。
-
时间特征:提取与时间相关的信息,如小时、分钟、秒等。
-
滞后特征:基于先前时间点的数据值创建的新特征,用于捕捉时间序列中的延迟效应。
-
滚动窗口特征:通过在指定窗口内计算统计量(如均值、总和等)来提取的特征,反映数据的局部趋势。
-
扩展窗口特征:基于更大时间范围内的数据计算的特征,用于捕捉长期趋势或周期性变化。
-
领域特定特征:根据特定应用领域的知识提取的特征,以增强模型对特定问题的理解和预测能力。
这篇文章我们基于 train 乘客数据集,包含属性:ID、时间熟悉、乘客数量(可关注微信公众号 Python数据技术极客,在消息框中输入 train,可获取百度网盘下载链接和提取码),来演示如何在时间序列中提取相应特征。
1、日期特征
我们的数据集中时间是以每小时来记录的,上班族的我们都知道在工作日的公交或地铁的乘客数量与周末会有很大差异,所以我们需要提取对应特征。以下为提取年、月、日、星期几特征的实现
import pandas as pd
data = pd.read_csv('train.csv')
data['Datetime'] = pd.to_datetime(data['Datetime'],format='%d-%m-%Y %H:%M') # 年
data['year']=data['Datetime'].dt.year
# 月
data['month']=data['Datetime'].dt.month
# 日
data['day']=data['Datetime'].dt.day
# 星期几(数字表示)
data['dayofweek_num']=data['Datetime'].dt.dayofweek
# 星期几(英文表示)
data['dayofweek_name']=data['Datetime'].dt.day_name() data.head()
2、时间特征
我们知道一天中乘客数量存在上班高峰期和下班高峰期,所以如果能够从时间戳中提取'小时'特征,就可以对数据进行更深入的分析。提取基于时间的特征与提取日期相关特征的方法类似,如下所示为提取小时和分钟的数据(因为我们的数据集以小时汇总,所以提取的分钟特征都为0)
import pandas as pd
data = pd.read_csv('train.csv')
data['Datetime'] = pd.to_datetime(data['Datetime'],format='%d-%m-%Y %H:%M') data['Hour'] = data['Datetime'].dt.hour
data['minute'] = data['Datetime'].dt.minute data.head()
除以上特征外,还可以提取多种特征,如以下列表汇总所示
# 提取时间特征
data['Year'] = data['Datetime'].dt.year # 年
data['Month'] = data['Datetime'].dt.month # 月
data['Day'] = data['Datetime'].dt.day # 日
data['Hour'] = data['Datetime'].dt.hour # 小时
data['Minute'] = data['Datetime'].dt.minute # 分钟
data['Second'] = data['Datetime'].dt.second # 秒
data['Microsecond'] = data['Datetime'].dt.microsecond # 微秒
data['Nanosecond'] = data['Datetime'].dt.nanosecond # 纳秒
data['Weekday'] = data['Datetime'].dt.weekday # 星期几(0=周一, 6=周日)
data['Day_Name'] = data['Datetime'].dt.day_name() # 星期几名称
data['Week_Number'] = data['Datetime'].dt.isocalendar().week # ISO 周数
data['ISO_Year'] = data['Datetime'].dt.isocalendar().year # ISO 年
data['ISO_Weekday'] = data['Datetime'].dt.isocalendar().day # ISO 星期几
data['Quarter'] = data['Datetime'].dt.quarter # 季度
data['Is_Workday'] = data['Datetime'].dt.weekday < 5 # 是否为工作日(布尔值)
data['Is_Month_Start'] = data['Datetime'].dt.is_month_start # 是否为月初(布尔值)
data['Is_Month_End'] = data['Datetime'].dt.is_month_end # 是否为月末(布尔值)
data['Is_Quarter_Start'] = data['Datetime'].dt.is_quarter_start # 是否为季度初(布尔值)
data['Is_Quarter_End'] = data['Datetime'].dt.is_quarter_end # 是否为季度末(布尔值)
data['Is_Year_Start'] = data['Datetime'].dt.is_year_start # 是否为年初(布尔值)
data['Is_Year_End'] = data['Datetime'].dt.is_year_end # 是否为年末(布尔值)
3、滞后特征
考虑这样一个场景 —正在预测一家公司的股票价格。那么前一天的股票价格对做出预测很重要,对吧?换句话说,t时刻的值极大地受到t-1时刻值的影响。这些过去的值被称为滞后,所以t-1是滞后1,t-2是滞后2,依此类推。实现滞后特征提取,我们可以使用 shift 方法,如下所示,lag 列表示的是前 1 个小时的数值
import pandas as pd
data = pd.read_csv('train.csv')
data['Datetime'] = pd.to_datetime(data['Datetime'],format='%d-%m-%Y %H:%M') data['lag_1'] = data['Count'].shift(1)
data = data[['Datetime', 'lag_1', 'Count']]
data.head()
我们为序列生成了滞后一特征。但为什么选择滞后1?为什么不是5或7?这是一个值得思考的问题。
我们选择的滞后值应该基于个别值与其过去值的相关性。
如果序列呈现每周趋势,即上周一的值可以用来预测这周一的值,那么创建七天的滞后特征可能更合适。
还可以创建多个滞后特征!假设想要从滞后1到滞后7的特征则可以让模型决定哪个是最有价值的。例如训练一个线性回归模型,它会为滞后特征分配适当的权重(或系数):
import pandas as pd
data = pd.read_csv('train.csv')
data['Datetime'] = pd.to_datetime(data['Datetime'],format='%d-%m-%Y %H:%M') data['lag_1'] = data['Count'].shift(1)
data['lag_2'] = data['Count'].shift(2)
data['lag_3'] = data['Count'].shift(3)
data['lag_4'] = data['Count'].shift(4)
data['lag_5'] = data['Count'].shift(5)
data['lag_6'] = data['Count'].shift(6)
data['lag_7'] = data['Count'].shift(7) data = data[['Datetime', 'lag_1', 'lag_2', 'lag_3', 'lag_4', 'lag_5', 'lag_6', 'lag_7', 'Count']]
data.head(10)
确定相关性显著的滞后有多种方法。例如可以使用ACF(自相关函数)和PACF(偏自相关函数)图
-
ACF:ACF图衡量时间序列与其滞后版本之间的相关性
-
PACF:PACF图衡量时间序列与其滞后版本之间的相关性,但在消除了已由中间比较解释的变异之后
对于我们的例子,这里是ACF和PACF图:
偏自相关函数显示与第一个滞后高度相关,与第二个和第三个滞后的相关性较低。自相关函数显示缓慢衰减,这表明未来值与其过去值有很强的相关性。
4、滚动窗口特征
滚动窗口特征(Rolling Window Features)是时间序列分析中常用的一种技术,用于提取数据的动态特征。这种方法通过在时间序列上定义一个固定大小的窗口,计算该窗口内的数据统计量,从而生成新的特征,这些特征可以帮助捕捉数据的趋势和波动性。
滚动窗口的基本概念:
-
窗口大小:指定要在时间序列中考虑的观测值数量。例如,窗口大小为 3 表示每次考虑连续的 3 个观测值。
-
滑动:窗口在时间序列上移动,通常是一个观测值的步长,这样可以生成覆盖整个序列的特征。
示例代码设置窗口大小为7,然后计算窗口内值的平均值,并将其用作特征。类似地,可以考虑计算选定窗口内的总和、最小值、最大值等作为特征。
import pandas as pd
data = pd.read_csv('train.csv')
data['Datetime'] = pd.to_datetime(data['Datetime'],format='%d-%m-%Y %H:%M') data['rolling_mean'] = data['Count'].rolling(window=7).mean()
data = data[['Datetime', 'rolling_mean', 'Count']]
data.head(10)
在时间序列中,近期性是一个重要因素。越接近当前日期的值通常包含更多相关信息。
因此我们可以使用加权平均值,给予最近的观察值更高的权重。数学上,过去7个值在时间t的加权平均值可以表示为:
w_avg = w1(t-1) + w2(t-2) + . . . . + w7*(t-7)
其中,w1>w2>w3> . . . . >w7。
5、扩展窗口特征
扩展窗口特征(Expanded Window Features)是对滚动窗口特征的一种改进,旨在通过更灵活的方式提取时间序列数据中的信息。与传统的固定大小窗口不同,扩展窗口特征允许窗口在时间序列中以不同的方式进行定义和使用,从而捕捉更复杂的模式和趋势。
扩展窗口的类型
-
增量窗口:窗口大小随着时间的推移而增加,从而使得每个时间点的特征包含越来越多的历史信息。这种方式可以捕捉长期趋势。
-
自适应窗口:根据数据的特性动态调整窗口大小。例如,在数据波动较大的时候使用较小的窗口,而在数据较平稳时使用较大的窗口。
-
重叠窗口:允许窗口之间有重叠部分,提取相邻窗口之间的特征,增加特征的细粒度
下面示例,我们演示如何在 Python 中使用expanding()函数轻松实现实现增量窗口
import pandas as pd
data = pd.read_csv('train.csv')
data['Datetime'] = pd.to_datetime(data['Datetime'],format='%d-%m-%Y %H:%M') data['expanding_mean'] = data['Count'].expanding(2).mean()
data = data[['Datetime','expanding_mean','Count' ]]
data.head(10)
6、领域特定特征
领域特定特征(Domain-Specific Features)是指根据特定领域的知识和经验,从数据中提取的特征。这些特征通常是基于业务逻辑、行业标准或领域内的常识,并且其能够反映出该领域的独特性质和规律,通常在数据分析中起到提升模型性能的重要作用。
例如,可以考虑以下问题:销售是否受当天天气的影响?销售是否会在国定假日期间出现显著变化?如果是,那么可以利用外部数据集,将节假日信息作为一个特征纳入模型。
领域特征需要基于具体问题具体分析,后续我们会选用特定场景来讲解领域特定特征,敬请期待
时间序列分析常被视为一个具有挑战性的主题,而时间序列特征的提取是重中之重,本文我们从简单到复杂详细介绍了 6 种时间序列特征提取:日期特征、时间特征、滞后特征、滚动窗口特征、扩展窗口特征、领域特定特征,希望对你有一定启发!
如果你喜欢本文,欢迎点赞,并且关注我们的微信公众号:Python技术极客,我们会持续更新分享 Python 开发编程、数据分析、数据挖掘、AI 人工智能、网络爬虫等技术文章!让大家在Python 技术领域持续精进提升,成为更好的自己!
添加作者微信(coder_0101),拉你进入行业技术交流群,进行技术交流~