数学建模时序数据分析——趋势性检验和平稳性检验

数学建模数据分析——趋势性检验和平稳性检验

在数学建模比赛中,经常需要对数据进行分析和预处理,常见的比如趋势分析(上升/下降/无明显趋势)和突变分析,很多时候靠人的经验观察得出结论,但这是不够严谨的。于是我们通常会采用一些更科学的方法,下面我们就来详细的捋一遍数据分析检验方法:

文章目录

  • 数学建模数据分析——趋势性检验和平稳性检验
    • 时间序列趋势性检验方法
      • 斜率法
      • Cox-Stuart检验法
      • Mann-Kendall检验法
    • 时间序列平稳性检验方法
      • 平稳时间序列定义与性质
      • 检验方法
        • 时序图检验法
        • 自相关图检验法
        • ADF检验法
        • KPSS检验
    • 非常有用的相关链接

时间序列趋势性检验方法

斜率法

原理

斜率法就是使用最小二乘法对时序数据进行拟合,根据拟合的直线的斜率K来判断序列的数据走势,当K>0时,则代表上升趋势;当k<0时,则代表下降趋势;

优缺点

优点为使用简单;缺点是要求数据是线性的,当数据波动较大时无法准确拟合,导致丧失了评价意义。

Cox-Stuart检验法

原理

直接考虑数据的变化趋势,若数据呈现上升趋势,则排在后面的数据的值要比排在前面的数据的值显著的大;反之,若数据呈现下降趋势,则排在后面的数据的值要比排在前面的数据的值显著的小。该方法利用前后两个时期不同数据的差值的正负来判断数据的总的变化趋势。

算法步骤

  1. x i x_i xi x i + c x_i+c xi+c组成一对 ( x i , x i + c ) (xi,xi+c) (xi,xi+c)。这里如果 n n n为偶数,则 c = n / 2 c=n/2 c=n/2,如果 n n n是奇数,则 c = ( n + 1 ) / 2 c=(n+1)/2 c=(n+1)/2。当n为偶数时,共有 n ’ = c n’=c n=c对,而 n n n是奇数时,共有 n ’ = c − 1 n’=c-1 n=c1对。
  2. 用每一对的两元素差 D i = x i − x i + c D_i=x_i−x_{i+c} Di=xixi+c的符号来衡量增减。令 S + S_+ S+为正的 D i D_i Di的数目, S − S_− S为负的 D i D_i Di的数目。显然当正号太对时有下降趋势,反之有增长趋势。在没有趋势的零假设下他们因服从二项分布 B ( n ’ , 0.5 ) B(n’,0.5) B(n,0.5)
  3. p ( + ) p(+) p(+)表示取到正数的概率,用 p ( − ) p(-) p()表示取到负数的概率,这样就得到符号检验方法来检验序列是否存在趋势性。

优缺点

优点是不依赖趋势结构,可以快速判断趋势是否存在;缺点是未考虑数据的时序性,仅从符号检验来判断

实现代码

假设有下面一个时序数据,波动性较大,无法根据经验判断数据呈上升还是下降趋势。

import matplotlib.pyplot as plt

a_array = [206,223,235,264,229,217,188,204,182,230,223,227,242,238,207,208,
           216,233,233,274,234,227,221,214,226,228,235,237,243,240,231,210]

plt.plot(range(1, len(a_array) + 1), a_array)

数学建模时序数据分析——趋势性检验和平稳性检验_第1张图片

统计正的 D i D_i Di出现次数为14次,负的 D i D_i Di出现次数为2次,接下来判断是否存在显著的上升趋势

做出原假设 H 0 H_0 H0:该数据不存在上升趋势;

做出替代假设 H 1 H_1 H1:该数据存在上升趋势。

运行CS趋势检验方法,可以发现,使用二项式离散分布检验得到p-value值为0.004181,小于0.05,因此有理由认为原假设 H 0 H_0 H0不成立,从而支持假设 H 1 H_1 H1:该数据存在上升趋势

import numpy as np
import pandas as pd
import scipy.stats as stats

