結論

エントロピーとは、結果の「予想しにくさ」を、平均して何ビットの情報かで表した数です。偏りが大きいほど小さくなります。

この記事でわかること

  • コイン7通り・サイコロ2通りのエントロピーの計算表
  • zlibで7種のデータを圧縮した率と、パスワードのビット数
  • 情報利得・交差エントロピー・KLをライブラリと照合

2026年10月23日更新|Python 3.11・scikit-learn 1.8.0で計算

IT で使う「エントロピー」は、すべて「確率から求める情報量の平均」が元になっています。そこから、圧縮・パスワード・決定木・機械学習の損失へ枝分かれします。

flowchart TD
    A[確率分布<br>結果ごとの出やすさ] --> B[情報量 −log2 p<br>珍しいほど大きい]
    B --> C[エントロピー<br>情報量の平均]
    C --> D[圧縮<br>パスワード]
    C --> E[決定木<br>情報利得]
    C --> F[損失関数<br>交差・KL]

急いでいる人向けに、よく調べられることの答えを先にまとめます。

知りたいこと 答え 詳しい節
エントロピーとは 予想しにくさを表す情報量の平均 エントロピーとは
計算式 H = −Σ p × log2(p) 計算方法
高い・低いの意味 高い=読めない、低い=偏っている 大きい・小さい
コインは何ビット 表裏が半々なら1ビット 計算方法
交差エントロピー 正解と予測のずれを測る損失 交差エントロピー
KLダイバージェンス 交差エントロピー − 正解側のエントロピー KL
決定木では 分けて減った分=情報利得 決定木
パスワードでは 長さ × log2(文字の種類) パスワード
熱力学では 乱雑さの量(単位 J/K) 熱力学との関係

