🦔

天気予報で学ぶ「情報量」と「クロスエントロピー」〜中学生でもわかる機械学習の基礎【第1回】〜

に公開

天気予報で学ぶ「情報量」と「クロスエントロピー」〜中学生でもわかる機械学習の基礎【第1回】〜

はじめに

こんにちは!今日は「情報量」と「クロスエントロピー」という、データサイエンスでとっても大切な概念を、Pythonを使って楽しく学んでいきましょう!

「えっ、難しそう...」と思った人も大丈夫!天気予報やサイコロ、ガチャゲームなど、身近な例を使って説明するので、中学生でも理解できます🎯

なぜこれを学ぶの?

AIや機械学習では、「予測がどれくらい正確か」を数値で表す必要があります。その時に使うのが今日学ぶ概念です!

例えば:

  • YouTubeのおすすめ動画
  • 天気予報アプリ
  • ゲームのガチャ確率

これらはすべて「確率」と「情報」を使っています。

1. 情報量ってなに?〜驚きを数値化しよう!〜

身近な例で考えてみよう

# 必要なライブラリをインポート
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

# 日本語フォントの設定(グラフで日本語を使うため)
plt.rcParams['font.family'] = 'DejaVu Sans'

想像してください:

  1. 「今日の給食はカレーだよ」(毎週金曜はカレー = 確率100%)
  2. 「今日は臨時休校だよ」(めったにない = 確率1%)

どっちが驚きますか?もちろん2番ですよね!

情報量を計算してみよう

def calculate_information(probability):
    """
    情報量を計算する関数
    確率が低いほど情報量は大きくなる!
    """
    if probability == 0:
        return float('inf')  # 無限大
    return -np.log2(probability)

# いろいろな確率で情報量を計算
events = {
    "給食がカレー(金曜日)": 1.0,
    "晴れ(夏)": 0.8,
    "コイン投げで表": 0.5,
    "サイコロで6": 1/6,
    "宝くじ1等": 0.000001
}

print("【情報量の比較】")
print("-" * 40)
for event, prob in events.items():
    info = calculate_information(prob)
    print(f"{event}: {info:.2f} ビット")

視覚的に見てみよう

# 確率と情報量の関係をグラフ化
probabilities = np.linspace(0.01, 1, 100)
information = [-np.log2(p) for p in probabilities]

plt.figure(figsize=(10, 6))
plt.plot(probabilities, information, linewidth=3, color='blue')
plt.xlabel('確率', fontsize=14)
plt.ylabel('情報量(ビット)', fontsize=14)
plt.title('確率が低いほど情報量は大きい!', fontsize=16)
plt.grid(True, alpha=0.3)
plt.axhline(y=1, color='red', linestyle='--', label='1ビット(コイン投げ)')
plt.legend()
plt.show()

2. 実際に問題を解いてみよう!

問題1:いろいろな確率の情報量

def solve_problem1():
    """問題1の解答をPythonで実装"""
    
    # (1) P(A) = 0.8 のとき
    p1 = 0.8
    i1 = calculate_information(p1)
    print(f"(1) 確率80%の情報量: {i1:.3f} ビット")
    
    # (2) P(A) = 0.5 のとき
    p2 = 0.5
    i2 = calculate_information(p2)
    print(f"(2) 確率50%の情報量: {i2:.3f} ビット")
    
    # 比較のために他の確率も計算
    print("\n【おまけ:他の確率との比較】")
    other_probs = [0.9, 0.1, 0.01]
    for p in other_probs:
        print(f"確率{p*100}%の情報量: {calculate_information(p):.3f} ビット")

solve_problem1()

3. クロスエントロピー〜予想の下手さを測ろう!〜

天気予報士の例

def cross_entropy(true_dist, predicted_dist):
    """
    クロスエントロピーを計算する関数
    true_dist: 本当の確率分布
    predicted_dist: 予想した確率分布
    """
    ce = 0
    for i in range(len(true_dist)):
        if predicted_dist[i] > 0:  # log(0)を避ける
            ce -= true_dist[i] * np.log2(predicted_dist[i])
    return ce

# 問題2を解いてみよう
print("【問題2:天気予報の精度】")
print("-" * 40)

# 真の分布(実際の天気)
true_weather = [0.5, 0.5]  # [晴れ, 雨]
print("実際の天気: 晴れ50%, 雨50%")

# 予報士の予想
prediction = [0.9, 0.1]  # [晴れ, 雨]
print("予報士の予想: 晴れ90%, 雨10%")

# クロスエントロピーを計算
ce = cross_entropy(true_weather, prediction)
print(f"\nクロスエントロピー: {ce:.3f} ビット")

# 完璧な予想の場合
perfect_prediction = [0.5, 0.5]
perfect_ce = cross_entropy(true_weather, perfect_prediction)
print(f"完璧な予想の場合: {perfect_ce:.3f} ビット")
print(f"予想の悪さ: {ce - perfect_ce:.3f} ビット分")

いろいろな予報士を比較してみよう!

