結合エントロピーと条件付きエントロピー

2つ以上の確率変数を同時に扱う場合、それらの不確実性をどう測るかが重要になります。結合エントロピーは2つの変数の「全体の不確実性」を、条件付きエントロピーは「一方を知った後の残りの不確実性」を表します。これらは情報理論における基本的な量であり、相互情報量やデータ圧縮の理解に不可欠です。

本記事の内容

  • 結合エントロピーの定義と性質
  • 条件付きエントロピーの定義と直感
  • エントロピーの連鎖律
  • 独立な確率変数の場合
  • Pythonでの計算と可視化

前提知識

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

結合エントロピーの定義

2つの離散確率変数 $X$, $Y$ の結合エントロピー(joint entropy)は次のように定義されます。

$$ \boxed{H(X, Y) = -\sum_{x}\sum_{y} P(x, y) \log P(x, y)} $$

ここで $P(x, y)$ は $X = x$ かつ $Y = y$ となる結合確率です。

結合エントロピーは「$X$ と $Y$ の組を観測したときの平均的な驚き(不確実性)」を表します。

性質

  1. 非負性: $H(X, Y) \geq 0$
  2. 上界: $H(X, Y) \leq H(X) + H(Y)$(等号は $X, Y$ が独立のとき)
  3. 下界: $H(X, Y) \geq \max(H(X), H(Y))$

性質2は直感的に理解できます。2つの変数の全体の不確実性は、それぞれの不確実性の和以下です。なぜなら、$X$ と $Y$ の間に関係(相関)があれば、片方を知ることでもう片方の不確実性が減るからです。

条件付きエントロピーの定義

$X$ を知った後の $Y$ の残りの不確実性を表す条件付きエントロピー(conditional entropy)は:

$$ \boxed{H(Y|X) = -\sum_{x}\sum_{y} P(x, y) \log P(y|x)} $$

これは条件付き自己情報量 $-\log P(y|x)$ の結合分布に関する期待値です。

別の表現

条件付きエントロピーを $X$ の各値で平均したものとしても書けます。

$$ H(Y|X) = \sum_{x} P(x) H(Y|X=x) $$

ここで:

$$ H(Y|X=x) = -\sum_{y} P(y|x) \log P(y|x) $$

は $X = x$ が与えられたときの $Y$ のエントロピーです。

導出

$H(Y|X)$ の定義式を変形します。

$$ \begin{align} H(Y|X) &= -\sum_{x}\sum_{y} P(x, y) \log P(y|x) \\ &= -\sum_{x}\sum_{y} P(x) P(y|x) \log P(y|x) \\ &= -\sum_{x} P(x) \sum_{y} P(y|x) \log P(y|x) \\ &= \sum_{x} P(x) H(Y|X=x) \end{align} $$

直感

条件付きエントロピー $H(Y|X)$ は:

  • $X$ と $Y$ が独立なら $H(Y|X) = H(Y)$($X$ を知っても $Y$ の不確実性は変わらない)
  • $Y$ が $X$ で完全に決まるなら $H(Y|X) = 0$($X$ を知れば $Y$ の不確実性はゼロ)
  • 一般に $0 \leq H(Y|X) \leq H(Y)$(条件付けは平均的にエントロピーを減らす)

エントロピーの連鎖律

結合エントロピーは次のように分解できます。

$$ \boxed{H(X, Y) = H(X) + H(Y|X)} $$

これが連鎖律(chain rule)です。

導出

$$ \begin{align} H(X, Y) &= -\sum_{x}\sum_{y} P(x, y) \log P(x, y) \\ &= -\sum_{x}\sum_{y} P(x, y) \log \left[P(x) P(y|x)\right] \\ &= -\sum_{x}\sum_{y} P(x, y) \log P(x) – \sum_{x}\sum_{y} P(x, y) \log P(y|x) \\ &= -\sum_{x} \log P(x) \underbrace{\sum_{y} P(x, y)}_{= P(x)} + H(Y|X) \\ &= -\sum_{x} P(x) \log P(x) + H(Y|X) \\ &= H(X) + H(Y|X) \end{align} $$