確認環境:Ubuntu 24.04.4 LTS(Linux カーネル 6.18)・Python 3.11.15・NumPy 2.4.4・SciPy 1.17.1・scikit-learn 1.8.0・zlib 1.3・OpenSSL 3.0.13。情報量とエントロピーの表、ハフマン符号、パスワードのビット数、決定木の情報利得、交差エントロピーと KL ダイバージェンス、圧縮率、ファイルのエントロピー、よくある間違いのエラー文は、この記事のコードをすべて実行して出力を載せています。乱数の種は 378 に固定しています。scikit-learn の決定木と log_loss は scikit-learn 1.9.1 の公式ドキュメント、scipy.stats.entropy は SciPy v1.18.0 の公式ドキュメント、PyTorch の CrossEntropyLoss は PyTorch 2.14 の公式ドキュメント、パスワードの長さの基準は NIST SP 800-63B(800-63-4 版)、乱数のデバイスは Linux の man ページとカーネルのドキュメント、言葉の定義と歴史は日本語版 Wikipedia で確かめました(確認日 2026年10月23日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「エントロピーとは|意味・計算・交差エントロピーをPythonで実演」

エントロピーとは(ITでの意味と、分野ごとの見分け方)

この節では、「エントロピー」がどの分野で、どんな意味で使われているかを見分けられます。

IT・データ分析でエントロピーと言えば、ほとんどの場合「情報エントロピー(平均情報量)」のことです。 結果がどれだけ予想しにくいかを、確率から計算した1つの数で表します。1948年にクロード・シャノンが論文「通信の数学的理論」で定めたので、シャノンエントロピーとも呼ばれます。

1情報理論

結果の予想しにくさ=情報量の平均。単位はビット。圧縮・通信・パスワードの強さの元になる。この記事の中心。

2機械学習

交差エントロピー(分類の損失関数)、KL ダイバージェンス(分布のずれ)、決定木の情報利得として使う。

3熱力学・物理

熱や分子の乱雑さを表す量で、単位は J/K(ジュール毎ケルビン)。式の形が情報エントロピーと似ている。

同じ言葉でも、測っているものが違います。どれの話をしているかを、次の表で見分けます。

呼び方 何を測るか この記事の節
エントロピー(情報エントロピー) 1つの分布の予想しにくさ 計算方法
自己情報量 1つの結果が起きたときの驚きの大きさ 情報量とは
交差エントロピー 正解の分布と予測の分布のずれ(損失) 交差エントロピー
KL ダイバージェンス 2つの分布の離れぐあい KL
情報利得 決定木で分けたときに減ったエントロピー 決定木
パスワードのエントロピー 無作為に選んだときの候補の多さ(ビット) パスワード
Linux のエントロピー 乱数を作るための「種」のたまりぐあい Linux
熱力学のエントロピー 熱・分子の乱雑さ(J/K) 熱力学との関係

日本語版 Wikipedia によると、エントロピーという言葉は1865年に物理学者クラウジウスが熱力学の量として名づけたもので、ギリシャ語の「変換」が語源です。情報理論のエントロピーは、統計力学のエントロピーと定数倍を除いて同じ形の式になることから、同じ名前で呼ばれています。

情報量とは(珍しいことほど情報が多い)

この節では、エントロピーの材料になる「情報量(自己情報量)」の意味と計算が分かります。

情報量は「その結果を知ったときの驚きの大きさ」で、確率 p の結果の情報量は −log2(p) ビットです。 確率が低い(珍しい)ほど大きく、必ず起きること(p=1)の情報量は0です。

たとえば、友だちが1〜8のどれかの数を思い浮かべていて、「はい・いいえ」で答える質問で当てるとします。「5以上?」「3以上?」のように半分ずつ絞ると、3回の質問で必ず当たります。8通りが同じ確率で出るとき、1つの答えの確率は 1/8 で、その情報量は −log2(1/8) = 3 ビット。1ビットは「はい・いいえ」の質問1回ぶんと考えると分かりやすくなります。

Python で、確率ごとの情報量を計算しました。

"""コインとサイコロ:情報量とエントロピーを計算する"""
import math
from scipy.stats import entropy

def info(p):                      # 自己情報量 I(p) = -log2(p) [ビット]
    return -math.log2(p) + 0.0     # -0.0 を 0.0 にそろえる

def H(ps):                        # エントロピー H = Σ p × (-log2 p)。p=0 の項は 0 とする
    return sum(p * -math.log2(p) for p in ps if p > 0)

print("確率 p  情報量 -log2(p)")
for p in [1, 1/2, 1/4, 1/8, 1/6, 1/100]:
    print(f"{p:<7.4g} {info(p):.4f} ビット")
確率 p  情報量 -log2(p)
1       0.0000 ビット
0.5     1.0000 ビット
0.25    2.0000 ビット
0.125   3.0000 ビット
0.1667  2.5850 ビット
0.01    6.6439 ビット
結果の例 確率 情報量
明日も太陽が昇る 1 0 ビット(驚きなし)
コインで表が出る 1/2 1 ビット
サイコロで3が出る 1/6 2.585 ビット
100人から1人の当選者 1/100 6.644 ビット

確率が半分になるたびに、情報量は1ビットずつ増えます。 1〜100 の数を当てるなら 6.644 ビットなので、「はい・いいえ」の質問は切り上げて7回あれば当てられます。

なぜ log(対数)を使うのか

独立した2つの結果の情報量を「足し算」で合わせられるからです。トランプ52枚から「ハートの4」を引く確率は 1/52 で、情報量は log2 52 = 5.700 ビット。これは「ハートである(1/4)」の 2 ビットと「4である(1/13)」の 3.700 ビットの和と一致します(Python で計算すると、どちらも 5.700439718141092)。確率は掛け算で合わさりますが、対数をとると足し算になります。

単位:ビット・ナット

対数の底(log の右下の数)で単位が変わります。値は定数倍だけ違い、意味は同じです。

対数の底 単位 よく使う場面
2 ビット(bit) 情報理論・圧縮・パスワード・決定木(scikit-learn)
e(自然対数) ナット(nat) 機械学習の損失(log_loss・PyTorch)・SciPy の既定
10 ディット(dit・ハートレー) あまり使わない

1 ナット = 1/ln2 ≒ 1.4427 ビットです。ライブラリの結果が教科書の値と合わないときは、まず底の違いを疑います。

エントロピーの計算方法(コインとサイコロ)

この節では、エントロピーの式と手計算の手順、偏りによって値がどう変わるかが分かります。

エントロピーは「各結果の情報量を、その確率で重みづけして平均したもの」です。 式は文字で書くと次のとおりです。

H = −Σ p(x) × log2 p(x)
  = (結果1の確率 × 結果1の情報量)+(結果2の確率 × 結果2の情報量)+ …
(p(x) が 0 の結果は、0 × log 0 = 0 として足さない)

この式は、結果が飛び飛びの値(コインの表裏・サイコロの目)のときのものです。身長のような連続した値には、確率密度を使う「微分エントロピー」という別の定義があります。

表が出る確率が 0.9 のゆがんだコインで、手で計算してみます。

1

結果と確率を書き出す

表 0.9、裏 0.1。確率の合計が1になることを確かめる。

確率

2

それぞれの情報量を出す

表:−log2 0.9 = 0.152 ビット。裏:−log2 0.1 = 3.322 ビット。裏のほうが珍しいので大きい。

−log2 p

3

確率を掛ける

表:0.9 × 0.152 = 0.137。裏:0.1 × 3.322 = 0.332。

重みづけ

4

足す

0.137 + 0.332 = 0.469 ビット。表裏が半々のコイン(1ビット)の半分以下になる。

合計

同じ計算を、表の確率を変えながら Python で行い、SciPy の scipy.stats.entropy(base=2 でビット)とも比べました。

print("\n表の確率  エントロピー(ビット)  SciPy(base=2)")
for p in [0.5, 0.6, 0.7, 0.8, 0.9, 0.99, 1.0]:
    print(f"{p:<9} {H([p, 1-p]):.4f}              {entropy([p, 1-p], base=2):.4f}")

dice = [1/6] * 6
loaded = [0.5, 0.1, 0.1, 0.1, 0.1, 0.1]       # 1 が半分の確率で出るサイコロ
print(f"\n公正なサイコロ   {H(dice):.4f} ビット  (log2 6 = {math.log2(6):.4f})")
print(f"1が出やすいサイコロ {H(loaded):.4f} ビット")
print(f"公正なサイコロ(ナット) {entropy(dice):.4f} nat = {H(dice):.4f} × ln2")
表の確率  エントロピー(ビット)  SciPy(base=2)
0.5       1.0000              1.0000
0.6       0.9710              0.9710
0.7       0.8813              0.8813
0.8       0.7219              0.7219
0.9       0.4690              0.4690
0.99      0.0808              0.0808
1.0       0.0000              0.0000

公正なサイコロ   2.5850 ビット  (log2 6 = 2.5850)
1が出やすいサイコロ 2.1610 ビット
公正なサイコロ(ナット) 1.7918 nat = 2.5850 × ln2

コインの偏りとエントロピー表が出る確率ごと。半々のとき最大の1ビット

0.51.000
0.60.971
0.70.881
0.80.722
0.90.469
0.990.081
1.00

偏ったコインほどエントロピーは小さく、必ず表が出るコインは0です。 結果の数が同じなら、すべてが同じ確率のときに最大の log2(結果の数)になります。サイコロは6通りなので、公正なら log2 6 = 2.585 ビット、1 が半分の確率で出るサイコロは 2.161 ビットに下がりました。

平均の意味を乱数で確かめる

「情報量の平均」が本当にエントロピーになるかを、コインを100万回投げて確かめました。

import numpy as np
rng = np.random.default_rng(378)
for p in [0.5, 0.9]:
    x = rng.random(1_000_000) < p                  # True=表
    avg = np.where(x, -np.log2(p), -np.log2(1 - p)).mean()
    print(f"p={p}: 100万回の情報量の平均 {avg:.4f} ビット / 理論値 {H([p, 1-p]):.4f}")
p=0.5: 100万回の情報量の平均 1.0000 ビット / 理論値 1.0000
p=0.9: 100万回の情報量の平均 0.4690 ビット / 理論値 0.4690

1回ごとの情報量(表なら 0.152、裏なら 3.322)を100万回ぶん平均すると、理論値の 0.4690 ビットと一致しました。 確率分布そのものの考え方(確率関数・期待値)は、関連記事「確率分布とは|種類一覧・平均と分散・選び方をPythonで実演」で扱っています。

エントロピーが大きい・小さいとは

エントロピーの大小で何が分かるか

小さい(0に近い)結果がほぼ決まっている。偏っている・そろっている。少ないビットで表せる(よく縮む)
→
大きい(最大に近い)どの結果も同じくらい出る。予想しにくい・ばらばら。たくさんのビットが要る(縮まない)

「エントロピーが高い=乱雑」は熱力学の言い方と同じ向き。情報理論では「次に何が来るか読めない」と読む

状況 エントロピー 読み方
毎日晴れの町の天気 0 に近い 天気予報を聞いても驚きがない
決定木の葉がすべて同じクラス 0 それ以上分ける意味がない
暗号化したファイルのバイト 8 ビット/バイトに近い 規則が見えず、圧縮できない
無作為に選んだ長いパスワード 大きい 当てるまでの候補が多い

エントロピーと圧縮(何ビットで表せるか)

この節では、エントロピーが「データを縮められる限界」を表すことを、ハフマン符号と zlib の実測で確かめます。

エントロピーは、1つの結果を表すのに平均で最低何ビット要るかを表します(シャノンの情報源符号化定理)。よく出る結果に短い符号、まれな結果に長い符号を割り当てると、平均の長さをエントロピーまで縮められます。

4種類の天気を符号にする例です。晴れ 1/2・くもり 1/4・雨 1/8・雪 1/8 の町と、4つが同じ確率の町で、ハフマン符号(出やすいものほど短い符号にする方法)を作りました。

"""ハフマン符号:1文字あたりの平均ビット数とエントロピーを比べる"""
import heapq, math

def huffman(probs):
    heap = [(p, i, {s: ""}) for i, (s, p) in enumerate(probs.items())]
    heapq.heapify(heap); n = len(heap)
    while len(heap) > 1:
        p1, _, c1 = heapq.heappop(heap); p2, _, c2 = heapq.heappop(heap)
        merged = {s: "0" + c for s, c in c1.items()} | {s: "1" + c for s, c in c2.items()}
        heapq.heappush(heap, (p1 + p2, n, merged)); n += 1
    return heap[0][2]

for name, probs in {
    "天気(偏りあり)": {"晴れ": 0.5, "くもり": 0.25, "雨": 0.125, "雪": 0.125},
    "天気(等確率)": {"晴れ": 0.25, "くもり": 0.25, "雨": 0.25, "雪": 0.25},
}.items():
    code = huffman(probs)
    avg = sum(probs[s] * len(c) for s, c in code.items())
    H = -sum(p * math.log2(p) for p in probs.values())
    print(name, {s: code[s] for s in probs}, f"平均 {avg:.3f} ビット / エントロピー {H:.3f} ビット")
天気(偏りあり) {'晴れ': '0', 'くもり': '10', '雨': '110', '雪': '111'} 平均 1.750 ビット / エントロピー 1.750 ビット
天気(等確率) {'晴れ': '00', 'くもり': '01', '雨': '10', '雪': '11'} 平均 2.000 ビット / エントロピー 2.000 ビット

偏りのある町は、1日あたり平均 1.75 ビットで天気を送れました。 4種類を同じ長さで送ると2ビット要るので、12.5%短くなります。等確率の町は、どう工夫しても2ビットより短くなりません。

zlib で偏ったデータとランダムなデータを圧縮する

100万バイトのデータを7種類作り、1バイトずつ数えたエントロピー(ビット/バイト)と、zlib(レベル9)・bz2・lzma で圧縮した大きさを比べました。英文は GPL v3 のライセンス文(35,149 バイト)です。

"""偏ったデータとランダムなデータを zlib で圧縮し、エントロピーと比べる"""
import math, os, zlib, bz2, lzma
from collections import Counter
import numpy as np

def byte_entropy(b):              # 1バイトずつ数えたエントロピー(ビット/バイト)
    n = len(b)
    return -sum(c / n * math.log2(c / n) for c in Counter(b).values()) + 0.0

N = 1_000_000
rng = np.random.default_rng(378)
data = {
    "同じ文字だけ": b"A" * N,
    "2種類 p=0.99": bytes(rng.choice([65, 66], N, p=[0.99, 0.01]).astype(np.uint8)),
    "2種類 p=0.9":  bytes(rng.choice([65, 66], N, p=[0.9, 0.1]).astype(np.uint8)),
    "2種類 p=0.5":  bytes(rng.choice([65, 66], N).astype(np.uint8)),
    "16種類 等確率": bytes(rng.integers(65, 81, N).astype(np.uint8)),
    "英文(GPL-3)": open("/usr/share/common-licenses/GPL-3", "rb").read(),
    "ランダム os.urandom": os.urandom(N),
}
print("データ | サイズ | エントロピー(ビット/バイト) | 下限(バイト) | zlib | 圧縮率 | bz2 | lzma")
for name, b in data.items():
    h = byte_entropy(b)
    z = len(zlib.compress(b, 9))
    print(f"{name} | {len(b):,} | {h:.3f} | {int(len(b)*h/8):,} | {z:,} | {z/len(b):.1%} | {len(bz2.compress(b, 9)):,} | {len(lzma.compress(b)):,}")
print("zlib", zlib.ZLIB_RUNTIME_VERSION)
データ | サイズ | エントロピー(ビット/バイト) | 下限(バイト) | zlib | 圧縮率 | bz2 | lzma
同じ文字だけ | 1,000,000 | 0.000 | 0 | 992 | 0.1% | 48 | 276
2種類 p=0.99 | 1,000,000 | 0.081 | 10,117 | 15,617 | 1.6% | 11,296 | 20,276
2種類 p=0.9 | 1,000,000 | 0.469 | 58,620 | 81,517 | 8.2% | 68,171 | 72,332
2種類 p=0.5 | 1,000,000 | 1.000 | 124,999 | 149,877 | 15.0% | 160,171 | 136,088
16種類 等確率 | 1,000,000 | 4.000 | 499,998 | 570,268 | 57.0% | 509,301 | 518,672
英文(GPL-3) | 35,149 | 4.573 | 20,093 | 12,112 | 34.5% | 10,706 | 11,428
ランダム os.urandom | 1,000,000 | 8.000 | 999,976 | 1,000,316 | 100.0% | 1,004,644 | 1,000,108
zlib 1.3

「下限」は、サイズ × エントロピー ÷ 8 で出した、1バイトずつ独立に符号化したときの最小のバイト数です(os.urandom は実行のたびに中身が変わるので、数バイトずれます)。

データ エントロピー 下限 zlib 後(圧縮率)
2種類 p=0.99 0.081 10,117 15,617(1.6%)
2種類 p=0.9 0.469 58,620 81,517(8.2%)
2種類 p=0.5 1.000 124,999 149,877(15.0%)
16種類 等確率 4.000 499,998 570,268(57.0%)
ランダム 8.000 999,976 1,000,316(100.0%)
1.6%99%が同じ文字エントロピー 0.081 ビット/バイト
15.0%2種類が半々エントロピー 1 ビット/バイト
100.0%ランダムなバイト316 バイト増えた

偏りが大きい(エントロピーが小さい)データほどよく縮み、ランダムなデータは1バイトも縮みませんでした。 zlib・bz2・lzma のどれも、ランダムなデータでは元より少し大きくなりました。エントロピーが8ビット/バイトのデータには、縮める余地が残っていないからです。

英文だけは、下限の 20,093 バイトより小さい 12,112 バイトまで縮みました。1バイトずつ数えたエントロピーは「前後の文字のつながり」を見ていませんが、zlib は「同じ単語や文が前にも出た」ことを使って縮めるためです。文章のように並び方に規則があるデータは、1文字ずつのエントロピーより実際の情報が少なく、そのぶん縮みます。

ファイルのエントロピーを測る

同じ考え方で、手元のファイルのエントロピーを測りました。

"""手元のファイルのエントロピー(ビット/バイト)を測る"""
import math, sys, zlib
from collections import Counter
def byte_entropy(b):
    n = len(b)
    return -sum(c / n * math.log2(c / n) for c in Counter(b).values()) + 0.0
for path in sys.argv[1:]:
    b = open(path, "rb").read()
    print(f"{path.rsplit('/', 1)[-1]:<28} {len(b):>9,} バイト  {byte_entropy(b):.3f}  zlib後 {len(zlib.compress(b, 9))/len(b):.1%}")
sample.json                     33,225 バイト  3.984  zlib後 8.4%
GPL-3                           35,149 バイト  4.573  zlib後 34.5%
ls                             142,312 バイト  5.935  zlib後 43.8%
changelog.Debian.gz              2,343 バイト  7.918  zlib後 100.5%
libreoffice-base.png            22,285 バイト  7.329  zlib後 82.9%
rand.bin                     1,000,000 バイト  8.000  zlib後 100.0%
sample.json.enc                 33,248 バイト  7.995  zlib後 100.1%

sample.json は500件の利用者データを書いた JSON、ls は実行ファイル、changelog.Debian.gz は gzip 済みのファイル、sample.json.enc は sample.json を OpenSSL の AES-256-CBC で暗号化したものです。すでに圧縮・暗号化されたファイルは8ビット/バイトに近く、zlib をかけても縮まない(.gz は 100.5%に増えた)ことが分かります。 同じ JSON でも、暗号化すると 3.984 から 7.995 に上がりました。

圧縮済みのファイルをさらに圧縮しても小さくならない理由は、これで説明できます。tar・gzip・xz などの形式ごとの圧縮率と速さは、関連記事「tarコマンドの使い方|圧縮・解凍の形式別早見表と速度の実測比較」で扱っています。

パスワードの強さとエントロピー(ビット数の計算)

この節では、パスワードの「強さ」をビット数で見積もる計算と、その計算が当てはまる条件が分かります。

文字の種類 N の中から、長さ L のパスワードを無作為に選ぶと、エントロピーは L × log2(N) ビットです。 候補の数は N の L 乗通りで、ビット数が1増えるたびに候補は2倍になります。

"""パスワードのエントロピー:文字の種類 N と長さ L から L × log2(N) ビット"""
import math, secrets, string

sets = {
    "数字のみ": string.digits,                                   # 10
    "英小文字": string.ascii_lowercase,                          # 26
    "英大小文字": string.ascii_letters,                          # 52
    "英大小+数字": string.ascii_letters + string.digits,         # 62
    "英大小+数字+記号": string.ascii_letters + string.digits + string.punctuation,  # 94
}
lengths = [4, 8, 12, 16, 20]
print("文字の種類 N 1文字 " + " ".join(f"{L:>4}字" for L in lengths))
for name, chars in sets.items():
    n = len(chars)
    print(f"{name:<10} {n:>3} {math.log2(n):5.2f} " + " ".join(f"{L*math.log2(n):6.1f}" for L in lengths))

# 単語を並べるパスフレーズ(7,776語のリストから無作為に選ぶ場合)
for k in [4, 5, 6]:
    print(f"7776語から{k}語: {k*math.log2(7776):.1f} ビット")

# 実際に secrets で無作為に作る(この作り方なら上の計算がそのまま当てはまる)
alphabet = string.ascii_letters + string.digits
pw = "".join(secrets.choice(alphabet) for _ in range(16))
print("例:", pw, f"→ {16*math.log2(len(alphabet)):.1f} ビット")
print("token_urlsafe(16):", secrets.token_urlsafe(16), "→ 16バイト = 128 ビット")
文字の種類 N 1文字    4字    8字   12字   16字   20字
数字のみ        10  3.32   13.3   26.6   39.9   53.2   66.4
英小文字        26  4.70   18.8   37.6   56.4   75.2   94.0
英大小文字       52  5.70   22.8   45.6   68.4   91.2  114.0
英大小+数字      62  5.95   23.8   47.6   71.5   95.3  119.1
英大小+数字+記号   94  6.55   26.2   52.4   78.7  104.9  131.1
7776語から4語: 51.7 ビット
7776語から5語: 64.6 ビット
7776語から6語: 77.5 ビット
例: yVHJX9ptJwVe29JZ → 95.3 ビット
token_urlsafe(16): Hq_SMI1bd-gLkooZOrRSiQ → 16バイト = 128 ビット
文字の種類 1文字のビット 8文字 16文字
数字のみ(10種) 3.32 26.6 53.2
英小文字(26種) 4.70 37.6 75.2
英大小+数字(62種) 5.95 47.6 95.3
英大小+数字+記号(94種) 6.55 52.4 104.9

文字の種類を62から94に増やしても1文字あたり 0.6 ビットしか増えませんが、長さを8から16にするとビット数は2倍になります。 英小文字だけの16文字(75.2 ビット)は、記号まで使う8文字(52.4 ビット)より大きくなりました。7,776語(6の5乗)の単語リストから無作為に5語を選ぶパスフレーズは 64.6 ビットです。

この計算が当てはまる条件

L × log2(N) は「1文字ずつ、すべての文字が同じ確率で無作為に選ばれた」ときの値です。人が考えたパスワードは、単語・名前・誕生日・キーボードの並び・末尾の「1!」のように偏りがあるので、同じ長さでも実際のエントロピーはずっと小さくなります。

  • 1作るのはプログラムの乱数に任せるPython は secrets(公式ドキュメントは、random はシミュレーション用で、セキュリティには secrets を使うと説明)
  • 2種類を増やすより長さを伸ばすNIST SP 800-63B は、単独で使うパスワードを15文字以上とし、最大長は64文字以上を受け付けるのが望ましいとしている
  • 3記号の強制ルールに頼らない同じ文書は、文字の種類を混ぜる決まり(構成ルール)を課してはならないとし、よく使われる・漏れたパスワードの一覧との照合を求めている
  • 4保存はハッシュ化するsecrets の公式ドキュメントも、平文や復号できる形で保存せず、ソルト付きの一方向ハッシュにするよう書いている

secrets の公式ドキュメントは、トークンの大きさの目安として「2015年時点では、32バイト(256ビット)の乱数で一般的な用途には足りると考えられている」と書いています。パスワードを保存するときのハッシュ関数の選び方は、関連記事「パスワードのハッシュ化|bcrypt・Argon2の推奨値と実測・移行コード」で扱っています。

決定木のエントロピーと情報利得(scikit-learnで実行)

この節では、決定木が「どの質問で分けるか」をエントロピーで選ぶ仕組みを、手計算と scikit-learn の両方で確かめます。

情報利得とは、データを分ける前のエントロピーから、分けた後のエントロピー(人数で重みづけした平均)を引いた値です。 分けた結果がそろうほど(エントロピーが下がるほど)情報利得は大きくなり、決定木はいちばん大きい分け方を選びます。情報利得で分ける決定木は、ID3・C4.5 という手法で知られています。

情報利得 = H(分ける前) − Σ(グループの件数 ÷ 全体の件数)× H(グループ)

14日分の「外で遊んだか」のデータ(天気・風・遊んだか)で計算しました。

"""決定木の情報利得:手計算と scikit-learn(criterion="entropy")を比べる"""
import math
from collections import Counter
import numpy as np
from sklearn.tree import DecisionTreeClassifier, export_text
from sklearn.metrics import mutual_info_score

# 14日分の「外で遊んだか」のデータ(天気・風・遊んだ)
rows = [
    ("晴れ", "弱", "いいえ"), ("晴れ", "強", "いいえ"), ("くもり", "弱", "はい"), ("雨", "弱", "はい"),
    ("雨", "弱", "はい"), ("雨", "強", "いいえ"), ("くもり", "強", "はい"), ("晴れ", "弱", "いいえ"),
    ("晴れ", "弱", "はい"), ("雨", "弱", "はい"), ("晴れ", "強", "はい"), ("くもり", "強", "はい"),
    ("くもり", "弱", "はい"), ("雨", "強", "いいえ"),
]
y = [r[2] for r in rows]

def H(labels):
    n = len(labels)
    return -sum(c / n * math.log2(c / n) for c in Counter(labels).values()) + 0.0

print(f"分ける前: はい{y.count('はい')} いいえ{y.count('いいえ')}  H = {H(y):.4f} ビット")
for col, name in [(0, "天気"), (1, "風")]:
    after = 0
    parts = []
    for v in sorted(set(r[col] for r in rows)):
        sub = [r[2] for r in rows if r[col] == v]
        after += len(sub) / len(rows) * H(sub)
        parts.append(f"{v}({sub.count('はい')}/{len(sub)}) H={H(sub):.3f}")
    print(f"{name}で分ける: " + "  ".join(parts))
    print(f"   分けた後の加重平均 {after:.4f} → 情報利得 {H(y) - after:.4f} ビット"
          f"  (mutual_info_score/ln2 = {mutual_info_score([r[col] for r in rows], y) / math.log(2):.4f})")
分ける前: はい9 いいえ5  H = 0.9403 ビット
天気で分ける: くもり(4/4) H=0.000  晴れ(2/5) H=0.971  雨(3/5) H=0.971
   分けた後の加重平均 0.6935 → 情報利得 0.2467 ビット  (mutual_info_score/ln2 = 0.2467)
風で分ける: 弱(6/8) H=0.811  強(3/6) H=1.000
   分けた後の加重平均 0.8922 → 情報利得 0.0481 ビット  (mutual_info_score/ln2 = 0.0481)

天気で分けると情報利得 0.2467 ビット、風で分けると 0.0481 ビットで、天気のほうがよい質問です。 くもりの日は4日とも遊んでいて(H=0)、そこで答えが決まるからです。「分けた後の加重平均」は条件付きエントロピーとも呼び、情報利得は相互情報量(2つの変数が共有している情報の量)と同じ値になります。scikit-learn の mutual_info_score(ナットで返す)を ln2 で割った値と一致しました。

scikit-learn の criterion="entropy" で木を作る

scikit-learn の DecisionTreeClassifier は数値しか受け取らないので、天気を「晴れか」「くもりか」「雨か」の3つの 0/1 の列に直して(one-hot)、深さ2までの木を作りました。

cats = ["晴れ", "くもり", "雨"]
X = np.array([[r[0] == c for c in cats] + [r[1] == "強"] for r in rows], dtype=int)
names = ["天気=晴れ", "天気=くもり", "天気=雨", "風=強"]
clf = DecisionTreeClassifier(criterion="entropy", max_depth=2, random_state=0).fit(X, y)
print(export_text(clf, feature_names=names, show_weights=True))
print("根のノードのエントロピー tree_.impurity[0] =", round(clf.tree_.impurity[0], 4))
print("各ノードのエントロピー:", np.round(clf.tree_.impurity, 4))

print("\nscikit-learn が試す「はい/いいえ」の2分割ごとの情報利得")
for j, nm in enumerate(names):
    left = [y[i] for i in range(len(y)) if X[i, j] == 0]
    right = [y[i] for i in range(len(y)) if X[i, j] == 1]
    g = H(y) - len(left) / len(y) * H(left) - len(right) / len(y) * H(right)
    print(f"  {nm:<8} 該当{len(right):>2}日  情報利得 {g:.4f}")
print("classes_ =", [str(c) for c in clf.classes_])
|--- 天気=くもり <= 0.50
|   |--- 風=強 <= 0.50
|   |   |--- weights: [2.00, 4.00] class: はい
|   |--- 風=強 >  0.50
|   |   |--- weights: [3.00, 1.00] class: いいえ
|--- 天気=くもり >  0.50
|   |--- weights: [0.00, 4.00] class: はい

根のノードのエントロピー tree_.impurity[0] = 0.9403
各ノードのエントロピー: [0.9403 1.     0.9183 0.8113 0.    ]

scikit-learn が試す「はい/いいえ」の2分割ごとの情報利得
  天気=晴れ    該当 5日  情報利得 0.1022
  天気=くもり   該当 4日  情報利得 0.2260
  天気=雨     該当 5日  情報利得 0.0032
  風=強      該当 6日  情報利得 0.0481
classes_ = ['いいえ', 'はい']

できた木を図にすると、次のようになります(H は各ノードのエントロピー、weights の並びは classes_ の順で[いいえ, はい])。

flowchart TD
    A{くもり?<br>14日 H=0.940} -->|はい| B[4日とも<br>遊んだ<br>H=0]
    A -->|いいえ| C{風が強い?<br>10日 H=1.000}
    C -->|いいえ| D[6日中<br>遊んだ4日<br>H=0.918]
    C -->|はい| E[4日中<br>遊ばない3日<br>H=0.811]

根のノードのエントロピー 0.9403 は手計算と同じで、scikit-learn は底2(ビット)で計算していました。 最初の質問には、4つの2分割の中で情報利得がいちばん大きい「くもりか」(0.2260)が選ばれました。scikit-learn の決定木はいつも「はい・いいえ」の2つに分けるので、天気を3つに一度に分ける場合(0.2467)とは値が違います。

公式ドキュメントでは、criterion に使える値は "gini"(既定)・"entropy"・"log_loss" で、"entropy" と "log_loss" はどちらもシャノンの情報利得を使います。また、エントロピーで分けることは、木の予測確率と正解との log loss(交差エントロピー)を小さくすることと同じだと説明されています。

エントロピーとジニ不純度の違い

エントロピー(entropy)

−Σ p × log2 p

2クラスで半々のとき最大 1

対数の計算がある

ジニ不純度(gini)

Σ p × (1 − p)。2クラスなら 1 − p² − (1 − p)²

2クラスで半々のとき最大 0.5

scikit-learn の既定

2クラスで、一方の割合 p ごとに両方を計算しました。エントロピーを2で割ると、ジニ不純度とほぼ同じ形になります。

一方の割合 p エントロピー ジニ不純度 エントロピー ÷ 2
0.5 1.0000 0.5000 0.5000
0.7 0.8813 0.4200 0.4406
0.9 0.4690 0.1800 0.2345
0.99 0.0808 0.0198 0.0404
1.0 0 0 0

scikit-learn に付いている3つのデータで、5分割交差検証の正解率を比べました(ほかの設定は既定のまま)。

from sklearn.datasets import load_iris, load_breast_cancer, load_wine
from sklearn.model_selection import cross_val_score
print("\nデータ        gini     entropy")
for nm, ld in [("iris", load_iris), ("wine", load_wine), ("breast_cancer", load_breast_cancer)]:
    Xd, yd = ld(return_X_y=True)
    s = [cross_val_score(DecisionTreeClassifier(criterion=c, random_state=0), Xd, yd, cv=5).mean() for c in ["gini", "entropy"]]
    print(f"{nm:<13} {s[0]:.4f}  {s[1]:.4f}")
データ        gini     entropy
iris          0.9600  0.9533
wine          0.8876  0.8992
breast_cancer 0.9174  0.9350

どちらが勝つかはデータによって変わり、差は1〜2ポイントでした。 どちらも「分けた後にどれだけそろったか」を測る点は同じなので、決定木の深さ(max_depth)や葉の最小件数のほうが結果に大きく効くことがよくあります。

交差エントロピーとは(機械学習の損失関数)

この節では、分類のモデルを学習させるときに使う「交差エントロピー(クロスエントロピー)」の意味と、ライブラリと手計算が一致することが分かります。

交差エントロピーとは、正しい分布 p の結果を、予測した分布 q の確率で表したときの情報量の平均です。 予測が正解に近いほど小さくなり、q が p と同じときに最小(p のエントロピーと同じ値)になります。

交差エントロピー H(p, q) = −Σ p(x) × log q(x)
分類の損失(正解が1つのとき) = −log(正解クラスに付けた予測確率)

分類では、正解のクラスだけ確率1、ほかは0の分布(one-hot)を p にします。すると式は「正解クラスの予測確率の −log」だけが残ります。scikit-learn では log_loss(対数損失)、ニューラルネットワークでは交差エントロピー誤差と呼ばれ、どれも同じ計算です。

"""交差エントロピーと KL ダイバージェンス:NumPy・SciPy・scikit-learn で一致を確かめる"""
import numpy as np
from scipy.stats import entropy
from sklearn.metrics import log_loss

# 分類の損失:正解ラベルは one-hot(正解クラスの確率が1)
y_true = [0, 2, 1, 0]
y_prob = np.array([[0.8, 0.1, 0.1],
                   [0.2, 0.2, 0.6],
                   [0.1, 0.7, 0.2],
                   [0.4, 0.4, 0.2]])
onehot = np.eye(3)[y_true]
manual = -np.mean(np.sum(onehot * np.log(y_prob), axis=1))
print(f"NumPy の交差エントロピー平均 = {manual:.6f}")
print(f"sklearn log_loss              = {log_loss(y_true, y_prob):.6f}")
print("1件ずつの損失 -ln(正解の確率):", np.round(-np.log(y_prob[np.arange(4), y_true]), 4))

print("\n正解クラスの予測確率  損失 -ln(p)")
for pr in [0.99, 0.9, 0.7, 0.5, 0.3, 0.1, 0.01]:
    print(f"{pr:<20} {-np.log(pr):.4f}")

# 2値分類(ロジスティック回帰と同じ形)
yb = [1, 0, 1, 1]
pb = np.array([0.9, 0.2, 0.6, 0.95])
print(f"\n2値: NumPy {-np.mean(np.array(yb)*np.log(pb) + (1-np.array(yb))*np.log(1-pb)):.6f}  log_loss {log_loss(yb, pb):.6f}")

# パープレキシティ = exp(交差エントロピー)
print(f"パープレキシティ exp({manual:.4f}) = {np.exp(manual):.4f}")
NumPy の交差エントロピー平均 = 0.501734
sklearn log_loss              = 0.501734
1件ずつの損失 -ln(正解の確率): [0.2231 0.5108 0.3567 0.9163]

正解クラスの予測確率  損失 -ln(p)
0.99                 0.0101
0.9                  0.1054
0.7                  0.3567
0.5                  0.6931
0.3                  1.2040
0.1                  2.3026
0.01                 4.6052

2値: NumPy 0.222656  log_loss 0.222656
パープレキシティ exp(0.5017) = 1.6516

NumPy で式どおりに計算した値と scikit-learn の log_loss が、小数第6位まで一致しました(0.501734)。 4件目は正解のクラス0に 0.4 しか付けておらず、損失 0.9163 がいちばん大きくなっています。log_loss は自然対数(ナット)で計算します。

正解クラスに付けた確率と損失 −ln p確率が低いほど損失が急に大きくなる

0.990.010
0.90.105
0.70.357
0.50.693
0.31.204
0.12.303
0.014.605

自信を持って外したとき(正解に 0.01 しか付けない)の損失は 4.605 で、0.5 のときの約 6.6 倍です。 交差エントロピーは、自信のある間違いを強くとがめる損失です。学習では、この値が小さくなる方向に重みを少しずつ動かします(誤差逆伝播)。ニューラルネットワークの学習で損失が下がる様子は、関連記事「ニューラルネットワークとは|仕組み・学習・AttentionをNumPyで実演」で扱っています。

PyTorch と scikit-learn で渡すものの違い

ライブラリ 関数 渡す予測 対数
scikit-learn log_loss(y_true, 予測確率) 確率(各行の合計が1) 自然対数
PyTorch nn.CrossEntropyLoss() ロジット(softmax 前の生の値) 自然対数
NumPy 自分で -np.log(...) 確率 書いた関数しだい

PyTorch 2.14 の公式ドキュメントでは、CrossEntropyLoss の入力は正規化していない値(ロジット)で、内部で LogSoftmax と NLLLoss を続けて計算します。正解はクラス番号(long 型)か、各行の合計が1の確率(float 型)で渡し、reduction の既定は 'mean'(平均)です。softmax を自分でかけてから CrossEntropyLoss に渡すと、softmax が2回かかります。 scikit-learn は 1.9 で log_loss の2つ目の引数の名前が y_pred から y_proba に変わりました(公式ドキュメント。以前の名前は 1.11 で削除予定)。位置で渡せば、どちらの版でも動きます。

パープレキシティとの関係

言語モデル(LLM)の評価で使うパープレキシティは、交差エントロピー(ナット)を exp で戻した値です。上の例では exp(0.5017) = 1.65 で、「平均して約1.65通りの候補の中で迷っている」と読めます。値が小さいほど、次に来るものをよく絞り込めています。

KLダイバージェンスとは(2つの分布のずれ)

この節では、KL ダイバージェンスと交差エントロピーの関係を、計算で確かめます。

KL ダイバージェンス(カルバック・ライブラー情報量)は、正しい分布 p の代わりに q を使ったとき、余分にかかる情報量です。 交差エントロピーから、p 自身のエントロピーを引いた値になります。

flowchart TD
    P[正しい分布 p] --> HP[p のエントロピー H(p)<br>どうしても要る量]
    P --> KL[KL(p‖q)<br>q を使った余分]
    Q[予測の分布 q] --> KL
    HP --> CE[交差エントロピー H(p,q)<br>= H(p)+ KL]
    KL --> CE
p = np.array([0.7, 0.2, 0.1])      # 正しい分布(たとえば本当の天気の出やすさ)
q = np.array([0.5, 0.3, 0.2])      # モデルが予測した分布
H_p  = -np.sum(p * np.log(p))
H_pq = -np.sum(p * np.log(q))      # 交差エントロピー H(p, q)
KL   =  np.sum(p * np.log(p / q))  # KL ダイバージェンス D(p||q)
print(f"H(p)   = {H_p:.4f} nat")
print(f"H(p,q) = {H_pq:.4f} nat")
print(f"KL     = {KL:.4f} nat   SciPy entropy(p, q) = {entropy(p, q):.4f}")
print(f"H(p) + KL = {H_p + KL:.4f}  ← H(p,q) と一致")
print(f"KL(q||p) = {entropy(q, p):.4f}  ← 向きを入れかえると値が変わる")
H(p)   = 0.8018 nat
H(p,q) = 0.8869 nat
KL     = 0.0851 nat   SciPy entropy(p, q) = 0.0851
H(p) + KL = 0.8869  ← H(p,q) と一致
KL(q||p) = 0.0920  ← 向きを入れかえると値が変わる

H(p) 0.8018 + KL 0.0851 = 0.8869 で、交差エントロピーと一致しました。 SciPy の scipy.stats.entropy(p, q) は、2つ目の引数を渡すと KL ダイバージェンスを返します(公式ドキュメント。底の既定は e、合計が1でない入力は正規化される)。

比べる点 エントロピー 交差エントロピー KL ダイバージェンス
使う分布 p だけ p と q p と q
最小値 0(結果が決まっている) H(p)(q=p のとき) 0(q=p のとき)
向き なし p と q を入れかえると変わる 入れかえると変わる(0.0851 と 0.0920)
主な使い道 不確かさ・圧縮・決定木 分類の損失関数 分布の比較・VAE・蒸留

分類の学習では、正解の分布 p は変わらないので H(p) は定数です。そのため、交差エントロピーを小さくすることは、KL ダイバージェンスを小さくすることと同じになります。KL は p と q を入れかえると値が変わるので、距離ではなく「ずれの向きつきの量」として扱います。

熱力学のエントロピーとの関係(エントロピー増大の法則)

この節では、物理のエントロピーと情報エントロピーの関係を、IT の読者向けに短く整理します。

熱力学のエントロピーは、熱や分子の「乱雑さ」を表す量で、単位は J/K です。 日本語版 Wikipedia によると、統計力学では、ミクロな状態の数 W を使って S = k log W(k はボルツマン定数)と書けます。とりうる状態が多いほど大きくなる点は、情報エントロピーで「結果の数が多く、均等なほど大きい」のと同じ考え方です。

「エントロピー増大の法則」は熱力学第二法則のことで、外と熱のやりとりをしない系では、エントロピーは減らない(コーヒーに入れたミルクが自然に混ざり、自然には分かれない)というものです。日常の会話で「放っておくと部屋は散らかる」のような意味で使われるのは、この法則のたとえです。情報理論のエントロピーには「増える法則」はなく、確率分布が決まれば値が1つに決まります。名前の似たエンタルピーは、熱の出入りにかかわるエネルギーの量(単位 J)で、エントロピーとは別の量です。

Linuxの「エントロピー」(乱数の種)

この節では、Linux で見かける「エントロピー」が何を指しているかが分かります。

Linux のカーネルは、デバイスなどから予測しにくい雑音(environmental noise)を集めて、乱数の種(エントロピープール)にしています。 カーネルのドキュメントでは、/proc/sys/kernel/random/entropy_avail はプールのエントロピーの量、poolsize はプールの大きさで、どちらも単位はビットです。

cat /proc/sys/kernel/random/entropy_avail /proc/sys/kernel/random/poolsize
256
256

man ページ random(4) によると、/dev/random は Linux 5.6 から、起動直後を除いて待たされる(ブロックする)ことがなくなりました。/dev/urandom はブロックせず、起動直後の乱数が要る場合を除いてすべての用途で /dev/urandom が勧められています(起動直後は getrandom(2) を使う)。Python の secrets や os.urandom は、OS のこの仕組みから乱数を受け取ります。前の節で圧縮できなかった os.urandom の100万バイトは、ここから来ています。

エントロピーの計算でよくある間違いとエラー

この節では、エントロピーや交差エントロピーを自分で計算したときに出やすい誤りと、その直し方が分かります。

確率0を含む配列や、確率でない値を渡したときの出力です。

import numpy as np
from sklearn.metrics import log_loss
from scipy.special import xlogy, softmax
from scipy.stats import entropy
p = np.array([0.5, 0.5, 0.0])
print("1) 確率0を含むまま計算:", -np.sum(p * np.log(p)))
print("   xlogy で 0×log0=0 にする:", -np.sum(xlogy(p, p)), " SciPy:", entropy(p, base=2) )
print("2) 予測確率0で正解:", log_loss([0, 1], [[1.0, 0.0], [1.0, 0.0]]))
try:
    print(log_loss([0, 1], [[0.6, 0.6], [0.3, 0.3]]))
except Exception as e:
    print("3)", type(e).__name__ + ":", e)
logits = np.array([[2.0, 0.5, -1.0]])
try:
    print(log_loss([0], logits, labels=[0, 1, 2]))
except Exception as e:
    print("4)", type(e).__name__ + ":", e)
print("   softmax にしてから:", log_loss([0], softmax(logits, axis=1), labels=[0, 1, 2]), softmax(logits, axis=1).round(4))
print("5) KL で q に0:", entropy([0.5, 0.5], [1.0, 0.0]))
~/demo/e6_err.py:6: RuntimeWarning: divide by zero encountered in log
  print("1) 確率0を含むまま計算:", -np.sum(p * np.log(p)))
~/demo/e6_err.py:6: RuntimeWarning: invalid value encountered in multiply
  print("1) 確率0を含むまま計算:", -np.sum(p * np.log(p)))
1) 確率0を含むまま計算: nan
   xlogy で 0×log0=0 にする: 0.6931471805599453  SciPy: 1.0
