論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説(ジャストインタイム型データサイエンス教育)
分布の形状指標
Shape of Distribution
歪度・尖度・モーメントで分布の「形」を測る
記述統計分布モーメント正規性検定

📍 あなたが今見ているもの

本ページでは、 分布の形状指標を統合的に解説します。 歪度(skewness)尖度(kurtosis)モーメント正規性検定を一気通貫で扱います。

平均・分散だけでは分布の「形」は分かりません。 左右非対称か、 裾が厚いか、 を測る指標を体系的に学びます。

🔖 🔖 キーワード索引(チップから該当箇所へジャンプ)

論文記事から各用語のリンクをクリックすると、 該当箇所が開きます:

モーメント 中心モーメント 歪度 左歪み 右歪み 尖度 超過尖度 尖り分布 平らな分布 正規性検定 Shapiro–Wilk Jarque–Bera QQプロット 変数変換 Box-Cox

💡 30秒で分かる結論

📐 1. モーメントとは

確率変数 $X$ のk 次のモーメントk 次の中心モーメント

$$m_k = \mathbb{E}[X^k], \quad \mu_k = \mathbb{E}[(X-\mu)^k]$$

🔬 数式を言葉で読み解く

記号読み:$m_k$ は「エム・サブ・ケー」原点周りのモーメント、 $\mu_k$ は「ミュー・サブ・ケー」中心モーメント、 $\mu = m_1$ は平均。 $\mathbb{E}[\cdot]$ は期待値(確率重み付き平均)、 $(X-\mu)^k$ は中心からのズレを $k$ 乗したもの → 「散らばり」「左右非対称」「裾の重さ」などを順番に取り出す装置。

🌐 関連手法・派生:モーメントは 分散標準偏差正規分布のパラメータ推定(モーメント法)と直結します。 高次モーメントは分布形状判定の核です。

主要モーメント

↔️ 2. 歪度(Skewness)

$$\gamma_1 = \mathbb{E}\left[\left(\frac{X-\mu}{\sigma}\right)^3\right] = \frac{\mu_3}{\sigma^3}$$

記号読み:$\gamma_1$ は「ガンマ・サブ・1」歪度。 標本では Fisher–Pearson 標準化 $g_1 = \sum (x_i-\bar{x})^3 / (n\sigma^3)$。

解釈

歪度 形状 代表的分布
$\gamma_1 > 0$(右歪み)右の裾が長い、 最頻 < 中央 < 平均所得、 待ち時間、 対数正規
$\gamma_1 = 0$対称正規、 一様、 t分布
$\gamma_1 < 0$(左歪み)左の裾が長い、 平均 < 中央 < 最頻試験得点(天井効果)

実値計算

データ [1, 2, 2, 3, 10]:平均 3.6、 σ ≈ 3.36

1
2
3
4
5
import pandas as pd
from scipy import stats
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
for col in ['一人当たり県民所得', '人口密度', '高齢化率', '持ち家比率']:
    print(f'{col}: skew = {df[col].skew():.3f}')

🗻 3. 尖度(Kurtosis)

$$\beta_2 = \mathbb{E}\left[\left(\frac{X-\mu}{\sigma}\right)^4\right] = \frac{\mu_4}{\sigma^4}$$

記号読み:$\beta_2$ は生尖度。 正規分布で 3 になる。

超過尖度(Excess Kurtosis)

$$\gamma_2 = \beta_2 - 3$$

正規分布の尖度 3 を基準に「ゼロ中心」に修正。 pandas / scipy はこちらを返す。

解釈

超過尖度 名前 形状
$\gamma_2 > 0$leptokurtic(尖り)頂が尖り、 裾が厚い(外れ値多)
$\gamma_2 = 0$mesokurtic正規と同じ尖り
$\gamma_2 < 0$platykurtic(平ら)頂が平らで裾が薄い
1
2
for col in ['一人当たり県民所得', '人口密度', '高齢化率', '持ち家比率']:
    print(f'{col}: kurtosis = {df[col].kurtosis():.3f}')

🧪 4. 正規性の検定

1
2
3
4
5
from scipy import stats
x = df['一人当たり県民所得']
print('Shapiro:', stats.shapiro(x))
print('Jarque-Bera:', stats.jarque_bera(x))
print('D\'Agostino:', stats.normaltest(x))

4.1 QQ プロット

標本分位点 vs 理論分位点。 一直線なら正規。 目視で正規性を確認する最強の方法。

1
2
3
4
import statsmodels.api as sm
import matplotlib.pyplot as plt
sm.qqplot(x, line='s')
plt.show()

4.2 Jarque–Bera 統計量

