ヘロログ
統計学

対数変換

所得データや株価、細菌の増殖数など、世の中には「右に裾が長い」分布をするデータが数多くある。このようなデータをそのまま分析すると、平均や分散が外れ値に引っ張られたり、正規分布を仮定した統計手法がうまく機能しなかったりする。

対数変換は、こうしたデータを扱いやすい形に変換する最も基本的な手法である。この記事では、対数変換がなぜ有効なのか、どのような場面で使うのかを、数式と具体例を通して解説する。

対数変換とは

対数変換(logarithmic transformation)とは、データ x に対して対数を取る変換である。

対数変換の定義
y = \log(x)

通常は自然対数(底が e \approx 2.718)を使うが、常用対数(底が10)を使う場合もある。統計学では特に断りがなければ自然対数を指すことが多い。

対数変換の前提として、データは正の値である必要がある。0以下の値には対数が定義されないためである(\log(0) = -\infty、負の値は定義されない)。

なぜ対数変換を使うのか

対数変換を使う主な理由は3つある。

理由1:右に裾が長い分布を対称に近づける

所得や資産、人口、細菌数などのデータは、多くの場合「右に裾が長い」分布をする。つまり、大部分のデータは小さな値に集中し、一部の大きな値が右側に長く伸びている。

このようなデータに対数変換を適用すると、大きな値が圧縮され、分布が左右対称(正規分布)に近づく。正規分布に近づけば、t検定や回帰分析など、正規性を仮定する統計手法が適用しやすくなる。

変換前(右に裾が長い) x log変換 変換後(対称に近い) log(x)
図1: 対数変換による分布の変化

理由2:乗法的な関係を加法的に変換する

複利計算や細菌の増殖のように、「掛け算」で成長するデータがある。対数の性質により、掛け算は足し算に変換される。

\log(ab) = \log(a) + \log(b)

例えば、年利5%で10年間複利運用した場合の資産は次のように表せる。

\text{資産} = \text{元本} \times 1.05^{10}

対数を取ると、乗法的な関係が加法的に変わる。

\log(\text{資産}) = \log(\text{元本}) + 10 \times \log(1.05)

このように変換することで、線形回帰などの手法が適用しやすくなる。

理由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(ただし緩やかに)

この性質により、回帰分析で目的変数が非負値の場合に対数変換を適用すると、予測値が負になる問題を回避できる。

x log(x) 0 1 2 3 4 5 0 1 2 (1, 0) x→0で−∞
図2: 対数関数 y = log(x) のグラフ

具体例:年収データの変換

ある企業の社員20人の年収データ(万円)を考える。

元データ

200310390430470 490510530550580
6307208109201050 12001400165019502400

基本統計量の比較

統計量 元データ (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万円より小さくなる。

ヒストグラムの比較

元データ(右に裾が長い) 年収(万円) 対数変換後(対称に近い) log(年収)
図3: 対数変換前後のヒストグラム比較

練習問題

問1. ある細菌は1時間ごとに2倍に増殖する。初期の細菌数を N_0 とするとき、t 時間後の細菌数 N(t) を式で表せ。また、両辺の自然対数を取った式を導け。

t 時間後の細菌数は次のようになる。

N(t) = N_0 \times 2^t

両辺の自然対数を取ると、

\log N(t) = \log N_0 + t \times \log 2

これは \log N(t)t の間に線形関係があることを示している。\log 2 \approx 0.693 なので、時間 t が1増えるごとに \log N(t) は約0.693増加する。

問2. 以下のデータ(5個)について、対数変換前後の平均と標準偏差を計算せよ(母標準偏差を用いよ)。
データ: 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)になる。

問3. 年間売上高が 1000万円 の店舗Aと、10億円(100000万円)の店舗Bがある。両者の売上高を対数変換(自然対数)した値をそれぞれ求め、その差を計算せよ。この差は元のスケールで何倍の違いに相当するか。

店舗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で確認してみよう。

log_transform.py
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}万円")
=== 元データ === 平均: 859.5 中央値: 605.0 標準偏差: 586.9 歪度: 1.27 === 対数変換後 === 平均: 6.56 中央値: 6.40 標準偏差: 0.64 歪度: 0.20 対数平均のexp: 706.2万円

歪度が1.27から0.20に減少し、分布が対称に近づいたことがわかる。

ヒストグラムの描画

histogram.py
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()