pandas 时间序列索引和统计模型中的频率
Frequency in pandas timeseries index and statsmodel
我有一个 pandas 时间序列 y
不能很好地与 statsmodel
函数一起使用。
import statsmodels.api as sm
y.tail(10)
2019-09-20 7.854
2019-10-01 44.559
2019-10-10 46.910
2019-10-20 49.053
2019-11-01 24.881
2019-11-10 52.882
2019-11-20 84.779
2019-12-01 56.215
2019-12-10 23.347
2019-12-20 31.051
Name: mean_rainfall, dtype: float64
我确认确实是一个时间序列
type(y)
pandas.core.series.Series
type(y.index)
pandas.core.indexes.datetimes.DatetimeIndex
从这里开始,我可以毫无问题地通过自相关函数传递时间序列,从而产生预期的输出
plot_acf(y, lags=72, alpha=0.05)
但是,当我尝试将这个完全相同的对象 y
传递给 SARIMA
mod = sm.tsa.statespace.SARIMAX(y.mean_rainfall, order=pdq, seasonal_order=seasonal_pdq)
results = mod.fit()
我收到以下错误:
A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
问题是我的时间序列的频率不规则(每个月的1号、10号和20号),所以我不能设置例如freq='m'
或freq='D'
。这种情况下的解决方法是什么?
我是使用时间序列的新手,任何关于如何在预测期间不忽略我的索引的建议都会有所帮助。这可以防止任何预测成为可能
如我所见,该包使用频率作为一切的前提,因为它是一个时间序列问题。
所以你将无法将它用于不同频率的数据。事实上,您将不得不为您的分析做出假设,以使您的数据足以供使用。一些选项是:
1) 考虑 3 种不同的分析(第 1 天、第 10 天、第 20 天)并使用 30 天的频率。
2) 由于你有 ~10d 等分的数据,你可以考虑使用某种插值,然后将采样频率降低到 1d。当然,此选项仅在取决于问题的性质和数据变化的速度的情况下才有意义。
无论哪种方式,我只想指出,在处理时间序列和数据科学时,如何对问题和数据建模是一个关键。根据我作为数据科学家的经验,我可以说在域(数据的来源)进行分析,您可以感觉到哪种方法效果更好。
首先,理解日期时间列和目标列(rainfall)之间的关系是非常重要的。查看您提供的代码段,我可以想到两种可能性:
- y 表示在当前行日期和下一行日期之间 date-range 发生的降雨量。如果是这种情况,则时间序列是一种聚合降雨量序列,具有不相等的日期桶,即 1-10、10-20、20-(end-of-month)。如果是这种情况,您有两个选择:
- 您可以使用相等的权重或更好的插值来分解数据,以创建连续且相对平滑的时间序列。然后,您可以在每日 time-series 上拟合您的模型,并生成在自然界中自然也是每日的预测。您可以将这些聚合回 1-10、10-20、20-(end-of-month) 个存储桶以获得您的预测。进行重采样的一种方法是使用下面的代码。
ts.Date = pd.to_datetime(ts.Date, format='%d/%m/%y')
ts['delta_time'] = (ts['Date'].shift(-1) - ts['Date']).dt.days
ts['delta_rain'] = ts['Rain'].shift(-1) - ts['Rain']
ts['timesteps'] = ts['Date']
ts['grad_rain'] = ts['delta_rain'] / ts['delta_time']
ts.set_index('timesteps', inplace=True )
ts = ts.resample('d').ffill()
ts
ts['daily_rain'] = ts['Rain'] + ts['grad_rain']*(ts.index - ts['Date']).dt.days
ts['daily_rain'] = ts['daily_rain']/ts['delta_time']
print(ts.head(50))
daily_rain
现在是目标列,index
即 timesteps
是时间戳。
- 另一种选择是您将 1-10、10-20、20-(EOM) 的 date-range 近似为大约 10 天,因此这些确实是相等的时间步长。当然 statsmodel 不允许这样做,因此您需要重置索引以模拟您维护映射的日期时间。以下是您在 statsmodel 中使用的 y 但确实保持映射回您的原始日期。 Freq 将 'd' 或 'daily',您还需要重新调整季节性,使其遵循新的日期范围。
y.tail(10)
2019-09-01 7.854
2019-09-02 44.559
2019-09-03 46.910
2019-09-04 49.053
2019-09-05 24.881
2019-09-06 52.882
2019-09-07 84.779
2019-09-08 56.215
2019-09-09 23.347
2019-09-10 31.051
Name: mean_rainfall, dtype: float64
我会推荐第一个选项,因为它本质上更准确。您也可以在模型训练和预测期间尝试其他聚合级别。更多控制!
- 第二种情况是数据仅表示日期本身的测量值,而不表示范围。这意味着从技术上讲,您现在没有足够的信息来构建准确的时间序列——您的时间步长不是等距的,并且您没有足够的信息来了解时间步长之间发生的事情。但是,您仍然可以即兴创作并获得一些近似值。上面列出的第二种方法仍然可以按原样工作。对于第一种方法,您需要进行插值,但考虑到目标变量降雨量和降雨量变化很大,我强烈建议不要这样做!!
我有一个 pandas 时间序列 y
不能很好地与 statsmodel
函数一起使用。
import statsmodels.api as sm
y.tail(10)
2019-09-20 7.854
2019-10-01 44.559
2019-10-10 46.910
2019-10-20 49.053
2019-11-01 24.881
2019-11-10 52.882
2019-11-20 84.779
2019-12-01 56.215
2019-12-10 23.347
2019-12-20 31.051
Name: mean_rainfall, dtype: float64
我确认确实是一个时间序列
type(y)
pandas.core.series.Series
type(y.index)
pandas.core.indexes.datetimes.DatetimeIndex
从这里开始,我可以毫无问题地通过自相关函数传递时间序列,从而产生预期的输出
plot_acf(y, lags=72, alpha=0.05)
但是,当我尝试将这个完全相同的对象 y
传递给 SARIMA
mod = sm.tsa.statespace.SARIMAX(y.mean_rainfall, order=pdq, seasonal_order=seasonal_pdq)
results = mod.fit()
我收到以下错误:
A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
问题是我的时间序列的频率不规则(每个月的1号、10号和20号),所以我不能设置例如freq='m'
或freq='D'
。这种情况下的解决方法是什么?
我是使用时间序列的新手,任何关于如何在预测期间不忽略我的索引的建议都会有所帮助。这可以防止任何预测成为可能
如我所见,该包使用频率作为一切的前提,因为它是一个时间序列问题。 所以你将无法将它用于不同频率的数据。事实上,您将不得不为您的分析做出假设,以使您的数据足以供使用。一些选项是:
1) 考虑 3 种不同的分析(第 1 天、第 10 天、第 20 天)并使用 30 天的频率。
2) 由于你有 ~10d 等分的数据,你可以考虑使用某种插值,然后将采样频率降低到 1d。当然,此选项仅在取决于问题的性质和数据变化的速度的情况下才有意义。
无论哪种方式,我只想指出,在处理时间序列和数据科学时,如何对问题和数据建模是一个关键。根据我作为数据科学家的经验,我可以说在域(数据的来源)进行分析,您可以感觉到哪种方法效果更好。
首先,理解日期时间列和目标列(rainfall)之间的关系是非常重要的。查看您提供的代码段,我可以想到两种可能性:
- y 表示在当前行日期和下一行日期之间 date-range 发生的降雨量。如果是这种情况,则时间序列是一种聚合降雨量序列,具有不相等的日期桶,即 1-10、10-20、20-(end-of-month)。如果是这种情况,您有两个选择:
- 您可以使用相等的权重或更好的插值来分解数据,以创建连续且相对平滑的时间序列。然后,您可以在每日 time-series 上拟合您的模型,并生成在自然界中自然也是每日的预测。您可以将这些聚合回 1-10、10-20、20-(end-of-month) 个存储桶以获得您的预测。进行重采样的一种方法是使用下面的代码。
ts.Date = pd.to_datetime(ts.Date, format='%d/%m/%y')
ts['delta_time'] = (ts['Date'].shift(-1) - ts['Date']).dt.days
ts['delta_rain'] = ts['Rain'].shift(-1) - ts['Rain']
ts['timesteps'] = ts['Date']
ts['grad_rain'] = ts['delta_rain'] / ts['delta_time']
ts.set_index('timesteps', inplace=True )
ts = ts.resample('d').ffill()
ts
ts['daily_rain'] = ts['Rain'] + ts['grad_rain']*(ts.index - ts['Date']).dt.days
ts['daily_rain'] = ts['daily_rain']/ts['delta_time']
print(ts.head(50))
daily_rain
现在是目标列,index
即 timesteps
是时间戳。
- 另一种选择是您将 1-10、10-20、20-(EOM) 的 date-range 近似为大约 10 天,因此这些确实是相等的时间步长。当然 statsmodel 不允许这样做,因此您需要重置索引以模拟您维护映射的日期时间。以下是您在 statsmodel 中使用的 y 但确实保持映射回您的原始日期。 Freq 将 'd' 或 'daily',您还需要重新调整季节性,使其遵循新的日期范围。
y.tail(10)
2019-09-01 7.854
2019-09-02 44.559
2019-09-03 46.910
2019-09-04 49.053
2019-09-05 24.881
2019-09-06 52.882
2019-09-07 84.779
2019-09-08 56.215
2019-09-09 23.347
2019-09-10 31.051
Name: mean_rainfall, dtype: float64
我会推荐第一个选项,因为它本质上更准确。您也可以在模型训练和预测期间尝试其他聚合级别。更多控制!
- 第二种情况是数据仅表示日期本身的测量值,而不表示范围。这意味着从技术上讲,您现在没有足够的信息来构建准确的时间序列——您的时间步长不是等距的,并且您没有足够的信息来了解时间步长之间发生的事情。但是,您仍然可以即兴创作并获得一些近似值。上面列出的第二种方法仍然可以按原样工作。对于第一种方法,您需要进行插值,但考虑到目标变量降雨量和降雨量变化很大,我强烈建议不要这样做!!