尺度と分布の形 関連の補強キーワード。 クリックで該当箇所へ:
🍰 まずはやさしく
データの形を測るものさしです。
分布のクセを見つけるために使います。
テストの点数の偏りを調べる時に便利です。
歪度や尖度の結論をまとめました。
🍰 まずはやさしく
データの見た目を表す指標です。
平均や分散だけでは分からない形を調べます。
スマホの利用時間のバラつきなどを考えます。
形を測る方法をまとめて学びます。
本ページでは、 分布の形状指標を統合的に解説します。 歪度(skewness)・尖度(kurtosis)・モーメント・正規性検定を一気通貫で扱います。
平均・分散だけでは分布の「形」は分かりません。 左右非対称か、 裾が厚いか、 を測る指標を体系的に学びます。
本ページでは「scale shape」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。
「scale shape」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。
🍰 まずはやさしく
データの形を絵にする方法です。
数字だけでは見えない特徴を視覚化します。
部活の記録をグラフにして比べます。
分布を可視化する色々な図について読みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import pandas as pd # df はこのあとのブロックで作っているので、ここでも用意しておく df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) import seaborn as sns import matplotlib.pyplot as plt fig, axes = plt.subplots(1, 3, figsize=(15, 4)) sns.histplot(df['A1101'], kde=True, ax=axes[0]) # A1101=総人口 sns.boxplot(y=df['A1101'], ax=axes[1]) sns.violinplot(y=df['A1101'], ax=axes[2]) plt.tight_layout(); plt.show() |
🍰 まずはやさしく
形の正体を計算する仕組みです。
データのズレを数値で表すために使います。
買い物で使う金額の偏りを計算します。
モーメントという考え方について読みます。
確率変数 $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$ 乗したもの → 「散らばり」「左右非対称」「裾の重さ」などを順番に取り出す装置。
🌐 関連手法・派生:モーメントは 分散・標準偏差・正規分布のパラメータ推定(モーメント法)と直結します。 高次モーメントは分布形状判定の核です。
$$\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.26
1 2 3 4 5 | import pandas as pd from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) for col in ['A1101', 'L3221', 'A1303', 'A4103']: print(f'{col}: skew = {df[col].skew():.3f}') |
$$\beta_2 = \mathbb{E}\left[\left(\frac{X-\mu}{\sigma}\right)^4\right] = \frac{\mu_4}{\sigma^4}$$
記号読み:$\beta_2$ は生尖度。 正規分布で 3 になる。
$$\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 ['A1101', 'L3221', 'A1303', 'A4103']: print(f'{col}: kurtosis = {df[col].kurtosis():.3f}') |
1 2 3 4 5 | from scipy import stats x = df['A1101'] print('Shapiro:', stats.shapiro(x)) print('Jarque-Bera:', stats.jarque_bera(x)) print('D\'Agostino:', stats.normaltest(x)) |
標本分位点 vs 理論分位点。 一直線なら正規。 目視で正規性を確認する最強の方法。
1 2 3 4 | import statsmodels.api as sm import matplotlib.pyplot as plt sm.qqplot(x, line='s') plt.show() |
$$JB = \frac{n}{6}\left(\gamma_1^2 + \frac{\gamma_2^2}{4}\right)$$
正規分布のもと $\chi^2_2$ に従う。
右歪みデータ(所得、 価格、 待ち時間など)に有効。 $y = \log(x+1)$ で 0 も扱える。
1 2 3 4 | import numpy as np df['log_A1101'] = np.log1p(df['A1101']) print('変換前 skew:', df['A1101'].skew()) print('変換後 skew:', df['log_A1101'].skew()) |
$$y(\lambda) = \begin{cases} (x^\lambda - 1)/\lambda & (\lambda \ne 0) \\ \log x & (\lambda = 0)\end{cases}$$
$\lambda$ を最尤推定して最も正規に近づける。 $x > 0$ が必要。
Box-Cox を負の値にも拡張した変換。
1 2 3 4 | from sklearn.preprocessing import PowerTransformer pt = PowerTransformer(method='yeo-johnson') df[['A1101_yj']] = pt.fit_transform(df[['A1101']]) print(df['A1101_yj'].skew()) |
| 分布 | 歪度 | 超過尖度 |
|---|---|---|
| 正規 $N(\mu, \sigma^2)$ | 0 | 0 |
| 一様 | 0 | -1.2 |
| t分布 (df=5) | 0 | +6 |
| 指数 | +2 | +6 |
| 対数正規 (σ=1) | +6.18 | +110 |
| ベルヌーイ (p=0.5) | 0 | -2 |
$\gamma_1 = 0,\ \gamma_2 = 0$(基準)
$\gamma_1 = 0,\ \gamma_2 = -6/5 = -1.2$(平坦)
$\gamma_1 = 2,\ \gamma_2 = 6$(強い右歪み・厚裾)
$\gamma_1 = \sqrt{8/k},\ \gamma_2 = 12/k$(k が小さいほど強い歪み)
$\gamma_1 = 2/\sqrt{\alpha},\ \gamma_2 = 6/\alpha$
$\alpha > \beta$ で左歪み、 $\alpha < \beta$ で右歪み。 $\alpha=\beta$ で対称。
$\gamma_1 = (e^{\sigma^2}+2)\sqrt{e^{\sigma^2}-1}$。 $\sigma$ が小さくても顕著な右歪み。
$\gamma_1 = 0,\ \gamma_2 = 6/(\nu-4)$(裾が厚い)
本講座は実データのみを扱いますが、 教育目的では「ある分布から大量サンプリングして歪度・尖度の収束を見る」シミュレーションが有効。 本ページでは数式と SSDSE-B の実データ計算で代替します。
SSDSE-B の主要変数の歪度・尖度を計算し、 上記の「主要分布」表と照合して、 どの分布に近いかを判断する練習を Q1-Q3 で実施できます。
A. 必要条件にはなりますが十分ではありません。 正規分布は $\gamma_1=0, \gamma_2=0$ ですが、 他にも条件を満たす分布があります。 QQプロット併用が必須。
A. 分散は「ばらつき」を測りますが「対称性」や「裾の厚さ」は捕捉しません。 リスク管理・モデル選択では裾の挙動が決定的に重要。
A. 一般に n < 30 では推定が不安定。 ブートストラップ CI で評価するか、 中央値ベースの頑健な歪度(Bowley)を使う。
「分布の形状」とは 中心 (mean / median) と ばらつき (variance / std) では掴みきれない、 分布の 非対称性 と 裾の重さ を数値化したものである。 ここでは SSDSE-B-2026 (47 都道府県データ、 出典: 独立行政法人統計センター) を実材料に、 歪度 (skewness)・尖度 (kurtosis) が どんなときに大きく動き、 どんなときに動かないか を都道府県の具体的事例で確認する。 直感を養うには「数式を眺める」ではなく「実値が動く瞬間を観察する」ことが最短ルートである。
歪度 $\gamma_1 = E[(X-\mu)^3]/\sigma^3$ は、 平均から見た「左右の非対称さ」を 3 乗で増幅して測る。 3 乗のため 外れ値が一発で値を引っ張る のが特徴。 SSDSE-B-2026 の代表列を歪度の大きい順に並べると、 47 都道府県の「東京一極集中」が数値として浮き彫りになる。
図 D1: ヒストグラムで分布形状 (中心位置・裾の伸び方・左右対称性) を直感的に確認するのが第一歩。 平均と中央値の位置関係が左右の歪みを示唆する。
| 列 (SSDSE-B-2026) | 意味 | 歪度の目安 | 解釈 |
|---|---|---|---|
| A1101 総人口 | 人 | +2.29 程度 | 東京・神奈川・大阪の右側ロングテール。 鳥取・島根が左の山を作る。 |
| A1303 65歳以上人口 | 人 | +1.84 程度 | 大都市に高齢者も集積し右裾。 |
| L322108 教育費(二人以上の世帯) | 円 | +1.37 程度 | 東京・埼玉など都市部で突出。 |
| L322107 交通・通信費 | 円 | +0.97 程度 | 車依存の地方で押し上げ。 |
| L322101 食料費 | 円 | +0.65 程度 | 東京がやや高い、 概ね対称に近い。 |
| L3221 消費支出 | 円 | -0.52 程度 | ほぼ左右対称(わずかに左裾)。 |
| A4103 合計特殊出生率 | — | -0.04 程度 | ほぼ左右対称。 沖縄が右、 東京が左。 |
歪度が大きい列は 平均値を「典型値」として報告すると過大評価 につながりやすい。 たとえば人口の平均値は 265 万人前後だが、 実際は 47 都道府県のうち 35 件が平均以下に集中し、 「平均的な都道府県」と呼べる場所が存在しない。 このような場合は 中央値・四分位 を併記する設計が必要になる。
尖度 $\gamma_2 = E[(X-\mu)^4]/\sigma^4 - 3$ (超過尖度) は 平均から離れた値が「想定より頻繁に」観測されるか を測る。 「尖り具合」と訳されがちだが、 実態は 裾 (tail) の厚み。 正規分布で 0、 t 分布や指数分布で正、 一様分布で負。
| 分布 | 超過尖度 | 裾の特徴 | 実世界の例 |
|---|---|---|---|
| 一様分布 U(0,1) | -1.2 | 裾が無い (端で打ち切り) | 乱数生成、 確率の基準 |
| 正規分布 N(0,1) | 0.0 | 標準的な裾 | 身長、 測定誤差 |
| t 分布 (df=5) | +6.0 | 重い裾 | 小標本の検定統計量 |
| 指数分布 | +6.0 | 右側に長い裾 | 待ち時間、 故障時間 |
| ラプラス分布 | +3.0 | 中心が尖り、 裾も厚い | 金融商品リターン |
| 対数正規分布 | +10 以上 | 非常に重い右裾 | 所得、 都市人口、 株価 |
| Cauchy 分布 | ∞ | 分散すら定義されない | 物理学の共鳴幅 |
SSDSE-B-2026 の総人口列は超過尖度がおよそ +5 と 正規よりはっきり重い裾 を示す。 これは「都道府県の人口分布は正規ではなく、 一部の超大都市が裾を引き伸ばしている」ことを定量化している。 t 検定・ANOVA など正規性を仮定する検定をそのまま適用すると、 p 値が過小評価される可能性がある。 Shapiro-Wilk 検定 での事前確認や 対数変換 による正規化が必要になる場面。
歪度の二乗 $\gamma_1^2$ と超過尖度 $\gamma_2$ には数学的に $\gamma_2 \geq \gamma_1^2 - 2$ の不等式が成り立つ (Pearson 不等式)。 つまり 歪度が大きい分布は必ず尖度も大きくなる。 47 都道府県データで観測する人口・世帯支出系の列の多くが「右裾 + 重い裾」になるのはこの数学的帰結。
図 D2: 47 都道府県を 2 次元にプロットすると、 1 変数の歪度・尖度だけでは見えない「外れ点 (東京) が周辺関係を全て持っていく」構造が見える。 散布図と形状指標は併用する。
このコードでやること: SSDSE-B-2026 の総人口列 A1101 と消費支出列 L3221(二人以上の世帯)について scipy.stats で歪度と尖度を計算し、 上位/下位 5 都道府県を表示する。 単に数値を出すだけでなく 「なぜその値になるのか」を都道府県名で確認 する。
📥 入力データ (SSDSE-B-2026 の 2023 年 冒頭 4 行):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import pandas as pd from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 最新年 (2023) の 47 都道府県 for col in ['A1101', 'L3221']: # A1101=総人口, L3221=消費支出 x = df[col].dropna() sk = stats.skew(x) ku = stats.kurtosis(x) # 超過尖度 (Fisher 定義) print(f'[{col}] n={len(x)} mean={x.mean():.1f} std={x.std():.1f}') print(f' skewness = {sk:+.3f}') print(f' kurtosis = {ku:+.3f} (超過尖度)') top = df.nlargest(5, col)[['Prefecture', col]] bot = df.nsmallest(5, col)[['Prefecture', col]] print(' 上位5:', top.to_dict('records')) print(' 下位5:', bot.to_dict('records')) |
📤 実行結果:
💬 結果の読み方: A1101 は歪度 +2.22、 超過尖度 +4.95 で 明確な右裾 + やや厚い裾。 東京 1409 万人は次点神奈川の 1.5 倍、 最小の鳥取の 26 倍。 L3221(消費支出)は歪度 -0.52、 超過尖度 +0.52 で「ほぼ左右対称(わずかに左裾)で正規に近い分布」。 消費支出は最大の埼玉 34.4 万円と最小の愛媛 22.3 万円の差が 1.5 倍 程度に収まり、 人口のような極端な集中はない。 このギャップが「人口や経済規模は一極集中するが、 1 世帯あたりの消費支出は地域差が小さい」という政策議論の数値的根拠になる。
歪度・尖度は 標本サイズが小さいと推定誤差が非常に大きい。 教科書的な経験則は「歪度の標準誤差 ≈ $\sqrt{6/n}$、 尖度の標準誤差 ≈ $\sqrt{24/n}$」。 47 都道府県データではそれぞれ約 0.36、 0.71 となる。
| 標本サイズ n | 歪度の標準誤差 | 尖度の標準誤差 | 使用可否 |
|---|---|---|---|
| 10 | 0.77 | 1.55 | 参考程度 |
| 47 (都道府県) | 0.36 | 0.71 | 大きな偏りなら検出可 |
| 100 | 0.24 | 0.49 | 中程度の偏りも検出 |
| 1000 | 0.08 | 0.15 | 小さい偏りも有意 |
| 10000 | 0.024 | 0.049 | 微小偏差まで検出 |
A1101 (総人口) の歪度 +2.22 は SE=0.36 に対して 6 倍以上の絶対値なので 明確に対称ではない と断言できる。 一方 A4103 (合計特殊出生率) の歪度 -0.04 は SE 内に収まるため「対称的とみなしてよい」。 ここを混同すると「47 都道府県すべての列に歪みがある」と過剰主張する誤りに繋がる。
図 D3: 箱ひげ図は中心位置 (中央値)・ばらつき (IQR)・外れ値・歪み (中央値が箱の中で偏る) を同時に可視化できる。 形状指標と組み合わせて使う標準ツール。
47 都道府県の人口分布は「東京一極集中 + 多数の中堅都市 + 少数の小都市」という 3 山構造に近い。 これは形状指標を「全体で 1 つ」しか出さない場合は見落とされる。 群分け (例: 三大都市圏 vs その他) して形状を別々に算出する「層別形状分析」が実務では多用される。
| 群 | 対象 | 平均人口 (人) | 歪度 | 尖度 |
|---|---|---|---|---|
| 三大都市圏 | 東京・神奈川・大阪・愛知・千葉・埼玉・兵庫 | 8,359,000 | +1.17 | +0.45 |
| 政令市保有県 | 福岡・京都・広島・宮城・新潟・静岡 | 3,053,500 | +1.13 | -0.14 |
| 地方圏 | 鳥取・島根・高知・徳島 | 637,000 | -0.90 | -0.83 |
形状指標は 間隔尺度・比率尺度 でしか定義されない。 名義 (例: 都道府県名) には足し算がないので平均すら存在せず、 順序 (例: 5 段階評価) でも数値差に意味がないため平均・分散の計算は本質的に不正確。 ところがアンケート 5 件法を平均して「3.8 点だから歪度は…」と語る分析は実務で頻発する。
| 尺度 | 例 | 平均 | 中央値 | 分散 | 歪度・尖度 |
|---|---|---|---|---|---|
| 名義 | 都道府県、 性別、 血液型 | × | × | × | × |
| 順序 | 5 件法アンケート、 学年 | △ (近似) | ○ | △ | × |
| 間隔 | 気温 (摂氏)、 西暦 | ○ | ○ | ○ | ○ |
| 比率 | 人口、 所得、 距離、 時間 | ○ | ○ | ○ | ○ (幾何平均・変動係数も可) |
SSDSE-B-2026 の数値列は全て比率尺度なので形状指標を計算してよい。 一方 SSDSE-E (学校データ) の教育課程コードや SSDSE-D (社会保障データ) の制度区分コードは名義尺度なので、 数値に見えても歪度を計算してはならない。 「標準化 後の値」「中央値 との比」など演算意味のある変換だけが許される。
形状指標は そのまま意思決定に使う数値ではなく、 次の分析を選ぶための予備調査値 である。 以下のフローは EDA 段階で頻出する判断パターン。
| |歪度| | 超過尖度 | 推奨アクション | 理由 |
|---|---|---|---|
| < 0.5 | |·| < 1 | 正規分布近似で t 検定・ANOVA | 対称・標準裾 |
| 0.5 - 1.0 | |·| < 2 | 中央値併記、 結論は慎重に | 中程度の歪み |
| 1.0 - 2.0 | 2 - 5 | 対数 / 平方根変換を検討 | 片側偏重 |
| > 2.0 | > 5 | ノンパラ検定 (Mann-Whitney 等) または対数変換必須 | 正規仮定は破綻 |
| 外れ値起因 | 突出値 | 外れ値除外 / Winsorize / robust 統計 | 1-2 点が支配 |
このコードでやること: 同じデータに対して scipy / pandas / numpy / statsmodels の歪度・尖度を比較し、 ライブラリごとの定義差 (Fisher vs Pearson、 バイアス補正の有無) を確認する。
📥 入力データ: SSDSE-B-2026 の A1101 列 (47 都道府県の総人口)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import pandas as pd import numpy as np from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] x = df['A1101'].dropna() print('scipy.stats.skew (Fisher, bias=True) :', stats.skew(x, bias=True)) print('scipy.stats.skew (Fisher, bias=False) :', stats.skew(x, bias=False)) print('pandas .skew() (Fisher, bias 補正済み) :', x.skew()) print('scipy.stats.kurtosis (Fisher, bias=True):', stats.kurtosis(x, bias=True)) print('scipy.stats.kurtosis (Pearson) :', stats.kurtosis(x, fisher=False)) print('pandas .kurt() (Fisher, bias 補正済み) :', x.kurt()) |
📤 実行結果:
💬 結果の読み方: 同じデータでも 3 通りの値が出る。 (1) Fisher vs Pearson の差は 3 (定義の引き算)。 (2) bias 補正 は小標本ほど効く。 47 都道府県程度では数 % の差。 (3) 論文・レポートに記載する際は「scipy.stats.kurtosis (Fisher, bias=True)」のように定義を明示 しないと再現できない。 デフォルトのまま使う場合でも、 README に書く運用を推奨。
歪度・尖度は便利だが、 以下の場合は値が動かず誤った安心を与える 危険がある。 EDA では数値だけでなく必ずヒストグラム・箱ひげ図と併用する。
形状指標は 「数値が小さい = 正常」では決してなく、 双峰・離散・打ち切りなど構造的な異常は見逃す。 必ず図と数値を合わせて判断する規律を持つ。 47 都道府県データは「歪度 +3 級が当たり前の世界」を体感する格好の教材になる。
製造業の品質管理、 不正取引検知、 サーバ監視など 「正常時の分布を学習し、 そこから外れた値を検出する」 場面では、 形状指標は次の 3 つの判断に直接使われる。
| 業界 | 監視対象 | 典型分布 | 歪度 | 尖度 | 推奨手法 |
|---|---|---|---|---|---|
| 製造業 | 寸法誤差 | 正規 | ≈ 0 | ≈ 0 | 3σ 管理図 (Shewhart) |
| サーバ監視 | レスポンス時間 (ms) | 対数正規 | +2 〜 +5 | +5 〜 +30 | 対数変換 + 3σ、 99 パーセンタイル |
| 金融 | 日次リターン (%) | t 分布 (df=4 〜 6) | ≈ -0.3 | +3 〜 +10 | VaR、 EVT (極値統計) |
| EC サイト | 注文金額 | 対数正規 | +3 〜 +6 | +10 以上 | ルールベース + Isolation Forest |
| 医療 | 検査値 (Cre, BNP 等) | 対数正規 | +1 〜 +3 | +2 〜 +10 | 対数変換 + Z スコア |
| 気象 | 降水量 (mm) | 対数正規 + ゼロ過剰 | +5 以上 | +20 以上 | ガンマ + GP 分布混合 |
機械学習モデルの種類ごとに、 特徴量の歪度・尖度が予測精度に与える影響は大きく異なる。
| モデル | 歪度の影響 | 尖度の影響 | 対策 |
|---|---|---|---|
| 線形回帰 (OLS) | 大 (係数が外れ値に引っ張られる) | 大 (残差の正規性が崩れる) | 対数変換、 Box-Cox、 robust 回帰 |
| ロジスティック回帰 | 中 (標準化で緩和) | 小 | 標準化 |
| k 近傍法 (kNN) | 大 (距離が偏る) | 大 | 標準化 必須、 外れ値除去 |
| 決定木 / ランダムフォレスト | 小 (順位ベース) | 小 | 通常は変換不要 |
| XGBoost / LightGBM | 小 | 小 | 通常は変換不要 |
| ニューラルネット | 中 (勾配消失/爆発) | 中 | BatchNorm、 LayerNorm、 標準化 |
| SVM (RBF カーネル) | 大 | 大 | 標準化 必須、 カーネル幅調整 |
SSDSE-B-2026 の人口列 A1101 (歪度 +2.2) をそのまま線形回帰に入れると、 東京 1 点が係数を支配する。 同じデータを XGBoost に渡せば順位情報だけ使うため、 東京の影響は限定的になる。 「データ形状を見てから、 モデルを選ぶ・前処理を決める」が EDA の最重要アウトプット。
SSDSE-B-2026 のおよそ 100 列のうち、 教材で扱う頻度の高い 20 列を歪度の絶対値順に並べた。 上位は「人口・世帯数の規模系」、 下位は「1 世帯あたり支出や比率系」になりがちで、 これが教材設計の指針になる。
| 順位 | 列 | 意味 | |歪度| | 解説 |
|---|---|---|---|---|
| 1 | A1302 15~64歳人口 | 人 | 2.52 | 都市圏に生産年齢人口が集中 |
| 2 | A4101 出生数 | 人 | 2.37 | 人口比例 |
| 3 | A1101 総人口 | 人 | 2.29 | 東京一極集中 |
| 4 | A1102 日本人人口 | 人 | 2.25 | 総人口とほぼ同型 |
| 5 | A1301 15歳未満人口 | 人 | 2.14 | 人口比例 |
| 6 | A4200 死亡数 | 人 | 1.86 | 人口規模に比例 |
| 7 | A1303 65歳以上人口 | 人 | 1.84 | 大都市に集積 |
| 8 | L322108 教育費 | 円 | 1.37 | 都市部で突出 |
| 9 | B4106 降水日数 | 日 | 1.01 | 日本海側が多い |
| 10 | L322107 交通・通信費 | 円 | 0.97 | 車依存の地方で高い |
| 11 | L322101 食料費 | 円 | 0.67 | 東京がやや高い |
| 12 | L322103 光熱・水道費 | 円 | 0.67 | 寒冷地が高い |
| 13 | L322106 保健医療費 | 円 | 0.66 | やや右 |
| 14 | B4109 降水量 | mm | 0.63 | 地域差 |
| 15 | L3221 消費支出 | 円 | 0.54 | わずかに左裾 |
| 16 | L322102 住居費 | 円 | 0.40 | 都市が高い |
| 17 | L322109 教養娯楽費 | 円 | 0.19 | ほぼ対称 |
| 18 | B4101 年平均気温 | ℃ | 0.16 | ほぼ対称(沖縄が高温側) |
| 19 | A4103 合計特殊出生率 | — | 0.04 | 左右対称 |
| 20 | L322104 家具・家事用品費 | 円 | 0.01 | 対称 |
「東京は何パーセンタイルに位置するか」は分布形状によって大きく変わる。 同じ z スコア 3 でも、 正規分布なら上位 0.13%、 対数正規 (歪度 3) なら上位 1% 程度、 t 分布 (df=5) なら上位 1.5% といった具合。
| 分布 | z = 2 の上側確率 | z = 3 の上側確率 | z = 4 の上側確率 | 99% パーセンタイルの z |
|---|---|---|---|---|
| 正規 N(0,1) | 2.28% | 0.13% | 0.003% | 2.33 |
| t (df=5) | 5.1% | 1.5% | 0.5% | 3.36 |
| t (df=3) | 7.0% | 2.9% | 1.4% | 4.54 |
| 指数 | 4.5% | 1.8% | 0.7% | 3.61 |
| 対数正規 (σ=1) | 3.5% | 1.5% | 0.7% | 3.71 |
SSDSE-B-2026 の人口列を z 化すると東京は z=4.0 付近にいる。 正規分布前提で考えると 3 万分の 1 の「奇跡」、 実際は対数正規前提で 100 分の 1 程度の「珍しいが起こり得る」現象。 この差が政策議論で「東京は特別」と片付けるか「他の都市にも起こり得る」と捉えるかの分かれ目になる。
レポートで形状指標を伝える際の標準テンプレート。 「数値だけ」「視覚化だけ」のいずれも不完全で、 両者を 1 つの表にまとめると読み手に最短で伝わる。
| 項目 | 総人口 A1101 | 消費支出 L3221 | 合計特殊出生率 A4103 |
|---|---|---|---|
| n | 47 | 47 | 47 |
| 単位 | 人 | 千円/人 | % |
| 平均 | 2,645,809 | 295,856 | 1.29 |
| 中央値 | 1,549,000 | 300,652 | 1.30 |
| 標準偏差 | 2,797,551 | 24,144 | 0.13 |
| 変動係数 | 1.06 | 0.08 | 0.10 |
| 歪度 (Fisher) | +2.22 | -0.52 | -0.04 |
| 超過尖度 | +4.95 | +0.52 | -0.44 |
| Shapiro-Wilk p | < 0.001 | 0.27 | 0.94 |
| 最小 | 537,000 (鳥取) | 223,423 (愛媛) | 0.99 (東京) |
| 最大 | 14,086,000 (東京) | 344,092 (埼玉) | 1.60 (沖縄) |
| 推奨報告値 | 中央値 + IQR | 平均で OK | 平均で OK |
| 推奨可視化 | 対数軸ヒスト + 箱ひげ | ヒストグラム | ヒストグラム |
この表 1 つで、 読み手は「どの列を平均で語ってよいか」「対数変換が必要か」「外れ値はどこか」を一覧できる。 形状指標を単独で出すのではなく、 中心傾向・ばらつき・検定 p 値・推奨アクションをワンセットで提示するのが熟練アナリストの定型。
| 項目 | 合格基準 | 不合格例 |
|---|---|---|
| 尺度水準の明示 | 列ごとに比率/間隔/順序/名義を明記 | アンケート 5 件法を比率扱い |
| 標本サイズ確認 | n と歪度 SE を併記 | 「歪度 +1.2」だけ |
| 定義の明示 | Fisher / Pearson、 bias 補正 | 「scipy で算出」だけ |
| 視覚化との併用 | ヒストグラム + 数値表 | 数値だけ |
| 外れ値の感度分析 | 除外前後を比較 | 外れ値の存在に言及無し |
| 次アクションの提示 | 対数変換・ノンパラ検定を勧告 | 「歪んでいる」で終わる |
| 中央値・IQR 併記 | 必ず併記 | 平均のみ報告 |
| 時系列変化 | 複数年度比較 | 1 時点のみ |
この 8 項目を全て満たして初めて「形状指標を理解した分析」と呼べる。 数値を出すだけなら scipy 1 行で終わるが、 そこから読み解きと意思決定に繋げるのが本来の使い方。 SSDSE-B-2026 と ヒストグラム・箱ひげ図・相関係数 を組み合わせれば、 47 都道府県を題材にした EDA の標準ワークフローを 1 ページで実演できる。
SSDSE-B-2026 の人口列 A1101 は歪度 +2.2、 超過尖度 +5.0 という明確な右裾分布だが、 各値に 自然対数を取るだけ で歪度はおよそ +0.8 まで縮み、 正規性検定でも棄却されない程度に対称化する。 これが対数変換が EDA・回帰分析の前処理で多用される理由である。
背景にある数学的理由は、 「東京 (1409 万) と鳥取 (54 万) は 26 倍の差」だが「log(1409 万) ≒ 16.46 と log(54 万) ≒ 13.19 は 1.25 倍の差」になるためである。 つまり対数変換は 「比率としての差」を「絶対値の差」に変換する 操作で、 比率に意味があるデータ (人口・所得・GDP・株価) に特に効く。
| 変換 | 数式 | 変換後の人口歪度 | 変換後の人口尖度 | 適用条件 |
|---|---|---|---|---|
| なし | $y = x$ | +2.22 | +4.95 | 対称データのみ |
| 平方根 | $y = \sqrt{x}$ | +1.49 | +1.54 | カウントデータ、 $x \geq 0$ |
| 対数 | $y = \ln x$ | +0.79 | -0.21 | $x > 0$、 比率に意味 |
| 逆数 | $y = 1/x$ | +0.55 | -0.28 | $x > 0$、 反転意味のあるデータ |
| Box-Cox | $y = (x^\lambda - 1) / \lambda$ | +0.12 | -0.74 | $\lambda$ を最尤推定 |
| Yeo-Johnson | 部分的に対数 | +0.12 | -0.74 | 負値・ゼロを含むデータ可 |
このコードでやること: SSDSE-B-2026 の総人口に 5 種類の変換を適用し、 変換前後の歪度・尖度を一覧表示する。 どの変換が最も「対称化」するかを実値で確認する。
📥 入力データ: SSDSE-B-2026 の A1101 列 (47 値)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import pandas as pd import numpy as np from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] x = df['A1101'].dropna() # 5 種類の変換 y_sqrt = np.sqrt(x) y_log = np.log(x) y_inv = 1.0 / x y_bc, lam = stats.boxcox(x) # Box-Cox print(f'{"変換":<10}{"歪度":>10}{"尖度":>10}') print(f'{"なし":<10}{stats.skew(x):>10.3f}{stats.kurtosis(x):>10.3f}') print(f'{"sqrt":<10}{stats.skew(y_sqrt):>10.3f}{stats.kurtosis(y_sqrt):>10.3f}') print(f'{"log":<10}{stats.skew(y_log):>10.3f}{stats.kurtosis(y_log):>10.3f}') print(f'{"1/x":<10}{stats.skew(y_inv):>10.3f}{stats.kurtosis(y_inv):>10.3f}') print(f'{"Box-Cox":<10}{stats.skew(y_bc):>10.3f}{stats.kurtosis(y_bc):>10.3f} (lambda={lam:.3f})') |
📤 実行結果:
💬 結果の読み方: Box-Cox の最適 λ ≈ -0.49 は 対数変換 (λ=0) と 逆数変換 (λ=-1) の中間で、 log 単独 (歪度 +0.79) よりさらに裾を圧縮し歪度を +0.12 まで下げる。 とはいえ log でも歪度は +2.2 → +0.8 に大きく改善し、 正規性検定 (D'Agostino) は棄却されなくなる。 実務では λ を最尤推定するより、 解釈しやすい対数変換を選ぶことが多い。
変換は万能ではない。 以下の落とし穴に注意する。
このコードでやること: 47 都道府県データから復元抽出を 10,000 回繰り返し、 歪度・尖度の 95% 信頼区間を経験分布から求める。 公式の標準誤差 $\sqrt{6/n}$ より信頼性が高い。
📥 入力データ: SSDSE-B-2026 の A1101 列 (47 値)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import pandas as pd import numpy as np from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] x = df['A1101'].dropna().to_numpy() B = 10000 # ブートストラップ反復回数 rng = np.random.default_rng(42) sk_boot = np.empty(B) ku_boot = np.empty(B) for b in range(B): sample = rng.choice(x, size=len(x), replace=True) sk_boot[b] = stats.skew(sample) ku_boot[b] = stats.kurtosis(sample) print(f'歪度: 推定={stats.skew(x):.3f}') print(f' 95% CI=[{np.percentile(sk_boot, 2.5):.3f}, {np.percentile(sk_boot, 97.5):.3f}]') print(f'尖度: 推定={stats.kurtosis(x):.3f}') print(f' 95% CI=[{np.percentile(ku_boot, 2.5):.3f}, {np.percentile(ku_boot, 97.5):.3f}]') |
📤 実行結果:
💬 結果の読み方: 歪度の 95% CI は [1.19, 3.29] と幅広く、 「正確な値はわからないが、 確実に正で、 おおむね 1.2 以上」と言える。 尖度はもっと幅広く [0.05, 11.85]、 つまり「裾は厚めだが、 どれくらい厚いかは標本では正確に分からない」。 n=47 という小標本での形状指標は 「方向は信頼できるが、 桁は信頼できない」 という認識が肝心。
教材として 1 時間使う想定の段取り。 学習者に「数値を出す」より「数値を解釈する」訓練を施す設計。
| 時間 | 活動 | 学習目標 |
|---|---|---|
| 0:00 - 0:10 | CSV 読み込み、 head() / describe() | データの全体像を掴む |
| 0:10 - 0:20 | A1101 のヒストグラム描画 | 右裾の存在を視覚で確認 |
| 0:20 - 0:30 | 歪度・尖度の計算、 値の意味 | 数値と図を対応付ける |
| 0:30 - 0:40 | 対数変換 → 再度ヒストグラム | 変換の効果を体感 |
| 0:40 - 0:50 | 他列 (L3221、 A4103) と比較 | 列ごとに形状が違うことを理解 |
| 0:50 - 1:00 | まとめ表作成、 次アクション選択 | レポート設計を実践 |
このワークショップを 3 回繰り返すと、 学習者は「ヒストグラムを見ると歪度の符号が予想できる」「数値を見ると変換の要否が判断できる」という直感を獲得する。 形状指標は 覚える対象ではなく、 慣れる対象 である。
| 誤解 | 正しい理解 |
|---|---|
| 「尖度は分布の尖り具合」 | 実態は「裾の厚さ」。 中心がいくら尖っても裾が薄ければ尖度は負になる。 |
| 「歪度 0 = 正規分布」 | 対称ならどんな分布でも歪度 0。 一様分布も二峰分布も歪度 0 になり得る。 |
| 「歪度・尖度が小さい = 正規」 | 正規性の必要条件であって十分条件ではない。 Shapiro-Wilk や Q-Q プロットで確認する。 |
| 「対数変換すれば必ず正規」 | 対数変換が効くのは対数正規型のみ。 t 分布や二峰分布には効かない。 |
| 「scipy のデフォルトでよい」 | scipy.stats.kurtosis のデフォルトは Fisher 定義・bias=True。 pandas は bias=False。 ライブラリ間で値が違うので定義の明示が必要。 |
| 「歪度が大きいとモデル精度が下がる」 | 線形モデルは下がるが、 木系モデル (XGBoost 等) は影響を受けにくい。 モデル次第。 |
| 「正規分布から外れたら検定不能」 | 大標本なら中心極限定理で平均の検定は使える。 中央値検定やノンパラ検定もある。 |
この記事を読み終えたら、 自分の手元のデータ (SSDSE-B-2026 や、 任意の業務データ) で ヒストグラム → 歪度・尖度算出 → 対数変換 → 再度形状確認 → レポート表作成、 という 1 時間ワークフローを実践してほしい。 「数値を出す」のではなく「数値で議論する」訓練が、 データサイエンティストとしての地力を作る。
歪度・尖度の概念は Karl Pearson (1857-1936) が 1890 年代に提唱した。 当時の問題意識は「経済データや生物計測データは正規分布に従わない場合が多い」というもので、 Pearson は分布族 (Pearson distribution family) を構築し、 そのパラメータとして歪度 (β₁) と尖度 (β₂) を導入した。 これが現代の skewness / kurtosis の祖型である。
その後 Ronald Fisher (1890-1962) がモーメント法と標準誤差の理論を整備し、 「歪度・尖度の標準誤差は標本サイズに依存する」ことを定量化した。 現代の scipy.stats における Fisher 定義 (超過尖度) はこの伝統を引き継いでいる。 一方 Pearson 定義 (尖度に 3 を足したもの) は教科書によって今も使われており、 ライブラリ間の値の食い違いの原因になっている。
| 年代 | 出来事 | 影響 |
|---|---|---|
| 1895 | K. Pearson が歪度・尖度を定義 | 分布族の特徴付け |
| 1925 | Fisher がモーメント法の標準誤差を確立 | 推定精度の数学化 |
| 1946 | Stevens が尺度水準 (名義/順序/間隔/比率) を分類 | 形状指標の適用範囲が明確化 |
| 1964 | Box & Cox が変換族を提案 | 歪度を消す手法の理論化 |
| 1970s | Tukey が EDA を提唱、 箱ひげ図が普及 | 数値と図の併用が標準化 |
| 1990s | scipy / pandas が形状指標の計算を 1 行で実装 | 実務での普及 |
| 2020s | 機械学習の前処理で形状指標が再注目 | XGBoost 等で必要性の再定義 |
古典的な歪度・尖度は外れ値に弱いため、 現代では以下の代替指標も使われる。
これらの 1 文を覚えておけば、 同僚や上司に 47 都道府県データの形状特性を 30 秒で説明できる。 細部の数式や標準誤差の公式は scipy.stats のドキュメントを引けば良いが、 「東京を 1 点除けば歪度は半減する」「対数を取れば対称」 という具体例は記憶に残しておく価値がある。
形状指標は 「使うと意思決定が速くなる道具」 であって、 「覚えるべき公式」ではない。 47 都道府県データで何度も実演し、 自分の感覚として根付かせるのが学習の王道。
| 正解数 | レベル | 次のアクション |
|---|---|---|
| 11 - 12 | 熟達 | L モーメント・分位回帰など発展手法へ |
| 8 - 10 | 実務可 | 自分のデータで報告書テンプレート Q を実装 |
| 5 - 7 | 理解中 | 深掘り I・II を再読、 SSDSE-B で実演 |
| 0 - 4 | 初学者 | 基本セクション 1-12 を読み直し、 ヒストグラム・平均・中央値 を先に確認 |
形状指標は 1 度の通読では身につかない。 同じ SSDSE-B-2026 で年度を変え、 列を変え、 群を変えて何度も実演するうちに、 ヒストグラムを見ただけで歪度の桁が言えるようになる。 そこまで来れば「形状指標を理解した」と言える。
中心傾向 (平均・中央値) と ばらつき (分散・標準偏差) は、 高校数学で習う「基本中の基本」である。 ところが 形状指標 (歪度・尖度) は教科書ではほとんど触れられず、 大学の統計学講義でも「定義だけ示して終わり」になりがちな扱いを受けている。 これは情報量に対する教育投資のミスマッチで、 現代のデータサイエンス実務では形状指標が以下の場面で必須となる。
SSDSE-B-2026 の 47 都道府県データは、 これら 5 つの場面を すべて 1 つの教材で体験できる 稀有な題材である。 是非自分の手元でコードを動かし、 数値を出し、 図を描き、 同僚に説明してほしい。 形状指標は 使うほど磨かれる感覚 であり、 公式を暗記するだけでは絶対に身につかない。 この記事を読み終えたあなたの次の一歩は、 自分のデータで歪度と尖度を計算することである。
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 28 | 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='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 最新年 (2023) の 47 都道府県 # 各変数の尺度・形状指標 fig, axes = plt.subplots(2, 3, figsize=(14, 8)) vars_to_check = ['A1101', 'A1303', 'L3221', 'L322101', 'A4103', 'L322109'] 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 | 解釈 |
| A1101 総人口 | +2.22 | +4.95 | < 0.001 | 右に長い裾(東京が突出) |
| A1303 65歳以上人口 | +1.78 | +2.46 | < 0.001 | 右裾(大都市に集積) |
| L3221 消費支出 | -0.52 | +0.52 | 0.27 | ほぼ対称 |
| L322101 食料費 | +0.65 | +0.06 | 0.05 | やや右・ほぼ正規 |
| A4103 合計特殊出生率 | -0.04 | -0.44 | 0.94 | 正規に近い |
| L322109 教養娯楽費 | +0.18 | +0.70 | 0.26 | ほぼ対称 |
👉 値は SSDSE-B-2026(2023 年・47 都道府県)の実測値。 同じ手順で他年度・他変数にも適用可能。
SSDSE-B-2026 風の右に長い分布(人口 1 千人未満の小規模自治体多数 + 東京・神奈川など極端値)を模した 10 件 x=[1,2,2,3,3,3,4,4,5,10] で歪度・尖度を計算する。
1 2 3 4 5 | import numpy as np from scipy import stats x = np.array([1, 2, 2, 3, 3, 3, 4, 4, 5, 10]) print(f"歪度: {stats.skew(x):.3f}") print(f"尖度: {stats.kurtosis(x):.3f}") |
💬 手計算 (Step 2) と Python 出力が完全一致。
| 用途 | 関数 |
|---|---|
| 歪度 | pandas .skew(), scipy.stats.skew |
| 尖度(超過) | pandas .kurtosis(), scipy.stats.kurtosis |
| Shapiro–Wilk | scipy.stats.shapiro |
| Jarque–Bera | scipy.stats.jarque_bera |
| D'Agostino | scipy.stats.normaltest |
| K-S | scipy.stats.kstest |
| Anderson–Darling | scipy.stats.anderson |
| QQプロット | statsmodels.api.qqplot, scipy.stats.probplot |
| Box-Cox | scipy.stats.boxcox |
| Yeo-Johnson | sklearn.preprocessing.PowerTransformer |
金融工学では「co-skewness」「co-kurtosis」など多変量への拡張が研究されています。 ただし高次モーメントは標本誤差が大きく、 実務では 3 次・4 次までが標準。
順序統計量に基づくモーメント。 通常のモーメントより外れ値に頑健。 水文学・気象統計でよく使われる。
$$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$ は有界。
$$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 が存在しない分布でも常に存在し、 分布を一意に決める。
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['A1101'].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) |
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['A1101'].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}') |
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['A1101'].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) |
| ライブラリ / 関数 | 用途 |
|---|---|
scipy.stats.skew, kurtosis | 歪度・尖度 |
scipy.stats.shapiro, kstest, jarque_bera | 正規性検定 |
scipy.stats.probplot | Q-Q プロット |
scipy.stats.boxcox, yeojohnson | 分布変換 |
statsmodels.graphics.gofplots.qqplot | Q-Q(より柔軟) |
このコードでやること: SSDSE-B-2026 の主要数値列について、 歪度・尖度・正規性検定 (D'Agostino) を一括計算し、 推奨される変換 (log, sqrt, Box-Cox) を提案する。
📥 入力例: 2023 年 47 都道府県 × A1101, A110101, A110102 (人口、 男性人口、 女性人口)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import pandas as pd, numpy as np from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) latest = df[df['SSDSE-B-2026'] == 2023] cols = ['A1101', 'A110101', 'A110102'] for c in cols: x = latest[c].values sk = stats.skew(x) kt = stats.kurtosis(x) stat, p = stats.normaltest(x) suggest = '対数変換を検討' if sk > 1 else 'そのままで OK' print(f'{c}: skew={sk:.2f} kurt={kt:.2f} p_normal={p:.2e} → {suggest}') |
📤 実行結果:
💬 男性・女性人口とも総人口と同じ右裾の歪み。 性比 (男/女) を計算すれば 0.94 前後にほぼ集中するため形状が変わる。 同じ「人口」系列でも、 比を取ると尺度水準と形状の両方が変わる典型例。
| 形状 | 特徴 | 代表分布 | SSDSE での例 |
|---|---|---|---|
| 釣鐘型 (対称) | 中心が高く左右対称 | 正規、 t | log(人口) のヒスト |
| 右裾長 (skew>0) | 少数の大きな値 | 対数正規、 ガンマ、 パレート | 人口、 所得、 GDP |
| 左裾長 (skew<0) | 天井近くに集中 | ベータ (a>b) | 出席率、 投票率 |
| 二峰 (bimodal) | 2 つの山 | 混合正規 | 都市圏 vs 地方の分布 |
| 一様 | 範囲内ほぼ平坦 | 一様分布 | 擬似乱数、 順位データ |
形状が複雑な場合 (二峰、 重い裾) は要約統計量の解釈に注意。 平均と中央値の差が大きいなら歪み、 IQR と SD の比が経験則 (約 1.35) から外れるなら重い裾を疑う。
降格は自由 (情報を捨てる)、 昇格は不可 (情報を作り出せない)。 「名義データを平均すれば間隔風になる」は錯覚。
| 落とし穴 | 対処 |
|---|---|
| 尖度の定義違い | 「超過尖度」か「生尖度」を明示。 pandas/scipy は超過尖度。 |
| 小標本の歪度・尖度 | n < 20 では推定が不安定。 ブートストラップ CI を付ける。 |
| 外れ値の影響 | 高次モーメントは外れ値に超敏感。 ロバスト指標(MAD等)も併用。 |
| 「p > 0.05 で正規」と決定 | 「棄却できない」は「正規である」ではない。 QQ プロット併用。 |
| 大標本での過検出 | n が大きいと僅かな逸脱でも有意に。 効果量を見る。 |
| 対数変換時の 0 値 | log1p(x) または log(x + c)。 |
| Box-Cox を負値に適用 | Yeo-Johnson に切り替える。 |
1 2 3 4 5 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) num = df.select_dtypes(include='number') sk = num.skew().sort_values(ascending=False) print(sk.head(10)) |
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['A1101'].hist(ax=axes[0,0], bins=20); axes[0,0].set_title(f'生 skew={df["A1101"].skew():.2f}') np.log1p(df['A1101']).hist(ax=axes[0,1], bins=20); axes[0,1].set_title(f'log skew={np.log1p(df["A1101"]).skew():.2f}') sm.qqplot(df['A1101'], line='s', ax=axes[1,0]) sm.qqplot(np.log1p(df['A1101']), line='s', ax=axes[1,1]) plt.tight_layout(); plt.show() |
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}') |
「総人口は歪んでいたので log を取りました。」
「総人口 (A1101) は強い右歪み(歪度 = 2.22, 超過尖度 = 4.95、 Shapiro–Wilk p < .001、 QQ プロットも著しく逸脱)を示したため、 対数変換を適用。 変換後は歪度 0.79、 超過尖度 -0.21、 D'Agostino 検定も棄却されず(p = 0.07)。 以降の解析は変換後の値で実施。」
このコードでやること: A1101 (総人口) の歪度を 2014 〜 2023 年で並べ、 形状の経年変化を確認する。
📥 入力例: 564 行 (47 県 × 12 年)
1 2 3 4 5 6 7 | import pandas as pd from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) for y in sorted(df['SSDSE-B-2026'].unique()): sub = df[df['SSDSE-B-2026'] == y]['A1101'] print(f'{y}: n={len(sub)} skew={stats.skew(sub):.3f} kurt={stats.kurtosis(sub):.3f}') |
📤 実行結果 (一部):
💬 歪度・尖度ともわずかに上昇 → 東京一極集中が進行し、 裾がより重くなっている。 形状指標は政策評価の客観的指標としても使える。
| 形状診断 | 推奨される 2 群比較 | 推奨される相関 |
|---|---|---|
| 正規 + 等分散 | Student t (ttest_ind) | Pearson |
| 正規 + 不等分散 | Welch t (equal_var=False) | Pearson |
| 非正規 (歪み中) | log 変換 → t | log 変換 → Pearson |
| 非正規 (強い歪み・外れ値) | Mann-Whitney U | Spearman, Kendall |
| 順序尺度 | Wilcoxon 順位和 | Spearman, Kendall |
| 名義尺度 | カイ二乗、 Fisher 正確検定 | クラメル V、 ファイ係数 |
正規性の判定は「サンプルサイズ依存」。 n=20 で「正規」と出ても n=2000 で「非正規」と出るのは検定の性質上当然。 ヒストグラム + Q-Q プロット + 効果量の総合判断が大切。
歪度・尖度の値から「どの分布族に近いか」を推測する目安:
| 歪度 | 超過尖度 | 候補分布 | 対処 |
|---|---|---|---|
| ≈ 0 | ≈ 0 | 正規 | そのまま解析可 |
| ≈ 0 | 負 | 一様・ベータ(2,2) | そのまま or ベータフィット |
| ≈ 0 | 正 | t分布・混合正規 | 頑健統計、 ノンパラ |
| 1〜2 | 3〜6 | 対数正規・ガンマ | log 変換 |
| > 2 | > 6 | パレート・指数 | log 変換、 Box-Cox |
| 負 | 正 | 天井効果データ | 反転後 log、 順位ベース |
分布のパラメータを「標本モーメント=理論モーメント」で推定する古典的手法。
MLE より計算簡便だが、 一般に効率が悪い(漸近分散が大きい)。
「位置・尺度・形状」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。
同じ平均でも分布の形が違えば 意味のある比較 はできない。 位置・尺度・形状の 3 視点で分布を立体的に捉えることが、 統計的判断の基本姿勢である。
「分布の形状指標」を扱う際の手法選択は、 状況に応じて以下のフローで判断すると迷いが減る。
このフローに沿って判断することで、 「分布の形状指標」を中核とした適切な手法選択ができる。
分布は 位置(平均 μ)・尺度(標準偏差 σ)・形状(歪度 γ₁・超過尖度 γ₂) の 3 要素で特徴づけられます。 スライダーを動かすと曲線がリアルタイムに変化します。 平均を変えると左右へ平行移動、 標準偏差を変えると幅が伸縮、 歪度を変えると左右非対称に、 尖度を変えると頂の尖り・裾の重さが変わります。 灰色の破線は「同じ平均・同じ標準偏差の正規分布」。 青い曲線と重ねることで、 平均と SD が同じでも形が全く違うことを体感できます。(曲線グラフ上を左右にドラッグ/スワイプしても平均を動かせます)
曲線は Gram–Charlier A 級数(正規分布を歪度・尖度で補正した密度)。 この密度は平均・分散・歪度・超過尖度がスライダー値に 厳密に一致 します。 極端な形状では密度が負に触れることがあり、その領域は 0 に丸めて表示しています(近似の限界)。
1 つの分布を言い当てるには、 まず どこにあるか(位置)、 次に どれだけ広がるか(尺度)、 最後に どんな形か(形状) の順に見ます。 平均は分布を左右に平行移動させるだけで形を変えません。 標準偏差は横に引き伸ばす/縮めるだけで対称性は保ちます。 歪度と尖度こそが「形」そのもの——左右非対称か、 中央が尖って裾が重いか——を決めます。
上の「正規分布」「右に歪む」「尖って厚裾」プリセットは いずれも平均 μ=0・標準偏差 σ=1.6 で共通ですが、 見た目は全く違います。 平均と標準偏差(=1・2 次モーメント)が一致しても、 3 次(歪度)・4 次(尖度)が違えば分布は別物です。 「平均 ± SD で 68%」のような正規分布前提の目安は、 右歪みや厚裾の分布では大きく外れます。 要約統計量を報告するときは ヒストグラム や 箱ひげ図・Q-Q プロット で形も併せて確認しましょう。
位置・尺度・形状は モーメントの階層に対応します。 1 次(平均)=位置、 2 次(分散/標準偏差)=尺度、 3 次(歪度)と 4 次(超過尖度)=形状。 標準化した分布(μ=0, σ=1)を残しても、 高次モーメントが分布を区別します。 実務では 「位置・尺度パラメータ」を持つ分布族(正規・t・ロジスティックなど)を選び、 形状は分布族そのもの(正規・対数正規・指数・t 分布…)で表現します。 上のデモの Gram–Charlier 展開は、 正規分布に歪度・尖度の項を足して「形をずらす」直感を与える古典的手法で、 正規性検定 の Jarque–Bera 統計量(歪度²+尖度²で正規からのズレを測る)とも発想を共有します。
本ページ本文(モーメント・歪度・尖度・A〜S の深掘り)とは重複しない角度として、ここでは (1) 数式ライブラリを使わずに歪みの向きを当てる実務ワザ と (2) 尖度が「たった 1 点」でどれほど崩れるかを、SSDSE-B-2026(2023 年・47 都道府県)の実測値だけで示す。合成データは一切使っていない。
歪度の厳密値(Fisher の $g_1$)は 3 乗のモーメントが必要で暗算できないが、符号(右裾か左裾か)だけなら中学生でも出せる。ピアソンの第 2 歪度係数 $\;\mathrm{Sk}_2 = \dfrac{\text{平均}-\text{中央値}}{\text{標準偏差}}\;$ を使えばよい。平均が中央値より大きければ右裾(正)、小さければ左裾(負)。SSDSE-B-2026 の実測 5 列で照合すると、符号は 5 列すべてで Fisher 歪度と一致した(下表は実際に pandas+scipy.stats.skew(bias=False) で出力した数値)。
| 列コード / 内容 | $\mathrm{Sk}_2=\frac{平均-中央値}{標準偏差}$ | Fisher 歪度 $g_1$ | 符号一致 |
|---|---|---|---|
| A1101 総人口 | +0.392 | +2.293 | ✅ |
| A5101 転入者数(日本人移動者) | +0.336 | +3.515 | ✅ |
| A1303 65 歳以上人口 | +0.356 | +1.842 | ✅ |
| B4102 最高気温(月平均の最高値) | −0.096 | −0.572 | ✅ |
| L3221 消費支出(二人以上世帯) | −0.199 | −0.537 | ✅ |
$\mathrm{Sk}_2$ は $[-3,+3]$ に収まる(ピアソン不等式)ため、絶対値は Fisher 歪度より圧縮されて出る。だが「向きを瞬時に掴む」目的には十分で、平均 と 中央値 を並べただけの表からでも歪みの向きが読める、という設計上の示唆になる。
本文 J 章でも「外れ値 1 点で動く」と触れているが、ここではその大きさを実数で確定させる。A1101 総人口から東京都(14,086,000 人)ただ 1 件を除くと(n=47→46)、実測値は次のように動く。
| 指標 | 全 47 件 | 東京都を除く 46 件 | 変化 |
|---|---|---|---|
| Fisher 歪度 $g_1$ | +2.293 | +1.820 | −21% |
| 超過尖度 $g_2$ | +5.661 | +2.404 | −58% |
| 平均 | 2,645,809 | 2,397,109 | −9.4% |
| 中央値 | 1,549,000 | 1,508,500 | −2.6% |
尖度は 47 分の 1 のデータを消しただけでほぼ半減した。これは偶然ではなく、歪度・尖度が定義上「破綻点(breakdown point)ゼロ」——たった 1 点の暴走で任意の値へ飛ぶ——だからだ。4 乗のモーメントを含む尖度は特に敏感で、最大値がずば抜けているほど 1 点支配になる。対照的に中央値の変化はわずか −2.6%。ここに、点推定の歪度・尖度を単独で報告してはいけない理由がある。必ず「外れ値を除いた感度分析」か ロバスト統計(中央値・IQR・MAD)を併記し、箱ひげ図 で 1 点支配の構造を可視化すること。
⚠️ さらに危険なのは符号が逆転しうるケース。上の例は元々右裾が強いので除去後も正のままだが、|歪度| が小さい列(本文の L322104 ≈ +0.01 など)では 1 点の増減で符号すら反転し、「右歪み」と「左歪み」を取り違える。|歪度|<0.3 の列で歪度の向きを断言するのは避けるのが安全側の運用。
モーメント型が脆いなら、分位点ベースの形状指標に置き換える手がある。ボウリー歪度(四分位歪度) $\;\dfrac{(Q_3-Q_2)-(Q_2-Q_1)}{Q_3-Q_1}\;$ は 四分位 だけで作れて破綻点 25% と頑健、範囲も $[-1,+1]$ に収まり解釈しやすい。裾の重さは「上位 1% と中央値の比」のような分位点比で測れば、4 乗モーメントの暴走を回避できる。実務フローとしては——(1) まず $\mathrm{Sk}_2$ で向きを掴む → (2) モーメント歪度・尖度で強さを測る → (3) 外れ値除去で感度を確認 → (4) 結論が 1 点で変わるならボウリー歪度や 中央値 報告に切り替える、という 4 段が破綻点ゼロの罠を回避する定石になる。標準化(z 化)は中心と尺度を揃えるだけで形状は変えない点に注意(歪みを直したいなら対数・平方根・Box-Cox)。
※ 本セクションの数値は pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) で読み、df[df['SSDSE-B-2026']==2023] の 47 都道府県に対し scipy.stats.skew / kurtosis (bias=False) を実行して得た実測値。合成・架空データは含まない。