計量經濟與時間序列_ACF自相關與PACF偏自相關算法解析(Python,TB(交易開拓者))


1   在時間序列中ACF圖和PACF圖是非常重要的兩個概念,如果運用時間序列做建模、交易或者預測的話。這兩個概念是必須的。

2   ACF和PACF分別為:自相關函數(系數)和偏自相關函數(系數)。

3   在許多軟件中比如Eviews分析軟件可以調出某一個序列的ACF圖和PACF圖,如下:

  

  3.1   有時候這張圖是橫躺着的,不過這個不重要,反正一側為小於0的負值范圍,一側為大於0的正值范圍,均值(准確的說是坐標y軸為0,有些橫着的圖,會把x軸和y軸表示出來,值都在x軸上下附近呈現出來)。

  3.2   紅色框框部分就是ACF圖,青色框框部分就是PACF圖,其中對應左邊的Autocorrelation就是英文單詞自相關的全稱;Partial Correlation就是英文單詞偏自相關的全稱。

  3.3   我們要計算的就是這兩列數值。

  3.4   其中紫色箭頭標注出來的是指的2倍標准誤范圍,后面可以用對應的數值是否超過范圍來判斷截尾、拖尾等信息,進而判斷采用哪種模型。

  3.5   這里特別注明一下在默認狀態下,這兩根線是如何計算的:

    在大樣本下(T很大的時候,這里T指的是樣本的個數;其實准確的說樣本符合均值為0的正太分布)。因此這里的對於ACF或PACF屬於一種分位點檢驗,這個東西在很多baidu可以找到一個正太分布圖,然后左右畫線會得到99%,90%...的分位點,這里的這兩根線就是指的這個。我們這里要做的是雙側對稱檢驗,所以上下兩根線分布式0±分位點的值。分位點=2倍×sqrt開方(1/T),這里的T指的是樣本的個數,樣本個數指的是原始的那個樣本的個數,不是ACF或PACF計算完的樣本個數。如果某一個值大於2倍標准誤,也就是說大於正態分布左/右的95%分位點,於是,在拒絕域,則拒絕0假設(也就是拒絕均值為0的假設)

    例如:樣本共10個,ACF或PACF計算完畢后,他們的數量都為9個,其分為點為:2×sqrt(1/10) = 0.6324555320...,雙側檢驗邊沿值為:(0-0.6324555320,0+0.6324555320) = [-0.6324555320,+0.6324555320](這就是兩根虛線的值)。    (3.5.1)

       另外我們還通過另外一個公式Sρk ≈ sqrt(1/n * (1+2*ρ12 + ... + 2*ρk-12))來計算acf的雙側檢驗值。具體在這篇博文中得出。http://www.cnblogs.com/noah0532/p/8453959.html

 

