相互情報量の定義と応用

相互情報量は「2つの確率変数がどれだけ情報を共有しているか」を測る量です。相関係数が線形な関係しか捉えられないのに対し、相互情報量は非線形な依存関係も含めた一般的な統計的依存性を定量化できます。機械学習での特徴選択や、通信路容量の計算など、幅広い応用を持ちます。

本記事の内容

  • 相互情報量の定義
  • エントロピーとの関係
  • KLダイバージェンスとの関係
  • 相互情報量の性質
  • 特徴選択への応用
  • Pythonでの実装と可視化

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

相互情報量の定義

2つの離散確率変数 $X$, $Y$ の相互情報量(mutual information)は次のように定義されます。

$$ \boxed{I(X; Y) = \sum_{x}\sum_{y} P(x, y) \log \frac{P(x, y)}{P(x)P(y)}} $$

相互情報量は、$X$ と $Y$ が独立($P(x,y) = P(x)P(y)$)からどれだけ離れているかを測ります。

エントロピーとの関係

相互情報量は、以下の等価な表現を持ちます。

$$ \boxed{I(X; Y) = H(X) – H(X|Y) = H(Y) – H(Y|X)} $$

導出

$$ \begin{align} I(X; Y) &= \sum_{x}\sum_{y} P(x, y) \log \frac{P(x, y)}{P(x)P(y)} \\ &= \sum_{x}\sum_{y} P(x, y) \log \frac{P(x|y)}{P(x)} \\ &= \sum_{x}\sum_{y} P(x, y) \log P(x|y) – \sum_{x}\sum_{y} P(x, y) \log P(x) \\ &= -H(X|Y) – \left(-H(X)\right) \\ &= H(X) – H(X|Y) \end{align} $$

同様に、$P(x,y)/P(x)P(y) = P(y|x)/P(y)$ を用いると:

$$ I(X; Y) = H(Y) – H(Y|X) $$

さらなる等価表現

$$ I(X; Y) = H(X) + H(Y) – H(X, Y) $$

導出

連鎖律 $H(X, Y) = H(X) + H(Y|X)$ より:

$$ \begin{align} I(X; Y) &= H(Y) – H(Y|X) \\ &= H(Y) – (H(X, Y) – H(X)) \\ &= H(X) + H(Y) – H(X, Y) \end{align} $$

直感

$I(X; Y)$ は次のように解釈できます。

  • $H(X)$ は $X$ の全不確実性
  • $H(X|Y)$ は $Y$ を知った後の $X$ の残りの不確実性
  • $I(X; Y) = H(X) – H(X|Y)$ は「$Y$ を知ることで $X$ について得られた情報量」

KLダイバージェンスとの関係

KLダイバージェンス(Kullback-Leibler divergence)は2つの確率分布の「距離」(厳密には距離ではない)を測る量です。

$$ D_{\text{KL}}(P \| Q) = \sum_{x} P(x) \log \frac{P(x)}{Q(x)} $$

相互情報量は結合分布 $P(X, Y)$ と独立分布 $P(X)P(Y)$ のKLダイバージェンスです。

$$ \boxed{I(X; Y) = D_{\text{KL}}\left(P(X, Y) \| P(X)P(Y)\right)} $$

導出

$$ \begin{align} D_{\text{KL}}(P(X,Y) \| P(X)P(Y)) &= \sum_{x}\sum_{y} P(x,y) \log \frac{P(x,y)}{P(x)P(y)} \\ &= I(X; Y) \end{align} $$

KLダイバージェンスの定義そのものが相互情報量の定義と一致します。

相互情報量の性質

  1. 非負性: $I(X; Y) \geq 0$(ギブスの不等式より)
  2. 対称性: $I(X; Y) = I(Y; X)$
  3. 上界: $I(X; Y) \leq \min(H(X), H(Y))$
  4. 独立のとき: $I(X; Y) = 0 \Leftrightarrow X, Y$ が独立
  5. 自己相互情報量: $I(X; X) = H(X)$

性質5は $H(X|X) = 0$ から直ちに従います。エントロピーは「自分自身との相互情報量」です。

特徴選択への応用

