and*_*and 13 python time-series matplotlib decomposition pandas
正确执行加法模型有一些问题。
当我运行此代码时:
import statsmodels as sm
import statsmodels.api as sm
decomposition = sm.tsa.seasonal_decompose(df, model = 'additive')
fig = decomposition.plot()
matplotlib.rcParams['figure.figsize'] = [9.0,5.0]
Run Code Online (Sandbox Code Playgroud)
我收到了这条消息:
ValueError: 您必须指定一个句点或 x 必须是一个带有 DatetimeIndex 且频率未设置为 None 的 Pandas 对象
上面我从这个地方截取的屏幕https://towardsdatascience.com/analyzing-time-series-data-in-pandas-be3887fdd621
que*_*o42 16
具有相同的 ValueError,这只是我自己的一些测试和少量研究的结果,并没有声称它是完整的或专业的。请评论或回答任何发现错误的人。
当然,您的数据应该按照索引值的正确顺序排列,您可以使用 来保证df.sort_index(inplace=True)这一点,正如您在答案中所述。这本身并没有错,尽管错误消息与排序顺序无关,而且我已经检查过这一点:在我对手头的巨大数据集的索引进行排序时,错误不会消失。是的,我也必须对 df.index 进行排序,但是分解()也可以处理未排序的数据以及项目在此处和那里及时跳转的情况:然后您只需从左到右再向后得到很多蓝线,直到整个图都填满它。更重要的是,通常情况下,排序已经是正确的顺序了。就我而言,排序无助于修复错误。因此,我也怀疑索引排序是否修复了您的情况下的错误,因为:错误实际上说明了什么?
值错误:您必须指定:
首先,如果您有一个列表列,以便您的时间序列嵌套到现在,请参阅将带有“列表列”中数据的 pandas df 转换为长格式的时间序列。使用三列:[数据列表] + [时间戳] + [持续时间]了解如何取消嵌套列表列的详细信息。这对于 1.) 和 2.) 都是需要的。
期间的定义
“期间,整数,可选”来自https://www.statsmodels.org/stable/generated/statsmodels.tsa.seasonal.seasonal_decompose.html:
系列的时期。如果 x 不是 Pandas 对象或者 x 的索引没有频率,则必须使用。如果 x 是具有时间序列索引的 Pandas 对象,则覆盖 x 的默认周期。
用整数设置的 period 参数表示您希望在数据中出现的周期数。如果您有一个 df 有 1000 行,其中有一个列表列(称为 df_nested),并且每个列表有例如 100 个元素,那么每个周期将有 100 个元素。period = len(df_nested)为了获得季节性和趋势的最佳分割,这可能是明智的选择(= 周期数)。如果每个周期的元素随时间变化,其他值可能会更好。
我不确定如何正确设置参数,因此问题statsmodels season_decompose(): What is the right “period of the series” on a list column (constant vs. variables of items) on Cross Validated which还没有回答。
选项 1.) 的“期间”参数比选项 2.) 有很大的优势。尽管它使用时间索引 (DatetimeIndex) 作为其 x 轴,但与选项 2 相比,它不需要项目准确地达到频率。)。相反,它只是将一行中的任何内容连接在一起,优点是您不需要填充任何间隙:前一个事件的最后一个值只是与下一个事件的下一个值连接,无论它是否已经在下一秒或第二天。
最大可能的“周期”值是多少?如果你有一个列表的列(称之为DF“df_nested”了),你应该先UNNEST的名单列到一个正常的列。最大周期为len(df_unnested)/2。
示例 1:x 中的 20 个项目(x 是 df_unnested 的所有项目的数量)最多可以有一个period = 10.
示例 2:拥有 20 个项目并period=20取而代之,这会引发以下错误:
ValueError:x 必须有 2 个完整的周期需要 40 个观察值。x 只有 20 个观察值
另一个旁注:要摆脱有问题的错误,period = 1应该已经把它去掉了,但对于时间序列分析,“=1”并没有显示任何新内容,每个周期只有1个项目,趋势与原始数据,季节性为0,残差始终为0。
####
df_test = pd.DataFrame({'timestamp': [1462352000000000000, 1462352100000000000, 1462352200000000000, 1462352300000000000],
'listData': [[1,2,1,9], [2,2,3,0], [1,3,3,0], [1,1,3,9]],
'duration_sec': [3.0, 3.0, 3.0, 3.0]})
tdi = pd.DatetimeIndex(df_test.timestamp)
df_test.set_index(tdi, inplace=True)
df_test.drop(columns='timestamp', inplace=True)
df_test.index.name = 'datetimeindex'
df_test = df_test.explode('listData')
sizes = df_test.groupby(level=0)['listData'].transform('size').sub(1)
duration = df_test['duration_sec'].div(sizes)
df_test.index += pd.to_timedelta(df_test.groupby(level=0).cumcount() * duration, unit='s')
Run Code Online (Sandbox Code Playgroud)
结果 df_test['listData'] 如下所示:
2016-05-04 08:53:20 1
2016-05-04 08:53:21 2
2016-05-04 08:53:22 1
2016-05-04 08:53:23 9
2016-05-04 08:55:00 2
2016-05-04 08:55:01 2
2016-05-04 08:55:02 3
2016-05-04 08:55:03 0
2016-05-04 08:56:40 1
2016-05-04 08:56:41 3
2016-05-04 08:56:42 3
2016-05-04 08:56:43 0
2016-05-04 08:58:20 1
2016-05-04 08:58:21 1
2016-05-04 08:58:22 3
2016-05-04 08:58:23 9
Run Code Online (Sandbox Code Playgroud)
现在看看不同时期的整数值。
period = 1:
result_add = seasonal_decompose(x=df_test['listData'], model='additive', extrapolate_trend='freq', period=1)
plt.rcParams.update({'figure.figsize': (5,5)})
result_add.plot().suptitle('Additive Decompose', fontsize=22)
plt.show()
Run Code Online (Sandbox Code Playgroud)
period = 2:
result_add = seasonal_decompose(x=df_test['listData'], model='additive', extrapolate_trend='freq', period=2)
plt.rcParams.update({'figure.figsize': (5,5)})
result_add.plot().suptitle('Additive Decompose', fontsize=22)
plt.show()
Run Code Online (Sandbox Code Playgroud)
如果您将所有项目的四分之一作为一个周期,这里是 4 个(共 16 个项目)。
period = 4:
result_add = seasonal_decompose(x=df_test['listData'], model='additive', extrapolate_trend='freq', period=int(len(df_test)/4))
plt.rcParams.update({'figure.figsize': (5,5)})
result_add.plot().suptitle('Additive Decompose', fontsize=22)
plt.show()
Run Code Online (Sandbox Code Playgroud)
或者,如果您在此处采用循环的最大可能大小,即 8 个(共 16 个项目)。
period = 8:
result_add = seasonal_decompose(x=df_test['listData'], model='additive', extrapolate_trend='freq', period=int(len(df_test)/2))
plt.rcParams.update({'figure.figsize': (5,5)})
result_add.plot().suptitle('Additive Decompose', fontsize=22)
plt.show()
Run Code Online (Sandbox Code Playgroud)
看看 y 轴如何改变它们的比例。
####
您将根据需要增加周期整数。您的问题的最大值:
sm.tsa.seasonal_decompose(df, model = 'additive', period = int(len(df)/2))
Run Code Online (Sandbox Code Playgroud)
要让 x 成为一个频率未设置为 None 的 DatetimeIndex,您需要使用 .asfreq('?') 和 ? 是您在https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#offset-aliases 的各种偏移别名中的选择。
在您的情况下,此选项 2. 更适合您,因为您似乎有一个没有空白的列表。您的月度数据可能应该被引入为“月开始频率”-->“MS”作为偏移别名:
sm.tsa.seasonal_decompose(df.asfreq('MS'), model = 'additive')
Run Code Online (Sandbox Code Playgroud)
请参阅如何使用 pd.to_datetime() 设置频率?有关更多详细信息,以及有关如何处理差距的信息。
如果您的数据在时间上高度分散,以至于有太多空白需要填补,或者如果时间空白并不重要,则使用“句点”的选项 1 可能是更好的选择。
在我的 df_test 示例中,选项 2. 不好。数据在时间上完全分散,如果我以一秒为频率,你会得到:
输出df_test.asfreq('s')(=频率以秒为单位):
2016-05-04 08:53:20 1
2016-05-04 08:53:21 2
2016-05-04 08:53:22 1
2016-05-04 08:53:23 9
2016-05-04 08:53:24 NaN
...
2016-05-04 08:58:19 NaN
2016-05-04 08:58:20 1
2016-05-04 08:58:21 1
2016-05-04 08:58:22 3
2016-05-04 08:58:23 9
Freq: S, Name: listData, Length: 304, dtype: object
Run Code Online (Sandbox Code Playgroud)
你在这里看到,虽然我的数据只有 16 行,但引入以秒为单位的频率迫使 df 为 304 行,只能从“08:53:20”到“08:58:23”,这里造成 288 个间隙. 更重要的是,在这里你必须打准确的时间。如果您将 0.1 甚至 0.12314 秒作为您的实际频率,则您将不会命中大多数带有索引的项目。
这是一个以 min 作为偏移别名的示例df_test.asfreq('min'):
2016-05-04 08:53:20 1
2016-05-04 08:54:20 NaN
2016-05-04 08:55:20 NaN
2016-05-04 08:56:20 NaN
2016-05-04 08:57:20 NaN
2016-05-04 08:58:20 1
Run Code Online (Sandbox Code Playgroud)
我们看到只有第一分钟和最后一分钟被填满,其余的没有被击中。
以天作为偏移别名,df_test.asfreq('d'):
2016-05-04 08:53:20 1
Run Code Online (Sandbox Code Playgroud)
我们看到您只得到第一行作为结果 df,因为只有一天覆盖。它会给你找到的第一个项目,其余的被丢弃。
将所有这些放在一起,在您的情况下,请选择选项 2。而在我的 df_test 示例中,需要选项 1。
小智 5
我遇到了同样的问题,最终证明(至少在我的情况下)是数据集中丢失数据点的问题。在示例中,我有一段时间内的每小时数据,并且缺少 2 个单独的每小时数据点(在数据集的中间)。所以我得到了同样的错误。当在没有丢失数据点的不同数据集上进行测试时,它的工作没有任何错误消息。希望这可以帮助。这不完全是一个解决方案。