4    ACF算法的實現(python

  4.1   首先:給定一組數據,這里的是線性數據,不用太多10個元素,一組的時間序列。

1 TimeSeries = [13, 8, 15, 4, 4, 12, 11, 7, 14, 12]  # 列表形式
2 print(TimeSeries)
3 # 顯示結果:[13, 8, 15, 4, 4, 12, 11, 7, 14, 12]

  4.2   算法表達式。

  

  4.3   算法解析:

  計算ρ1:

  給定一階滯后序列:其中滯后用L來表示,具體表示方法見鏈接:http://www.cnblogs.com/noah0532/p/8449991.html

1 LZt = TimeSeries[:-1:]
2 print(LZt)
3 # 顯示結果:[13, 8, 15, 4, 4, 12, 11, 7, 14]

  對應的這兩個序列分別為:

  [13, 8, 15, 4, 4, 12, 11, 7, 14, 12]
  [13, 8, 15, 4, 4, 12, 11, 7, 14]

  我們在把原始序列與一階滯后序列進行對齊:

1 Zt = TimeSeries[1::]
2 print(Zt)
3 # 顯示結果:[8, 15, 4, 4, 12, 11, 7, 14, 12]

  這樣兩個序列變為:

  [ 8, 15, 4, 4, 12, 11, 7, 14, 12]
  [13, 8, 15, 4, 4, 12, 11, 7, 14]  

  對這兩個序列進行計算就會得出ρ1的結果(也就是ACF的第一個值)

  4.4   其實我們可以得到這樣一個結果,就是這樣不斷的比較下去,計算每一個滯后,原始序列會少一個值來對應滯后的序列,然后分別來進行計算。我們把這個過程化簡一下,代碼如下(以如上10個序列為例,最后會得出9對)

 1 TimeSeries = [13, 8, 15, 4, 4, 12, 11, 7, 14, 12]  # 列表形式
 2 Zt = []
 3 LZt = []
 4 i = 1
 5 while i < len(TimeSeries):
 6     L = TimeSeries[i::]
 7     LL = TimeSeries[:-i:]
 8     Zt.append(L)
 9     LZt.append(LL)
10     i += 1
11 print(TimeSeries)
12 print(Zt)
13 print(LZt)
14 # 顯示結果:
15 # [13, 8, 15, 4, 4, 12, 11, 7, 14, 12]
16 # [[8, 15, 4, 4, 12, 11, 7, 14, 12], [15, 4, 4, 12, 11, 7, 14, 12], [4, 4, 12, 11, 7, 14, 12], [4, 12, 11, 7, 14, 12], [12, 11, 7, 14, 12], [11, 7, 14, 12], [7, 14, 12], [14, 12], [12]]
17 # [[13, 8, 15, 4, 4, 12, 11, 7, 14], [13, 8, 15, 4, 4, 12, 11, 7], [13, 8, 15, 4, 4, 12, 11], [13, 8, 15, 4, 4, 12], [13, 8, 15, 4, 4], [13, 8, 15, 4], [13, 8, 15], [13, 8], [13]]

  4.5   通過這種遍歷加減方式,如果原始列表為10個元素的話會得到9對ACF帶計算序列,以此類推,這樣做的目的就是為了把序列進行對齊計算。把這9對列出來看一下:

  [8, 15, 4, 4, 12, 11, 7, 14, 12]
  [13, 8, 15, 4, 4, 12, 11, 7, 14]

  [15, 4, 4, 12, 11, 7, 14, 12]
  [13, 8, 15, 4, 4, 12, 11, 7]

  [4, 4, 12, 11, 7, 14, 12]
  [13, 8, 15, 4, 4, 12, 11]

  [4, 12, 11, 7, 14, 12]
  [13, 8, 15, 4, 4, 12]

  [12, 11, 7, 14, 12]
  [13, 8, 15, 4, 4]

  [11, 7, 14, 12]
  [13, 8, 15, 4]

  [7, 14, 12]
  [13, 8, 15]

  [14, 12]
  [13, 8]

  [12]
  [13]

   4.6   根據算法公式,其分母為原始序列每一個元素距離平均值的平方。因此我們也可以把分母計算出來。

 1 TimeSeries = [13, 8, 15, 4, 4, 12, 11, 7, 14, 12]  # 列表形式
 2 Zt = []
 3 LZt = []
 4 sum = 0
 5 i = 1
 6 while i < len(TimeSeries):
 7     L = TimeSeries[i::]
 8     LL = TimeSeries[:-i:]
 9     sum = sum + TimeSeries[i - 1]
10     Zt.append(L)
11     LZt.append(LL)
12     i += 1
13 sum = sum + TimeSeries[-1]
14 avg = sum / len(TimeSeries)
15 print(TimeSeries)
16 print(Zt)
17 print(LZt)
18 print(avg)
19 # 顯示結果:
20 # 10.0

  4.7   我們具備了這些所有的元素后開始計算這些所有ACF的ρ值,最終我們還是用列表來表示

 1 k = 0
 2 result_Deno = 0
 3 # 首先計算分母=分母都為通用
 4 while k < len(TimeSeries):
 5     result_Deno = result_Deno + pow((TimeSeries[k] - avg), 2)
 6     k += 1
 7 print(result_Deno)
 8 # 顯示結果:144.0
 9 
10 # 然后計算分子
11 p = 0
12 q = 0
13 14 acf = []
15 while p < len(Zt):
16     # print(Zt[p])
17     # print(LZt[p])
18     q = 0
19     result_Mole = 0
20     while q < len(Zt[p]):
21         result_Mole = result_Mole + (Zt[p][q] - avg) * (LZt[p][q] - avg)
22         q += 1
23     acf.append(round(result_Mole / result_Deno, 3))  # 保留小數點后三位
24     p += 1
25 print(acf)
26 # 顯示結果:
27 # [-0.188, -0.201, 0.181, -0.132, -0.326, 0.118, -0.049, 0.056, 0.042]

  4.7   結果驗證:與用Eviews軟件計算的結果一致,算法結束:

[-0.188, -0.201, 0.181, -0.132, -0.326, 0.118, -0.049, 0.056, 0.042]

 

5   PACF算法的實現(python

    5.1   PACF算法源於ACF算法,必須先算出ACF的值來,然后再計算PACF,PACF這里用的是一個遞推形式的公式,計算每一個φ值。在書中有些φ值用φkk來表示,有時候也用一個大Pk來表示,其實道理都一樣。

  5.2   遞推式如下:

  5.3   這個遞推式,紫色框內為每期值,下面的屬於過度值,用於遞推累計。

  5.4   這個遞推式算法看起來無從下手比較麻煩。我們先分解一下:

  5.5   j和k的下標解析

    如果k = 1,那么 j = 1,2

    如果k = 2,那么 j = 1,2

    如果k = 3,那么 j = 1,2,3

    如果k = 4,那么 j = 1,2,3,4

    如果k = 5,那么 j = 1,2,3,4,5

    如果k = 6,那么 j = 1,2,3,4,5,6

    如果k = 7,那么 j = 1,2,3,4,5,6,7

    如果k = 8,那么 j = 1,2,3,4,5,6,7,8

    如果k = 9,那么 j = 1,2,3,4,5,6,7,8,9

    ... ....

    從下標可以看出這個遞推關系,如果處於k的某種狀態(數值),那么 j 將從當前狀態遞減到1。這也就是 j = 1,...,k的解析。

  5.6   從這個下標解析可以看出,這兩部分的遞推式,第一部分(紫色框框中)的是計算PACF當前值,而第二部分是計算每階段的PACF值的缺省值(所需值)的計算。因此每期的PACF值的計算,需要遞推第二個公式中的值,然后再去計算下一期PACF值。這個邏輯是這樣

  5.7   從5.5的這個規律可以看出,j 是 k遞減數,也就是當前值如果為k = 3的話,我們需要有3個第二個公式的值;如果k = 7的話,我們需要有7個第二個公式的值;這個邏輯是沒有問題的,我們以一個多的為例子

    k = 8 通式如下:

    φ9,j = φ8j - φ998,9-j

    j = 1

    φ91 = φ81 - φ9988

    j = 2

    φ92 = φ82 - φ9987

    j = 3

    φ93 = φ83 - φ9986

    j = 4

    φ94 = φ84 - φ9985

    j = 5

    φ95 = φ85 - φ9984

    j = 6

    φ96 = φ86 - φ9983

    j = 7

    φ97 = φ87 - φ9982

    j = 8

    φ98 = φ88 - φ9981

   5.8   正如上面所示,我們會得到8個表達式。其每一期的表達式的值我們需要用列表來進行記錄;這里的規律是φ99來自於第一個部分的公式,其φ8x和后面的φ8x是來自第二部分公式計算的上一期的值。這樣這個第二部分的表達式我們就可以計算出來了。

   5.9   我們再來遞推第一部分的那個公式。還是以上面的為例子。我們舉一個小點兒的數。

    k = 2   通式如下

    φ33 = φ3 - sigma(φ2j3-j) / 1 - sigma(φ2jj)

    j = 1

    φ33 = φ3 - sigma(φ212) / 1 - sigma(φ211)

    j = 2

    φ33 = φ3 - sigma(φ221) / 1 - sigma(φ222)

    我們把sigma中的兩部分進行合並得:

    φ33 = φ3 - (φ212 +  φ221) / 1 - (φ211 φ222)

   5.10   我們發現一個規律。如果要計算33的時候,其括號內的值φ的順序不變,其ρ值為反向求積然后再求和。

   5.11   我們現在試着來求一下這段代碼的寫法,以上面計算出來的ACF值,接着來計算PACF值:

  ACF = [-0.188, -0.201, 0.181, -0.132, -0.326, 0.118, -0.049, 0.056, 0.042]

  ACF[0] = ρ1 = -0.188

  ACF[1] = ρ2 = -0.201

  ACF[2] = ρ4 = 0.181

  ACF[3] = ρ5 = -0.132

  ACF[4] = ρ6 = -0.326

  ACF[5] = ρ7 = 0.118

  ACF[6] = ρ8 = -0.049

  ACF[7] = ρ9 = 0.056

  ACF[8] = ρ9 = 0.042

  5.12   (具體過程稍顯復雜,所以下面用這個顏色寫,這樣更清楚一些):

    (1):遞推算法,在編寫的時候可能會對初學者燒腦一些。重要的是對於每一種算法,我們首先要找到他們的規律,再不會算,可以找張紙先手工驗算一下。

    (2):acf值與pacf值的長度都是一樣,且第一個值都相等。φkk如果是兩個整數,比如φ11,φ33,這就是我們要求的pacf對應每期的值。

    (3):正如上面所說的,都是整數的話是所求的值,那么不是整數的話,類似於φ41,φ42,φ43...等等這些,就是第二個遞推式所需要計算的值。這是值是為了求下一組數值所用。

    (4):因此我們得出這樣一個規律,除去第一個值(pacf和acf第一個值都相等)。后面每期值分兩組來進行計算,然后一組循環結束,以此類推,知道pacf長度減-1都完成為止。

    (5):那么一組是什么樣子的?比如第一組是:φ22,φ21;第二組:φ33,φ32,φ31;第三組:φ44,φ43,φ42,φ41...以此類推。一組等於一個大循環。

    (6):每組值分第一部分整值計算和第二部分非整值計算,每一組所需的φ值(看遞推公式),是來自於上一組的值。因此我們計算完一組后,把所需要的值(代碼中是用個過渡變量bridge來記錄),送給下一組計算用,計算完畢刪除,再賦新值,再給下一組。循環往復,直到結束。

    (7):那每組需要的值是什么樣子,以計算到φ44,這個為例子,所需要的bridge值為[φ31,φ32,φ33]。用完了后,bridge更新為[φ41,φ42,φ43,φ44],供下一組φ55使用,其他每組都是這個原理。在這里引入了一個橋變量

    (8):由於精度可能略有差別,這樣我們把之前計算的acf值先不要保留小數點后三位,計算完畢后,我們統一保留小數點后三位。

    (9):最后再把上邊界和下邊界的值算出來。這個公式上面有。

  5.13   具體代碼如下:

  1 TimeSeries = [13, 8, 15, 4, 4, 12, 11, 7, 14, 12]  # 列表形式
  2 Zt = []
  3 LZt = []
  4 total = 0
  5 i = 1
  6 while i < len(TimeSeries):
  7     L = TimeSeries[i::]
  8     LL = TimeSeries[:-i:]
  9     total = total + TimeSeries[i-1]
 10     Zt.append(L)
 11     LZt.append(LL)
 12     i += 1
 13 total = total + TimeSeries[-1]
 14 avg = total / len(TimeSeries)
 15 
 16 k = 0
 17 result_Deno = 0
 18 # 首先計算分母=分母都為通用
 19 while k < len(TimeSeries):
 20     result_Deno = result_Deno + pow((TimeSeries[k] - avg), 2)
 21     k += 1
 22 # print(result_Deno)
 23 # 顯示結果:144.0
 24 
 25 # 然后計算分子
 26 p = 0
 27 q = 0
 28 acf = []
 29 while p < len(Zt):
 30     # print(Zt[p])
 31     # print(LZt[p])
 32     q = 0
 33     result_Mole = 0
 34     while q < len(Zt[p]):
 35         result_Mole = result_Mole + (Zt[p][q] - avg) * (LZt[p][q] - avg)
 36         q += 1
 37     acf.append(result_Mole / result_Deno)  # 我們把前面計算的acf值先不要保留小數點后三位。
 38     # acf.append(result_Mole / result_Deno)
 39     p += 1
 40 # print(acf)
 41 
 42 # 初始化pacf
 43 pacf = []
 44 bridge = []
 45 bridge.append(acf[0])
 46 pacf.append(acf[0])   # 第一個φ11等於ρ1,再初始化pacf的第一個值。
 47 # 這里采用的是bridge這個循環變量。計算的邏輯是每次重新賦值一遍共下一輪計算所用。
 48 
 49 
 50 T = 0  # 初始化大循環的值為0,9個數值一共循環7次。原因是下面。
 51 while T < len(acf)-1:   # pacf的初始值已經計算過一個了,acf的長度和pacf的長度是一樣的,因此,len(acf)此時要減去一個1
 52     # 每進行一輪循環,這些變量都重新初始化一遍
 53     Mole = 0 # 計算紫框中Σ累加的分子值
 54     Deno = 0 # 計算紫框中Σ累計的分母值
 55     cross = 0 # 每計算完一遍第一部分的值,暫時用cross這個變量先保存起來。
 56     UnderCross = [] # 每計算完第二步的值,用UnderCross的值先保存起來,因為有時候第二步的值不是一個,所以用列表形式。
 57 
 58     # 計算第一部分
 59     t = 0
 60     while t < len(bridge):    # 計算φ22,φ33,φ44,φ55,φ66,φ22,φ77,φ88...這些值
 61         Mole = Mole + (bridge[t] * acf[len(bridge)-1-t])
 62         Deno = Deno + (bridge[t] * acf[t])
 63         t += 1
 64     cross = (acf[t] - Mole) / (1 - Deno)  # acf[t] 正確,每次迭代完成,都是分子的第一個值。
 65     # print(cross)
 66     # print(t)
 67 
 68     # 計算第二部分
 69     p = 0
 70     while p < len(bridge):   # 計算像φ21,φ32,φ31...這樣的值
 71         UnderCross.append(bridge[p] - cross * bridge[len(bridge)-1-p])
 72         p += 1
 73 
 74     bridge = []  # bridge使用完畢,初始化,再次賦值供下一次計算
 75     bridge.extend(UnderCross)   # 把計算完畢的Under值賦值到bridge
 76     bridge.append(cross)   # 把計算完畢的cross值存放到最后的位置
 77     pacf.append(cross)   # 把pacf值累計進行添加並記錄
 78     # print(bridge)
 79     # print(UnderCross)
 80 
 81     T += 1
 82 # print(pacf)
 83 # 整個的一段循環完畢。
 84 
 85 
 86 # 最后我們重新遍歷一遍,然后把acf和pacf都保留小數點后三位。
 87 AcfValue = []
 88 PacfValue = []
 89 lag = 0
 90 for sht in acf:
 91     lag = round(sht, 3)
 92     AcfValue.append(lag)
 93     lag = 0
 94 print("acf值(保留小數點后三位)為:", AcfValue)
 95 
 96 for sht in pacf:
 97     lag = round(sht, 3)
 98     PacfValue.append(lag)
 99     lag = 0
100 print("pacf值(保留小數點后三位)為:", PacfValue)
101 
102 
103 # 最后把bounds值算出來。
104 import math
105 bound = []
106 bound.append(-2*math.sqrt(1/len(TimeSeries)))
107 bound.append(2*math.sqrt(1/len(TimeSeries)))
108 print("上下邊界值分別為:", bound)
109 
110 # 最終顯示結果:
111 # acf值(保留小數點后三位)為: [-0.188, -0.201, 0.181, -0.132, -0.326, 0.118, -0.049, 0.056, 0.042]
112 # pacf值(保留小數點后三位)為: [-0.188, -0.245, 0.097, -0.134, -0.361, -0.126, -0.213, 0.036, -0.119]
113 # 上下邊界值分別為: [-0.6324555320336759, 0.6324555320336759]

  5.14   最終結果驗證:

acf值(保留小數點后三位)為: [-0.188, -0.201, 0.181, -0.132, -0.326, 0.118, -0.049, 0.056, 0.042]
pacf值(保留小數點后三位)為: [-0.188, -0.245, 0.097, -0.134, -0.361, -0.126, -0.213, 0.036, -0.119]
上下邊界值分別為: [-0.6324555320336759, 0.6324555320336759]這里是計算的pacf的bound值。在看圖的時候直接通用pacf的bound值。但是實際過程中這兩個標准差是不太一樣。具體見這篇博文http://www.cnblogs.com/noah0532/p/8453959.html

  對照上面給出的Eviews軟件自動統計的值

  結果完全一致  

 6   TB(交易開拓者代碼)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(持續編輯中。。。。。。。。。。)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM