You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何计算两个numpy向量互信息结果相同?正确计算方法是什么?

问题

我想要计算两个numpy向量之间的互信息,使用sklearn的mutual_info_score函数进行测试:

>>>from sklearn.metrics.cluster import mutual_info_score
>>>import numpy as np

>>>a, b = np.random.rand(10), np.random.rand(10)
>>>mutual_info_score(a, b)
1.6094379124341005

>>>a, b = np.random.rand(10), np.random.rand(10)
>>>mutual_info_score(a, b)
1.6094379124341005

可以看到,尽管更新了a和b,却返回相同的值。随后我尝试了另一组示例:

>>>a = np.array([167.52523295,  73.2904335 ,  98.61953303, 152.17297007,
       211.01341451, 327.72296346, 356.60500081,  43.9371432 ,
       119.09474284, 125.20180842])

>>>b = np.array([280.9287028 , 131.76304983, 176.0277832 , 188.56630096,
       229.09811401, 228.47200012, 617.67000122,  52.7211511 ,
       125.95361582, 148.55247447])

>>>mutual_info_score(a, b)
2.302585092994046


>>>a = np.array([ 6.71381009,  1.43607653,  3.78729242, -4.75706796, -3.81281173,
        3.23440092, 10.84495625, -0.19646145,  4.09724507, -0.13858104])

>>>b = np.array([ 4.25330873,  3.02197642, -3.2833848 ,  0.41855662, -3.74693531,
        0.7674982 , 11.36459148,  0.64636462,  0.51817262,  1.65318943])

>>>mutual_info_score(a, b)
2.302585092994046

为何会出现这种情况?这些向量数值差异明显,却返回相同结果?更重要的是,如何正确计算两个向量之间的互信息?

原因分析

sklearn.metrics.cluster.mutual_info_score是为离散类别数据设计的工具,比如聚类标签、分类任务的类别,它会将输入中的每个唯一值视为一个独立类别。

当你输入连续型numpy向量时,由于随机生成的浮点数几乎全是唯一值,函数会把每个样本当成单独的类别。此时:

  • 每个a的类别对应唯一的b类别(因为样本是成对的(a_i, b_i)),条件熵H(b|a)=0
  • 互信息I(a;b) = H(a) - H(a|b) = H(a)(或等于H(b),因为两者熵值相同)

你的测试案例中:

  • 第二组的两个向量都包含10个唯一值,所以H(a)=ln(10)≈2.3025,与返回结果一致
  • 第一组的随机向量恰好包含5个唯一值,因此返回ln(5)≈1.6094,两次随机生成的向量类别数相同,结果自然一致

正确计算连续向量互信息的方法

方法1:分箱离散化后计算

先把连续向量划分为若干离散区间,再用mutual_info_score计算:

import numpy as np
from sklearn.metrics.cluster import mutual_info_score
from sklearn.preprocessing import KBinsDiscretizer

# 生成连续向量
a = np.random.rand(100)
b = np.random.rand(100)

# 分箱离散化,分成10个区间
discretizer = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')
a_discrete = discretizer.fit_transform(a.reshape(-1, 1)).flatten()
b_discrete = discretizer.transform(b.reshape(-1, 1)).flatten()

# 计算互信息
mi = mutual_info_score(a_discrete, b_discrete)
print(mi)

方法2:使用连续变量专用函数

sklearn.feature_selection.mutual_info_regression可以直接计算连续特征与连续目标的互信息:

import numpy as np
from sklearn.feature_selection import mutual_info_regression

a = np.random.rand(100).reshape(-1, 1)
b = np.random.rand(100)

# 计算互信息
mi = mutual_info_regression(a, b)[0]
print(mi)

方法3:手动估计概率密度计算

通过核密度估计(KDE)计算联合概率密度和边缘概率密度,再按互信息定义计算:

import numpy as np
from scipy.stats import kde

def mutual_info_continuous(x, y):
    # 估计联合概率密度
    kde_xy = kde.gaussian_kde([x, y])
    # 估计边缘概率密度
    kde_x = kde.gaussian_kde(x)
    kde_y = kde.gaussian_kde(y)
    
    # 生成网格点计算密度
    x_grid, y_grid = np.meshgrid(np.linspace(x.min(), x.max(), 100), 
                                 np.linspace(y.min(), y.max(), 100))
    positions = np.vstack([x_grid.ravel(), y_grid.ravel()])
    
    p_xy = kde_xy(positions)
    p_x = kde_x(positions[0])
    p_y = kde_y(positions[1])
    
    # 计算互信息,避免log(0)
    mask = p_xy > 0
    mi = np.sum(p_xy[mask] * np.log(p_xy[mask] / (p_x[mask] * p_y[mask])))
    # 归一化网格面积
    mi *= (x.max() - x.min()) * (y.max() - y.min()) / (100*100)
    return mi

# 测试
a = np.random.rand(100)
b = np.random.rand(100)
print(mutual_info_continuous(a, b))

内容的提问来源于stack exchange,提问作者Shayan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 05:05:22