本文介紹了幾個重要的變量相關性的度量,包括皮爾遜相關系數、距離相關性和最大信息系數等,并用簡單的代碼和示例數據展示了這些度量的適用性對比。
從信號的角度來看,這個世界是一個嘈雜的地方。為了弄清楚所有的事情,我們必須有選擇地把注意力集中到有用的信息上。
通過數百萬年的自然選擇過程,我們人類已經變得非常擅長過濾背景信號。我們學會將特定的信號與特定的事件聯系起來。
例如,假設你正在繁忙的辦公室中打乒乓球。為了回擊對手的擊球,你需要進行大量復雜的計算和判斷,將多個相互競爭的感官信號考慮進去。為了預測球的運動,你的大腦必須重復采樣球的位置并估計它未來的軌跡。更厲害的球員還會將對手擊球時施加的旋轉考慮進去。最后,為了擊球,你需要考慮對手的位置、自己的位置、球的速度,以及你打算施加的旋轉。
所有這些都涉及到了大量的潛意識微分學。一般來說,我們理所當然的認為,我們的神經系統可以自動做到這些(至少經過一些練習之后)。
同樣令人印象深刻的是,人類大腦是如何區別對待它所接收到的無數競爭信號的重要性的。例如,球的位置被認為比你身后發生的對話或你面前打開的門更重要。
這聽起來似乎不值得一提,但實際上這證明了可以多大程度上學習從噪聲數據中做出準確預測。
當然,一個被給予連續的視聽數據流的空白狀態機將會面臨一個困難的任務,即確定哪些信號能夠最好地預測最佳行動方案。
幸運的是,有統計和計算方法可以用來識別帶噪聲和復雜的數據中的模式。
相關性
一般來說,當我們談到兩個變量之間的「相關性(correlation)」時,在某種意義上,我們是指它們的「關系(relatedness)」。
相關變量是包含彼此信息的變量。兩個變量的相關性越強,其中一個變量告訴我們的關于另一個變量的信息就越多。
你可能之前就看過:正相關、零相關、負相關
你可能已經對相關性、它的作用和它的局限性有了一定了解。事實上,這是一個數據科學的老生常談:
「相關性不意味著因果關系」
這當然是正確的——有充分的理由說明,即使是兩個變量之間有強相關性也不保證存在因果關系。觀察到的相關性可能是由于隱藏的第三個變量的影響,或者完全是偶然的。
也就是說,相關性確實允許基于另一個變量來預測一個變量。有幾種方法可以用來估計線性和非線性數據的相關性。我們來看看它們是如何工作的。
我們將用 Python 和 R 來進行數學和代碼實現。本文示例的代碼可以在這里找到:
GitHub https://gist.github.com/anonymous/fabecccf33f9c3feb568384f626a2c07
皮爾遜相關系數
皮爾遜相關系數(PCC, 或者 Pearson\’s r)是一種廣泛使用的線性相關性的度量,它通常是很多初級統計課程的第一課。從數學角度講,它被定義為「兩個向量之間的協方差,通過它們標準差的乘積來歸一化」。
兩個成對的向量之間的協方差是它們在均值上下波動趨勢的一種度量。也就是說,衡量一對向量是否傾向于在各自平均值的同側或相反。
讓我們看看在 Python 中的實現:
def mean(x):
return sum(x)/len(x)
def covariance(x,y):
calc = []
for i in range(len(x)):
xi = x[i] - mean(x)
yi = y[i] - mean(y)
calc.append(xi * yi)
return sum(calc)/(len(x) - 1)
a = [1,2,3,4,5] ; b = [5,4,3,2,1]
print(covariance(a,b))
協方差的計算方法是從每一對變量中減去各自的均值。然后,將這兩個值相乘。
如果都高于(或都低于)均值,那么結果將是一個正數,因為正數 × 正數 = 正數;同樣的,負數 × 負數 = 負數。
如果在均值的不同側,那么結果將是一個負數(因為正數 × 負數 = 負數)。
一旦我們為每一對變量都計算出這些值,將它們加在一起,并除以 n-1,其中 n 是樣本大小。這就是樣本協方差。
如果這些變量都傾向于分布在各自均值的同一側,協方差將是一個正數;反之,協方差將是一個負數。這種傾向越強,協方差的絕對值就越大。
如果不存在整體模式,那么協方差將會接近于零。這是因為正值和負值會相互抵消。
最初,協方差似乎是兩個變量之間「關系」的充分度量。但是,請看下面的圖:
協方差 = 0.00003
看起來變量之間有很強的關系,對吧?那為什么協方差這么小呢(大約是 0.00003)?
這里的關鍵是要認識到協方差是依賴于比例的。看一下 x 和 y 坐標軸——幾乎所有的數據點都落在了 0.015 和 0.04 之間。協方差也將接近于零,因為它是通過從每個個體觀察值中減去平均值來計算的。
為了獲得更有意義的數字,歸一化協方差是非常重要的。方法是將其除以兩個向量標準差的乘積。
在希臘字母中 ρ 常用來表示皮爾遜相關系數
在 Python 中:
import math
def stDev(x):
variance = 0
for i in x:
variance = (i - mean(x) ** 2) / len(x)
return math.sqrt(variance)
def Pearsons(x,y):
cov = covariance(x,y)
return cov / (stDev(x) * stDev(y))
這樣做的原因是因為向量的標準差是是其方差的平方根。這意味著如果兩個向量是相同的,那么將它們的標準差相乘就等于它們的方差。
有趣的是,兩個相同向量的協方差也等于它們的方差。
因此,兩個向量之間協方差的最大值等于它們標準差的乘積(當向量完全相關時會出現這種情況)。這將相關系數限制在 -1 到 1 之間。
箭頭指向哪個方向?
順便說一下,一個定義兩個向量的 PCC 的更酷的方法來自線性代數。
首先,我們通過從向量各自的值中減去其均值的方法來「集中」向量。
a_centered = [i - mean(a) for i in a]
b_centered = [j - mean(b) for j in b]
現在,我們可以利用向量可以看做指向特定方向的「箭頭」的事實。
例如,在 2-D 空間中,向量 [1,3] 可以代表一個沿 x 軸 1 個單位,沿 y 軸 3 個單位的箭頭。同樣,向量 [2,1] 可以代表一個沿 x 軸 2 個單位,沿 y 軸 1 個單位的箭頭。
兩個向量 (1,3) 和 (2,1) 如箭頭所示。
類似地,我們可以將數據向量表示為 n 維空間中的箭頭(盡管當 n > 3 時不能嘗試可視化)。
這些箭頭之間的角度 可以使用兩個向量的點積來計算。定義為:
或者,在 Python 中:
def dotProduct(x,y):
calc = 0
calc = x[i] * y[i]
return calc
點積也可以被定義為:
其中 || x || 是向量 x 的大小(或「長度」)(參考勾股定理), 是箭頭向量之間的角度。
正如一個 Python 函數:
def magnitude(x):
x_sq = [i ** 2 for i in x]
return math.sqrt(sum(x_sq))
我們通過將點積除以兩個向量大小的乘積的方法得到 cos()。
def cosTheta(x,y):
mag_x = magnitude(x)
mag_y = magnitude(y)
return dotProduct(x,y) / (mag_x * mag_y)
現在,如果你對三角學有一定了解,你可能會記得,余弦函數產生一個在 1 和 -1 之間震蕩的圖形。
cos() 的值將根據兩個箭頭向量之間的角度而發生變化。
當角度為零時(即兩個向量指向完全相同的方向),cos() 等于 1。
當角度為 -180°時(兩個向量指向完全相反的方向),cos() 等于 -1。
當角度為 90°時(兩個向量指向完全不相關的方向),cos() 等于 0。
這可能看起來很熟悉——一個介于 1 和 -1 之間的衡量標準似乎描述了兩個向量之間的關系?那不是 Pearson’s r 嗎?
那么——這正是它的解釋!通過將數據視為高維空間中的箭頭向量,我們可以用它們之間的角度 作為相似度的衡量。
A) 正相關向量; B) 負相關向量; C) 不相關向量
該角度 的余弦在數學上與皮爾遜相關系數相等。當被視為高維箭頭時,正相關向量將指向一個相似的方向。負相關向量將指向相反的方向。而不相關向量將指向直角。
就我個人而言,我認為這是一個理解相關性的非常直觀的方法。
統計顯著性?
正如頻率統計一樣,重要的是詢問從給定樣本計算的檢驗統計量實際上有多重要。Pearson\’s r 也不例外。
不幸的是,PCC 估計的置信區間不是完全直接的。
這是因為 Pearson\’s r 被限制在 -1 和 1 之間,因此不是正態分布的。而估計 PCC,例如 0.95 之上只有很少的容錯空間,但在其之下有大量的容錯空間。
幸運的是,有一個解決方案——用一個被稱為 Fisher 的 Z 變換的技巧:
像平常一樣計算 Pearson\’s r 的估計值。
用 Fisher 的 Z 變換將 r→z,用公式 z = arctanh(r) 完成。
現在計算 z 的標準差。幸運的是,這很容易計算,由 SDz = 1/sqrt(n-3) 給出,其中 n 是樣本大小。
選擇顯著性閾值,alpha,并檢查與此對應的平均值有多少標準差。如果取 alpha = 0.95,用 1.96。
通過計算 z (1.96 × SDz) 找到上限,通過計算 z – (1.96 × SDz) 找到下限。
用 r = tanh(z) 將這些轉換回 r。
如果上限和下限都在零的同一側,則有統計顯著性!
這里是在 Python 中的實現:
r = Pearsons(x,y)
z = math.atanh(r)
SD_z = 1 / math.sqrt(len(x) - 3)
z_upper = z 1.96 * SD_z
z_lower = z - 1.96 * SD_z
r_upper = math.tanh(z_upper)
r_lower = math.tanh(z_lower)
當然,當給定一個包含許多潛在相關變量的大數據集時,檢查每對的相關性可能很吸引人。這通常被稱為「數據疏浚」——在數據集中查找變量之間的任何明顯關系。
如果確實采用這種多重比較方法,則應該用適當的更嚴格的顯著性閾值來降低發現錯誤相關性的風險(即找到純粹偶然相關的無關變量)。
一種方法是使用 Bonferroni correction。
小結
到現在為止還好。我們已經看到 Pearson\’s r 如何用來計算兩個變量之間的相關系數,以及如何評估結果的統計顯著性。給定一組未知的數據,用于開始挖掘變量之間的重要關系是很有可能的。
但是,有一個重要的陷阱——Pearson\’s r 只適用于線性數據。
看下面的圖。它們清楚地展示了一種看似非隨機的關系,但是 Pearson\’s r 非常接近于零。
原因是因為這些圖中的變量具有非線性關系。
我們通常可以將兩個變量之間的關系描繪成一個點云,分散在一條線的兩側。點云的分散度越大,數據越「嘈雜」,關系越弱。
然而,由于它將每個單獨的數據點與整體平均值進行比較,所以 Pearson\’s r 只考慮直線。這意味著檢測非線性關系并不是很好。
在上面的圖中,Pearson\’s r 并沒有顯示研究對象的相關性。
然而,這些變量之間的關系很顯然是非隨機的。幸運的是,我們有不同的相關性方法。
讓我們來看看其中幾個。
距離相關性
距離相關性與 Pearson\’s r 有一些相似之處,但是實際上是用一個相當不同的協方差概念來計算的。該方法通過用「距離」類似物替代常用的協方差和標準差(如上所定義)的概念。
類似 Pearson\’s r,「距離相關性」被定義為「距離協方差」,由「距離標準差」來歸一化。
距離相關性不是根據它們與各自平均值的距離來估計兩個變量如何共同變化,而是根據與其他點的距離來估計它們是如何共同變化的,從而能更好捕捉變量之間非線性依賴關系。
深入細節
出生于 1773 年的 Robert Brown 是一名蘇格蘭植物學家。當布朗在顯微鏡下研究植物花粉時,注意到液面上有隨機運動的有機顆粒。
他沒有想到,這一觀察竟使他名垂千古——他成為了布朗運動的(重新)發現者。
他更不會知道,近一個世紀的時間后愛因斯坦才對這種現象做出了解釋,從而證實了原子的存在。同年,愛因斯坦發表了關于狹義相對論的論文(E=MC),并打開了量子理論的大門。
布朗運動是這樣一個物理過程:由于與周圍粒子的碰撞,微小粒子隨機運動。
布朗運動背后的數學原理可以被推廣為維納過程(Weiner process),維納過程在數學金融中最著名的模型 Black-Scholes 中也扮演著重要的角色。
有趣的是,Gabor Szekely 在 20 世紀中期的研究表明,布朗運動和維納過程和一個非線性關聯度量相關。
讓我們來看看如何由長度為 N 的向量 x 和 y 計算這個量。
1. 首先,我們對每個向量構建 N×N 的距離矩陣。距離矩陣和地圖中的道路距離表非常類似——每行、每列的交點顯示了相應城市間的距離。在距離矩陣中,行 i 和列 j 的交點給出了向量的第 i 個元素和第 j 個元素之間的距離。
2. 第二,矩陣是「雙中心」的。也就是說,對于每個元素,我們減去了它的行平均值和列平均值。然后,我們再加上整個矩陣的總平均值。
上述公式中,加「^」表示「雙中心」,加「-」表示「平均值」。
3. 在兩個雙中心矩陣的基礎上,將 X 中每個元素的均值乘以 Y 中相應元素的均值,則可計算出距離協方差的平方。
4. 現在,我們可以用類似的辦法找到「距離方差」。請記住,若兩個向量相同,其協方差與其方差相等。因此,距離方差可表示如下:
5. 最后,我們利用上述公式計算距離相關性。請記住,(距離)標準差與(距離)方差的平方根相等。
如果你更喜歡代碼實現而非數學符號,那么請看下面的 R 語言實現:
set.seed(1234)
doubleCenter <- function(x){
centered <- x
for(i in 1:dim(x)[1]){
for(j in 1:dim(x)[2]){
centered[i,j] <- x[i,j] - mean(x[i,]) - mean(x[,j]) mean(x)
}
}
return(centered)
}
distanceCovariance <- function(x,y){
N <- length(x)
distX <- as.matrix(dist(x))
distY <- as.matrix(dist(y))
centeredX <- doubleCenter(distX)
centeredY <- doubleCenter(distY)
calc <- sum(centeredX * centeredY)
return(sqrt(calc/(N^2)))
}
distanceVariance <- function(x){
return(distanceCovariance(x,x))
}
distanceCorrelation <- function(x,y){
cov <- distanceCovariance(x,y)
sd <- sqrt(distanceVariance(x)*distanceVariance(y))
return(cov/sd)
}
# Compare with Pearson\'s r
x <- -10:10
y <- x^2 rnorm(21,0,10)
cor(x,y) # --> 0.057
distanceCorrelation(x,y) # --> 0.509
任意兩變量的距離相關性都在 0 和 1 之間。其中,0 代表兩變量相互獨立,而接近于 1 則表明變量間存在依賴關系。
如果你不想從頭開始編寫距離相關方法,你可以安裝 R 語言的 energy 包(https://cran.r-project.org/web/packages/energy/index.html),設計此方案的研究者提供了本代碼。在該程序包中,各類可用方案調用的是 C 語言編寫的函數,因此有著很大的速度優勢。
物理解釋
關于距離相關性的表述,有著一個更令人驚訝的結果——它與布朗關聯(Brownian correlation)有著確切的等價關系。
布朗關聯指的是兩個布朗過程之間的獨立性(或依賴性)。相互依賴的布朗過程將會表現出彼此「跟隨」的趨勢。
讓我們用一個簡單的比喻來把握距離相關性的概念——請看下圖中漂浮在湖面上的小紙船。
如果沒有盛行風向,那么每艘船都將進行隨機漂流——這與布朗運動類似。
無盛行風向時,小船隨機漂流
如果存在盛行風向,那么小船漂流的方向將依賴于風的強度。風力越強,依賴性越顯著。
有盛行風向時,小船傾向于同向漂流
與之類似,無關變量可以被看作無盛行風向時隨機漂流的小船;相關變量可以被看作在盛行風向影響下漂流的小船。在這個比喻中,風的強弱就代表著兩個變量之間相關性的強弱。
如果我們允許盛行風向在湖面的不同位置有所不同,那么我們就可以引入非線性的概念。距離相關性利用「小船」之間的距離推斷盛行風的強度。
置信區間?
我們可以采取「重采樣(resampling)」方法為距離相關性估計建立置信區間。一個簡單的例子是 bootstrap 重采樣。
這是一個巧妙的統計技巧,需要我們從原始數據集中隨機抽樣(替換)以「重建」數據。這個過程將重復多次(例如 1000 次),每次都計算感興趣的統計量。
這將為我們感興趣的統計量產生一系列不同的估計值。我們可以通過它們估計在給定置信水平下的上限和下限。
請看下面的 R 語言代碼,它實現了簡單的 bootstrap 函數:
bootstrap <- function(x,y,reps,alpha){
estimates <- c()
original <- data.frame(x,y)
N <- dim(original)[1]
for(i in 1:reps){
S <- original[sample(1:N, N, replace = TRUE),]
estimates <- append(estimates, distanceCorrelation(S$x, S$y))
}
u <- alpha/2 ; l <- 1-u
interval <- quantile(estimates, c(l, u))
return(2*(dcor(x,y)) - as.numeric(interval[1:2]))
}
# Use with 1000 reps and threshold alpha = 0.05
bootstrap(x,y,1000,0.05) # --> 0.237 to 0.546
如果你想建立統計顯著性,還有另一個重采樣技巧,名為「排列檢驗(permutation test)」。
排列檢驗與上述 bootstrap 方法略有不同。在排列檢驗中,我們保持一個向量不變,并通過重采樣對另一個變量進行「洗牌」。這接近于零假設(null hypothesis)——即,在變量之間不存在依賴關系。
這個經「洗牌」打亂的變量將被用于計算它和常變量間的距離相關性。這個過程將被執行多次,然后,結果的分布將與實際距離相關性(從未被「洗牌」的數據中獲得)相比較。
然后,大于或等于「實際」結果的經「洗牌」的結果的比例將被定為 P 值,并與給定的顯著性閾值(如 0.05)進行比較。
以下是上述過程的代碼實現:
permutationTest <- function(x,y,reps){
observed <- distanceCorrelation(x,y)
y_i <- sample(y, length(y), replace = T)
estimates <- append(estimates, distanceCorrelation(x, y_i))
}
p_value <- mean(estimates >= observed)
return(p_value)
}
# Use with 1000 reps
permutationTest(x,y,1000) # --> 0.036
最大信息系數
最大信息系數(MIC)于 2011 年提出,它是用于檢測變量之間非線性相關性的最新方法。用于進行 MIC 計算的算法將信息論和概率的概念應用于連續型數據。
深入細節
由克勞德·香農于 20 世紀中葉開創的信息論是數學中一個引人注目的領域。
信息論中的一個關鍵概念是熵——這是一個衡量給定概率分布的不確定性的度量。概率分布描述了與特定事件相關的一系列給定結果的概率。
概率分布的熵是「每個可能結果的概率乘以其對數后的和」的負值
為了理解其工作原理,讓我們比較下面兩個概率分布:
X 軸標明了可能的結果;Y 軸標明了它們各自的概率
左側是一個常規六面骰子結果的概率分布;而右邊的六面骰子不那么均勻。
從直覺上來說,你認為哪個的熵更高呢?哪個骰子結果的不確定性更大?讓我們來計算它們的熵,看看答案是什么。
entropy <- function(x){
pr <- prop.table(table(x))
H <- sum(pr * log(pr,2))
return(-H)
}
dice1 <- 1:6
dice2 <- c(1,1,1,1,2:6)
entropy(dice1) # --> 2.585
entropy(dice2) # --> 2.281
不出所料,常規骰子的熵更高。這是因為每種結果的可能性都一樣,所以我們不會提前知道結果偏向哪個。但是,非常規的骰子有所不同——某些結果的發生概率遠大于其它結果——所以它的結果的不確定性也低一些。
這么一來,我們就能明白,當每種結果的發生概率相同時,它的熵最高。而這種概率分布也就是傳說中的「均勻」分布。
交叉熵是熵的一個拓展概念,它引入了第二個變量的概率分布。
crossEntropy <- function(x,y){
prX <- prop.table(table(x))
prY <- prop.table(table(y))
H <- sum(prX * log(prY,2))
}
兩個相同概率分布之間的交叉熵等于其各自單獨的熵。但是對于兩個不同的概率分布,它們的交叉熵可能跟各自單獨的熵有所不同。
這種差異,或者叫「散度」可以通過 KL 散度(Kullback-Leibler divergence)量化得出。
兩概率分布 X 與 Y 的 KL 散度如下:
概率分布 X 與 Y 的 KL 散度等于它們的交叉熵減去 X 的熵
KL 散度的最小值為 0,僅當兩個分布相同。
KL_divergence <- function(x,y){
kl <- crossEntropy(x,y) - entropy(x)
return(kl)
}
為了發現變量具有相關性,KL 散度的用途之一是計算兩個變量的互信息(MI)。
互信息可以定義為「兩個隨機變量的聯合分布和邊緣分布之間的 KL 散度」。如果二者相同,MI 值取 0。如若不同,MI 值就為一個正數。二者之間的差異越大,MI 值就越大。
為了加深理解,我們首先簡單回顧一些概率論的知識。
變量 X 和 Y 的聯合概率就是二者同時發生的概率。例如,如果你拋擲兩枚硬幣 X 和 Y,它們的聯合分布將反映拋擲結果的概率。假設你拋擲硬幣 100 次,得到「正面、正面」的結果 40 次。聯合分布將反映如下:
P(X=H, Y=H) = 40/100 = 0.4
jointDist <- function(x,y){
u <- unique(append(x,y))
joint <- c()
for(i in u){
for(j in u){
f <- x[paste0(x,y) == paste0(i,j)]
joint <- append(joint, length(f)/N)
}
}
return(joint)
}
邊緣分布是指不考慮其它變量而只關注某一特定變量的概率分布。假設兩變量獨立,二者邊緣概率的乘積即為二者同時發生的概率。仍以拋硬幣為例,假如拋擲結果是 50 次正面和 50 次反面,它們的邊緣分布如下:
P(X=H) = 50/100 = 0.5 ; P(Y=H) = 50/100 = 0.5
P(X=H) × P(Y=H) = 0.5 × 0.5 = 0.25
marginalProduct <- function(x,y){
marginal <- c()
fX <- length(x[x == i]) / N
fY <- length(y[y == j]) / N
marginal <- append(marginal, fX * fY)
}
return(marginal)
}
現在讓我們回到拋硬幣的例子。如果兩枚硬幣相互獨立,邊緣分布的乘積表示每個結果可能發生的概率,而聯合分布則為實際得到的結果的概率。
如果兩硬幣完全獨立,它們的聯合概率在數值上(約)等于邊緣分布的乘積。若只是部分獨立,此處就存在散度。
這個例子中,P(X=H,Y=H) > P(X=H) × P(Y=H)。這表明兩硬幣全為正面的概率要大于它們的邊緣分布之積。
聯合分布和邊緣分布乘積之間的散度越大,兩個變量之間相關的可能性就越大。兩個變量的互信息定義了散度的度量方式。
X 和 Y 的互信息等于「二者邊緣分布積和的聯合分布的 KL 散度」
mutualInfo <- function(x,y){
joint <- jointDist(x,y)
marginal <- marginalProduct(x,y)
Hjm <- - sum(joint[marginal > 0] * log(marginal[marginal > 0],2))
Hj <- - sum(joint[joint > 0] * log(joint[joint > 0],2))
return(Hjm - Hj)
}
此處的一個重要假設就是概率分布是離散的。那么我們如何把這些概念應用到連續的概率分布呢?
分箱算法
其中一種方法是量化數據(使變量離散化)。這是通過分箱算法(bining)實現的,它能將連續的數據點分配對應的離散類別。
此方法的關鍵問題是到底要使用多少「箱子(bin)」。幸運的是,首次提出 MIC 的論文給出了建議:窮舉!
也就是說,去嘗試不同的「箱子」個數并觀測哪個會在變量間取到最大的互信息值。不過,這提出了兩個挑戰:
要試多少個箱子呢?理論上你可以將變量量化到任意間距值,可以使箱子尺寸越來越小。
互信息對所用的箱子數很敏感。你如何公平比較不同箱子數目之間的 MI 值?
第一個挑戰從理論上講是不能做到的。但是,論文作者提供了一個啟發式解法(也就是說,解法不完美,但是十分接近完美解法)。他們也給出了可試箱子個數的上限。
最大可用箱子個數由樣本數 N 決定
至于如何公平比較取不同箱子數對 MI 值的影響,有一個簡單的做法……就是歸一化!這可以通過將每個 MI 值除以在特定箱子數組合上取得的理論最大值來完成。我們要采用的是產生最大歸一化 MI 總值的箱子數組合。
互信息可以通過除以最小的箱子數的對數來歸一化
最大的歸一化互信息就是 X 和 Y 的最大信息系數(MIC)。我們來看看一些估算兩個連續變量的 MIC 的代碼。
MIC <- function(x,y){
maxBins <- ceiling(N ** 0.6)
MI <- c()
for(i in 2:maxBins) {
for (j in 2:maxBins){
if(i * j > maxBins){
next
Xbins <- i; Ybins <- j
binnedX <-cut(x, breaks=Xbins, labels = 1:Xbins)
binnedY <-cut(y, breaks=Ybins, labels = 1:Ybins)
MI_estimate <- mutualInfo(binnedX,binnedY)
MI_normalized <- MI_estimate / log(min(Xbins,Ybins),2)
MI <- append(MI, MI_normalized)
}
}
return(max(MI))
}
x <- runif(100,-10,10)
y <- x**2 rnorm(100,0,10)
MIC(x,y) # --> 0.751
以上代碼是對原論文中方法的簡化。更接近原作的算法實現可以參考 R package minerva(https://cran.r-project.org/web/packages/minerva/index.html)。
在 Python 中的實現請參考 minepy module(https://minepy.readthedocs.io/en/latest/)。
MIC 能夠表示各種線性和非線性的關系,并已得到廣泛應用。它的值域在 0 和 1 之間,值越高表示相關性越強。
置信區間?
為了建立 MIC 估計值的置信區間,你可以簡單地使用一個像我們之前介紹過的 bootstrap 函數。我們可以利用 R 語言的函數式編程,通過傳遞我們想要用作參數的函數來泛化 bootstrap 函數。
bootstrap <- function(x,y,func,reps,alpha){
estimates <- append(estimates, func(S$x, S$y))
}
l <- alpha/2 ; u <- 1 - l
interval <- quantile(estimates, c(u, l))
return(2*(func(x,y)) - as.numeric(interval[1:2]))
}
bootstrap(x,y,MIC,100,0.05) # --> 0.594 to 0.88
總結
為了總結相關性這一主題,我們來測試下各算法在人工生成數據上的處理能力。
完整代碼:https://gist.github.com/anonymous/fabecccf33f9c3feb568384f626a2c07
噪聲函數
set.seed(123)
# Noise
x0 <- rnorm(100,0,1)
y0 <- rnorm(100,0,1)
plot(y0~x0, pch = 18)
cor(x0,y0)
distanceCorrelation(x0,y0)
MIC(x0,y0)
Pearson\’sr = – 0.05
距離相關性 = 0.157
MIC = 0.097
簡單線性函數
# Simple linear relationship
x1 <- -20:20
y1 <- x1 rnorm(41,0,4)
plot(y1~x1, pch =18)
cor(x1,y1)
distanceCorrelation(x1,y1)
MIC(x1,y1)
Pearson\’s r= 0.95
距離相關性 = 0.95
MIC = 0.89
簡單二次函數
# y ~ x**2
x2 <- -20:20
y2 <- x2**2 rnorm(41,0,40)
plot(y2~x2, pch = 18)
cor(x2,y2)
distanceCorrelation(x2,y2)
MIC(x2,y2)
Pearson\’s r = 0.003
距離相關性 = 0.474
MIC = 0.594
三次函數
# Cosine
x3 <- -20:20
y3 <- cos(x3/4) rnorm(41,0,0.2)
plot(y3~x3, type=\'p\', pch=18)
cor(x3,y3)
distanceCorrelation(x3,y3)
MIC(x3,y3)
Pearson\’s r=- 0.035
距離相關性 = 0.382
MIC = 0.484
圓函數
# Circle
n <- 50
theta <- runif (n, 0, 2*pi)
x4 <- append(cos(theta), cos(theta))
y4 <- append(sin(theta), -sin(theta))
plot(x4,y4, pch=18)
cor(x4,y4)
distanceCorrelation(x4,y4)
MIC(x4,y4)
Pearson\’s r< 0.001
距離相關性 = 0.234
MIC = 0.218
原文鏈接:https://medium.freecodecamp.org/how-machines-make-predictions-finding-correlations-in-complex-data-dfd9f0d87889
本文為機器之心編譯,轉載請聯系本公眾號獲得授權。
原創文章,作者:賴頌強講孩子沉迷網絡游戲怎么辦,如若轉載,請注明出處:http://www.69xo69.com/153714.html