def cox_staut(list_c):
    lst=list_c.copy() ## 副本
    n0 = len(lst) ##列表长度
    
    ## 判断奇偶性
    if n0%2 == 1:
        del lst[int((n0-1)/2)] #奇数删除中间数值
        
    ## 配对前后数据
    c=int(len(lst)/2)
    ## 统计正Di和负Di出现次数
    pos=neg=0
    for i in range(c):
        diff=lst[i+c]-lst[i]
        if diff>0:
            pos+=1
        elif diff<0:
            neg+=1
        else:
            continue
    
    n1=pos+neg
    k=min(pos,neg)
    ## 使用二项式离散分布检验趋势是否显著
    p=2*stats.binom.cdf(k,n1,0.5)
    print('fall:%i  rise:%i  p-value:%f'%(neg, pos, p))

cox_staut(a_array)
fall:2  rise:14  p-value:0.004181

Mann-Kendall检验法

原理
Mann-Kendall检验不需要样本遵循一定的分布,也不受少数异常值的干扰。在Mann-Kendall检验中,原假设 H 0 H_0 H0为时间序列数据 ( X 1 , … , X n ) (X1,…,Xn) (X1,Xn),是 n n n个独立的、随机变量同分布的样本;备择假设 H 1 H_1 H1 是双边检验,对于所有的 k , j ≤ n k,j≤n kjn,且 k ≠ j k≠j k=j X k X_k Xk X j X_j Xj的分布是不相同的。若原假设是不可接受的,即在α置信水平上,时间序列数据存在明显的上升或下降趋势。对于统计量 Z Z Z,大于0时是上升趋势;小于0时是下降趋势。