2) 予測確率0で正解: 18.021826694558577
.../sklearn/metrics/_classification.py:310: UserWarning: The y_prob values do not sum to one. Make sure to pass probabilities.
  warnings.warn(
0.8573992140459634
4) ValueError: y_prob contains values greater than 1: 2.0
   softmax にしてから: 0.24131129665715703 [[0.7856 0.1753 0.0391]]
5) KL で q に0: inf
症状・エラー文 原因 直し方
divide by zero encountered in log と結果が nan 確率0で log(0) = −∞、0 × (−∞) = nan scipy.special.xlogy か scipy.stats.entropy を使う。0の項を除く
損失が 18.02 のように極端に大きい 正解クラスに確率0を付けた。log_loss は内部で 0 を小さな値に置きかえる 予測確率が 0・1 ちょうどにならないモデルか、確率の出し方を見直す
The y_prob values do not sum to one 各行の合計が1でない。正規化されずに計算が続く 確率の列をそろえる。softmax・predict_proba の出力を渡す
y_prob contains values greater than 1 確率ではなくロジット(生のスコア)を渡した softmax をかけてから渡す(PyTorch は逆にロジットのまま)
KL が inf p では起きる結果を、q が確率0としている q に0を作らない(小さな値を足す・平滑化)
教科書の値と合わない(約 0.69 倍) ビット(log2)とナット(ln)の取り違え SciPy は base=2、NumPy は np.log2 にそろえる
決定木の情報利得が手計算と合わない scikit-learn は2分割だけを試す one-hot の列ごとの2分割で計算し直す
  1. 1確率の合計を確かめる各行の合計が1か、負の値や1を超える値がないかを sum・min・max で見る
  2. 20 の扱いを決めるエントロピーは 0 × log 0 を 0 にする。交差エントロピー・KL は予測側に0を作らない
  3. 3対数の底をそろえるビットなら log2、ナットなら ln。ライブラリの既定は SciPy・log_loss・PyTorch が e、scikit-learn の決定木が 2
  4. 4ライブラリと手計算を照合する小さな例で NumPy の式と log_loss・entropy の値が一致するかを確かめてから、大きなデータに使う

