对于 m x n 矩阵,计算所有列对( n x n )的互信息的最佳(最快)方法是什么?
按mutual information,我的意思是:
I(X,Y)= H(X)+ H(Y) - H(X,Y)
其中 H(X)指的是 X 的香农熵。
目前,我正在使用np.histogram2d
和np.histogram
来计算联合(X,Y)和个人(X或Y)计数。对于给定的矩阵A
(例如,250000 X 1000浮点矩阵),我正在进行嵌套的for
循环,
n = A.shape[1]
for ix = arange(n)
for jx = arange(ix+1,n):
matMI[ix,jx]= calc_MI(A[:,ix],A[:,jx])
当然必须有更好/更快的方法来做到这一点?
顺便说一下,我还在数组上寻找列(列式或行式操作)上的映射函数,但还没有找到一个很好的通用答案。
这是我的完整实施,遵循the Wiki page中的约定:
import numpy as np
def calc_MI(X,Y,bins):
c_XY = np.histogram2d(X,Y,bins)[0]
c_X = np.histogram(X,bins)[0]
c_Y = np.histogram(Y,bins)[0]
H_X = shan_entropy(c_X)
H_Y = shan_entropy(c_Y)
H_XY = shan_entropy(c_XY)
MI = H_X + H_Y - H_XY
return MI
def shan_entropy(c):
c_normalized = c / float(np.sum(c))
c_normalized = c_normalized[np.nonzero(c_normalized)]
H = -sum(c_normalized* np.log2(c_normalized))
return H
A = np.array([[ 2.0, 140.0, 128.23, -150.5, -5.4 ],
[ 2.4, 153.11, 130.34, -130.1, -9.5 ],
[ 1.2, 156.9, 120.11, -110.45,-1.12 ]])
bins = 5 # ?
n = A.shape[1]
matMI = np.zeros((n, n))
for ix in np.arange(n):
for jx in np.arange(ix+1,n):
matMI[ix,jx] = calc_MI(A[:,ix], A[:,jx], bins)
虽然我的嵌套for
循环的工作版本以合理的速度完成,但我想知道是否有更优化的方法在{{1}的所有列上应用calc_MI
}(计算他们的成对互信息)?
我也想知道:
是否有有效的方法来映射函数以对A
的列(或行)进行操作(可能像np.arrays
,看起来更像装饰器)?
此特定计算(互信息)是否还有其他最佳实施方式?
答案 0 :(得分:44)
我无法建议在n *(n-1)/ 2上更快地计算外环
向量,但您的calc_MI(x, y, bins)
实现可以简化
如果你可以使用scipy版本0.13或scikit-learn。
在scipy 0.13中,lambda_
参数已添加到scipy.stats.chi2_contingency
此参数控制由函数计算的统计信息。如果
您使用lambda_="log-likelihood"
(或lambda_=0
),对数似然比
退回。这通常也称为G或G 2 统计。以外
系数为2 * n(其中n是意外事件中的样本总数
表),这个是的互信息。所以你可以实现calc_MI
为:
from scipy.stats import chi2_contingency
def calc_MI(x, y, bins):
c_xy = np.histogram2d(x, y, bins)[0]
g, p, dof, expected = chi2_contingency(c_xy, lambda_="log-likelihood")
mi = 0.5 * g / c_xy.sum()
return mi
这和你的实现之间的唯一区别就是这个
实现使用自然对数而不是base-2对数
(因此它以“nats”而不是“bits”表示信息)。如果
你真的更喜欢比特,只需将mi
除以log(2)。
如果您有(或可以安装)sklearn
(即scikit-learn),您可以使用
sklearn.metrics.mutual_info_score
,并将calc_MI
实施为:
from sklearn.metrics import mutual_info_score
def calc_MI(x, y, bins):
c_xy = np.histogram2d(x, y, bins)[0]
mi = mutual_info_score(None, None, contingency=c_xy)
return mi