対称性より:

$$ H(X, Y) = H(Y) + H(X|Y) $$

も成り立ちます。

$n$ 変数への一般化

$$ H(X_1, X_2, \dots, X_n) = \sum_{i=1}^{n} H(X_i | X_1, \dots, X_{i-1}) $$

独立な確率変数の場合

$X$ と $Y$ が独立のとき $P(y|x) = P(y)$ なので:

$$ H(Y|X) = H(Y) $$

したがって連鎖律より:

$$ \boxed{H(X, Y) = H(X) + H(Y) \quad \text{($X, Y$ が独立のとき)}} $$

独立な場合、結合エントロピーは単にそれぞれのエントロピーの和になります。

具体例

天気 $X \in \{\text{晴れ}, \text{雨}\}$ と傘 $Y \in \{\text{持つ}, \text{持たない}\}$ の同時分布を考えます。

持つ 持たない $P(X)$
晴れ 0.10 0.50 0.60
0.25 0.15 0.40
$P(Y)$ 0.35 0.65 1.00

$$ \begin{align} H(X) &= -(0.6\log_2 0.6 + 0.4\log_2 0.4) \approx 0.971 \text{ bit} \\ H(Y) &= -(0.35\log_2 0.35 + 0.65\log_2 0.65) \approx 0.934 \text{ bit} \end{align} $$

$$ \begin{align} H(X, Y) &= -(0.10\log_2 0.10 + 0.50\log_2 0.50 + 0.25\log_2 0.25 + 0.15\log_2 0.15) \\ &\approx 1.755 \text{ bit} \end{align} $$

連鎖律から:

$$ H(Y|X) = H(X, Y) – H(X) \approx 1.755 – 0.971 = 0.784 \text{ bit} $$

$H(Y|X) = 0.784 < H(Y) = 0.934$ なので、天気を知ることで傘の不確実性が減ることが確認できます。

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 joint_entropy(joint_probs):
    """結合エントロピーを計算"""
    return entropy(joint_probs)

def conditional_entropy(joint_probs):
    """H(Y|X) を計算(joint_probs は行が X, 列が Y)"""
    joint = np.array(joint_probs)
    px = joint.sum(axis=1)  # X の周辺分布
    H_Y_given_X = 0.0
    for i in range(joint.shape[0]):
        if px[i] > 0:
            p_y_given_x = joint[i, :] / px[i]
            H_Y_given_X += px[i] * entropy(p_y_given_x)
    return H_Y_given_X

# --- 天気と傘の例 ---
joint = np.array([
    [0.10, 0.50],  # 晴れ: (持つ, 持たない)
    [0.25, 0.15],  # 雨:   (持つ, 持たない)
])

px = joint.sum(axis=1)  # P(X)
py = joint.sum(axis=0)  # P(Y)

H_X = entropy(px)
H_Y = entropy(py)
H_XY = joint_entropy(joint)
H_Y_given_X = conditional_entropy(joint)
H_X_given_Y = H_XY - H_Y

print("=== 天気(X)と傘(Y)の例 ===")
print(f"H(X)     = {H_X:.4f} bit")
print(f"H(Y)     = {H_Y:.4f} bit")
print(f"H(X,Y)   = {H_XY:.4f} bit")
print(f"H(Y|X)   = {H_Y_given_X:.4f} bit")
print(f"H(X|Y)   = {H_X_given_Y:.4f} bit")
print(f"H(X)+H(Y|X) = {H_X + H_Y_given_X:.4f} bit  (= H(X,Y))")
print(f"H(X)+H(Y)   = {H_X + H_Y:.4f} bit  (>= H(X,Y))")

連鎖律とベン図の可視化

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle

# --- エントロピーのベン図 ---
fig, ax = plt.subplots(figsize=(8, 6))

# 2つの円
c1 = Circle((0.35, 0.5), 0.3, fill=False, edgecolor='blue', linewidth=2, label='H(X)')
c2 = Circle((0.65, 0.5), 0.3, fill=False, edgecolor='red', linewidth=2, label='H(Y)')
ax.add_patch(c1)
ax.add_patch(c2)