NumPy の配列の作り方や np.log・np.sum(axis=1) の使い方は、関連記事「NumPyの使い方 基本一覧|配列の作成・演算・形状変更」で扱っています。

よくある質問

Q. エントロピーとは簡単に言うと何ですか? A. 結果がどれだけ予想しにくいかを表す数です。IT では、各結果の情報量(−log2 p)を確率で重みづけして平均した値で、単位はビットです。表裏が半々のコインは1ビットです。

Q. エントロピーが高い・低いとはどういう意味ですか? A. 高いと、どの結果も同じくらい起きて予想しにくい状態、低いと、結果が偏っていてほぼ決まっている状態です。結果の数が同じなら、すべて同じ確率のときに最大になります。

Q. エントロピーの計算方法は? A. 各結果の「確率 × −log2(確率)」を出して、すべて足します。表 0.9・裏 0.1 のコインなら 0.137 + 0.332 = 0.469 ビットです。Python では scipy.stats.entropy(確率のリスト, base=2) で計算できます。

Q. 平均情報量と自己情報量の違いは? A. 自己情報量は1つの結果の情報量(−log2 p)、平均情報量はそれを確率で平均した値で、エントロピーと同じものです。

Q. 交差エントロピー(クロスエントロピー)とは? A. 正しい分布と予測した分布のずれを測る量で、分類モデルの損失関数として使います。正解が1つなら「−log(正解クラスの予測確率)」の平均で、scikit-learn の log_loss と同じ値になります。

