Python中的时间序列分解函数

54

时间序列分解是一种将时间序列数据集分解成三个(或更多)组成部分的方法。例如:

x(t) = s(t) + m(t) + e(t)

在哪里

t is the time coordinate
x is the data
s is the seasonal component
e is the random error term
m is the trend

在Python中,我可以使用scipy.signal.stlpandas.Series.diff函数来实现相同的功能。请注意保留HTML标签。

5个回答

76

我也遇到了类似的问题,正在尝试找到最佳解决方案。尝试将您的数据移入Pandas DataFrame,然后调用StatsModelstsa.seasonal_decompose函数。请看下面的示例

import statsmodels.api as sm

dta = sm.datasets.co2.load_pandas().data
# deal with missing values. see issue
dta.co2.interpolate(inplace=True)

res = sm.tsa.seasonal_decompose(dta.co2)
resplot = res.plot()

从上述输入产生的三个图形

然后,您可以从中恢复分解的各个组件:

res.resid
res.seasonal
res.trend

我希望这可以帮助你!


你如何从这些组件中重新构建出原始的时间序列? - vgoklani
你可以选择通过减法或除法来分解它们。通常使用加法的方法,这种情况下你只需要将组件相加即可。 - AN6U5
在那段代码片段中,哪个变量保存了输入数据? - davneetnarang
dta.co2是输入,但在调用后您也应该能够通过res.observed访问它。 - AN6U5
2
根据StatsModels文档,与STL相比,这是一种天真的分解方法。不确定是参数不好还是什么原因,但您不希望在余数序列中看到这种季节性结构。正如cast42在下面指出的那样,最好使用https://github.com/andreas-h/pyloess。 - user41871
请查看使用Loess进行季节性和趋势分解(STL)的内容:https://github.com/jrmontag/STLDecompose - AChervony

11

我已经在这里回答了这个问题,但下面是一个快速的函数,可以使用rpy2在Python中使用R的稳健统计分解与loess。

    import pandas as pd

    from rpy2.robjects import r, pandas2ri
    import numpy as np
    from rpy2.robjects.packages import importr


def decompose(series, frequency, s_window = 'periodic', log = False,  **kwargs):
    '''
    Decompose a time series into seasonal, trend and irregular components using loess, 
    acronym STL.
    https://www.rdocumentation.org/packages/stats/versions/3.4.3/topics/stl

    params:
        series: a time series

        frequency: the number of observations per “cycle” 
                   (normally a year, but sometimes a week, a day or an hour)
                   https://robjhyndman.com/hyndsight/seasonal-periods/

        s_window: either the character string "periodic" or the span 
                 (in lags) of the loess window for seasonal extraction, 
                 which should be odd and at least 7, according to Cleveland 
                 et al.

        log:    boolean.  take log of series



        **kwargs:  See other params for stl at 
           https://www.rdocumentation.org/packages/stats/versions/3.4.3/topics/stl
    '''

    df = pd.DataFrame()
    df['date'] = series.index
    if log: series = series.pipe(np.log)
    s = [x for x in series.values]
    length = len(series)
    s = r.ts(s, frequency=frequency)
    decomposed = [x for x in r.stl(s, s_window).rx2('time.series')]
    df['observed'] = series.values
    df['trend'] = decomposed[length:2*length]
    df['seasonal'] = decomposed[0:length]
    df['residuals'] = decomposed[2*length:3*length]
    return df

以上函数假定您的时间序列具有日期时间索引。它返回一个包含各个组件的数据框,您可以使用您喜欢的绘图库来绘制它们。

您可以传递stl参数,在此处查看,但将任何周期更改为下划线,例如上面函数中的位置参数是s_window,但在上面链接中它是s.window。此外,我在这个存储库中找到了一些上面的代码。

示例数据

希望以下数据有效,老实说我自己没有试过,因为这是我回答问题之后很久的一个请求。

import pandas as pd
import numpy as np
obs_per_cycle = 52
observations = obs_per_cycle * 3
data = [v+2*i for i,v in enumerate(np.random.normal(5, 1, observations))]
tidx = pd.date_range('2016-07-01', periods=observations, freq='w')
ts = pd.Series(data=data, index=tidx)
df = decompose(ts, frequency=obs_per_cycle, s_window = 'periodic')

这个库能在Python 3中使用吗?还是只能在Python 2中使用? - Tanguy
1
这与statsmodels方法相比如何? - dstandish
@chorbs 来自 stats 的内容是:"这是一种简单的分解方法。更复杂的方法应该被优先考虑。" 来自 OTexts 的内容是:"STL 是一种非常多才多艺且强大的时间序列分解方法... STL 相对于经典分解方法和 X-12-ARIMA 有几个优点..." - Jeff Tilton
1
@Tanguy,这几乎就是我的确切设置。使用rpy2可能会感觉有点不正规,如果你要进行大量的时间序列分析,R现在可能是两者中更强大的语言,并且只需轻松运行即可。Rob Hyndman的预测包在R中非常稳定,而且没有任何麻烦。 - Jeff Tilton
1
@Googme 只需要一个 pandas series。它期望一个 datetime 索引,但即使没有也可能运行。我在上面放了一个例子,但还没有测试过。 - Jeff Tilton
显示剩余3条评论

5

该调用目前无法正常工作。不确定原因。 - Toly

0

你是否已经了解scipy?从我在一些PDF/网站上看到的内容来看,

这里这里

它是可行的。但如果没有看到具体的示例,对于某人来展示代码示例将会很困难。Scipy非常棒,我在我的研究中使用它,它从未让我失望。


3
是的,我目前正在使用Scipy,包括statsmodel、pandas和numpy。我能找到的最接近的东西是使用pandas中的“resample”,但它不能让你去季节性调整一个时间序列。 - user3084006
scipy可以进行优化,但无法提供额外所需的内容,例如statsmodels.tsa中的AR模型可以提供 - 包括模型验证和预测的置信区间。如果使用scipy.signal.minimize/maximize,您将需要自行完成其余部分。 - JeeyCi
除了“自相关因子”之外,在从AR系列调整模型时,还可以轻松调整适当的周期/季节性用于ARIMA/SARIMA模型。 - JeeyCi

0
也可以使用LOESS进行季节性趋势分解(STL)
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import statsmodels.api as sm

dta = sm.datasets.co2.load_pandas().data

# deal with missing values
dta.co2.interpolate(inplace=True)

#################### sm.tsa.seasonal_decompose
##res = sm.tsa.seasonal_decompose(dta.co2)
##resplot = res.plot()
##plt.show()

#################### Seasonal-Trend decomposition using LOESS (STL)
## https://www.statsmodels.org/dev/examples/notebooks/generated/stl_decomposition.html

from statsmodels.tsa.seasonal import STL

stl = STL(dta.co2, seasonal=13)
##stl = STL(dta.co2, period=12, seasonal_deg=0, trend_deg=1, low_pass_deg=1, robust=True)
res = stl.fit()
fig = res.plot()
plt.show()

trend = res.trend
seasonal = res.seasonal
residual = res.resid

df = pd.concat([res.trend, res.seasonal, res.resid], 1)
print(df)

使用STL残差一瞥似乎更接近正态分布(在较大程度上类似白噪声)... 仍在此处发表评论这里

seasonal_decompose使用移动平均,而不是LOESS。

P.S. 使用SARIMA进行建模比手动分解得到的结果更合理 - 尽管结果可能是可比较的 - 例如


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接