68

对于mxn矩阵,计算所有列对( nxn )的互信息的最佳(最快)方法是什么?

通过互信息,我的意思是:

I(X, Y) = H(X) + H(Y) - H(X,Y)

其中H(X)是指 X 的香农

目前我正在使用np.histogram2dandnp.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])

当然必须有更好/更快的方法来做到这一点?

顺便说一句,我还在数组上的列(按列或按行操作)上寻找映射函数,但还没有找到一个好的通用答案。

这是我的完整实现,遵循Wiki 页面中的约定:

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循环的工作版本以合理的速度运行,但我想知道是否有更优化的方法应用于calc_MI所有列A(以计算它们的成对互信息)?

我也想知道:

  1. 是否有有效的方法来映射函数以对np.arrays(可能像np.vectorize,它看起来更像一个装饰器)的列(或行)进行操作?

  2. 对于这个特定的计算(互信息)是否还有其他优化的实现方式?

4

1 回答 1

67

我不能建议对 n*(n-1)/2 向量的外循环进行更快的计算,但是如果您可以使用 scipy 版本 0.13 或scikit-learncalc_MI(x, y, bins) ,则可以简化您的实现。

在 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

这与您的实现之间的唯一区别是此实现使用自然对数而不是以 2 为底的对数(因此它用“nats”而不是“bits”表示信息)。如果您真的更喜欢位,只需除以milog(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
于 2013-12-10T21:20:10.690 回答