Q. KL ダイバージェンスと交差エントロピーの違いは? A. 交差エントロピー = 正しい分布のエントロピー + KL ダイバージェンスです。KL は「予測の分布を使ったために余分にかかる量」だけを取り出したもので、分布が同じなら0になります。

Q. 決定木の情報利得とは? A. データを分ける前のエントロピーから、分けた後のエントロピー(件数で重みづけした平均)を引いた値です。決定木は、情報利得がいちばん大きい分け方を選びます。scikit-learn では criterion="entropy" で使えます(既定は gini)。

Q. パスワードのエントロピーはどう計算しますか? A. 無作為に選んだ場合、長さ × log2(文字の種類)ビットです。英大小文字と数字(62種)の16文字なら 95.3 ビットです。人が考えたパスワードは偏りがあるので、この計算より小さくなります。

Q. エントロピーの単位は? A. 情報エントロピーは、対数の底が2ならビット、自然対数ならナットです。熱力学のエントロピーの単位は J/K(ジュール毎ケルビン)で、別の量です。

Q. エントロピー増大の法則とは? A. 熱力学第二法則のことで、外と熱のやりとりをしない系ではエントロピーが減らない、というものです。情報理論のエントロピーには、この「増える法則」はありません。

Q. 圧縮とエントロピーはどう関係しますか? A. エントロピーは、平均で最低何ビットあれば表せるかの目安です。偏ったデータ(エントロピーが低い)はよく縮み、ランダムなデータや暗号化したデータ(8ビット/バイトに近い)は縮みません。zlib の実測では、99%が同じ文字のデータは 1.6%に縮み、ランダムなデータは 100.0%のままでした。

