本文中,云朵君和大家一起学习了五个Python时间序列库,包括Darts和Gluonts库的数据结构,以及如何在这些库中转换pandas数据框,并将其转换回pandas。
Pandas DataFrame通常用于处理时间序列数据。对于单变量时间序列,可以使用带有时间索引的 Pandas 序列。而对于多变量时间序列,则可以使用带有多列的二维 Pandas DataFrame。然而,对于带有概率预测的时间序列,在每个周期都有多个值的情况下,情况又如何呢?图(1)展示了销售额和温度变量的多变量情况。每个时段的销售额预测都有低、中、高三种可能值。尽管 Pandas 仍能存储此数据集,但有专门的数据格式可以处理具有多个协变量、多个周期以及每个周期具有多个样本的复杂情况。
图片
在时间序列建模项目中,充分了解数据格式可以提高工作效率。本文的目标是介绍 DarTS、GluonTS、Sktime、pmdarima 和 Prophet/NeuralProphet 库的数据格式。由于 Sktime、pmdarima 和 Prophet/NeuralProphet 都与 pandas 兼容,因此只需花更多时间学习。
- DarTS
- GluonTS
Pandas DataFrame是许多数据科学家的基础。学习的简单方法是将其转换为其他数据格式,然后再转换回来。本文还将介绍长格式和宽格式数据,并讨论库之间的转换。
请用 pip 安装以下库:
!pip install pandas numpy matplotlib darts gluonts
!pip install sktime pmdarima neuralprophet
获取长式数据集
加载一个长式数据集。
这里我们将使用Kaggle.com上的沃尔玛数据集,其中包含了45家商店的多元时间序列数据。我们选择这个数据集是因为它是一个长式数据集,所有组的数据都是垂直堆叠的。该数据集以Pandas数据帧的形式加载。
data = pd.read_csv('/walmart.csv', delimiter=",")
# 数据获取:公众号:数据STUDIO 后台回复 云朵君
data['ds'] = pd.to_datetime(data['Date'], format='%d-%m-%Y')
data.index = data['ds']
data = data.drop('Date', axis=1)
data.head()
将字符串列 "Date" 转换为 Pandas 中的日期格式是十分关键的,因为其他库通常需要日期字段采用 Pandas 数据时间格式。图(2)展示了最初的几条记录。
图(2):沃尔玛数据
该数据集包含
- Date - 日期 - 销售周
- Store - 商店 - 商店编号
- Weekly sales - 周销售额 - 商店的销售额
- Holiday flag - 假日标志 - 本周是否为特殊假日周 1 - 假日周 0 - 非假日周
- Temperature - 温度 - 销售当天的温度
- Fuel price - 燃料价格 - 该地区的燃料成本
两个宏观经济指标,即消费者价格指数和失业率,对零售额有影响。沃尔玛数据集堆叠了 45 家商店的多个序列,每家店有 143 周的数据。
使数据集成为宽格式
宽格式数据结构是指各组多元时间序列数据按照相同的时间索引横向附加,接着我们将按商店和时间来透视每周的商店销售额。
# 将数据透视成正确的形状
storewide = data.pivot(index='ds', columns='Store', values='Weekly_Sales')
storewide = storewide.loc[:,1:10] # Plot only Store 1 - 10
# 绘制数据透视表
storewide.plot(figsize=(12, 4))
plt.legend(loc='upper left')
plt.title("Walmart Weekly Sales of Store 1 - 10")
图(3): 沃尔玛商店的销售额
10 家商店的每周销售额如图(3)所示:
(4): 商店销售额曲线图
检查一下时间索引,它是一个 Pandas DateTimeIndex。
print(storewide.index)
图片
除了每周商店销售额外,还可以对其他任何列进行同样的长格式到宽格式的转换。
Darts
Darts 库是如何处理长表和宽表数据集的?
Python的时间序列库darts以投掷飞镖的隐喻为名,旨在帮助数据分析中的准确预测和命中特定目标。它为处理各种时间序列预测模型提供了一个统一的界面,包括单变量和多变量时间序列。这个库被广泛应用于时间序列数据科学。
Darts的核心数据类是其名为TimeSeries的类。它以数组形式(时间、维度、样本)存储数值。
- 时间:时间索引,如上例中的 143 周。
- 维度:多元序列的 "列"。
- 样本:列和时间的值。在图(A)中,第一周期的值为 [10,15,18]。这不是一个单一的值,而是一个值列表。例如,未来一周的概率预测值可以是 5%、50% 和 95% 量级的三个值。习惯上称为 "样本"。
Darts--来自长表格式 Pandas 数据框
转换长表格式沃尔玛数据为darts格式只需使用from_group_datafrme()函数,需要提供两个关键输入:组IDgroup_cols和时间索引time_col。在这个示例中,group_cols是Store列,而time_col是时间索引ds。
from darts import TimeSeries
darts_group_df = TimeSeries.from_group_dataframe(data, group_cols='Store', time_col='ds')
print("The number of groups/stores is: ", len(darts_group_df))
print("The number of time period is: ", len(darts_group_df[0]))
商店 1 的数据存储在 darts_group_df[0] 中,商店 2 的数据存储在 darts_group_df[1] 中,以此类推。一共有 45 个商店,因此飞镖数据 darts_group_df 的长度为 45。每个商店有 143 周,因此商店 1 darts_group_df[0] 的长度为 143。
The number of groups/stores is: 45
The number of time period is: 143
darts_group_df
图(5):沃尔玛商店销售数据的darts数据格式
图 (5) 表示(ds: 143,component:6,sample:1)143 周,6 列,每个商店和周有 1 个样本。商店 1 的数据为 darts_group_df[0]。可以使用 .components 函数列出列名。
darts_group_df[0].components
Index([‘Weekly_Sales’, ‘Holiday_Flag’, ‘Temperature’, ‘Fuel_Price’, ‘CPI’,
‘Unemployment’], dtype=’object’, name=’component’)
Darts--从宽表格式的pandas数据框转换
继续学习如何将宽表格式数据框转换为darts数据结构。
你只需使用 Darts 中 TimeSeries 类的.from_dataframe()函数:
from darts import TimeSeries
darts_df = TimeSeries.from_dataframe(storewide)
darts_df
输出结果如图 (F) 所示:
图(6):Darts数据数组
图(6)表示(ds: 143, component:10, sample:1)143 周、10 列以及每个商店和周的 1 个样本。可以展开小图标查看组件,组件指的是列名。
Darts--绘图
如何使用 Darts 绘制曲线?
绘图语法与 Pandas 中的一样简单。只需执行 .plot():
darts_df.plot()
图(7):10个序列的曲线图
Darts--单变量 Pandas 序列
如果我们只有一个序列呢?如何转换为 Darts?
列 storewide[1] 是商店 1 的 Pandas 序列。可以使用 .from_series() 将 Pandas 序列方便地转换为 Darts:
darts_str1 = TimeSeries.from_series(storewide[1])
darts_str1
图 (8) 显示了输出结果。如 (ds:143, component:1, sample:1) 所示,每周有 143 周、1 列和 1 个样本。
图(8):序列的数据结构
绘制过程如图(9)所示:
darts_str1.plot()
图(9):单变量的曲线图
Darts - 转换回 Pandas
如何将 Darts 数据集转换回 Pandas 数据框?
只需使用 .pd_dataframe():
# 将 darts 数据框转换为 pandas 数据框
darts_to_pd = TimeSeries.pd_dataframe(darts_df)
darts_to_pd
输出结果是一个二维 Pandas 数据框:
不是所有的Darts数据都可以转换成二维Pandas数据框。比如一周内商店的概率预测值,无法存储在二维Pandas数据框中,可以将数据输出到Numpy数组中。
Darts--转换为 Numpy 数组
Darts 可以让你使用 .all_values 输出数组中的所有值。缺点是会丢弃时间索引。
# 将所有序列导出为包含所有序列值的 numpy 数组。
# https://unit8co.github.io/darts/userguide/timeseries.html#exporting-data-from-a-timeseries
TimeSeries.all_values(darts_df)
图片
学习了 Darts 的数据结构后,再学习另一个流行的时间序列库 - Gluonts 的数据结构。
Gluonts
Gluonts是亚马逊开发的处理时间序列数据的Python库,包含多种建模算法,特别是基于神经网络的算法。这些模型可以处理单变量和多变量序列,以及概率预测。Gluonts数据集是Python字典格式的时间序列列表。可以将长式Pandas数据框转换为Gluonts。
Gluonts--从长表格式 Pandas 数据框
gluons.dataset.pandas 类有许多处理 Pandas 数据框的便捷函数。要在 Pandas 中加载长表格式数据集,只需使用 .from_long_dataframe():
# Method 1: from a long-form
from gluonts.dataset.pandas import PandasDataset
data_long_gluonts = PandasDataset.from_long_dataframe(
data,
target="Weekly_Sales",
item_id="Store",
timestamp='ds',
freq='W')
data_long_gluonts
打印 Gluonts 数据集时,会显示元数据:
PandasDataset<size=45, freq=W, num_feat_dynamic_real=0,
num_past_feat_dynamic_real=0,
num_feat_static_real=0,
num_feat_static_cat=0,
static_cardinalities=[]>
Gluonts--从宽表格式的 Pandas 数据框
PandasDataset() 类需要一个时间序列字典。因此,首先要将宽表 Pandas 数据框转换为 Python 字典,然后使用 PandasDataset():
# Method 2: from a wide-form
from gluonts.dataset.pandas import PandasDataset
data_wide_gluonts = PandasDataset(dict(storewide))
data_wide_gluonts
通常,我们会将 Pandas 数据框分成训练数据("实时")和测试数据("非实时"),如下图所示。
len_train = int(storewide.shape[0] * 0.85)
len_test = storewide.shape[0] - len_train
train_data = storewide[0:len_train]
test_data = storewide[len_train:]
[train_data.shape, test_data.shape] # The output is [(121,5), (22,5)
如前所述,Gluonts 数据集是 Python 字典格式的数据列表。我们总是可以使用 Gluonts 中的 ListDataset()类。我们使用 ListDataset() 转换数据:
Gluonts - ListDataset() 进行任何常规转换
Gluonts 数据集是 Python 字典格式的时间序列列表,可使用 ListDataset() 作为一般转换工具,该类需要时间序列的基本元素,如起始时间、值和周期频率。
将图(3)中的宽格式商店销售额转换一下。数据帧中的每一列都是带有时间索引的 Pandas 序列,并且每个 Pandas 序列将被转换为 Pandas 字典格式。字典将包含两个键:字段名.START 和字段名.TARGET。因此,Gluonts 数据集是一个由 Python 字典格式组成的时间序列列表。
def convert_to_gluonts_format(dataframe, freq):
start_index = dataframe.index.min()
data = [{
FieldName.START: start_index,
FieldName.TARGET: dataframe[c].values,
}
for c in dataframe.columns]
#print(data[0])
return ListDataset(data, freq=freq)
train_data_lds = convert_to_gluonts_format(train_data, 'W')
test_data_lds = convert_to_gluonts_format(test_data, 'W')
train_data_lds
生成的结果是由Python字典列表组成,其中每个字典包含 start 关键字代表时间索引,以及 target 关键字代表对应的值。
图片
Gluonts - 转换回 Pandas
如何将 Gluonts 数据集转换回 Pandas 数据框。
Gluonts数据集是一个Python字典列表。要将其转换为Python数据框架,首先需使Gluonts字典数据可迭代。然后,枚举数据集中的键,并使用for循环进行输出。
在沃尔玛商店的销售数据中,包含了时间戳、每周销售额和商店 ID 这三个关键信息。因此,我们需要在输出数据表中创建三列:时间戳、目标值和索引。
# 将 gluonts 数据集转换为 pandas 数据帧
# Either long-form or wide-form
the_gluonts_data = data_wide_gluonts # you can also test data_long_gluonts
timestamps = [] # This is the time index
target_values = [] # This is the weekly sales
index = [] # this is the store in our Walmart case
# Iterate through the GluonTS dataset
for i, entry in enumerate(the_gluonts_data):
timestamp = entry["start"]
targets = entry["target"]
# Append timestamp and target values for each observation
for j, target in enumerate(targets):
timestamps.append(timestamp)
target_values.append(target)
index.append(i) # Keep track of the original index for each observation
# Create a pandas DataFrame
df = pd.DataFrame({
"timestamp": timestamps,
"target": target_values,
"original_index": index
})
print(df)
图片
Darts和Gluonts支持复杂数据结构的建模算法,可以建立多个时间序列的全局模型和概率预测。当所有时间序列中存在一致的基本模式或关系时,它就会被广泛使用。沃尔玛案例中的时间序列数据是全局模型的理想案例。相反,如果对多个时间序列中的每个序列都拟合一个单独的模型,则该模型被称为局部模型。在沃尔玛数据中,我们将建立45个局部模型,因为有45家商店。
在熟悉了Darts和Gluonts的数据结构后,我们将继续学习Sktime、pmdarima和Prophet/NeuralProphet的数据格式,它们与pandas兼容,因此无需进行数据转换,这将使学习变得更加容易。
Sktime
Sktime旨在与scikit-learn集成,利用各种scikit-learn时间序列算法。它提供了统一的界面和实现常见的时间序列分析任务,简化了时间序列数据处理过程。提供了预测、分类和聚类等算法,可用于处理和分析时间序列数据。
import lightgbm as lgb
from sktime.forecasting.compose import make_reduction
lgb_regressor = lgb.LGBMRegressor(num_leaves = 10,
learning_rate = 0.02,
feature_fraction = 0.8,
max_depth = 5,
verbose = 0,
num_boost_round = 15000,
nthread = -1
)
lgb_forecaster = make_reduction(lgb_regressor, window_length=30, strategy="recursive")
lgb_forecaster.fit(train)
Pmdarima
Pmdarima是Python封装程序,基于流行的"statsmodels"库,将ARIMA和SARIMA模型合并在一起。它能自动选择最佳ARIMA模型,功能强大且易于使用,接受一维数组或pandas Series作为数据输入。
import pmdarima as pm
model = pm.auto_arima(train,
d=None,
seasnotallow=False,
stepwise=True,
suppress_warnings=True,
error_actinotallow="ignore",
max_p=None,
max_order=None,
trace=True)
图片
Prophet/NeuralProphet
Prophet是Facebook开发的时间序列预测库,具有自动检测季节性模式、处理缺失数据以及纳入假日效应的能力。它拥有用户友好的界面和交互式plotly风格的输出,分析师几乎不需要人工干预即可生成预测结果。Prophet因其灵活的趋势建模功能和内置的不确定性估计而深受欢迎。该库可用于执行单变量时间序列建模,需要使用Pandas数据框架,其中列名为['ds', 'y']。
这里加载了一个 Pandas 数据框 "bike" 来训练一个 Prophet 模型。
import pandas as pd
from prophet import Prophet
bike.columns = ['ds','y']
m = Prophet()
m.fit(bike)
Prophet的图像很吸引人。
图(10):Prophet
NeuralProphet是基于先知框架的神经网络架构,加强了先知的加法模型,允许更灵活、更复杂地对时间序列数据进行建模。它集成了Prophet的优势,包括自动季节性检测和假日效应处理,并专注于单变量时间序列预测。以下是一个使用Pandas数据帧来训练NeuralProphet模型的示例。
from neuralprophet import NeuralProphet
df = pd.read_csv(path + '/bike_sharing_daily.csv')
# Create a NeuralProphet model with default parameters
m = NeuralProphet()
# Fit the model
metrics = m.fit(df)
它的绘图能力就像Prophet一样吸引人。
图(11): neuralprophet
结论
本文中,云朵君和大家一起学习了五个Python时间序列库,包括Darts和Gluonts库的数据结构,以及如何在这些库中转换pandas数据框,并将其转换回pandas。此外,还介绍了Sktime、pmdarima和Prophet/NeuralProphet库。这些库都有各自的优势和特点,选择使用哪个取决于对速度、与其他Python环境的集成以及模型熟练程度的要求。