所得データや株価、細菌の増殖数など、世の中には「右に裾が長い」分布をするデータが数多くある。このようなデータをそのまま分析すると、平均や分散が外れ値に引っ張られたり、正規分布を仮定した統計手法がうまく機能しなかったりする。
対数変換は、こうしたデータを扱いやすい形に変換する最も基本的な手法である。この記事では、対数変換がなぜ有効なのか、どのような場面で使うのかを、数式と具体例を通して解説する。
対数変換とは
対数変換(logarithmic transformation)とは、データ x に対して対数を取る変換である。
通常は自然対数(底が e \approx 2.718)を使うが、常用対数(底が10)を使う場合もある。統計学では特に断りがなければ自然対数を指すことが多い。
対数変換の前提として、データは正の値である必要がある。0以下の値には対数が定義されないためである(\log(0) = -\infty、負の値は定義されない)。
なぜ対数変換を使うのか
対数変換を使う主な理由は3つある。
理由1:右に裾が長い分布を対称に近づける
所得や資産、人口、細菌数などのデータは、多くの場合「右に裾が長い」分布をする。つまり、大部分のデータは小さな値に集中し、一部の大きな値が右側に長く伸びている。
このようなデータに対数変換を適用すると、大きな値が圧縮され、分布が左右対称(正規分布)に近づく。正規分布に近づけば、t検定や回帰分析など、正規性を仮定する統計手法が適用しやすくなる。
理由2:乗法的な関係を加法的に変換する
複利計算や細菌の増殖のように、「掛け算」で成長するデータがある。対数の性質により、掛け算は足し算に変換される。
例えば、年利5%で10年間複利運用した場合の資産は次のように表せる。
対数を取ると、乗法的な関係が加法的に変わる。
このように変換することで、線形回帰などの手法が適用しやすくなる。
理由3:変動係数が一定のデータの分散を安定化する
「大きな値ほどばらつきも大きい」というデータがある。例えば、年収300万円の人と年収3000万円の人では、変動の絶対額が異なる。
このような場合、変動係数(標準偏差÷平均)が一定であることが多く、対数変換によって分散を安定化できる。
対数変換は「右に裾が長い分布の正規化」「乗法関係の線形化」「分散の安定化」に有効。特に、所得・資産・人口・株価・生物の成長データなどでよく使われる。
対数変換の数学的性質
対数変換の重要な性質を整理する。
基本的な性質
| 性質 | 式 |
|---|---|
| 積 → 和 | \log(ab) = \log(a) + \log(b) |
| 商 → 差 | \log(a/b) = \log(a) - \log(b) |
| 累乗 → 定数倍 | \log(a^n) = n \times \log(a) |
| 定義域 | x > 0(正の値のみ) |
| 値域 | -\infty < \log(x) < \infty(実数全体) |
定義域の変換
対数変換の重要な特徴として、正の値 (0, \infty) を実数全体 (-\infty, \infty) に写すことがある。
- x \to 0 のとき、\log(x) \to -\infty
- x = 1 のとき、\log(x) = 0
- x \to \infty のとき、\log(x) \to \infty(ただし緩やかに)
この性質により、回帰分析で目的変数が非負値の場合に対数変換を適用すると、予測値が負になる問題を回避できる。
具体例:年収データの変換
ある企業の社員20人の年収データ(万円)を考える。
元データ
| 200 | 310 | 390 | 430 | 470 | 490 | 510 | 530 | 550 | 580 |
| 630 | 720 | 810 | 920 | 1050 | 1200 | 1400 | 1650 | 1950 | 2400 |
基本統計量の比較
| 統計量 | 元データ (x) | 対数変換後 (log x) |
|---|---|---|
| 平均 | 859.5 | 6.56 |
| 中央値 | 605.0 | 6.40 |
| 標準偏差 | 586.9 | 0.64 |
| 歪度 | 1.27(右裾長) | 0.20(ほぼ対称) |
元データでは平均(859.5万円)と中央値(605.0万円)に大きな差があり、高所得者に引っ張られている。対数変換後は歪度が1.27から0.20に減少し、分布が対称に近づいた。
対数変換後のデータに対して計算した平均 E[\log X] は、元のスケールでの平均 E[X] とは異なる。\exp(6.56) \approx 706 万円であり、元の平均859.5万円より小さくなる。
ヒストグラムの比較
練習問題
t 時間後の細菌数は次のようになる。
両辺の自然対数を取ると、
これは \log N(t) と t の間に線形関係があることを示している。\log 2 \approx 0.693 なので、時間 t が1増えるごとに \log N(t) は約0.693増加する。
データ: 10, 20, 40, 80, 160
元データの統計量:
- 平均: (10 + 20 + 40 + 80 + 160) / 5 = 310 / 5 = 62
- 分散: [(10-62)^2 + (20-62)^2 + (40-62)^2 + (80-62)^2 + (160-62)^2] / 5
= [2704 + 1764 + 484 + 324 + 9604] / 5 = 14880 / 5 = 2976 - 標準偏差: \sqrt{2976} \approx 54.55
対数変換後のデータ:
- \log(10) \approx 2.303
- \log(20) \approx 2.996
- \log(40) \approx 3.689
- \log(80) \approx 4.382
- \log(160) \approx 5.075
対数変換後の統計量:
- 平均: (2.303 + 2.996 + 3.689 + 4.382 + 5.075) / 5 \approx 3.689
- 標準偏差: \approx 0.98
元データは等比数列(公比2)なので、対数変換後は等差数列(公差 \log 2 \approx 0.693)になる。
店舗A: \log(1000) \approx 6.91
店舗B: \log(100000) \approx 11.51
差: 11.51 - 6.91 = 4.61
この差 4.61 は \log(100000/1000) = \log(100) に等しい。\exp(4.61) \approx 100 なので、100倍の違いに相当する。
一般に、対数変換後の差 d は、元のスケールで \exp(d) 倍の違いを意味する。
まとめ
| 項目 | 内容 |
|---|---|
| 定義 | y = \log(x)(通常は自然対数) |
| 適用条件 | x > 0(正の値のみ) |
| 主な用途 | 右裾長分布の正規化、乗法関係の線形化、分散安定化 |
| よく使う場面 | 所得・資産、株価、人口、細菌数、売上高など |
| 数学的効果 | 積→和、商→差、累乗→定数倍 |
| 注意点 | E[\log X] \neq \log(E[X])、解釈時は注意が必要 |
Pythonで実装する
対数変換の効果をPythonで確認してみよう。
import numpy as np
from scipy import stats
# 年収データ(万円)
income = np.array([200, 310, 390, 430, 470, 490, 510, 530, 550, 580,
630, 720, 810, 920, 1050, 1200, 1400, 1650, 1950, 2400])
# 対数変換
log_income = np.log(income)
# 基本統計量の比較
print("=== 元データ ===")
print(f"平均: {income.mean():.1f}")
print(f"中央値: {np.median(income):.1f}")
print(f"標準偏差: {income.std(ddof=1):.1f}")
print(f"歪度: {stats.skew(income):.2f}")
print("\n=== 対数変換後 ===")
print(f"平均: {log_income.mean():.2f}")
print(f"中央値: {np.median(log_income):.2f}")
print(f"標準偏差: {log_income.std(ddof=1):.2f}")
print(f"歪度: {stats.skew(log_income):.2f}")
# 対数平均を元のスケールに戻す
print(f"\n対数平均のexp: {np.exp(log_income.mean()):.1f}万円")
歪度が1.27から0.20に減少し、分布が対称に近づいたことがわかる。
ヒストグラムの描画
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
# 元データ
axes[0].hist(income, bins=8, edgecolor='black', alpha=0.7)
axes[0].set_xlabel('年収(万円)')
axes[0].set_ylabel('度数')
axes[0].set_title('元データ')
# 対数変換後
axes[1].hist(log_income, bins=8, edgecolor='black', alpha=0.7, color='green')
axes[1].set_xlabel('log(年収)')
axes[1].set_ylabel('度数')
axes[1].set_title('対数変換後')
plt.tight_layout()
plt.savefig('log_transform_hist.png', dpi=150)
plt.show()