確率分布を特徴づける指標として、期待値(平均)と分散はよく知られている。しかし、これら2つの指標だけでは分布の「形」を完全には表現できない。
たとえば、年収の分布と身長の分布を考えてみよう。どちらも平均と分散で要約できるが、年収の分布は右に長い裾を持ち、身長の分布は左右対称に近い形をしている。このような分布の形状の違いを数値化するのが、歪度(わいど)と尖度(せんど)である。
また、「標準偏差10」という値は、平均が100のときと平均が1000のときでは意味が異なる。平均に対する相対的なばらつきを表すのが変動係数である。
本記事では、これらの特性値について定義から計算方法まで詳しく解説する。
位置の指標:期待値・中央値・最頻値
分布の「中心」を表す代表値には、主に3種類ある。
期待値(平均)
確率変数 X の期待値(expected value)は、確率で重み付けした値の総和である。
中央値
中央値(median)は、累積分布関数 F(x) において F(a) = 0.5 となる値 a である。データを小さい順に並べたとき、ちょうど真ん中に位置する値に対応する。
最頻値(モード)
最頻値(mode)は、確率関数または確率密度関数が最大となる値である。最も出現しやすい値を表す。
3つの指標の関係
左右対称かつ単峰な分布では、期待値・中央値・最頻値はすべて一致する。しかし、分布が非対称な場合は異なる値をとる。
右に裾が長い分布(正の歪み)では:最頻値 < 中央値 < 期待値
左に裾が長い分布(負の歪み)では:期待値 < 中央値 < 最頻値
散らばりの指標:変動係数
標準偏差はデータの散らばりを表す代表的な指標だが、測定単位や平均の大きさに依存するという欠点がある。たとえば、象の体重の標準偏差とハムスターの体重の標準偏差を単純に比較することはできない。
変動係数(coefficient of variation, CV)は、標準偏差を平均で割った値であり、平均に対する相対的なばらつきを表す。
変動係数は無次元量であり、単位が異なるデータ間でもばらつきの程度を比較できる。
計算例:製品の品質管理
ある工場で2種類の製品の重量を測定した。
| 製品 | 測定値 (g) | 平均 | 標準偏差 | 変動係数 |
|---|---|---|---|---|
| 製品A(大型) | 495, 502, 498, 505, 500 | 500.0 g | 3.81 g | 0.76% |
| 製品B(小型) | 48, 52, 49, 51, 50 | 50.0 g | 1.58 g | 3.16% |
標準偏差だけを見ると製品Aの方がばらつきが大きいように見えるが、変動係数で比較すると製品Bの方が相対的なばらつきが大きいことがわかる。つまり、製品Bの製造工程の方が品質管理上の課題があると判断できる。
変動係数は、平均が0に近い場合や負の値を取りうる場合には適切に定義できない。主に非負の値をとるデータに対して使用する。
分布の形状:歪度と尖度
歪度(わいど)
歪度(skewness)は、分布の非対称性を表す指標である。3次の中心モーメントを標準偏差の3乗で基準化して定義される。
歪度の解釈は以下の通りである。
- 歪度 = 0:左右対称な分布
- 歪度 > 0:右に裾が長い(正の歪み)
- 歪度 < 0:左に裾が長い(負の歪み)
歪度が0でない場合、分布の裾の長い方向に外れ値が存在しやすいことを意味する。年収や資産額の分布は典型的な正の歪みを持つ例である。
尖度(せんど)
尖度(kurtosis)は、分布の裾の重さを表す指標である。4次の中心モーメントを分散の2乗で基準化して定義される。
尖度の解釈は以下の通りである。
- 正規分布の尖度は3(基準値)
- 尖度 > 3:正規分布より裾が重い(外れ値が出やすい)
- 尖度 < 3:正規分布より裾が軽い
正規分布を基準として「尖度 − 3」を超過尖度と呼び、これを尖度の定義とする文献もある。その場合、正規分布の超過尖度は0となる。
上図では、赤い実線が尖度の高い分布(裾が重い分布)を表している。中心付近ではほぼ同じ形をしているが、裾の部分で大きな差がある。尖度が高い分布では、極端な値(外れ値)が発生する確率が正規分布よりも高くなる。
代表的な分布の歪度・尖度
| 分布 | 歪度 | 尖度 | 特徴 |
|---|---|---|---|
| 正規分布 | 0 | 3 | 基準となる対称分布 |
| 一様分布 | 0 | 1.8 | 裾が軽い(外れ値なし) |
| 指数分布 | 2 | 9 | 右に歪み、裾が重い |
| t分布 (df=3) | 0 | ∞(理論値) | 対称だが裾が非常に重い |
計算例
次のデータについて、歪度と尖度を計算してみよう。
ステップ1:平均の計算
ステップ2:各データの偏差
| x_i | x_i - \mu | (x_i - \mu)^2 | (x_i - \mu)^3 | (x_i - \mu)^4 |
|---|---|---|---|---|
| 1 | −2 | 4 | −8 | 16 |
| 2 | −1 | 1 | −1 | 1 |
| 3 | 0 | 0 | 0 | 0 |
| 4 | 1 | 1 | 1 | 1 |
| 5 | 2 | 4 | 8 | 16 |
| 合計 | 0 | 10 | 0 | 34 |
ステップ3:中心モーメントの計算
ステップ4:歪度と尖度の計算
このデータは完全に対称なので歪度は0である。また、尖度は1.7で正規分布の3より小さく、裾が軽い分布であることがわかる。
練習問題
- 数学:平均75点、標準偏差15点
- 英語:平均60点、標準偏差18点
各科目の変動係数を計算する。
英語の方が変動係数が大きく、平均に対する相対的なばらつきが大きい。つまり、英語の成績の方が個人差が大きいといえる。
ステップ1:平均を計算する。
ステップ2:偏差と累乗を計算する。
| x_i | x_i - \mu | (x_i - \mu)^2 | (x_i - \mu)^3 |
|---|---|---|---|
| 2 | −2 | 4 | −8 |
| 4 | 0 | 0 | 0 |
| 4 | 0 | 0 | 0 |
| 6 | 2 | 4 | 8 |
| 合計 | 0 | 8 | 0 |
ステップ3:中心モーメントを計算する。
ステップ4:歪度を計算する。
このデータは平均4を中心に対称(2と6が対称、4が2つ)なので、歪度は0となる。
- 所得の分布(少数の高所得者がいる)
- 製造誤差の分布(目標値を中心に対称)
- 100点満点の試験で平均95点(ほとんどが高得点、少数が低得点)
- 所得:正の歪度(右に裾が長い。少数の高所得者が平均を引き上げる)
- 製造誤差:歪度ゼロ(対称分布)
- 高得点試験:負の歪度(左に裾が長い。少数の低得点者がいる)
まとめ
| 特性値 | 定義 | 意味 | 基準 |
|---|---|---|---|
| 変動係数 CV | \dfrac{\sigma}{\mu} | 平均に対する相対的なばらつき | 大きいほどばらつきが大きい |
| 歪度 | \dfrac{E[(X-\mu)^3]}{\sigma^3} | 分布の非対称性 | 0で対称、正で右に歪む |
| 尖度 | \dfrac{E[(X-\mu)^4]}{\sigma^4} | 裾の重さ | 正規分布で3、大きいほど裾が重い |
異なる単位のばらつき比較 → 変動係数
分布が対称かどうか → 歪度
外れ値の出やすさ → 尖度
Pythonで実装する
import numpy as np
from scipy import stats
# サンプルデータ
data = np.array([1, 2, 3, 4, 5])
# 基本統計量
mean = np.mean(data)
std = np.std(data, ddof=0) # 母標準偏差
print(f"平均: {mean}")
print(f"標準偏差: {std:.4f}")
# 変動係数
cv = std / mean
print(f"変動係数: {cv:.4f}")
# 歪度と尖度(scipy使用)
skewness = stats.skew(data, bias=True) # 母歪度
kurtosis = stats.kurtosis(data, fisher=False, bias=True) # 母尖度
print(f"歪度: {skewness:.4f}")
print(f"尖度: {kurtosis:.4f}")
# 手計算での確認
m2 = np.mean((data - mean)**2)
m3 = np.mean((data - mean)**3)
m4 = np.mean((data - mean)**4)
print(f"\n--- 手計算 ---")
print(f"2次中心モーメント: {m2}")
print(f"3次中心モーメント: {m3}")
print(f"4次中心モーメント: {m4}")
print(f"歪度: {m3 / m2**1.5:.4f}")
print(f"尖度: {m4 / m2**2:.4f}")
様々な分布の比較
import numpy as np
from scipy import stats
np.random.seed(42)
n = 10000
# 各分布からサンプリング
normal = np.random.normal(0, 1, n)
exponential = np.random.exponential(1, n)
uniform = np.random.uniform(-1, 1, n)
distributions = {
"正規分布": normal,
"指数分布": exponential,
"一様分布": uniform
}
print(f"{'分布':<12} {'歪度':>8} {'尖度':>8}")
print("-" * 30)
for name, data in distributions.items():
skew = stats.skew(data)
kurt = stats.kurtosis(data, fisher=False)
print(f"{name:<12} {skew:>8.4f} {kurt:>8.4f}")