# ラベル
ax.text(0.20, 0.5, 'H(X|Y)', fontsize=13, ha='center', va='center', color='blue')
ax.text(0.80, 0.5, 'H(Y|X)', fontsize=13, ha='center', va='center', color='red')
ax.text(0.50, 0.5, 'I(X;Y)', fontsize=13, ha='center', va='center', color='purple')
ax.text(0.50, 0.05, 'H(X,Y)', fontsize=14, ha='center', va='center',
        bbox=dict(boxstyle='round', facecolor='lightyellow'))

# 数値(天気と傘の例)
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 = joint_entropy(joint)
I_XY = H_X + H_Y - H_XY

ax.text(0.20, 0.35, f'{H_X - I_XY:.3f}', fontsize=11, ha='center', va='center', color='blue')
ax.text(0.80, 0.35, f'{H_Y - I_XY:.3f}', fontsize=11, ha='center', va='center', color='red')
ax.text(0.50, 0.35, f'{I_XY:.3f}', fontsize=11, ha='center', va='center', color='purple')

ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_aspect('equal')
ax.set_title('Entropy Venn Diagram (Weather & Umbrella)', fontsize=14)
ax.legend(loc='upper right', fontsize=11)
ax.axis('off')

plt.tight_layout()
plt.show()

独立性とエントロピーの関係

import numpy as np
import matplotlib.pyplot as plt

# --- 独立度合いとエントロピーの変化 ---
# パラメータ alpha で独立性を制御
# alpha=0: 完全に独立, alpha=1: 強い依存

alphas = np.linspace(0, 0.9, 50)
H_XY_list = []
H_X_list = []
H_Y_list = []
H_Y_given_X_list = []

for alpha in alphas:
    # 2x2 の結合分布を作成
    # 独立分布: px=[0.5,0.5], py=[0.5,0.5] → joint = [[0.25,0.25],[0.25,0.25]]
    # 依存を加える
    joint = np.array([
        [0.25 + alpha * 0.25, 0.25 - alpha * 0.25],
        [0.25 - alpha * 0.25, 0.25 + alpha * 0.25],
    ])
    joint = np.clip(joint, 1e-10, None)
    joint /= joint.sum()

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

    H_XY_list.append(joint_entropy(joint))
    H_X_list.append(entropy(px))
    H_Y_list.append(entropy(py))
    H_Y_given_X_list.append(conditional_entropy(joint))

fig, ax = plt.subplots(figsize=(10, 6))

ax.plot(alphas, H_XY_list, 'b-', linewidth=2, label='H(X,Y)')
ax.plot(alphas, H_X_list, 'g--', linewidth=2, label='H(X)')
ax.plot(alphas, H_Y_list, 'r--', linewidth=2, label='H(Y)')
ax.plot(alphas, H_Y_given_X_list, 'm-', linewidth=2, label='H(Y|X)')
ax.plot(alphas, np.array(H_X_list) + np.array(H_Y_list), 'k:', linewidth=2, label='H(X)+H(Y)')

ax.set_xlabel('Dependence parameter α', fontsize=12)
ax.set_ylabel('Entropy [bit]', fontsize=12)
ax.set_title('Entropy quantities vs dependence', fontsize=13)
ax.legend(fontsize=11)
ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

まとめ

本記事では、結合エントロピーと条件付きエントロピーについて解説しました。

  • 結合エントロピー: $H(X, Y) = -\sum_{x,y} P(x,y) \log P(x,y)$
  • 条件付きエントロピー: $H(Y|X) = -\sum_{x,y} P(x,y) \log P(y|x)$
  • 連鎖律: $H(X, Y) = H(X) + H(Y|X)$
  • 独立のとき: $H(X, Y) = H(X) + H(Y)$
  • 条件付けは平均的にエントロピーを減少させる: $H(Y|X) \leq H(Y)$

次のステップとして、以下の記事も参考にしてください。