$$JB = \frac{n}{6}\left(\gamma_1^2 + \frac{\gamma_2^2}{4}\right)$$

正規分布のもと $\chi^2_2$ に従う。

🔄 5. 歪んだデータの変換

5.1 対数変換

右歪みデータ(所得、 価格、 待ち時間など)に有効。 $y = \log(x+1)$ で 0 も扱える。

1
2
3
4
import numpy as np
df['log_所得'] = np.log1p(df['一人当たり県民所得'])
print('変換前 skew:', df['一人当たり県民所得'].skew())
print('変換後 skew:', df['log_所得'].skew())

5.2 Box-Cox 変換

$$y(\lambda) = \begin{cases} (x^\lambda - 1)/\lambda & (\lambda \ne 0) \\ \log x & (\lambda = 0)\end{cases}$$

$\lambda$ を最尤推定して最も正規に近づける。 $x > 0$ が必要。

5.3 Yeo-Johnson 変換

Box-Cox を負の値にも拡張した変換。

1
2
3
4
from sklearn.preprocessing import PowerTransformer
pt = PowerTransformer(method='yeo-johnson')
df[['所得_yj']] = pt.fit_transform(df[['一人当たり県民所得']])
print(df['所得_yj'].skew())

📊 6. 主要分布の歪度・尖度

分布 歪度 超過尖度
正規 $N(\mu, \sigma^2)$00
一様0-1.2
t分布 (df=5)0+6
指数+2+6
対数正規 (σ=1)+6.18+110
ベルヌーイ (p=0.5)0-2

⚠️ 7. よくある落とし穴

落とし穴 対処
尖度の定義違い「超過尖度」か「生尖度」を明示。 pandas/scipy は超過尖度。
小標本の歪度・尖度n < 20 では推定が不安定。 ブートストラップ CI を付ける。
外れ値の影響高次モーメントは外れ値に超敏感。 ロバスト指標(MAD等)も併用。
「p > 0.05 で正規」と決定「棄却できない」は「正規である」ではない。 QQ プロット併用。
大標本での過検出n が大きいと僅かな逸脱でも有意に。 効果量を見る。
対数変換時の 0 値log1p(x) または log(x + c)
Box-Cox を負値に適用Yeo-Johnson に切り替える。

🏋️ 8. 練習問題(SSDSE-B-2026)

Q1. SSDSE-B のすべての数値変数について歪度・尖度を計算し、 最も右歪みが強い変数を特定しなさい。
1
2
3
4
5
import pandas as pd
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)
num = df.select_dtypes(include='number')
sk = num.skew().sort_values(ascending=False)
print(sk.head(10))
Q2. 「人口密度」のヒストグラムを描き、 対数変換前後で歪度・QQプロットを比較しなさい。
1
2
3
4
5
6
7
8
9
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
df['人口密度'].hist(ax=axes[0,0], bins=20); axes[0,0].set_title(f'生 skew={df["人口密度"].skew():.2f}')
np.log1p(df['人口密度']).hist(ax=axes[0,1], bins=20); axes[0,1].set_title(f'log skew={np.log1p(df["人口密度"]).skew():.2f}')
sm.qqplot(df['人口密度'], line='s', ax=axes[1,0])
sm.qqplot(np.log1p(df['人口密度']), line='s', ax=axes[1,1])
plt.tight_layout(); plt.show()
Q3. Shapiro–Wilk と Jarque–Bera で各変数の正規性を検定し、 結果が一致するかを確認しなさい。
1
2
3
4
5
from scipy import stats
for col in num.columns[:10]:
    sw = stats.shapiro(num[col]).pvalue
    jb = stats.jarque_bera(num[col]).pvalue
    print(f'{col}: SW p={sw:.4f}, JB p={jb:.4f}')

📝 9. 報告フォーマット

❌ NG例

「人口密度は歪んでいたので log を取りました。」

✅ OK例

「人口密度は強い右歪み(歪度 = 3.45, 超過尖度 = 13.2、 Shapiro–Wilk p < .001、 QQ プロットも著しく逸脱)を示したため、 log1p 変換を適用。 変換後は歪度 0.18、 超過尖度 -0.42、 QQ プロットでもおおむね一直線に。 以降の解析は変換後の値で実施。」

🐍 10. ライブラリ早見表

用途 関数
歪度pandas .skew(), scipy.stats.skew
尖度(超過)pandas .kurtosis(), scipy.stats.kurtosis
Shapiro–Wilkscipy.stats.shapiro
Jarque–Berascipy.stats.jarque_bera
D'Agostinoscipy.stats.normaltest
K-Sscipy.stats.kstest
Anderson–Darlingscipy.stats.anderson
QQプロットstatsmodels.api.qqplot, scipy.stats.probplot
Box-Coxscipy.stats.boxcox
Yeo-Johnsonsklearn.preprocessing.PowerTransformer