# 複数の予報士を比較
forecasters = {
    "完璧な予報士": [0.5, 0.5],
    "楽観的な予報士": [0.9, 0.1],
    "悲観的な予報士": [0.1, 0.9],
    "普通の予報士": [0.6, 0.4],
    "最悪の予報士": [1.0, 0.0]
}

results = []
for name, prediction in forecasters.items():
    ce = cross_entropy(true_weather, prediction)
    results.append({
        "予報士": name,
        "晴れ予想": f"{prediction[0]*100}%",
        "雨予想": f"{prediction[1]*100}%", 
        "クロスエントロピー": round(ce, 3)
    })

# データフレームで見やすく表示
df = pd.DataFrame(results)
df = df.sort_values("クロスエントロピー")
print("\n【予報士ランキング】")
print(df.to_string(index=False))

グラフで可視化

# 予報士の成績を棒グラフで表示
plt.figure(figsize=(10, 6))
names = df["予報士"].values
scores = df["クロスエントロピー"].values

bars = plt.bar(names, scores, color=['green', 'lightgreen', 'yellow', 'orange', 'red'])
plt.ylabel('クロスエントロピー(低いほど良い)', fontsize=12)
plt.title('天気予報士の成績比較', fontsize=16)
plt.xticks(rotation=45)

# 1ビットのラインを追加
plt.axhline(y=1, color='blue', linestyle='--', alpha=0.5)
plt.text(0, 1.05, '理論的最小値(1ビット)', fontsize=10)

plt.tight_layout()
plt.show()

4. 実践!ガチャゲームで学ぶ情報理論

def gacha_information():
    """ガチャの当たりやすさと情報量の関係"""
    
    gacha_rates = {
        "★★★★★ (激レア)": 0.003,  # 0.3%
        "★★★★ (レア)": 0.03,      # 3%
        "★★★ (やや珍しい)": 0.15,  # 15%
        "★★ (普通)": 0.35,         # 35%
        "★ (よくある)": 0.467      # 46.7%
    }
    
    print("【ガチャの情報量】")
    print("-" * 50)
    
    for rarity, rate in gacha_rates.items():
        info = calculate_information(rate)
        print(f"{rarity}: 確率{rate*100:.1f}% → {info:.2f}ビットの驚き!")
    
    # シミュレーション
    print("\n【10連ガチャシミュレーション】")
    np.random.seed(42)  # 結果を再現可能にする
    
    rarities = list(gacha_rates.keys())
    probabilities = list(gacha_rates.values())
    
    total_info = 0
    for i in range(10):
        result = np.random.choice(rarities, p=probabilities)
        info = calculate_information(gacha_rates[result])
        total_info += info
        print(f"{i+1}回目: {result} (情報量: {info:.2f}ビット)")
    
    print(f"\n合計情報量: {total_info:.2f}ビット")
    print(f"平均情報量: {total_info/10:.2f}ビット")

gacha_information()

5. 機械学習での活用例

def ml_example():
    """機械学習でクロスエントロピーを使う例"""
    
    # 画像認識の例(犬・猫・鳥の3クラス分類)
    print("【AIの画像認識】")
    print("-" * 40)
    
    # 正解ラベル(これは猫の画像)
    true_label = [0, 1, 0]  # [犬, 猫, 鳥]
    
    # AIの予測
    ai_predictions = {
        "自信満々AI": [0.1, 0.8, 0.1],
        "迷っているAI": [0.3, 0.4, 0.3],
        "間違えたAI": [0.7, 0.2, 0.1],
        "完全に外したAI": [0.0, 0.0, 1.0]
    }
    
    print("正解: 猫の画像\n")
    
    for ai_name, pred in ai_predictions.items():
        ce = cross_entropy(true_label, pred)
        print(f"{ai_name}:")
        print(f"  予測 - 犬:{pred[0]*100:.0f}%, 猫:{pred[1]*100:.0f}%, 鳥:{pred[2]*100:.0f}%")
        print(f"  クロスエントロピー: {ce:.3f}ビット")
        print()

ml_example()

まとめ

今日学んだことを整理しましょう!

📊 情報量

  • 確率が低い = 情報量が大きい(驚きが大きい)
  • 確率が高い = 情報量が小さい(驚きが小さい)
  • 計算式:I = -log2(確率)

🎯 クロスエントロピー

  • 予測の下手さを測る指標
  • 値が小さい = 予測が上手
  • 値が大きい = 予測が下手

💡 実世界での応用

  • AI/機械学習の精度評価
  • データ圧縮
  • 通信の効率化
  • ゲームバランスの設計

次のステップ

  1. 練習問題を作ってみよう:自分の好きなゲームやスポーツの確率で情報量を計算してみましょう
  2. データ収集:実際の天気データを集めて、天気予報の精度を測ってみましょう
  3. 機械学習入門:簡単な画像認識や文字認識に挑戦してみましょう

最後まで読んでいただきありがとうございました!
この記事が面白かった・役に立ったと思ったら、ぜひ「いいね」をお願いします🎉

質問やコメントもお待ちしています!

Discussion