機械学習において、入力特徴量 $X_i$ とターゲット変数 $Y$ の相互情報量 $I(X_i; Y)$ が大きい特徴量を選ぶことで、予測に有用な特徴量を選択できます。

相関係数に対する利点は:

  • 非線形な依存関係も検出できる
  • カテゴリ変数にも適用できる

Pythonでの実装

相互情報量の計算

import numpy as np
import matplotlib.pyplot as plt

def entropy(probs):
    """エントロピーを計算(底2)"""
    probs = np.array(probs).flatten()
    probs = probs[probs > 0]
    return -np.sum(probs * np.log2(probs))

def mutual_information(joint_probs):
    """結合確率分布から相互情報量を計算"""
    joint = np.array(joint_probs)
    px = joint.sum(axis=1)
    py = joint.sum(axis=0)
    H_X = entropy(px)
    H_Y = entropy(py)
    H_XY = entropy(joint)
    return H_X + H_Y - H_XY

def kl_divergence(p, q):
    """KLダイバージェンス D_KL(P||Q) を計算"""
    p = np.array(p).flatten()
    q = np.array(q).flatten()
    mask = p > 0
    return np.sum(p[mask] * np.log2(p[mask] / q[mask]))

# --- 天気と傘の例 ---
joint = np.array([
    [0.10, 0.50],
    [0.25, 0.15],
])
px = joint.sum(axis=1)
py = joint.sum(axis=0)

I_XY = mutual_information(joint)

# KLダイバージェンスとしての計算
independent = np.outer(px, py)
I_XY_kl = kl_divergence(joint, independent)

print("=== 天気(X)と傘(Y)の相互情報量 ===")
print(f"H(X)     = {entropy(px):.4f} bit")
print(f"H(Y)     = {entropy(py):.4f} bit")
print(f"H(X,Y)   = {entropy(joint):.4f} bit")
print(f"I(X;Y)   = {I_XY:.4f} bit")
print(f"I(X;Y) via KL = {I_XY_kl:.4f} bit")

相互情報量と依存度の関係

import numpy as np
import matplotlib.pyplot as plt

def entropy(probs):
    probs = np.array(probs).flatten()
    probs = probs[probs > 0]
    return -np.sum(probs * np.log2(probs))

def mutual_information(joint_probs):
    joint = np.array(joint_probs)
    px = joint.sum(axis=1)
    py = joint.sum(axis=0)
    return entropy(px) + entropy(py) - entropy(joint)

# --- 依存度パラメータと相互情報量の関係 ---
alphas = np.linspace(0, 0.49, 200)
mi_values = []

for alpha in alphas:
    joint = np.array([
        [0.25 + alpha, 0.25 - alpha],
        [0.25 - alpha, 0.25 + alpha],
    ])
    joint = np.clip(joint, 1e-15, None)
    mi_values.append(mutual_information(joint))

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# 左: 相互情報量 vs 依存度
axes[0].plot(alphas, mi_values, 'b-', linewidth=2)
axes[0].set_xlabel('Dependence parameter α', fontsize=12)
axes[0].set_ylabel('I(X;Y) [bit]', fontsize=12)
axes[0].set_title('Mutual Information vs Dependence', fontsize=13)
axes[0].grid(True, alpha=0.3)

# 右: ベン図(エントロピーの関係)
from matplotlib.patches import Circle

joint = np.array([[0.10, 0.50], [0.25, 0.15]])
px = joint.sum(axis=1)
py = joint.sum(axis=0)
H_X = entropy(px)
H_Y = entropy(py)
H_XY = entropy(joint)
I_XY = H_X + H_Y - H_XY

c1 = Circle((0.35, 0.5), 0.25, fill=False, edgecolor='blue', linewidth=2)
c2 = Circle((0.60, 0.5), 0.25, fill=False, edgecolor='red', linewidth=2)
axes[1].add_patch(c1)
axes[1].add_patch(c2)

axes[1].text(0.22, 0.5, f'H(X|Y)\n{H_X-I_XY:.3f}', fontsize=11, ha='center', va='center', color='blue')
axes[1].text(0.73, 0.5, f'H(Y|X)\n{H_Y-I_XY:.3f}', fontsize=11, ha='center', va='center', color='red')
axes[1].text(0.475, 0.5, f'I(X;Y)\n{I_XY:.3f}', fontsize=11, ha='center', va='center', color='purple')
axes[1].text(0.475, 0.1, f'H(X,Y) = {H_XY:.3f} bit', fontsize=12, ha='center')