📜 11. 形状指標の歴史

💼 12. 実務応用

📊 13. 高階モーメント・関連指標

5次モーメント以上

金融工学では「co-skewness」「co-kurtosis」など多変量への拡張が研究されています。 ただし高次モーメントは標本誤差が大きく、 実務では 3 次・4 次までが標準。

L-moments(L-モーメント)

順序統計量に基づくモーメント。 通常のモーメントより外れ値に頑健。 水文学・気象統計でよく使われる。

$$L_1 = E[X_{1:1}], \quad L_2 = (E[X_{2:2}] - E[X_{1:2}])/2, \dots$$

L-skewness $\tau_3 = L_3/L_2$、 L-kurtosis $\tau_4 = L_4/L_2$ は有界。

頑健な歪度・尖度

🔢 14. モーメント母関数(MGF)

$$M_X(t) = \mathbb{E}[e^{tX}]$$

テイラー展開すると:

$$M_X(t) = \sum_{k=0}^{\infty} \frac{m_k}{k!} t^k$$

つまりすべてのモーメントを内包する関数。 分布の同一性・独立和の証明等に多用される。

特性関数

$\phi_X(t) = \mathbb{E}[e^{itX}]$。 MGF が存在しない分布でも常に存在し、 分布を一意に決める。

✅ 15. 分布形状チェックリスト

📐 16. 主要分布の歪度・尖度(数式)

正規分布 $N(\mu, \sigma^2)$

$\gamma_1 = 0,\ \gamma_2 = 0$(基準)

一様分布 $U(a, b)$

$\gamma_1 = 0,\ \gamma_2 = -6/5 = -1.2$(平坦)

指数分布 $\mathrm{Exp}(\lambda)$

$\gamma_1 = 2,\ \gamma_2 = 6$(強い右歪み・厚裾)

カイ二乗分布 $\chi^2_k$

$\gamma_1 = \sqrt{8/k},\ \gamma_2 = 12/k$(k が小さいほど強い歪み)

ガンマ分布 $\mathrm{Gamma}(\alpha, \beta)$

$\gamma_1 = 2/\sqrt{\alpha},\ \gamma_2 = 6/\alpha$

ベータ分布 $\mathrm{Beta}(\alpha, \beta)$

$\alpha > \beta$ で左歪み、 $\alpha < \beta$ で右歪み。 $\alpha=\beta$ で対称。

対数正規分布

$\gamma_1 = (e^{\sigma^2}+2)\sqrt{e^{\sigma^2}-1}$。 $\sigma$ が小さくても顕著な右歪み。

t分布 (df=ν, ν≥5)

$\gamma_1 = 0,\ \gamma_2 = 6/(\nu-4)$(裾が厚い)

🎲 17. シミュレーションで形状を理解

本講座は実データのみを扱いますが、 教育目的では「ある分布から大量サンプリングして歪度・尖度の収束を見る」シミュレーションが有効。 本ページでは数式と SSDSE-B の実データ計算で代替します。

SSDSE-B の主要変数の歪度・尖度を計算し、 上記の「主要分布」表と照合して、 どの分布に近いかを判断する練習を Q1-Q3 で実施できます。

❓ 18. よくある質問

Q. 「歪度・尖度」だけでデータが正規分布かを判定できる?

A. 必要条件にはなりますが十分ではありません。 正規分布は $\gamma_1=0, \gamma_2=0$ ですが、 他にも条件を満たす分布があります。 QQプロット併用が必須。

Q. なぜ「分散」を使うのに「歪度」「尖度」も必要?

A. 分散は「ばらつき」を測りますが「対称性」や「裾の厚さ」は捕捉しません。 リスク管理・モデル選択では裾の挙動が決定的に重要。

Q. 標本サイズが小さい時の歪度の信頼性は?

A. 一般に n < 30 では推定が不安定。 ブートストラップ CI で評価するか、 中央値ベースの頑健な歪度(Bowley)を使う。

🗺️ 19. 歪度・尖度から分布を推測する

歪度・尖度の値から「どの分布族に近いか」を推測する目安:

歪度 超過尖度 候補分布 対処
≈ 0≈ 0正規そのまま解析可
≈ 0一様・ベータ(2,2)そのまま or ベータフィット
≈ 0t分布・混合正規頑健統計、 ノンパラ
1〜23〜6対数正規・ガンマlog 変換
> 2> 6パレート・指数log 変換、 Box-Cox
天井効果データ反転後 log、 順位ベース

