爲了檢測時間序列的相關性,我們經常使用自相關,互相關或歸一化互相關。
互相關(Cross-Correlation)
互相關是兩個不同時間序列的比較,以檢測具有相同最大值和最小值的指標之間是否存在相關性。例如:“兩個音頻信號同相嗎?”
爲了檢測兩個信號之間的相關程度,我們使用互相關。 只需將兩個時間序列相乘和相加即可計算得出。
在以下示例中,序列A和B是互相關的,但序列C都不與此相關。
a = [1, 2, -2, 4, 2, 3, 1, 0]
b = [2, 3, -2, 3, 2, 4, 1, -1]
c = [-2, 0, 4, 0, 1, 1, 0, -2]
pyplot.figure()
pyplot.title("Series")
pyplot.plot(range(len(a)), a, color="#f44e2e", label="a")
pyplot.plot(range(len(b)), b, color="#27ccc0", label="b")
pyplot.plot(range(len(c)), c, color="#273ecc", label="c")
pyplot.ylabel("value")
pyplot.xlabel("index")
pyplot.show()
使用上面的互相關公式,我們可以計算序列之間的相關度。
import numpy as np
def cross_corr(set1, set2):
return np.sum(set1 * set2)
a = np.array([1, 2, -2, 4, 2, 3, 1, 0])
b = np.array([2, 3, -2, 3, 2, 4, 1, -1])
c = np.array([-2, 0, 4, 0, 1, 1, 0, -2])
print(f"Cross Correlation a,b: {cross_corr(a, b)}")
print(f"Cross Correlation a,c: {cross_corr(a, c)}")
print(f"Cross Correlation b,c: {cross_corr(b, c)}")
OUTPUT:
Cross Correlation a,b: 41
Cross Correlation a,c: -5
Cross Correlation b,c: -4
序列a和b互相關性較大,值爲41。序列a和c,a和b相關性較小,值分別爲:-5,-4.
標準化的互相關(Normalized Cross-Correlation)
標準化的互相關也是用於兩個時間序列的比較,但是使用了不同的評分結果。除了簡單的互相關,它還可以比較具有不同值範圍的指標。例如:“商店中的顧客數量與每天的銷售數量之間是否存在相關性?”
使用互相關值評價相關性存在三個問題:
- 互相關的評分值難以理解。
- 兩個序列必須具有相同的幅度。如如果一個序列值縮小了一半,那麼他的相關性會減少。
- 無法解決序列值爲0的問題,根據互相關公式,由於和,因此無法解決0值。
爲了解決這些問題,使用標準化的互相關:
計算上邊a,b,c序列的標準化的相關性如下:
import numpy as np
def norm_cross_corr(set1, set2):
# python中求Normalized Cross Correlation的函數是: statsmodels.tsa.stattools.ccf
return np.sum(set1 * set2) / (np.linalg.norm(set1) * np.linalg.norm(set2))
a = np.array([1, 2, -2, 4, 2, 3, 1, 0])
b = np.array([2, 3, -2, 3, 2, 4, 1, -1])
c = np.array([-2, 0, 4, 0, 1, 1, 0, -2])
print(f"Normalized Cross Correlation a,b: {norm_cross_corr(a, b)}")
print(f"Normalized Cross Correlation a,c: {norm_cross_corr(a, c)}")
print(f"Normalized Cross Correlation b,c: {norm_cross_corr(b, c)}")
OUTPUT:
Normalized Cross Correlation a,b: 0.9476128352180998
Normalized Cross Correlation a,c: -0.15701857325533194
Normalized Cross Correlation b,c: -0.11322770341445959
標準化的互相關值很容易理解:
- 值越高,相關性越高。
- 當兩個信號完全相同時,最大值爲1:
- 當兩個信號完全相反時,最小值爲-1:
標準化的互相關可以檢測兩個幅度不同的信號的相關性,如:。信號A和具有一半振幅的同一信號之間具有最高的相關性!
自相關(Auto-Correlation)
自相關是時間序列在不同時間與其自身的比較。例如,其目的是檢測重複模式或季節性。例如:“服務器網站上是否有每週的季節性?”“本週的數據與前一週的數據高度相關嗎?”
自相關的用途非常廣泛,其中之一就是檢測由於季節性導致的可重複的模式。
下圖展示了具有季節性爲8的序列:
import numpy as np
np.random.seed(10)
a = np.tile(np.array(range(8)), 8) + np.random.normal(loc=0.0, scale=0.5, size=64)
pyplot.figure(figsize=(12, 4))
pyplot.title("Series")
pyplot.plot(range(len(a)), a, color="#f44e2e", label="a")
pyplot.ylabel("value")
pyplot.xlabel("index")
pyplot.legend(loc="upper right")
pyplot.show()
圖像由如上代碼生成,他是1~8的可重複序列,並且夾雜了一些隨機噪聲。
接下來計算時間偏移爲4和時間偏移爲8時信號與自身之間的自相關。
import numpy as np
np.random.seed(10)
a = np.tile(np.array(range(8)), 8) + np.random.normal(loc=0.0, scale=0.5, size=64)
ar4 = a[:len(a) - 4]
ar4_shift = a[4:]
print(f"Auto Correlation with shift 4: {cross_correlation(ar4, ar4_shift)}")
pyplot.figure(figsize=(12, 4))
pyplot.title("Series")
pyplot.plot(range(len(ar4)), ar4, color="blue", label="ar4")
pyplot.plot(range(len(ar4_shift)), ar4_shift, color="green", label="ar4_shift")
pyplot.ylabel("value")
pyplot.xlabel("index")
pyplot.legend(loc="upper right")
pyplot.show()
OUTPUT:
Auto Correlation with shift 4: 623.797612892277
import numpy as np
np.random.seed(10)
a = np.tile(np.array(range(8)), 8) + np.random.normal(loc=0.0, scale=0.5, size=64)
ar8 = a[:len(a) - 8]
ar8_shift = a[8:]
print(f"Auto Correlation with shift 4: {cross_correlation(ar8, ar8_shift)}")
pyplot.figure(figsize=(12, 4))
pyplot.title("Series")
pyplot.plot(range(len(ar4)), ar4, color="blue", label="ar4")
pyplot.plot(range(len(ar4_shift)), ar4_shift, color="green", label="ar4_shift")
pyplot.ylabel("value")
pyplot.xlabel("index")
pyplot.legend(loc="upper right")
pyplot.show()
OUTPUT:
Auto Correlation with shift 8: 996.8417240253186
上圖清楚地顯示了時間偏移8處的高自相關,而時間偏移4處沒有。計算出的自相關值可以看到shift爲8時的自相關值大於shift爲4時的值。所以相比於4,我們覺得季節性更可能爲8。
標準化的自相關(Normalized Auto-Correlation)
如前所述,用標準化的互相關可以更好地表達兩個序列的相關性
print(f"Auto Correlation with shift 4: {norm_cross_correlation(ar4, ar4_shift)}")
print(f"Auto Correlation with shift 8: {norm_cross_correlation(ar8, ar8_shift)}")
OUTPUT:
Auto Correlation with shift 4: 0.5779124931215941
Auto Correlation with shift 8: 0.9874907451139486
相關性與時移(Correlation with Time Shift)
標準化的互相關與時移(Normalized Cross-Correlation with Time Shift)
時移可以應用於所有上述算法。想法是將指標與具有不同“時間偏移”的另一個指標進行比較。將時間偏移應用於歸一化互相關函數將導致“具有X的時間偏移的歸一化互相關”。這可以用來回答以下問題:“當許多顧客進我的商店時,我的銷售額在20分鐘後會增加嗎?”
爲了處理時移,我們將原始信號與由x元素向右或向左移動的另一個信號關聯。就像我們爲自相關所做的一樣。
爲了檢測兩個指標是否與時移相關,我們需要計算所有可能的時移。
from statsmodels.tsa.stattools import ccf
a = np.array([0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4])
b = np.array([1, 2, 3, 3, 0, 1, 2, 3, 4, 0, 1, 1, 4, 4, 0, 1, 2, 3, 4, 0])
res_ary = ccf(a, b, unbiased=False) # 計算各種time shift下的互相關值
print(res_ary)
pyplot.bar(range(len(res_ary)), res_ary, fc="blue")
pyplot.show()
OUTPUT:
[-3.29180823e-17 8.67261700e-01 1.27247799e-01 -4.65751654e-01
-3.92862138e-01 -1.09726941e-17 6.20178595e-01 1.27247799e-01
-2.92793480e-01 -2.94028896e-01 -2.47083106e-02 3.48387179e-01
1.02539489e-01 -1.19835306e-01 -1.70487343e-01 -2.47083106e-02
1.01304073e-01 5.31228677e-02 -2.10020640e-02 -4.69457901e-02]
從上圖以及數據可以看出,當time shift爲1時,序列a和b高度相關。
標準化的自相關與時移(Normalized Auto-Correlation with Time Shift)
from statsmodels.tsa.stattools import acf
np.random.seed(5)
a = np.tile(np.array(range(8)), 8) + np.random.normal(loc=0.0, scale=0.5, size=64)
res_ary = acf(a, nlags=30, fft=False)
print(res_ary)
pyplot.bar(range(len(res_ary)), res_ary, fc="blue")
pyplot.show()
OUTPUT:
[ 1. 0.33436187 -0.06325233 -0.39112367 -0.46168766 -0.43537856
-0.15175395 0.24403119 0.86075234 0.31051923 -0.03270547 -0.32083613
-0.40031665 -0.38383002 -0.14645852 0.20649692 0.72864895 0.2693097
-0.01707009 -0.2658133 -0.3339456 -0.32771517 -0.1214095 0.17008013
0.60740024 0.22492556 -0.01633838 -0.21157885 -0.27896827 -0.27765971
-0.10762048]
原始序列是有8的季節性,自相關檢測也看到了在8的整數倍的偏移處得到了較高的自相關值。
將相關指標聚類(Cluster Correlated Metrics Together)
我們可以用Normalized Cross Correlation,根據相似度將相關性較大的metric聚類。
使用數據集:graphs45.csv
import numpy as np
import pandas as pd
def get_correlation_table(metric_df):
metric_cnt = metric_df.shape[1]
correlation_table = np.zeros((metric_cnt, metric_cnt))
for i in range(metric_cnt):
metric_1 = metric_df.iloc[:, i]
for j in range(metric_cnt):
if i == j:
continue
else:
metric_2 = metric_df.iloc[:, j]
cc_ary = ccf(metric_1, metric_2, unbiased=False)
correlation_table[i, j] = cc_ary[0]
return correlation_table
def find_related_metric(correlation_table, orig, high_corr):
metric_corr_table = correlation_table[orig]
corr_metric_lst = []
for i in range(len(metric_corr_table)):
if metric_corr_table[i] > high_corr:
corr_metric_lst.append(i)
return corr_metric_lst
if __mian__:
metric_df = pd.read_csv("./graphs45.csv")
correlation_table_ary = get_correlation_table(metric_df)
orig = 3
high_corr = 0.9
corr_metric_lst = find_related_metric(correlation_table_ary, orig, high_corr)
corr_metric_lst.append(orig)
print(corr_metric_lst)
pyplot.figure()
pyplot.title("Series")
for idx in corr_metric_lst:
metric = metric_df.iloc[:, idx]
pyplot.plot(range(len(metric)), metric, label=f"graph_{idx + 1}")
pyplot.ylabel("value")
pyplot.xlabel("index")
pyplot.legend(loc="upper right")
pyplot.show()
get_correlation_table()計算了所有metric之間的標準化的互相關值,結果存在correlation_table中,correlation_table[i,j]代表第i個metric和第j個metric之間的相關值。
然後find_related_metric()根據相關值表找出和graph_4相關值大於0.9的序列,最後找出的相關序列畫圖如下: