散らばり(dispersion)に関連する用語を、 計算量・スケール・代表値との関係 別に整理しました。
| カテゴリ | キーワード(日本語) | キーワード(英語) |
|---|---|---|
| 基本量 | 分散、 標準偏差、 範囲、 四分位範囲、 平均絶対偏差 | variance, standard deviation, range, IQR, MAD |
| 無次元化指標 | 変動係数、 ジニ係数、 エントロピー | CV, Gini coefficient, entropy |
| 理論基盤 | 期待値、 モーメント、 自由度、 不偏推定量 | expectation, moment, degrees of freedom, unbiased |
| 関連手法 | 分散分析、 F検定、 主成分分析、 共分散行列 | ANOVA, F-test, PCA, covariance matrix |
| 外れ値耐性 | ロバスト、 中央絶対偏差、 トリム平均 | robust, MAD (median absolute deviation), trimmed mean |
| 実装関数 | np.var、 np.std、 pd.Series.var、 scipy.stats.iqr、 statsmodels | numpy.var, ddof, pandas describe, scipy.stats.iqr |
論文記事から各用語のリンクをクリックすると、 該当箇所が開きます:
🍰 まずはやさしく
データの散らばり具合のことです。
データの個性を数字で表すために使います。
テストの点数の差などを測る時に便利です。
ここでは5つの指標について学びます。
| 指標 | 記号 | 式 | 単位 | 外れ値耐性 |
|---|---|---|---|---|
| 分散 | $\sigma^2$ | $\frac{1}{n}\sum(x_i-\bar{x})^2$ | 元の単位² | ❌ 弱い |
| 標準偏差 | $\sigma$ | $\sqrt{\sigma^2}$ | 元の単位 | ❌ 弱い |
| 共分散 | $\sigma_{xy}$ | $\frac{1}{n}\sum(x_i-\bar{x})(y_i-\bar{y})$ | X単位×Y単位 | ❌ 弱い |
| 範囲 | R | max - min | 元の単位 | ❌❌ 最弱 |
| MAD | MAD | $\mathrm{median}(|x_i - \tilde{x}|)$ | 元の単位 | ✅ 強い |
🍰 まずはやさしく
データの広がりを示す道具です。
平均だけでは分からない特徴を知るために使います。
部活の記録がどれくらいバラバラかを見ます。
中心からどれだけ離れているかを読みましょう。
論文や記事中に 「分散」「標準偏差」「共分散」「MAD」「範囲」 として登場する用語群です。 代表値(平均・中央値)が「中心の位置」を示すのに対し、 ばらつき指標は「そこからどれだけ散らばっているか」を示します。
代表値とばらつきはセットで初めて分布を要約できます(例:平均 $\bar{x}$ ± 標準偏差 $s$)。
🍰 まずはやさしく
予測がどれくらいズレるかという幅です。
平均で代表した時の誤差を知るために使います。
スマホの利用時間の個人差を考える時に役立ちます。
ズレ幅を数値にする方法について読みましょう。
散らばり(dispersion)は、 「平均値で代表したときに、 個々のデータがどれだけ外れるか」という予測誤差の典型サイズと理解すると応用が効く。 例: 47 都道府県の人口の平均は 270 万人だが、 個別の県を予測すると最大 1100 万人以上外れる。 「平均だけで代表する」のがどれだけ大胆な簡略化かを散らばりは数値化してくれる。
比喩で言えば、 平均は「クラスの代表点」、 散らばりは「個性の幅」。 平均だけ語ると「全員同じ」のように見えるが、 SD・IQR を添えると初めて「多様性」が定量化される。
🍰 まずはやさしく
散らばり具合を計算する基本の数字です。
重心からどれだけ離れているかを測るために使います。
買い物で使う金額のバラつきを計算する時に使えます。
分散の計算方法と仕組みについて読みましょう。
分散は、 データの散らばり具合を1つの数字で表す最も基本的な指標。 各データから平均までの距離(偏差)の2乗を平均したもの。 平均が「重心」だったのに対し、 分散は「重心からどれだけ離れているか」を測ります。
母分散の定義は
$$ \sigma^2 = \mathbb{E}[(X - \mu)^2] = \frac{1}{N} \sum_{i=1}^{N} (x_i - \mu)^2 $$
記号:$\sigma^2$ は「シグマの二乗」(母分散)、 $\mu$ は「ミュー」(母平均)、 $\mathbb{E}[\cdot]$ は「期待値」、 $(x_i - \mu)^2$ は「偏差の2乗」。
偏差 $(x_i - \mu)$ を素朴に足すと、 正の偏差と負の偏差が打ち消し合って必ずゼロになります(これが「平均は重心」の意味)。 2乗すれば全て非負になり「散らばりの大きさ」を測れます。
| 都道府県 | $x_i$ | $x_i - \bar{x}$ | $(x_i - \bar{x})^2$ |
|---|---|---|---|
| 青森県 | 77.899 | -2.925 | 8.5556 |
| 岩手県 | 81.997 | +1.173 | 1.3759 |
| 宮城県 | 83.835 | +3.011 | 9.0661 |
| 秋田県 | 78.124 | -2.700 | 7.2900 |
| 山形県 | 84.105 | +3.281 | 10.7650 |
| 福島県 | 78.984 | -1.840 | 3.3856 |
| 合計 | ≈ 0 | 40.4382 |
平均 $\bar{x} = 80.824$、 $n = 6$。 標本分散(÷n)= $40.4382/6 = \mathbf{6.7397}$ (千円²)、 不偏分散(÷(n-1))= $40.4382/5 = \mathbf{8.0876}$ (千円²)。
「÷n」だと標本分散は母分散を過小評価します($\mathbb{E}[s_n^2] = \frac{n-1}{n}\sigma^2$)。 そこで $\frac{n}{n-1}$ を掛けて補正したものが不偏分散:
$$ s^2 = \frac{1}{n - 1} \sum_{i=1}^{n} (x_i - \bar{x})^2 $$
直感的説明:n 個のデータから $\bar{x}$ を計算した時点で、 偏差の合計がゼロになるという「1つの制約」が生じる。 残りの自由な情報は n − 1 個 → これが自由度。
$\boldsymbol{x} \in \mathbb{R}^n$ について、 中心化ベクトル $\tilde{\boldsymbol{x}} = \boldsymbol{x} - \bar{x}\mathbf{1}$ を使うと:
$$ s_n^2 = \frac{1}{n} \|\tilde{\boldsymbol{x}}\|^2 = \frac{1}{n} \tilde{\boldsymbol{x}}^\top \tilde{\boldsymbol{x}} $$
「中心化ベクトルのノルムの2乗 ÷ n」。 標準偏差はそのノルムを $\sqrt{n}$ で割ったもの。 多次元行列 $X \in \mathbb{R}^{n \times d}$ なら列ごとの分散ベクトル $\boldsymbol{s}^2 \in \mathbb{R}^d$、 これが共分散行列の対角成分に。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import numpy as np import pandas as pd x = np.array([77.899, 81.997, 83.835, 78.124, 84.105, 78.984]) # 標本分散(÷n)と不偏分散(÷(n-1)) print(np.var(x)) # 標本分散 (NumPy デフォルト) print(np.var(x, ddof=1)) # 不偏分散 # Pandas(÷(n-1) がデフォルト) s = pd.Series(x) print(s.var()) # 不偏 print(s.var(ddof=0)) # 標本 # 行列の列ごと分散 X = np.array([[1, 10], [3, 30], [5, 50], [7, 70], [9, 90]]) print(np.var(X, axis=0, ddof=1)) # [10.0, 1000.0] # ベクトル表記での確認 mean = x.mean() print(np.linalg.norm(x - mean) ** 2 / len(x)) # 標本分散と一致 |
標準偏差は分散の平方根。 分散は単位が「元の単位の2乗」(食料費なら千円²)で解釈しにくいので、 平方根を取って元の単位に戻したものです。
$$ \sigma = \sqrt{\sigma^2} = \sqrt{\frac{1}{N} \sum (x_i - \mu)^2} $$
東北6県の食料費の例では、 標本標準偏差 $s_n = \sqrt{6.7397} ≈ 2.596$ 千円、 不偏標準偏差 $s = \sqrt{8.0876} ≈ 2.844$ 千円。 「東北6県の食料費は平均 80.8 千円から平均的に ±2.8 千円ずれる」と解釈できます。
データが正規分布に従うとき、 標準偏差で「データが含まれる範囲」を予測できます:
これは「品質管理」「異常検知」「信頼区間」の基礎。 シックスシグマ品質管理の $\pm 6\sigma$ は 99.9999998% カバレッジを意味します。
異なる単位の変数を比較するには、 「平均からのズレを標準偏差で割る」標準化:
$$ z = \frac{x - \mu}{\sigma} $$
$z$ は無次元で「平均から何標準偏差離れているか」。 偏差値はこれを変形した $T = 50 + 10z$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import numpy as np from sklearn.preprocessing import StandardScaler x = np.array([77.899, 81.997, 83.835, 78.124, 84.105, 78.984]) print(np.std(x)) # 標本SD: 2.60 print(np.std(x, ddof=1)) # 不偏SD: 2.84 # z-score 標準化 z = (x - x.mean()) / x.std(ddof=1) print(z) # 平均 0, SD 1 # sklearn の StandardScaler(機械学習で多用) X = np.array([[1, 10], [3, 30], [5, 50]]) scaler = StandardScaler() X_scaled = scaler.fit_transform(X) print(X_scaled.mean(axis=0)) # ≈ 0 print(X_scaled.std(axis=0)) # ≈ 1 |
共分散は「2つの変数が一緒に動くか」を測る指標。 分散の2変数版とも言えます。 平均からの偏差を 2変数で掛け合わせたものの平均。
$$ \sigma_{xy} = \mathbb{E}[(X - \mu_X)(Y - \mu_Y)] = \frac{1}{N} \sum (x_i - \mu_X)(y_i - \mu_Y) $$
散布図上で平均 $(\bar{x}, \bar{y})$ を原点として4象限に分けると:
これらを全部足して n で割ると共分散。 第1・第3象限に多ければ正の共分散、 第2・第4 に多ければ負。
| 都道府県 | 食料費 $x$ | 教育費 $y$ | $x - \bar{x}$ | $y - \bar{y}$ | $(x-\bar{x})(y-\bar{y})$ |
|---|---|---|---|---|---|
| 青森県 | 77.90 | 6.71 | -2.925 | -1.021 | +2.9864 |
| 岩手県 | 82.00 | 6.75 | +1.173 | -0.986 | -1.1566 |
| 宮城県 | 83.83 | 11.24 | +3.011 | +3.511 | +10.5716 |
| 秋田県 | 78.12 | 4.32 | -2.700 | -3.418 | +9.2286 |
| 山形県 | 84.11 | 7.27 | +3.281 | -0.467 | -1.5322 |
| 福島県 | 78.98 | 10.12 | -1.840 | +2.381 | -4.3810 |
| 合計 | +15.7168 | ||||
不偏共分散 $s_{xy} = 15.7168 / (6 - 1) = \mathbf{3.1434}$。 正の値なので「食料費が高い県は教育費も高い」傾向。
2つの中心化ベクトル $\tilde{\boldsymbol{x}}, \tilde{\boldsymbol{y}}$ について:
$$ s_{xy} = \frac{1}{n-1} \tilde{\boldsymbol{x}}^\top \tilde{\boldsymbol{y}} $$
$d$ 変数のデータ行列 $X \in \mathbb{R}^{n \times d}$ について、 中心化行列 $\tilde{X}$ から共分散行列:
$$ \Sigma = \frac{1}{n-1} \tilde{X}^\top \tilde{X} \in \mathbb{R}^{d \times d} $$
$d \times d$ の対称・半正定値行列。 対角は各変数の分散、 非対角がペアの共分散。 これを固有値分解すればPCA になります。
共分散は単位に依存するため、 大小比較が困難です。 同じデータでも単位を変えれば共分散が変わってしまいます:
これを解消するため、 標準偏差で正規化したのが 相関係数:$r = \sigma_{xy} / (\sigma_x \sigma_y)$。 $r \in [-1, +1]$ で単位フリー。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import numpy as np import pandas as pd x = np.array([77.899, 81.997, 83.835, 78.124, 84.105, 78.984]) y = np.array([6.713, 6.748, 11.245, 4.316, 7.267, 10.115]) # NumPy の cov(デフォルトは不偏、 ddof=1) print(np.cov(x, y)) # 2x2 共分散行列 print(np.cov(x, y)[0, 1]) # x と y の共分散 # Pandas df = pd.DataFrame({'x': x, 'y': y}) print(df.cov()) print(df['x'].cov(df['y'])) # 多変数の共分散行列 X = np.random.randn(100, 5) Sigma = np.cov(X, rowvar=False) print(Sigma.shape) # (5, 5) diag = np.diag(Sigma) # 各列の分散 |
範囲は最も単純なばらつき指標:$\mathrm{Range} = \max(x) - \min(x)$。 「データの広がる幅」。
長所:計算が極めて簡単、 直感的。
短所:外れ値に最も弱い(1点で値が変わる)、 中央のデータ分布の情報を失う。
実務では「最低・最高」を併記して提示するか、 四分位範囲(IQR)に置き換えることが多い。
標準偏差は平均と分散をベースとするため外れ値に弱い。 そのロバスト版がMAD(Median Absolute Deviation):
$$ \mathrm{MAD} = \mathrm{median}(|x_i - \mathrm{median}(x)|) $$
「中央値からの絶対距離の中央値」。 平均と標準偏差が外れ値で歪むのに対し、 MAD は50% 崩壊点(半分のデータが壊れても影響なし)。
正規分布の場合、 $\sigma \approx 1.4826 \times \mathrm{MAD}$。 つまり MAD を 1.4826 倍すれば「ロバストな標準偏差」になります。
1 2 3 4 5 6 7 8 9 | from scipy import stats import numpy as np # 外れ値を含むデータ data = np.array([1, 2, 3, 4, 5, 6, 7, 100]) print(np.std(data, ddof=1)) # 33.8(外れ値で歪む) print(stats.median_abs_deviation(data)) # 2.5(ロバスト) print(stats.median_abs_deviation(data, scale='normal')) # 3.7(正規分布換算) |
散らばり(dispersion)を測る指標は 分散・標準偏差・範囲・四分位範囲(IQR)・平均絶対偏差(MAD)・変動係数(CV)の 6 つが代表的。 それぞれが「どの中心からどう距離を測るか」という設計思想で分かれる。 ここではすべての数式を一覧し、 各記号がどんな意味を持つかを徹底的に読み解く。
標本分散は次のように定義される(不偏分散、 分母 \(n-1\))。
$$ s^2 = \frac{1}{n-1} \sum_{i=1}^{n} (x_i - \bar{x})^2 $$つまり「中心からのズレを 2 乗してから平均する。 ただし平均値を標本から推定したぶんの誤差を補正する」というのが標本分散の意味。
分散の平方根を取るだけだが、 これにより単位が元データと同じになるのが決定的に重要。 人口(人)の分散の単位は「人²」だが、 SD の単位は「人」。 グラフの目盛りや日常的な感覚と直接比較できる。 \(\bar{x} \pm s\) の範囲に正規分布なら約 68% のデータが入る、 という直感的な解釈もここから生まれる。
外れ値が両端 25% に隠れるので、 IQR は外れ値の影響をほぼ受けない。 箱ひげ図の「箱」の長さがまさにこれ。
平均ではなく中央値を中心に取り、 偏差の絶対値を取って、 さらにその中央値を取る。 平均・分散は外れ値 1 個で大きく動くが、 MAD は半分以上のデータが入れ替わらない限り動かない、 という極めて頑健な指標。 正規分布のとき \(1.4826 \times \mathrm{MAD} \approx \sigma\) という換算が成り立つので、 ロバスト統計では SD の代用として使われる。
SD を平均で割ることで無次元化される。 単位が異なる変数間(例: 人口と面積)や、 桁が大きく違うデータ間で「相対的なばらつきの大きさ」を比較するときに使う。 平均が 0 近くだと不安定になるので、 比率や正の量で使うのが定石。
ここまでに紹介した 分散・標準偏差・範囲・IQR・MAD・変動係数 を、 同じデータ(SSDSE-B-2026 の都道府県 総人口、 2023 年、 N=47)に対して一気に計算し、 値の意味を読み比べる。
すべて生データから直接計算しているので、 自分の手元で再現したときも数値は一致する。 数字が動くタイミング(外れ値の有無、 ddof の選び方、 平均周りか中央値周りか)を体感するのが目的。
47 都道府県のうち、 ばらつきを支配する 上位 5 件と、 ばらつきの底を作る 下位 5 件を抜粋する。 最大値の東京都(14,086,000 人)と最小値の鳥取県(537,000 人)の差はおよそ 26 倍。 この極端な右側の尾が、 後で平均・分散と中央値・MAD の値を大きく食い違わせる原因になる。
このコードでやること: SSDSE-B-2026 を読み込み、 最新年(2023)に絞ってから numpy と pandas で 平均・不偏分散・標準偏差・範囲(range)を計算する。
分散と SD は ddof=1(標本分散・標本標準偏差)を使う。 ddof=0 と 1 でわずかに値が変わる理由は、 後で対比して示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932') latest = df[df['SSDSE-B-2026'] == 2023] x = latest['A1101'].astype(float).values print('N :', len(x)) print('平均 :', round(np.mean(x), 1)) print('不偏分散 :', round(np.var(x, ddof=1), 1)) print('標準偏差 :', round(np.std(x, ddof=1), 1)) print('範囲(max-min):', x.max() - x.min()) print('最大 :', x.max(), '最小:', x.min()) |
📤 実行すると次の出力が得られる:
💬 平均 約 265 万人に対して SD が 約 280 万人と、 SD のほうが平均より大きい。 これは右側に巨大な外れ値(東京)が引っ張っているサイン。 範囲 1354.9 万人は「最大の都道府県と最小の都道府県の差」そのもの。 範囲は 1 つの巨大値だけで決まるので、 散らばりの代表値には向かない。
このコードでやること: 同じデータで 中央値・第 1 四分位・第 3 四分位・IQR・MAD を計算する。 平均・分散と違い、 これらは外れ値の影響を受けにくい(ロバスト統計)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932') latest = df[df['SSDSE-B-2026'] == 2023] x = latest['A1101'].astype(float).values med = np.median(x) q1 = np.percentile(x, 25) q3 = np.percentile(x, 75) iqr = q3 - q1 mad = np.median(np.abs(x - med)) print('中央値 :', med) print('Q1 :', q1) print('Q3 :', q3) print('IQR(Q3-Q1):', iqr) print('MAD :', mad) print('1.4826*MAD :', round(1.4826 * mad, 1), ' ← 正規分布なら SD と一致するはずの値') |
📤 実行すると次の出力が得られる:
💬 中央値 155 万人は平均 265 万人より 110 万人も小さい。 これも分布が右に長く伸びていることを示す。 IQR は 160 万人なので、 「真ん中 50% の都道府県は 103.4 万人〜263.7 万人の間に収まる」と読める。 MAD は 62.3 万人と、 SD(280 万人)の 4 分の 1 以下。 \(1.4826 \times \mathrm{MAD} \approx 92\) 万人と SD(280 万人)が大きく食い違うのは「正規分布から外れている」シグナル。 人口データのように極端な外れ値がある場合は、 SD ではなく IQR や MAD で散らばりを語るほうが、 実態に合う説明になりやすい。
このコードでやること: 変動係数 \(\mathrm{CV} = s/\bar{x}\) を「全 47 都道府県」と「東京都を除く 46 都道府県」で計算し、 1 件の外れ値がばらつきの相対指標をどれだけ動かすかを確認する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932') latest = df[df['SSDSE-B-2026'] == 2023] x_all = latest['A1101'].astype(float).values x_noTokyo = latest[latest['Prefecture'] != '東京都']['A1101'].astype(float).values def stats(x, label): print(f'--- {label} ---') print(f' N : {len(x)}') print(f' 平均 : {np.mean(x):.1f}') print(f' SD : {np.std(x, ddof=1):.1f}') print(f' CV : {np.std(x, ddof=1) / np.mean(x):.4f}') stats(x_all, '全 47 都道府県') stats(x_noTokyo, '東京都を除く 46 都道府県') |
📤 実行すると次の出力が得られる:
💬 1 件除いただけで CV は 1.057 → 0.936(12% 減少)。 SD は 280 万 → 224 万人と 20% も縮む。 これは「平均と分散は外れ値 1 個で大きく動く」という座学の主張を、 実データで肌で感じるための実験。 一方、 中央値・IQR・MAD は東京都を抜いても 0〜数% しか変化しない(自分で確かめてみると良い)。
| 指標 | 値 | 直感的な意味 | 外れ値への強さ |
|---|---|---|---|
| 平均 | 2,645,808 | 「散らばりの中心」 | 弱い(外れ値に引っ張られる) |
| 不偏分散 \(s^2\) | 7.83 × 10¹² | 偏差の二乗平均(単位は人²) | 非常に弱い(外れ値の二乗で爆発する) |
| 標準偏差 \(s\) | 2,797,551 | 平均からの「典型的なズレ幅」 | 弱い |
| 範囲(max−min) | 13,549,000 | いちばん広い・狭いの差 | 最弱(1 点だけで決まる) |
| IQR | 1,602,500 | 真ん中 50% が収まる幅 | 強い(外側 25% は無視) |
| MAD | 623,000 | 中央値からの典型的なズレ | 非常に強い(破綻点 50%) |
| 変動係数 CV | 1.057 | SD を平均で割った無次元量 | 弱い(SD と平均、 両方が外れ値に弱い) |
💬 この表のキモは、 同じデータで指標を変えるだけで「散らばり」の大きさが 60 万〜1350 万人と、 桁が変わって見える こと。 ばらつきの値を引用するときは、 必ず「どの指標か」を併記しないと、 読み手は誤解する。 特にレポートで「平均 ± SD」とだけ書くのは、 分布が大きく歪んでいる場合(人口・所得・医療費・売上など)に意味を失いやすい。
手計算と Python・Excel で値がわずかにずれた経験はないだろうか。 原因の 9 割は 分母の取り方 である。 分散の式には大きく 2 種類ある。
| 名称 | 式 | 分母 | 用途 | Python での書き方 |
|---|---|---|---|---|
| 標本分散(母分散の最尤推定) | \(\frac{1}{n}\sum (x_i - \bar{x})^2\) | n | 記述統計、 機械学習の特徴量スケーリング | np.var(x, ddof=0)(既定) |
| 不偏分散 | \(\frac{1}{n-1}\sum (x_i - \bar{x})^2\) | n − 1 | 統計推測(信頼区間・t 検定など) | np.var(x, ddof=1)、 pandas .var() の既定 |
n が大きいほど両者の差は無視できるほど小さくなる(47 件なら 1/46 vs 1/47 で 2% 弱)。
一方、 n=5 程度では 25% も違うので、 必ず「分母をどちらにしたか」を明示するのがプロの作法。
Excel の VAR.P と VAR.S、 numpy の ddof、 pandas の既定(n−1)が混在するのは、 業務でよく遭遇する罠なので警戒する。
このコードでやること: SSDSE-B-2026 都道府県人口で、 ddof=0 と ddof=1 の分散・SD を並べて表示する。 比 (n−1)/n を計算して両者の比率を可視化する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932') latest = df[df['SSDSE-B-2026'] == 2023] x = latest['A1101'].astype(float).values n = len(x) var0 = np.var(x, ddof=0) var1 = np.var(x, ddof=1) print(f'n : {n}') print(f'var ddof=0 (母分散の最尤推定): {var0:.1f}') print(f'var ddof=1 (不偏分散) : {var1:.1f}') print(f'比 var1/var0 = {var1/var0:.6f} (理論値 n/(n-1) = {n/(n-1):.6f})') print(f'sd ddof=0 : {np.sqrt(var0):.1f}') print(f'sd ddof=1 : {np.sqrt(var1):.1f}') |
📤 実行すると次の出力が得られる:
💬 ddof=0 と ddof=1 の比はぴったり n/(n−1) = 47/46 = 1.0217。 SD では √1.0217 = 1.0108 倍と、 およそ 1% 差。
47 件ではこの差は小さいが、 n=10 では 10/9 = 1.111 倍、 SD でも 5.4% 差になる。
論文・報告書では原則 不偏分散(ddof=1)を使う。 機械学習の StandardScaler(scikit-learn)は ddof=0 なので、 同じデータの SD でも値が違って見える原因になる。
共分散 \(\mathrm{Cov}(X, Y)\) は、 2 変数版の分散だと思って良い。 同じ変数同士の共分散はそのまま分散になる:
$$ \mathrm{Cov}(X, X) = E[(X-\mu_X)^2] = \mathrm{Var}(X) $$また 2 変数 X, Y の和の分散は次の式で表せる:
$$ \mathrm{Var}(X+Y) = \mathrm{Var}(X) + \mathrm{Var}(Y) + 2\,\mathrm{Cov}(X, Y) $$この式は、 ポートフォリオ理論・誤差伝播・線形回帰の予測区間など、 統計の至るところで顔を出す基本公式。 X と Y が無相関(Cov = 0)なら和の分散は単純な足し算になり、 相関が正なら和の分散は単独の和より大きく、 負なら小さくなる。 これが「分散投資」の数学的根拠でもある。
| 指標 | 記号 | 単位 | スケール | 解釈の難しさ |
|---|---|---|---|---|
| 分散 | \(\sigma^2, s^2\) | 元単位の二乗(例: 人²) | 非負・無限大 | 高(直感に乗りにくい) |
| 標準偏差 | \(\sigma, s\) | 元単位(例: 人) | 非負・無限大 | 中 |
| 共分散 | \(\mathrm{Cov}(X,Y)\) | X と Y の単位の積(例: 人 × 円) | 符号付き | 高(値の大小の意味が薄い) |
| 相関係数 | \(r, \rho\) | 無次元 | [−1, 1] | 低(最も解釈しやすい) |
💬 相関係数 \(r = \mathrm{Cov}(X, Y) / (\sigma_X \sigma_Y)\) は、 共分散を X と Y それぞれの SD で割って無次元化したもの。 だから「相関係数の絶対値が共分散より大きく見えても、 共分散のほうが情報量が多い、 という訳ではない」 — むしろ単位とスケールの違いを揃えた結果、 一段抽象度が上がっただけと理解すべき。 詳細は 相関係数 の解説を参照。
現場で「このデータ、 ばらつきが大きい/小さい」と言うとき、 何を基準に判断すれば良いのか。 以下は実務で繰り返し使える判断フローを 7 ステップで整理したもの。
正規分布のとき、 平均から ±1σ 内に約 68%、 ±2σ 内に約 95%、 ±3σ 内に約 99.7% のデータが入る、 という経験則がよく使われる。 しかし、 分布の形を仮定しない場合は Chebyshev の不等式 が頼りになる:
$$ P\!\left(|X - \mu| \geq k\sigma \right) \leq \frac{1}{k^2} $$例えば k=2 なら、 どんな分布でも「平均から 2σ 以上離れた点」の割合は 25% 以下と保証される。 k=3 なら 11.1% 以下、 k=5 なら 4% 以下。 正規分布前提の経験則ほどタイトではないが、 分布形を仮定せずに使える普遍的な上限 として、 異常検知や品質管理の理論的根拠となっている。
分散は単なる「散らばりの量」ではなく、 いくつかの便利な代数的性質を持つ。 これらは推測統計の証明や、 ポートフォリオ理論の最適化計算で繰り返し使われる。
全データに同じ値を足すと、 平均が同じだけ動くので偏差は変わらず、 分散もそのまま。 気温データに「+273.15 で絶対温度に変換」しても、 ばらつきの大きさは同じ。
つまり SD は \(|a|\) 倍に縮む・伸びる。 単位変換(m → cm)で分散は 10,000 倍、 SD は 100 倍になる。 これが「分散を扱うときは単位を明示しないと混乱する」最大の理由。
これにより、 n 個の独立な観測値の 平均の分散は \(\sigma^2/n\) となり、 SE = \(\sigma/\sqrt{n}\) という有名な式が導かれる。 「観測回数を 4 倍にすれば SE は半分になる」というのは、 この加法性と平方根の関係から来ている。
定義式 \(E[(X - \mu)^2]\) を展開すると上記が得られる。 これにより、 数列が「足し算可能」な形で分散を計算できる(オンライン分散計算で重要)。 ただし数値計算では \(E[X^2]\) と \((E[X])^2\) が近い大きさのとき桁落ちが発生しやすい。 大規模データでは Welford のオンラインアルゴリズムを使うのが安全。
ポートフォリオ理論の中核式。 2 資産 X, Y を比率 a, b で持つときのリスク(分散)が、 個別リスクの単純和ではなく 相関に依存することを表す。 Cov が負(逆相関)なら和の分散は小さくなり、 これが「分散投資でリスクが減る」数学的根拠。
| 性質 | 変換 | 変換前 SD | 変換後 SD | 予測通りか |
|---|---|---|---|---|
| 性質 1(平行移動) | x + 1,000,000 | 2,797,551 | 2,797,551 | ○(変化なし) |
| 性質 2(定数倍) | x × 0.001(千人単位) | 2,797,551 | 2,797.55 | ○(0.001 倍) |
| 性質 3(和) | 独立 2 列の合計 | 理論で確認可 | — | ○(実証可) |
| 性質 4(恒等式) | E[X²] − (E[X])² | — | var と一致 | ○ |
| 性質 5(線形結合) | 総人口 + 15歳未満人口 | — | Cov に依存 | ○ |
💬 これら 5 性質は 分散・SD・共分散の代数そのもの。 暗記より、 単純な数式変形で導けることを 1 度自分の手で確かめておくと、 後で出てくる回帰・分散分析・主成分分析の式の中で「ああ、 これは性質 N だ」とすぐに気付ける。 特にデータサイエンスの文脈では性質 5(線形結合の分散)が、 線形回帰の係数推定や、 ベイズ統計の事後分布の分散計算に直結する。
このコードでやること: SSDSE-B-2026 の都道府県 総人口 と 15歳未満人口 という 2 列を取って、 Var(X+Y) と Var(X)+Var(Y)+2 Cov(X,Y) がぴったり一致することを実測で確認する。 「式が本当に成り立っているのか」と疑ったときは、 こうやって自分のデータで再現するのが最速の理解手段。
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 df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932') latest = df[df['SSDSE-B-2026'] == 2023] x = latest['A1101'].astype(float).values y = latest['A1301'].astype(float).values # 列が無ければ別の人口列に置き換える var_x = np.var(x, ddof=1) var_y = np.var(y, ddof=1) cov = np.cov(x, y, ddof=1)[0, 1] lhs = np.var(x + y, ddof=1) rhs = var_x + var_y + 2 * cov print(f'Var(X) = {var_x:.3e}') print(f'Var(Y) = {var_y:.3e}') print(f'Cov(X, Y) = {cov:.3e}') print(f'Var(X+Y) = {lhs:.3e} ← 直接計算') print(f'V(X)+V(Y)+2Cov = {rhs:.3e} ← 性質 5 から計算') print(f'差 = {abs(lhs - rhs):.3e} ← 浮動小数誤差レベルで一致するはず') |
💬 出力された 2 つの分散の差は通常 10^-7 オーダー以下の浮動小数誤差に収まり、 数式が確かに成立していることが確認できる。 こうした「式の手元検証」は、 公式を覚えるよりも遥かに記憶に残るし、 実務で式を逆向きに使うとき(例えば Cov を Var(X+Y) から逆算する)の自信にもなる。
群間で「分散が等しいか」を統計的に検定するのが等分散検定。 t 検定や ANOVA の前提条件「等分散性」が成り立つかをチェックする際に使う。 代表的なのが Levene 検定(ロバスト、 非正規でも使える)と Bartlett 検定(正規分布を仮定、 検出力が高い)の 2 つ。
要は「絶対偏差に対して ANOVA をかける」のが Levene。 ANOVA の枠組みを「ばらつきのばらつき」に応用していると思えばよい。 中央値を中心とする Brown-Forsythe 版がより頑健で、 scipy ではデフォルトで使われる。
このコードでやること: SSDSE-B-2026 の人口を「関東 vs 関西 vs 九州」の 3 群に分け、 scipy.stats.levene と scipy.stats.bartlett で等分散性を検定する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import pandas as pd from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df47 = df[df['SSDSE-B-2026'] == 2023].copy() kanto = ['茨城県','栃木県','群馬県','埼玉県','千葉県','東京都','神奈川県'] kansai = ['滋賀県','京都府','大阪府','兵庫県','奈良県','和歌山県'] kyushu = ['福岡県','佐賀県','長崎県','熊本県','大分県','宮崎県','鹿児島県'] g1 = df47[df47['Prefecture'].isin(kanto)]['A1101'] g2 = df47[df47['Prefecture'].isin(kansai)]['A1101'] g3 = df47[df47['Prefecture'].isin(kyushu)]['A1101'] print(f'関東 SD = {g1.std():,.0f}') print(f'関西 SD = {g2.std():,.0f}') print(f'九州 SD = {g3.std():,.0f}') stat_l, p_l = stats.levene(g1, g2, g3, center='median') stat_b, p_b = stats.bartlett(g1, g2, g3) print(f'Levene W = {stat_l:.3f}, p = {p_l:.4f}') print(f'Bartlett T = {stat_b:.3f}, p = {p_b:.4f}') |
📤 実行例:
💬 結果の読み方: 関東の SD は 449 万人、 九州は 149 万人と 3 倍前後違う。 正規性を仮定する Bartlett は p=0.024 で 5% 有意だが、 中央値ベースでロバストな Levene は p=0.104 で有意とはいえない。 これは「正規性に敏感な Bartlett が分散差を検出する一方、 外れ値・非正規に頑健な Levene は慎重に判断する」という両検定の性格差がそのまま出た例。 分散が等しいと言い切れない以上、 これらの群を ANOVA で比較するなら、 等分散を仮定しない Welch ANOVA が無難。
| 観点 | Levene | Bartlett |
|---|---|---|
| 正規性の仮定 | 不要(中央値中心ならロバスト) | 必要(敏感に違反する) |
| 検出力(正規分布下) | やや低い | 高い |
| 外れ値への頑健性 | 中央値版で高い | 低い |
| サンプルサイズ要件 | 少数でも比較的安定 | 十分大きい標本が必要 |
| 推奨用途 | 非正規・外れ値あり時の標準選択 | 正規性確認済の高検出力検定 |
実務的には Levene(中央値中心、 Brown-Forsythe)を第一選択にし、 正規性が QQ プロット等で確認できているとき Bartlett を補助的に使うのが安全。
分散の点推定だけでなく「信頼区間」を出すと、 推定の不確かさが伝えられて報告の質が上がる。 正規分布を仮定すれば \((n-1)s^2/\sigma^2 \sim \chi^2_{n-1}\) からカイ二乗ベースの CI が出るが、 SSDSE のような小標本・歪んだ分布では bootstrap CI の方が安全。
\((n-1)s^2/\sigma^2\) が自由度 \(n-1\) のカイ二乗分布に従うという事実を反転し、 母分散 \(\sigma^2\) について解いた区間。 正規分布前提に強く依存する。
このコードでやること: SSDSE-B-2026 の人口データから np.random.choice でリサンプリングを 5000 回行い、 SD のパーセンタイル CI を得る。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) pop = df[df['SSDSE-B-2026'] == 2023]['A1101'].values B = 5000 rng = np.random.default_rng() sd_boot = np.empty(B) for i in range(B): resample = rng.choice(pop, size=len(pop), replace=True) sd_boot[i] = resample.std(ddof=1) lo, hi = np.percentile(sd_boot, [2.5, 97.5]) print(f'点推定 SD = {pop.std(ddof=1):,.0f} 人') print(f'95% CI = [{lo:,.0f}, {hi:,.0f}] 人') |
📤 実行例(乱数で変動):
💬 結果の読み方: 点推定 SD は 280 万人だが、 bootstrap 95% CI は 169 万〜374 万と非常に広い。 47 都道府県という小標本かつ右に歪んだ分布のため、 SD の推定は不安定。 「SD は 280 万人」と断言するより「不確かさを含めると 170 万〜370 万の範囲」と報告すべき、 という重要な実務的教訓が出る。
SSDSE-B-2026 から「47都道府県の総人口(万人)」を取り出して、 各種の散らばり指標を計算します。
総人口の最小値:約 53.7(鳥取県)、 最大値:約 1408.6(東京都)、 中央値:約 154.9(単位: 万人)
| 指標 | 値 | 解釈 |
|---|---|---|
| 範囲 (Range) | 1354.9 | 最大と最小の差。 東京と鳥取で約 1355 万人差。 |
| 分散 (Variance, ddof=1) | ≈ 78263 | 単位は「万人²」で直感的に解釈しにくい。 |
| 標準偏差 (SD) | ≈ 280 | 平均からの典型的なズレが 280 万人。 直感的に分かる。 |
| IQR | ≈ 160 | 真ん中50%の幅。 外れ値(東京)の影響を受けない。 |
| 変動係数 CV | ≈ 1.06 | SD / 平均。 単位なし。 他県・他項目との比較が可能。 |
| MAD(中央絶対偏差) | ≈ 62 | 外れ値の影響を最も受けない。 ロバスト統計の基礎。 |
💡 SD と IQR が大きく異なるのは、 東京都が外れ値として SD を引っ張っているためです。 外れ値の影響を避けたい場合は IQR や MAD を使います。
SSDSE-B-2026 の A1101 総人口(人) 列を 47 都道府県すべてで読み込み、 分散・SD・範囲・IQR・MAD・CV を実際に計算する。
全国合計行・年次違いを除外し、 最新年のみを抽出してから計算する点に注意。
data/raw/SSDSE-B-2026.csv の先頭数行は次の構造。 1 行目がメタ、 2 行目がヘッダ、 3 行目以降が実データ。
このコードでやること: SSDSE-B-2026 を読み込み、 47 都道府県の総人口について var(ddof=1) で不偏分散、 std(ddof=1) で SD、 SD/mean で CV を計算する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) # 最新年(2023)の 47 都道府県を抽出 df47 = df[df['SSDSE-B-2026'] == 2023].copy() pop = df47['A1101'] # 総人口 (人) print(f'n = {len(pop)}') print(f'平均 = {pop.mean():,.0f} 人') print(f'分散 = {pop.var(ddof=1):,.0f} 人²') print(f'SD = {pop.std(ddof=1):,.0f} 人') print(f'CV = {pop.std(ddof=1)/pop.mean():.3f}') print(f'範囲 = {pop.max() - pop.min():,} 人') print(f'IQR = {pop.quantile(0.75) - pop.quantile(0.25):,.0f} 人') print(f'MAD = {np.median(abs(pop - pop.median())):,.0f} 人') |
📤 実行例:
💬 結果の読み方: 47 都道府県人口の SD は約 280 万人で平均(約 265 万人)とほぼ同じ。 CV ≈ 1.06 は「平均と同じくらい散らばっている」ことを意味し、 これは東京・神奈川・大阪などのメガ都市が分布を大きく右に歪めているため。 一方 IQR は 160 万人、 MAD は 62 万人と SD よりはるかに小さい。 これは SD が外れ値(東京 1409 万人)に大きく引っ張られているサインで、 ロバスト指標(IQR・MAD)の方が「典型的な県の散らばり」をよく表している。
全 47 県は人手では追えないので、 北海道(509)・宮城(226)・東京(1409)・大阪(876)・福岡(510)の 5 県(単位: 万人)で分散・SD を手計算してみる。
| 県 | 人口 \(x_i\) (万人) | 偏差 \(x_i - \bar{x}\) | 偏差² \((x_i - \bar{x})^2\) |
|---|---|---|---|
| 北海道 | 509 | −197 | 38,809 |
| 宮城 | 226 | −480 | 230,400 |
| 東京 | 1409 | +703 | 494,209 |
| 大阪 | 876 | +170 | 28,900 |
| 福岡 | 510 | −196 | 38,416 |
| 合計 | 3,530 | 0 | 830,734 |
平均 \(\bar{x} = 3530/5 = 706\) 万人。 偏差平方和 = 830,734、 標本分散 \(s^2 = 830734/(5-1) = 207,684\) 万人²、 SD \(s = \sqrt{207684} \approx 456\) 万人。 平均 706 万人に対して SD 456 万人は大きい(CV ≈ 0.65)。 5 県でも東京が大きく分散を押し上げているのが分かる。
合成データ [2,4,7,5,3] で 3 つの散らばり指標を計算する。
1 2 3 4 5 6 | import numpy as np x = np.array([2, 4, 7, 5, 3]) print(f"範囲: {x.max() - x.min()}") print(f"標本分散: {x.var(ddof=1)}") print(f"標本 SD: {x.std(ddof=1):.3f}") print(f"CV: {x.std(ddof=1)/x.mean():.3f}") |
💬 手計算 (Step 1-3) と Python 出力が完全一致。
1 2 3 4 5 6 7 8 9 10 11 | import numpy as np import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) x = df[df['SSDSE-B-2026'] == 2023]['A1101'].to_numpy() print('範囲 :', x.max() - x.min()) print('分散 (ddof=0):', np.var(x, ddof=0)) # 母分散 print('分散 (ddof=1):', np.var(x, ddof=1)) # 標本分散 print('標準偏差(ddof=1):', np.std(x, ddof=1)) print('CV :', np.std(x, ddof=1) / np.mean(x)) |
1 2 3 4 5 6 7 8 9 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) print(df[df['SSDSE-B-2026'] == 2023][['A1101', 'L3221', 'B4101']].describe()) # mean, std, min, 25%, 50%, 75%, max # IQR q1 = df[df['SSDSE-B-2026'] == 2023]['L3221'].quantile(0.25) q3 = df[df['SSDSE-B-2026'] == 2023]['L3221'].quantile(0.75) print('IQR:', q3 - q1) |
1 2 3 4 5 6 7 8 9 10 11 12 | from scipy import stats import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) x = df[df['SSDSE-B-2026'] == 2023]['A1101'] print('IQR :', stats.iqr(x)) print('MAD :', stats.median_abs_deviation(x)) print('歪度 :', stats.skew(x)) print('尖度 :', stats.kurtosis(x)) print('5%トリム平均:', stats.trim_mean(x, 0.05)) print('20%trimVar:', stats.tvar(x, limits=(x.quantile(0.1), x.quantile(0.9)))) |
1 2 3 4 5 6 7 8 9 | import statsmodels.api as sm import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) desc = sm.stats.DescrStatsW(df[df['SSDSE-B-2026'] == 2023]['A1101']) print('mean:', desc.mean) print('std :', desc.std) print('var :', desc.var) print('95% CI:', desc.tconfint_mean()) |
1 2 3 4 5 6 7 8 9 10 | import matplotlib.pyplot as plt import seaborn as sns import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) fig, ax = plt.subplots(1, 2, figsize=(10, 4)) sns.boxplot(y=df[df['SSDSE-B-2026'] == 2023]['A1101'], ax=ax[0]) sns.violinplot(y=df[df['SSDSE-B-2026'] == 2023]['A1101'], ax=ax[1]) plt.tight_layout() plt.show() |
numpy.std はデフォルト ddof=0(母分散の計算)、 pandas.std はデフォルト ddof=1(不偏分散)。 ライブラリを混ぜると同じデータで違う値が出るので、 明示的に ddof=1 を書く。ddof を明示したか正規分布を仮定すると、 ロバスト指標から SD 相当値への換算定数は次のように定まる。 これを覚えておくとレポートで「SD ≒ ◯」と添えやすい。
| 指標 | 換算式 | SSDSE 47 県人口で適用 |
|---|---|---|
| MAD | σ ≈ 1.4826 × MAD | 1.4826 × 623,000 ≈ 92 万人 |
| IQR | σ ≈ IQR / 1.349 | 1,602,500 / 1.349 ≈ 119 万人 |
| Range | σ ≈ Range / \(d_n\)(管理図表) | n=47 の \(d_n\) ≈ 4.0 → 約 339 万人 |
SSDSE の実際の SD は約 280 万人。 ロバスト換算は MAD 由来で 92 万、 IQR 由来で 119 万人とかなり低い。 これは 分布が右に強く歪んでいる証拠で、 「正規分布前提のロバスト換算が大きく外れる ⇒ 正規分布で近似してはいけない」というアラートを発している。
VAR.S と VAR.P、 scikit-learn の StandardScaler(ddof=0)。 同じデータでも分母が違うと値が変わる。 報告時は ddof を明示。VarianceThreshold(scikit-learn)で事前に除去するのが定石。| 分布の形 | 第一選択 | 第二選択 | 避けるべき | 例 |
|---|---|---|---|---|
| 左右対称・単峰(正規分布近似) | SD | IQR | 範囲 | 身長、 IQ、 試験得点 |
| 右に歪み(lognormal 風) | IQR | 対数変換後の SD | 生の SD・平均 | 所得、 売上、 都市人口 |
| 外れ値多数 | MAD | IQR | SD・分散 | 医療費、 株価リターン |
| 双峰・多峰 | サブグループに分割 | 分布ごとの SD | 全体 SD で語ること | 男女混在の身長 |
| 単位や桁が違う変数間比較 | CV | 標準化後の SD | 生の SD | 人口 vs GDP |
💬 この表は「分布の形が先、 ばらつき指標は後」というメッセージ。 まずヒストグラムや箱ひげ図で形を見て、 そこから指標を選ぶ。 機械的に SD を使うのは禁物。
ばらつきは「平均」「中央値」のような中心値から派生して、 偏差 → 分散 → 標準偏差 → 共分散 → 相関係数 へと階段状に拡張される。 ヒストグラム・箱ひげ図は同じ概念を可視化したもの、 期待値 E[X] と Var[X] は理論側からの定式化である。
ばらつきは「個々の値が平均からどれだけ離れているか」を一つの数値で集約する操作であり、 後段の回帰・PCA・分散分析・標準化すべてが分散の存在を前提にしている。 SSDSE-B-2026 の都道府県別データを 1 つ取ると、 平均値だけでは説明できない地域差の大きさが分散・標準偏差に凝縮され、 政策議論や比較指標の出発点になる。
ばらつき (分散・標準偏差・共分散) は単独の指標ではなく、 平均との対比で意味が確定し、 正規分布の前提や回帰の残差分析へと連鎖する。 以下の接続点を押さえることで「数値の散らばり」を統計的推測の出発点に育てられる。
ばらつきは「平均だけでは見えない不均一性」を可視化する指標群で、 上流の前処理で外れ値が分散を歪めていないか、 並列で共分散・標準偏差のスケールを揃えているか、 下流で回帰や検定の前提に矛盾がないかを常にセットで点検する。
| 状況 | 推奨指標 | 理由 |
|---|---|---|
| 対称分布(正規分布)、 外れ値少 | 分散・標準偏差 | CLT・信頼区間の前提 |
| 外れ値・歪んだ分布 | MAD、 IQR | ロバスト性 |
| 2変数の関係 | 共分散(→ 相関で正規化) | 単位フリーは相関 |
| 多変数の関係 | 共分散行列・ 相関行列 | PCA の前提 |
| 単位の異なる変数の比較 | 変動係数 (CV) = $\sigma/\mu$ | 無次元化 |
| 概観把握のみ | 範囲(min/max) | 計算容易だが情報少 |
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 29 30 31 32 33 | import pandas as pd # ── この抜粋だけで動くように、47 都道府県・最新年度を読み込む ── _d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) _d = _d[_d['SSDSE-B-2026'] == 2023] import numpy as np from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler, RobustScaler from sklearn.feature_selection import VarianceThreshold from sklearn.decomposition import PCA X = _d[['A1101', 'A1301', 'A1303', 'A4101']].astype(float).values y = (_d['A1101'] > _d['A1101'].median()).astype(int).values X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=0, stratify=y) # 標準化(学習用) scaler = StandardScaler() X_train_std = scaler.fit_transform(X_train) X_test_std = scaler.transform(X_test) # 訓練でfit、 テストはtransform X_std = scaler.fit_transform(X) # ロバスト版(外れ値に強い) scaler = RobustScaler() # 中央値と IQR ベース # 分散ほぼゼロの特徴量を除外 selector = VarianceThreshold(threshold=0.01) X_filtered = selector.fit_transform(X_std) # PCA(共分散行列を分解) pca = PCA(n_components=2) X_pca = pca.fit_transform(X_std) print(pca.explained_variance_ratio_) # 主成分の寄与率 |
| ❌ よくある誤解 | ✅ 正しい理解 |
|---|---|
| 「÷n」も「÷(n-1)」も同じ | 推測には ÷(n-1)(不偏)、 記述には ÷n。 ライブラリのデフォルトを確認 |
| 標準偏差と標準誤差は同じ | SD はデータのばらつき、 SE は推定値のばらつき($\sigma/\sqrt{n}$) |
| 分散の単位は元と同じ | 分散は単位の2乗。 解釈には標準偏差を使う |
| 共分散の大きさで関係の強さが分かる | 単位依存で比較不可。 相関係数(正規化済み)を使う |
| 外れ値があっても標準偏差で十分 | 2乗で外れ値の影響が増幅。 MAD・IQR を併用 |
| 共分散ゼロ ⇒ 独立 | 線形関係がないだけ。 非線形(U字など)はあり得る |
| 68-95-99.7 ルールはどんな分布でも使える | 正規分布の話。 歪んだ分布では成り立たない |
| 変動係数(CV)で全部比較可能 | 平均がゼロに近い/負の場合は意味を失う |
解答:$\bar{x} = 30$、 偏差: $(-20, -10, 0, 10, 20)$、 二乗和 $= 400 + 100 + 0 + 100 + 400 = 1000$。
標本分散 $= 1000/5 = 200$。 不偏分散 $= 1000/4 = 250$。 標本標準偏差 $= \sqrt{200} \approx 14.14$、 不偏標準偏差 $= \sqrt{250} \approx 15.81$。
解答:MAD。 標準偏差は偏差を2乗するため、 外れ値の影響が大きく増幅されてしまう。 MAD は中央値ベースで 50% 崩壊点を持つロバスト指標。 正規分布なら $\sigma \approx 1.4826 \times \mathrm{MAD}$ で標準偏差相当の値も得られる。
解答:「÷n」は標本分散(最尤推定)、 「÷(n-1)」は不偏分散。 母集団の分散を推定したい場合は ÷(n-1)(バイアス補正)、 標本そのものの記述には ÷n。 NumPy の np.var はデフォルトで ddof=0(÷n)、 Pandas の df.var() はデフォルトで ddof=1(÷(n-1))。 違いに注意。
解答:平均 → 2倍、 分散 → 4倍($\mathrm{Var}(aX) = a^2 \mathrm{Var}(X)$)、 標準偏差 → 2倍。 これが「分散は2乗で動くが、 標準偏差は元の単位で動く」の意味。
解答:$r = \sigma_{xy} / (\sigma_x \sigma_y) = 100 / (5 \times 8) = 100/40 = 2.5$。 …これは $|r| \le 1$ の制約に違反しているので、 与えられた値が矛盾している(共分散の絶対値は $\sigma_x \sigma_y$ を超えない)。 「共分散が標準偏差の積より大きいことは数学的にあり得ない」(コーシー・シュワルツの不等式)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) data = df.copy() data['年度'] = data['SSDSE-B-2026'] df23 = data[data['年度'] == 2023] cols = ['L322101', 'L322108', 'L322102'] # 食料・教育・住居 X = df23[cols].apply(pd.to_numeric, errors='coerce').dropna() / 1000 # 共分散行列 print(np.cov(X.values, rowvar=False)) # PCA の前に標準化(必須) X_std = StandardScaler().fit_transform(X) |
PCA は分散最大方向を見つけるので、 単位が大きい変数(住居費)が支配的になってしまう。 標準化すると全変数が等しいスケールになり、 真の構造が捉えられる。 つまり「単位の違いを取り除いてから分散構造を見る」が標準化の目的。
ばらつき指標を報告するときは、 必ず代表値(平均または中央値)とセットで示します。 単に「分散 = X」では意味を成しません。
「47都道府県の食料費(2023年・ SSDSE-B-2026)は、 平均 80.6 千円 ± 標準偏差 5.8 千円(不偏推定)、 範囲は 71.1〜97.8 千円。 分布は概ね対称だが、 一部の都市県が右側にやや長い裾を作る。 MAD ベースのロバスト標準偏差は 6.9 千円で古典的 SD とほぼ同等、 極端な外れ値の影響は限定的。 (n=47)」
「ばらつき(分散・標準偏差・共分散)」を扱う際の手法選択は、 状況に応じて以下のフローで判断すると迷いが減る。
このフローに沿って判断することで、 「ばらつき(分散・標準偏差・共分散)」を中核とした適切な手法選択ができる。
数直線上の青い点をドラッグして散らしたり集めたりしてみましょう(スマホはタッチでOK)。 範囲・分散・標準偏差(SD)・四分位範囲(IQR)・変動係数(CV) がリアルタイムで計算されます。 点を広げるとばらつき指標は増え、 平均付近に集めると減ります。 赤い帯が平均 ± SD、 緑の帯が IQR(真ん中50%)です。
試してみよう: 「外れ値を追加」を押すと、 SD(赤)は大きく跳ね上がるのに IQR(緑)はほとんど動かないはず。 これが「SD は外れ値に敏感/IQR は頑健」の体感です。 「集める」を繰り返すと全指標がゼロに近づき、 平均だけでは同じでもばらつきが全く違う分布を作れます。
ここまでは「ある1時点のデータの散らばりを1つの数字にする」話だった。 この節では一歩進めて、 ばらつきを部分に分解する視点と、 時間の関数として追いかける視点を紹介する。 どちらも SSDSE-B-2026 の実測値だけで確認できる。
47 都道府県の食料費がばらつく理由は 2 層に分けられる。 「地方ブロックごとに水準が違う」(グループ間)と「同じブロック内でも県ごとに違う」(グループ内)だ。 実は全体の分散は、 この 2 つの和に厳密に分解できる:
$$ \underbrace{\frac{1}{n}\sum_i (x_i - \bar{x})^2}_{\text{全体分散}} = \underbrace{\frac{1}{n}\sum_g n_g(\bar{x}_g - \bar{x})^2}_{\text{群間分散}} + \underbrace{\frac{1}{n}\sum_g \sum_{i \in g} (x_i - \bar{x}_g)^2}_{\text{群内分散}} $$
SSDSE-B-2026 の食料費(二人以上の世帯、 2023 年、 千円)を 6 地方ブロック(北海道・東北 7 / 関東 7 / 中部 9 / 近畿 7 / 中国・四国 9 / 九州・沖縄 8 県)に分けて実測すると:
| 成分 | 値(千円²、 ÷n) | 全体に占める割合 |
|---|---|---|
| 全体分散 | 33.400 | 100.0% |
| 群間分散(ブロック平均の差) | 13.118 | 39.3% |
| 群内分散(ブロック内の県差) | 20.282 | 60.7% |
ブロック平均は関東 86.67、 近畿 83.08、 中部 82.18、 北海道・東北 79.90、 中国・四国 77.13、 九州・沖縄 75.84 千円と確かに差がある。 しかし全体のばらつきの 6 割は「同じ地方の中」の県差で生まれている。 「関東は食料費が高い」というブロック間の物語だけでは、 ばらつきの半分も説明できていない — 分解して初めて見える構図だ。
地域経済学では、 地域間格差が縮まることを「地域間 CV が年々小さくなる」ことで定義し、 σ(シグマ)収束と呼ぶ。 逆に CV が増え続ければσ発散(格差拡大)。 ばらつき指標そのものを時系列プロットするという、 本ページの内容の直接の応用だ。 SSDSE-B-2026(2012〜2023 年)で実測すると:
| 年 | 総人口の CV(47 都道府県) | 食料費の CV(同) |
|---|---|---|
| 2012 | 98.17% | 6.77% |
| 2017 | 101.14% | 6.89% |
| 2020 | 103.08% | 6.48% |
| 2023 | 104.60% | 7.17% |
総人口の CV は 12 年間毎年一度も下がらず 98.17%→104.60% と単調増加 — 人口分布は明確にσ発散している(一極集中の定量的な証拠)。 一方、 食料費の CV は 6.5〜8% 前後を行き来するだけでトレンドがない — 家計の支出構造は地域間で発散も収束もしていない。 同じ 47 都道府県でも、 変数によって「格差のダイナミクス」が全く違うことが、 CV の時系列 1 本で読み取れる。 なお、 平均値の低い地域ほど成長率が高いか、 という別の収束概念は β収束と呼ばれ、 σ収束とは判定基準が異なる(β収束してもσ収束するとは限らない)。
分解の考え方はさらに広がる: 群間/群内の比較を検定にしたものが分散分析(ANOVA)、 多変数の分散・共分散をまとめた共分散行列の「分散が最大の方向」を探すのが主成分分析、 予測誤差の期待値を分解するのがバイアス・バリアンス分解だ。 「全体のばらつき=成分の和」という一本の発想が、 統計学の広い範囲を貫いている。