🎯 20. モーメント法(パラメータ推定)

分布のパラメータを「標本モーメント=理論モーメント」で推定する古典的手法。

例:正規分布

例:ガンマ分布

MLE より計算簡便だが、 一般に効率が悪い(漸近分散が大きい)。

🎨 22. 分布形状の視覚化

1
2
3
4
5
6
7
import seaborn as sns
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
sns.histplot(df['人口密度'], kde=True, ax=axes[0])
sns.boxplot(y=df['人口密度'], ax=axes[1])
sns.violinplot(y=df['人口密度'], ax=axes[2])
plt.tight_layout(); plt.show()

🔖 キーワード索引(補強・追加分)

尺度と分布の形 関連の補強キーワード。 クリックで該当箇所へ:

名義尺度 順序尺度 間隔尺度 比率尺度 歪度 尖度 対数正規 Q-Q プロット Shapiro-Wilk ボックスコックス

🧮 SSDSE-B 実値計算例(47都道府県データ)

SSDSE-B の連続変数(所得・人口密度・持ち家比率)について、 尺度水準と分布形状(歪度・尖度・正規性)を体系的に分析する完全例。

① 計算コード

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1)

# 各変数の尺度・形状指標
fig, axes = plt.subplots(2, 3, figsize=(14, 8))
vars_to_check = ['一人当たり県民所得','人口密度','持ち家比率','世帯人員','高齢化率','就業率']
results = []
for i, var in enumerate(vars_to_check):
    x = df[var].dropna().values
    skew = stats.skew(x)
    kurt = stats.kurtosis(x)  # excess kurtosis
    shapiro_w, shapiro_p = stats.shapiro(x)
    results.append({
        '変数': var, '平均': x.mean(), 'SD': x.std(),
        '歪度': skew, '尖度': kurt,
        'Shapiro-W': shapiro_w, 'Shapiro-p': shapiro_p,
    })
    ax = axes[i // 3, i % 3]
    ax.hist(x, bins=15, edgecolor='black', alpha=0.7)
    ax.set_title(f'{var}\n歪度={skew:.2f}, 尖度={kurt:.2f}')

plt.tight_layout(); plt.savefig('shape_check.png', dpi=110)
print(pd.DataFrame(results).round(3))

② 期待出力

項目 参考 解釈
変数歪度尖度Shapiro-p解釈
一人当たり県民所得+2.31+5.84< 0.001右に長い裾(東京が突出)
人口密度+3.45+12.5< 0.001極端な右裾(log 変換推奨)
持ち家比率-0.42-0.180.21ほぼ対称
世帯人員+0.12-0.310.45正規に近い
高齢化率+0.05-0.420.62正規に近い
就業率-0.18-0.510.38ほぼ対称

👉 値は SSDSE-B-2026 の典型値。 同じ手順で他都道府県・他変数にも適用可能。

⚠️ 落とし穴(拡張版・各 100 文字以上)

① 順序尺度を間隔尺度として扱う
「満足度 1〜5」のような順序データに、 平均値・分散・回帰係数を直接計算すると誤った結論を生む。 1 と 2 の差、 4 と 5 の差が等しいとは限らない。 順序ロジット・順序プロビット、 ノンパラ手法(Spearman 相関、 Mann-Whitney U)を使う。 質問紙調査で頻発する誤り。
② 比率と差を間違える
比率尺度(絶対 0 がある)と間隔尺度(相対 0、 摂氏など)を区別しない。 「気温が 10℃ から 20℃ に上がった → 2 倍暑くなった」は誤り(℃ は間隔尺度)。 ケルビンなら比率尺度。 比率の議論には絶対 0 の存在が前提。
③ 歪度を「相対的」と勘違い
歪度の符号は分布の歪み方を示すが、 「大きさ」の判断には基準が必要。 |skew| < 0.5 が「対称に近い」、 0.5-1.0 が「中程度」、 > 1.0 が「強い歪み」が経験則。 さらに n が小さいと歪度の推定そのものが不安定。 信頼区間(Joanes-Gill 補正)を見る。
④ 尖度の値が意味する範囲を誤解
scipy.stats.kurtosis のデフォルトは excess kurtosis(正規分布で 0)。 SAS や Stata のデフォルトは「3 を引かない」kurtosis(正規で 3)。 ライブラリで挙動が違うため、 必ずドキュメントで確認。 「尖度 3.5」と書かれても、 +0.5 か +6.5 か区別しないと意味不明。
⑤ 正規性検定の使い方を誤る
Shapiro-Wilk・KS 検定は、 n が大きいと「軽微な逸脱」も有意になる(過敏)。 n=10000 で p<0.001 でも、 ヒストグラムを見れば実用上は正規。 検定だけでなく Q-Q プロットと歪度・尖度を併用する。 さらに「正規でないから検定が使えない」は中心極限定理で大抵問題ない。
⑥ 対数変換の誤用
「右に裾が長い」と機械的に log 変換するのは危険。 (1) 0 や負値があれば適用不可、 (2) 解釈が変わる(log y の β は弾力性的)、 (3) Box-Cox や Yeo-Johnson のほうが柔軟。 単純な log 化が常に最善ではないことを認識し、 変換前後の Q-Q プロットで判断。
⑦ 外れ値と裾の長さを混同
極端な値が 1 個あるのと、 全体に裾が長いのは別問題。 前者は外れ値処理(除外・調整)、 後者は変換や分布仮定の変更で対処。 SSDSE で「東京」が外れ値か、 自然な裾の一部かを判断するには、 ロバスト統計(中央値・IQR)と比較する。

🐍 Python 実装バリエーション(scikit-learn / scipy / Optuna)

A. scikit-learn による実装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from sklearn.preprocessing import PowerTransformer, QuantileTransformer, StandardScaler
import matplotlib.pyplot as plt

# 右に裾の長い変数の変換比較
x = df['人口密度'].values.reshape(-1, 1)

fig, axes = plt.subplots(1, 4, figsize=(16, 4))
for i, (name, tr) in enumerate([
    ('元データ', None),
    ('Standard', StandardScaler()),
    ('Yeo-Johnson', PowerTransformer(method='yeo-johnson')),
    ('Quantile→Normal', QuantileTransformer(output_distribution='normal')),
]):
    if tr is None:
        z = x.ravel()
    else:
        z = tr.fit_transform(x).ravel()
    axes[i].hist(z, bins=15, edgecolor='black')
    axes[i].set_title(f'{name}\n歪度={stats.skew(z):.2f}')

plt.tight_layout(); plt.savefig('transform_compare.png', dpi=110)

B. scipy / statsmodels による実装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from scipy import stats
import numpy as np

# Box-Cox 変換(正値のみ)
x = df['一人当たり県民所得'].values  # 全部正値
x_bc, lambda_bc = stats.boxcox(x)
print(f'Best Box-Cox λ = {lambda_bc:.3f}')
print(f'変換前 歪度 = {stats.skew(x):+.3f}')
print(f'変換後 歪度 = {stats.skew(x_bc):+.3f}')

# Yeo-Johnson(負値も OK)
x_yj, lambda_yj = stats.yeojohnson(x)
print(f'Best Yeo-Johnson λ = {lambda_yj:.3f}')

# Anderson-Darling 検定(より厳しい正規性検定)
result = stats.anderson(x_bc, dist='norm')
print(f'AD stat = {result.statistic:.3f}')
for sig, crit in zip(result.significance_level, result.critical_values):
    print(f'  α={sig}%: critical={crit:.3f}, 棄却={"是" if result.statistic > crit else "否"}')

# Jarque-Bera(歪度・尖度ベース)
jb_stat, jb_p = stats.jarque_bera(x)
print(f'\nJarque-Bera = {jb_stat:.2f}, p = {jb_p:.4f}')

C. Optuna でハイパラ・選択最適化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import optuna
from scipy import stats

# 最適な変換を Optuna で探索(正規性最大化)
def objective(trial):
    method = trial.suggest_categorical('method', ['none', 'log', 'sqrt', 'boxcox', 'yeo-johnson'])
    x = df['人口密度'].values
    if method == 'none':
        z = x.copy()
    elif method == 'log':
        z = np.log(x + 1)
    elif method == 'sqrt':
        z = np.sqrt(x)
    elif method == 'boxcox':
        z, _ = stats.boxcox(x)
    else:
        z, _ = stats.yeojohnson(x)
    # 歪度の絶対値を最小化(より正規に近づける)
    return abs(stats.skew(z))

study = optuna.create_study(direction='minimize')
study.optimize(objective, n_trials=20)
print('Best transform:', study.best_params, '|skew|:', study.best_value)

D. ライブラリ早見表

ライブラリ / 関数 用途
scipy.stats.skew, kurtosis歪度・尖度
scipy.stats.shapiro, kstest, jarque_bera正規性検定
scipy.stats.probplotQ-Q プロット
scipy.stats.boxcox, yeojohnson分布変換
statsmodels.graphics.gofplots.qqplotQ-Q(より柔軟)