まとめ

  • エントロピーは、結果の予想しにくさを「情報量の平均」で表した数。式は H = −Σ p × log2 p で、単位はビット。
  • 珍しい結果ほど情報量(−log2 p)が大きい。1ビットは「はい・いいえ」の質問1回ぶん。
  • 偏るほど小さく、均等なほど大きい。コインは半々で 1 ビット、表 0.9 で 0.469 ビット、必ず表なら 0。
  • エントロピーは圧縮の限界の目安。zlib でランダムなデータは縮まず、偏ったデータはよく縮んだ。
  • パスワードは長さ × log2(文字の種類)。種類を増やすより、長くして無作為に作るほうがビット数が増える。
  • 決定木は情報利得(減ったエントロピー)が最大の分け方を選ぶ。scikit-learn の値は手計算と一致した。
  • 交差エントロピー = H(p) + KL。NumPy の計算と log_loss は 0.501734 で一致し、KL は SciPy の entropy(p, q) と一致した。

参考・出典

確認日はいずれも 2026年10月23日です。

  • Wikipedia「情報量」:https://ja.wikipedia.org/wiki/情報量
  • Wikipedia「エントロピー」:https://ja.wikipedia.org/wiki/エントロピー
  • SciPy v1.18.0「scipy.stats.entropy」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.entropy.html
  • scikit-learn 1.9.1「Decision Trees(Mathematical formulation)」:https://scikit-learn.org/stable/modules/tree.html
  • scikit-learn 1.9.1「DecisionTreeClassifier」:https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html
  • scikit-learn 1.9.1「sklearn.metrics.log_loss」:https://scikit-learn.org/stable/modules/generated/sklearn.metrics.log_loss.html
  • PyTorch 2.14「CrossEntropyLoss」:https://docs.pytorch.org/docs/2.14/generated/torch.nn.CrossEntropyLoss.html
  • Python ドキュメント「secrets --- Generate secure random numbers for managing secrets」:https://docs.python.org/3/library/secrets.html
  • NIST「SP 800-63B Authentication and Authenticator Management」:https://pages.nist.gov/800-63-4/sp800-63b.html
  • Linux man-pages「random(4)」:https://man7.org/linux/man-pages/man4/random.4.html
  • The Linux Kernel documentation「Documentation for /proc/sys/kernel/」:https://www.kernel.org/doc/html/latest/admin-guide/sysctl/kernel.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「エントロピーとは|意味・計算・交差エントロピーをPythonで実演」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?