算法步骤

  1. 将数据按采集时间列出: x 1 , x 2 , … , x n x_1,x_2,…,x_n x1,x2,,xn,即分别在时间 1 , 2 , … , n 1,2,…,n 1,2,,n得到的数据。

  2. 确定所有 n ( n − 1 ) / 2 n(n-1)/2 n(n1)/2 x j − x k xj−xk xjxk差值的符号,其中 j > k j > k j>k,,这些差值是: x 2 − x 1 , x 3 − x 1 , … , x n − x 1 , x 3 − x 2 , x 4 − x 2 , … , x n − x n − 2 , x n − x n − 1 x_2 - x_1,x_3 - x_1, … , x_n - x_1,x_3 - x_2,x_4 - x_2,…,x_n - x_{n-2},x_n - x_{n-1} x2x1x3x1,,xnx1x3x2x4x2xnxn2xnxn1

  3. s g n ( x j − x k ) sgn(x_j−x_k) sgn(xjxk)作为指示函数,依据 x j − x k x_j−x_k xjxk的正负号取值为1,0或-1,即
    s g n ( x j − x k ) = { 1 , x j − x k > 0 − 1 , x j − x k < 0 0. x j − x k = 0 sgn(x_j-x_k)= \begin{cases} 1, x_j − x_k > 0\\ -1, x_j − x_k < 0\\ 0. x_j − x_k = 0 \end{cases} sgn(xjxk)=1,xjxk>01,xjxk<00.xjxk=0

  4. 计算 S = ∑ k − 1 n − 1 ∑ j − k + 1 n s g n ( x j − x k ) S=∑^{n−1}_{k−1}∑^n_{j−k+1}sgn(x_j−x_k) S=k1n1jk+1nsgn(xjxk)。即差值为正的数量减去差值为负的数量。如果 S S S是一个正数,那么后一部分的观测值相比之前的观测值会趋向于变大;如果S是一个负数,那么后一部分的观测值相比之前的观测值会趋向于变小。

  5. 如果 n ≤ 10 n \leq 10 n10,依据Gilbert (1987, page 209, Section 16.4.1)中所描述的程序,接下来要在概率表 (Gilbert 1987, Table A18, page 272) 中查找 S S S。如果此概率小于 α \alpha α(认为没有趋势时的截止概率),那就拒绝零假设,认为趋势存在。如果在概率表中找不到n(存在结数据——tied data values——会发生此情况),就用表中远离0的下一个值。比如 S = 12 S=12 S=12,如果概率表中没有 S = 12 S=12 S=12,那么就用 S = 13 S=13 S=13来处理也是一样的。
    如果 n > 10 n > 10 n>10,则依以下步骤6-10来判断有无趋势。这里遵循的是Gilbert (1987, page 211, Section 16.4.2)中的程序。

  6. 计算S的方差如下: V A R ( S ) = 1 18 [ n ( n − 1 ) ( 2 n + 5 ) − ∑ p − 1 g t p ( t p − 1 ) ( 2 t p + 5 ) ] VAR(S)=\frac{1}{18}[n(n−1)(2n+5)−∑^g_{p−1}t_p(t_p−1)(2t_p+5)] VAR(S)=181[n(n1)(2n+5)p1gtp(tp1)(2tp+5)]。其中 g g g是结组(tied groups)的数量, t p t_p tp是第p组的观测值的数量。例如:在观测值的时间序列 23 , 24 , 29 , 6 , 29 , 24 , 24 , 29 , 23 {23, 24, 29, 6, 29, 24, 24, 29, 23} 23,24,29,6,29,24,24,29,23中有 g = 3 g = 3 g=3个结组,相应地,对于结值(tiied value)23有 t 1 = 2 t_1=2 t1=2、结值24有 t 2 = 3 t_2=3 t2=3、结值29有 t 3 = 3 t_3=3 t3=3。当因为有相等值或未检测到而出现结时, V A R ( S ) VAR(S) VAR(S)可以通过Helsel (2005, p. 191)中的结修正方法来调整。

  7. 计算MK检验统计量Z_{MK}:
    Z M K = { S − 1 V A R ( S ) , S > 0 0 , S = 0 S + 1 V A R ( S ) , S > 0 Z_{MK}=\begin{cases} \frac{S-1}{\sqrt{VAR(S)}},& S>0\\ \qquad0\quad,& S=0\\ \frac{S+1}{\sqrt{VAR(S)}},& S>0 \end{cases} ZMK=VAR(S) S1,0,VAR(S) S+1,S>0S=0S>0
    设想要测试零假设。 H 0 H_0 H0(没有单调趋势)对比替代假设Ha(有单调增趋势),其1型错误率为α,0<α<0.50(注意α是MK检验错误地拒绝了零假设时可容忍的概率——即MK检验拒绝了零假设是错误地,但这个事情发生概率是α,我们可以容忍这个错误)。如果 Z M K ≥ Z 1 − α Z_{MK}≥Z_1−α ZMKZ1α,就拒绝零假设H0,接受替代假设 H a H_a Ha,其中 Z 1 − α Z_1−α Z1α是标准正态分布的100(1−α)th百分位。

  8. 测试上面的H0与Ha(有单调递减趋势),其1型错误率为alpha,0<α<0.5,如果ZZMK≤–Z1−α,就拒绝零假设H0,接受替代假设Ha

  9. 测试上面的H0与Ha(有单调递增或递减趋势),其1型错误率为alpha,0<α<0.5,如果|ZMK|≥Z1−α2,就拒绝零假设H0,接受替代假设Ha,其中竖线代表绝对值。

实现代码

笔者自己找了一个时序数据,长度为2000,由于数据较长,就不再展示了。由时序图可以看出该数据波动性较大,无法根据经验判断数据呈上升还是下降趋势。

plt.plot(range(1, len(b_array) + 1), b_array)

数学建模时序数据分析——趋势性检验和平稳性检验_第2张图片

根据上述提供的思路,做出假设,并判断数据的变化趋势。

运行MK趋势检验方法,可以发现,P-value值为4.10e-12,小于给定的显著性水平,因此有理由认为该时序数据呈现上升趋势。

import math
from scipy.stats import norm, mstats
import numpy as np

def mk_test(x, alpha=0.05):
    n = len(x)

    # calculate S
    s = 0
    for k in range(n-1):
        for j in range(k+1, n):
            s += np.sign(x[j] - x[k])

    # calculate the unique data
    unique_x, tp = np.unique(x, return_counts=True)
    g = len(unique_x)

    # calculate the var(s)
    if n == g:  # there is no tie
        var_s = (n*(n-1)*(2*n+5))/18
    else:  # there are some ties in data
        var_s = (n*(n-1)*(2*n+5) - np.sum(tp*(tp-1)*(2*tp+5)))/18

    if s > 0:
        z = (s - 1)/np.sqrt(var_s)
    elif s < 0:
        z = (s + 1)/np.sqrt(var_s)
    else: # s == 0:
        z = 0

    # calculate the p_value
    p = 2*(1-norm.cdf(abs(z)))  # two tail test
    h = abs(z) > norm.ppf(1-alpha/2)

    if (z < 0) and h:
        trend = 'decreasing'
    elif (z > 0) and h:
        trend = 'increasing'
    else:
        trend = 'no trend'

    return trend, p, h

mk_test(b_array)
('increasing', 4.100275674545628e-12, True)

时间序列平稳性检验方法

平稳时间序列定义与性质

平稳时间序列按照限定条件的严格程度可以分为以下两种类型:

严平稳时间序列:严平稳顾名思义,是一种条件非常苛刻的平稳性,它要求序列随着时间的推移,其统计性质保持不变。

{ X t } \{X_t\} {Xt}为一时间序列,对任意的正整数 m m m,任取 t 1 , t 2 , ⋯   , t m ∈ T t_1, t_2, \cdots, t_m ∈ T t1,t2,,tmT,对任意整数 τ \tau τ,其联合概率密度函数满足:

F t 1 , t 2 , ⋯   , t m ( x 1 , x 2 , ⋯   , x m ) = F t 1 + τ , t 2 + τ , ⋯   , t m + τ ( x 1 , x 2 , ⋯   , x m ) F_{t_1, t_2,\cdots,t_m} (x_1, x_2, \cdots, x_m)= F_{t_{1+\tau}, t_{2+\tau}, \cdots, t_{m+\tau}}(x_1, x_2, \cdots, x_m) Ft1,t2,,tm(x1,x2,,xm)=Ft1+τ,t2+τ,,tm+τ(x1,x2,,xm)
则称时间序列 { X t } \{X_t\} {Xt}为严平稳时间序列。严平稳的条件只是理论上的存在,现实中用得比较多的是宽平稳的条件。

宽平稳时间序列:宽平稳也叫弱平稳或者二阶平稳(均值和方差平稳),满足:

  1. 均值为常数,即
    E ( X t ) = u , ∀ t ∈ T E(X_t)=u,\quad \forall t \in T E(Xt)=u,tT

  2. 方差为常数
    D ( X t ) = γ ( t , t ) = γ ( 0 ) , ∀ t ∈ T D(X_t)=\gamma(t,t)=\gamma(0), \quad \forall t \in T D(Xt)=γ(t,t)=γ(0),tT

  3. 自协方差为常数,即自协方差函数和自相关系数只依赖于时间的平移长度,而与时间的起点无关。
    γ ( t , s ) = γ ( k , k + s − t ) , ∀ t , s , k ∈ T \gamma(t,s)=\gamma(k, k+s-t),\quad \forall t,s,k \in T γ(t,s)=γ(k,k+st),t,s,kT
    因此,可以记 γ ( k ) \gamma(k) γ(k)为时间序列 { X t } \{X_t\} {Xt}的延迟 k k k自协方差函数。

在现实生活中,时间序列是很难满足严平稳时间序列的要求的,因此,一般所讲的平稳时间序列在默认情况下都是指宽平稳时间序列。

由于平稳时间序列具有这些优良性质,因此,对于一个平稳时间序列来说,其待估计的参数量就变得少了很多,因为他们的均值、方差都是一样的,因此,可以利用全部的样本来估计总体的均值和方差,即:
μ ^ = x ˉ = ∑ i = 1 n x n γ ^ ( 0 ) = ∑ t − 1 n ( x t − x ˉ ) 2 n − 1 \hat \mu = \bar x = \frac{\sum_{i=1}^nx}{n}\\ \hat \gamma(0) = \frac{\sum_{t-1}^{n}(x_t - \bar x)^2}{n-1} μ^=xˉ=ni=1nxγ^(0)=n1t1n(xtxˉ)2
所以当拿到一个时间序列后,需要对其进行平稳性检验。

检验方法

平稳性检验的主要方法是看时序图、ACF图和单位根检验,其中单位根检验方法有ADF、PP、KPSS等。其中ADF和PP检验都拒绝原假设,即认为序列平稳;KPSS拒绝原假设,即认为序列非平稳(KPSS零假设和ADF/PP恰好相反)。当出现不一致时,需要根据属于下面哪种平稳过程来判断,有一种观点认为KPSS检验结果更强更鲁棒,因为ADF和PP检验将差分平稳模型作为零假设,它检验随机游走或带漂移的随机游走效果奇好,但它们都需要假设是否包含常数均值和时间趋势,因此拒绝零假设的功效(low power)较低,而KPSS则完全不需要选择假设类型。

时序图检验法

那么,当拿到一个时间序列后,应该如何对其进行平稳性的检验呢?目前,对时间序列的平稳性检验主要有两种方法,一种是图检法,即根据时序图和自相关图进行直观判断,另一种是构造检验统计量的方法,目前主要有单位根检验法。
    对于图检法,我们一般绘制时间序列的时序图,如下图所示,如果时间序列是平稳的,那么序列应该是围绕某一个均值上下随机波动,而下图中的序列明显具有一定的增长趋势,因此,可以断定该序列肯定不是平稳时间序列。
数学建模时序数据分析——趋势性检验和平稳性检验_第3张图片

自相关图检验法

对于平稳时间序列,其自相关图一般随着阶数的递增,自相关系统会迅速衰减至0附近,而非平稳时间序列则可能存在先减后增或者周期性波动等变动。如下图所示,该时间序列随着阶数的递增,自相关系数始终在 [ 0.8 , 1 ] [0.8,1] [0.8,1]之间,衰减微弱,因此,可以判断该时间序列不是平稳时间序列。

from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

plot_acf(b_array)
plot_pacf(b_array)

数学建模时序数据分析——趋势性检验和平稳性检验_第4张图片

数学建模时序数据分析——趋势性检验和平稳性检验_第5张图片

除了上述两种方法,便是单位根检验,下面这张图对单位根检验做了很好地说明。

数学建模时序数据分析——趋势性检验和平稳性检验_第6张图片

ADF检验法

在使用很多时间序列模型的时候,如 ARMA、ARIMA,都会要求时间序列是平稳的,所以一般在研究一段时间序列的时候,第一步都需要进行平稳性检验,除了用肉眼检测的方法,另外比较常用的严格的统计检验方法就是ADF检验,也叫做单位根检验。

ADF检验全称是 Augmented Dickey-Fuller test,顾名思义,ADF是 Dickey-Fuller检验的增广形式。DF检验只能应用于一阶情况,当序列存在高阶的滞后相关时,可以使用ADF检验,所以说ADF是对DF检验的扩展。
原理

ADF检验就是判断序列是否存在单位根:如果序列平稳,就不存在单位根;否则,就会存在单位根。

所以,ADF检验做出的假设为:

**原假设 H 0 H_0 H0*假设原时序数据不平稳,即存在单位根;

替代假设 H 1 H_1 H1:原时序数据平稳,即不存在单位根。

如果得到的显著性检验统计量小于三个置信度(10%,5%,1%),则对应有(90%,95,99%)的把握来拒绝原假设。

实现代码

我们仍然使用之前的那段时间序列数据来检验平稳性,从时序图上看,直观感受该数据为非平稳数据,但缺少严格科学依据。

import pandas as pd
import numpy as np

a_array = [206,223,235,264,229,217,188,204,182,230,223,227,242,238,207,208,
           216,233,233,274,234,227,221,214,226,228,235,237,243,240,231,210]

import matplotlib.pyplot as plt
plt.plot(a_array)

数学建模时序数据分析——趋势性检验和平稳性检验_第7张图片

可以看到,ADF检验该数据的p-value值为0.438>0.05,因此有理由认为该数据是不平稳的。

这里的5%是常用的阈值,也可以根据自己的实际需求进行设定。

from statsmodels.tsa.stattools import adfuller

dftest = adfuller(a_array, autolag='AIC')
dftest

if dftest[1]>0.05:
    print("当前接通率不平稳")
else:
    print(dftest)
    print("当前接通率平稳")
(-1.68597312727734,
 0.43835364827956663,
 10,
 21,
 {'1%': -3.7883858816542486,
  '5%': -3.013097747543462,
  '10%': -2.6463967573696143},
 172.30195618901666)

ADF检验输出参数说明:

第一个值:表示Test Statistic , 即T值,表示T统计量

第二个值:p-value,即p值,表示T统计量对应的概率值

第三个值:Lags Used,即表示延迟

第四个值:Number of Observations Used,即表示测试的次数

大括号中的值,分别表示1%, 5%, 10% 的三个level。

KPSS检验

KPSS检验是另一种用于检查时间序列的平稳性 (与迪基-福勒检验相比稍逊一筹) 的统计检测方法。KPSS检验的原假设与备择假设与ADF检验的原假设与备择假设相反,常造成混淆。

KPSS检验的作者将原假设定义为趋势平稳的过程,并将备择假设定义为单位根序列。我们将在下一节详细了解趋势平稳。现在,来看一下KPSS检验的实现,并查看KPSS检验的结果。

做出原假设 H 0 H_0 H0:该时间序列是趋势平稳的;

替代假设 H 1 H_1 H1:该时间序列不是趋势平稳的。

KPSS检验-检验统计量、p-值和临界值和置信区间分别为1%、2.5%、5%和10%。对于航空乘客数据集的检验结果如下,在所有置信区间,检验统计量的值都大于临界值,因此可以说该序列是趋势平稳的。

from statsmodels.tsa.stattools import kpss
import pandas as pd

a_array = [206,223,235,264,229,217,188,204,182,230,223,227,242,238,207,208,
           216,233,233,274,234,227,221,214,226,228,235,237,243,240,231,210]

#define KPSS
def kpss_test(timeseries):
    kpss_test = kpss(timeseries)
    kpss_output = pd.Series(kpss_test[:3], index=['Test Statistic', 'p-value', 'Lags Used'])
    for key, value in kpss_test[3].items():
        kpss_output['Critical Value (%s)'%key] = value
    print(kpss_output)
    
kpss_test(a_array)
Test Statistic            0.238598
p-value                   0.100000
Lags Used                10.000000
Critical Value (10%)      0.347000
Critical Value (5%)       0.463000
Critical Value (2.5%)     0.574000
Critical Value (1%)       0.739000
dtype: float64

非常有用的相关链接

以上内容均为学习过程中的一点小笔记,以防自己遗忘,仅供学习参考

趋势性检验方法

利用python进行时间序列分析——数据挖掘https://zhuanlan.zhihu.com/p/35128342
python中的Mann-Kendall单调趋势检验–及原理说明:https://blog.csdn.net/liuchengzimozigreat/article/details/87931248

信用特征检验/模型稳健性检验的代码实现http://www.cxyzjd.com/article/sinat_23971513/111273478#KS_%E6%A3%80%E9%AA%8C

数据平稳性检验

单位根检验、航空模型、季节模型https://zhuanlan.zhihu.com/p/52084533

收入时间序列——之模型探索篇https://zhuanlan.zhihu.com/p/49945157

平稳性的单位根检验大全http://blog.sina.cn/dpool/blog/s/blog_4d69f4fe0101hzz7.html

用Python处理非平稳时间序列攻略https://zhuanlan.zhihu.com/p/44873076

再次感谢上述博主!!

你可能感兴趣的:(python,数学建模心得,数据分析,python,数据分析)