axes[1].set_xlim(0, 1)
axes[1].set_ylim(0, 1)
axes[1].set_aspect('equal')
axes[1].set_title('Information Venn Diagram', fontsize=13)
axes[1].axis('off')

plt.tight_layout()
plt.show()

特徴選択への応用

import numpy as np
import matplotlib.pyplot as plt

def mutual_information_continuous(x, y, bins=30):
    """連続値の相互情報量をヒストグラムで推定"""
    # 2次元ヒストグラムで結合分布を推定
    hist_2d, x_edges, y_edges = np.histogram2d(x, y, bins=bins)
    joint = hist_2d / hist_2d.sum()

    px = joint.sum(axis=1)
    py = joint.sum(axis=0)

    # 相互情報量を計算
    mi = 0.0
    for i in range(len(px)):
        for j in range(len(py)):
            if joint[i, j] > 0 and px[i] > 0 and py[j] > 0:
                mi += joint[i, j] * np.log2(joint[i, j] / (px[i] * py[j]))
    return mi

# --- 特徴選択の例 ---
np.random.seed(42)
n = 1000

# ターゲット変数
y = np.random.randn(n)

# 特徴量
x1 = y + 0.1 * np.random.randn(n)     # 強い線形関係
x2 = y**2 + 0.3 * np.random.randn(n)  # 非線形関係
x3 = np.random.randn(n)                # 独立(ノイズ)
x4 = np.sin(2 * y) + 0.2 * np.random.randn(n)  # 非線形周期的関係

features = {'x1 (linear)': x1, 'x2 (quadratic)': x2,
            'x3 (noise)': x3, 'x4 (sinusoidal)': x4}

# 相互情報量と相関係数を計算
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

mi_values = {}
corr_values = {}

for ax, (name, x) in zip(axes.flatten(), features.items()):
    mi = mutual_information_continuous(x, y, bins=25)
    corr = np.corrcoef(x, y)[0, 1]
    mi_values[name] = mi
    corr_values[name] = corr

    ax.scatter(x, y, alpha=0.3, s=5)
    ax.set_title(f'{name}\nMI={mi:.3f}, corr={corr:.3f}', fontsize=12)
    ax.set_xlabel('Feature', fontsize=11)
    ax.set_ylabel('Target y', fontsize=11)
    ax.grid(True, alpha=0.3)

plt.suptitle('Feature Selection: MI vs Correlation', fontsize=14)
plt.tight_layout()
plt.show()

# 比較棒グラフ
fig, axes = plt.subplots(1, 2, figsize=(12, 4))

names = list(features.keys())
mis = [mi_values[n] for n in names]
corrs = [abs(corr_values[n]) for n in names]

axes[0].barh(names, mis, color='steelblue')
axes[0].set_xlabel('Mutual Information [bit]', fontsize=12)
axes[0].set_title('Mutual Information', fontsize=13)

axes[1].barh(names, corrs, color='coral')
axes[1].set_xlabel('|Correlation|', fontsize=12)
axes[1].set_title('Absolute Correlation', fontsize=13)

plt.tight_layout()
plt.show()

相関係数は $x_2$(2次関数的な関係)に対して低い値を示しますが、相互情報量は非線形な関係も検出できるため、より高い値を示します。これが特徴選択において相互情報量が有用な理由です。

まとめ

本記事では、相互情報量の定義と応用について解説しました。

  • 定義: $I(X; Y) = \sum P(x,y) \log \frac{P(x,y)}{P(x)P(y)}$
  • エントロピーとの関係: $I(X; Y) = H(X) – H(X|Y) = H(Y) – H(Y|X)$
  • KLダイバージェンス: $I(X; Y) = D_{\text{KL}}(P(X,Y) \| P(X)P(Y))$
  • 非線形依存性: 相関係数では捉えられない非線形関係も検出可能
  • 特徴選択: $I(X_i; Y)$ の大きい特徴量を選ぶことで予測性能を向上