分散と関連する重要用語:
🍰 まずはやさしく
データの広がりを表す物差しです。
中心からどれくらい離れているかを知るために使います。
テストの点数がクラスでバラバラかを確認する時に便利です。
分散の意味と計算の基本について読みましょう。
分散(variance)は、 データの「広がり(散らばり)」を測る量です。 平均だけでは「中心」しか分からないので、 散らばりを定量化するために使います。
計算:「各データ点と平均との差」を 2乗して、 平均したもの。 2乗するのは正負を打ち消して、 散らばりだけを取り出すため。
単位の問題:元の単位の2乗(cm² など)になるため、 直感的に使いにくい。 そこで平方根を取って元の単位に戻したのが 標準偏差。 実用ではこちらの方が好まれます。
応用:(i) 回帰の R² は「分散の分解」、 (ii) ANOVA(分散分析)は「群間分散 vs 群内分散」、 (iii) PCA は「分散最大の方向」を探す。 分散は統計の中核概念です。
🍰 まずはやさしく
データの散らばりを測るための言葉です。
分析の中でデータの広がりを正しく扱うために使います。
都道府県ごとのデータを比べる時に役立ちます。
定義や数式などの詳しい解説を順番に読みましょう。
論文中に 「分散」として登場する用語。
分散 とは:「平均からのズレ」の2乗の平均。データの広がりを測る。標準偏差の2乗。
本ページでは「variance」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。
「variance」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。
🍰 まずはやさしく
データのばらつきを数字にしたものです。
平均だけでは分からない広がり方を掴むために使います。
部活の練習時間が人によって違うかを見る時に似ています。
なぜ計算に2乗を使うのかという理由を読みましょう。
分散(variance)は、 データの散らばり具合を1つの数字で表す指標。 平均から各データがどれくらい離れているか、 を2乗してから平均したものです。
各バーが東北6県の食料費。 赤線が平均、 オレンジ矢印が各県から平均までの距離(偏差)。 この偏差を集約したのが分散です。
左:偏差はプラスとマイナスが混在し、 合計はゼロになります(重心の性質)。 そのままでは「ばらつき」を表せません。
右:偏差を2乗するとすべて非負になり、 「平均からの距離の大きさ」を測れます。 この平均が分散。
同じ平均(μ=50)でも、 分散が大きいほどデータは広がります。 分散は不確実性の大きさとも解釈できます。
💡 分散は幾何学的には「平均からの距離の2乗の平均」、 物理学的には「慣性モーメント」、 確率論的には「期待値の2次モーメント」と多角的に理解できます。
数直線上の点をドラッグして動かしたり、 空いた所をクリック(タップ)して点を追加すると、 平均・分散・標準偏差がリアルタイムで更新されます。 各点から平均への偏差を線で、 偏差の二乗を正方形の面積で描きます。 「分散 = 偏差二乗(正方形の面積)の平均」を目で体感してください。
分散とは「各データが平均からどれだけ離れているか」を偏差の二乗の平均で測った散布度。 母分散は $$ \sigma^2 = \frac{1}{N}\sum (x_i-\mu)^2 $$、 不偏分散は $$ s^2 = \frac{1}{n-1}\sum (x_i-\bar{x})^2 $$。
偏差 (xᵢ − x̄) はそのまま足すと必ず 0 になる(平均の定義より)。 符号を消す方法は主に 2 つ:絶対値を取るか、二乗するか。
この「二乗ゆえの外れ値感度」を避けたいときは、 絶対値ベースの頑健な散布度(MAD・IQR)を使う。 詳しくは ロバスト統計 を参照。
標本から母分散を推定するとき、 分母を n にすると系統的に過小評価される($$ \mathbb{E}[s^2_n] = \frac{n-1}{n}\sigma^2 < \sigma^2 $$)。 これは偏差を「未知の母平均 μ」ではなく「標本から計算した x̄」で測るため、 平方和が必ず最小になってしまうから。 分母を n−1(=自由度)にすると期待値が母分散に一致する(不偏推定量)。 これをベッセル補正と呼ぶ。 上のシミュレータで「母分散/不偏分散」を切り替えると、 n が小さいほど両者の差が大きい(比は n/(n−1))ことが確認できる。
分散は単位が「元の単位の二乗」(万人²・千円² など)になり解釈しづらい。 その平方根を取って元の単位に戻したのが 標準偏差(SD = √分散)。 実務の報告・可視化では SD が好まれる。 シミュレータの紫の破線正方形(一辺 = SD)は、 色付き正方形の面積の平均(=分散)にちょうど等しく、 「SD は分散を長さに戻したもの」であることを示している。
偏差を二乗するため、 平均から大きく離れた 1 点が分散に与える影響は距離の二乗で効く。 例えば 47 都道府県の総人口は、 東京都(突出値)を含めると SD ≈ 280 万人、 除くと ≈ 224 万人と大きく変わる。 外れ値が疑われるデータでは、 分散・SD の代わりに IQR や MAD といった頑健な指標を併用する。 → ロバスト統計
分散は「1 変数の偏差 × 同じ偏差」の平均だが、 これを「x の偏差 × y の偏差」の平均に一般化すると 共分散 $$ \mathrm{Cov}(X,Y) = \frac{1}{n}\sum (x_i-\bar{x})(y_i-\bar{y}) $$ になる。 実際 $$ \mathrm{Cov}(X,X) = \mathrm{Var}(X) $$ であり、 分散は共分散の特殊ケース。 2 変数の和の分散には共分散項が現れる($$ \mathrm{Var}(X+Y)=\mathrm{Var}(X)+\mathrm{Var}(Y)+2\,\mathrm{Cov}(X,Y) $$)。 共分散を標準偏差で割って無次元化すると相関係数、 多変数に並べると分散共分散行列となり、 PCA やポートフォリオ理論の基礎になる。
🍰 まずはやさしく
分散を計算するためのルールです。
ばらつきの大きさを正確に求めるために使います。
スマホの利用時間の平均からのズレを計算するイメージです。
記号の意味と計算式の読み方を詳しく読みましょう。
$$ \sigma^2 = \mathbb{E}[(X - \mu)^2] = \frac{1}{N} \sum_{i=1}^{N} (x_i - \mu)^2 $$
$$ s^2 = \frac{1}{n - 1} \sum_{i=1}^{n} (x_i - \bar{x})^2 $$
| 記号 | 読み方 | 意味 |
|---|---|---|
| σ² | シグマの二乗 | 母分散 |
| s² | エスの二乗 | 不偏分散(標本ベース) |
| (xᵢ - x̄)² | エックスアイ マイナス エックスバー の二乗 | 偏差の二乗 |
| E[·] | 期待値 | 確率変数の重み付き平均 |
展開すると:
$$ s^2_n = \overline{x^2} - \bar{x}^2 = \frac{1}{n} \sum x_i^2 - \bar{x}^2 $$
「二乗の平均 − 平均の二乗」とも呼ばれます。 計算量が少なく、 ストリーミングデータでも使いやすい。
$$ \text{Var}(X + c) = \text{Var}(X) $$
全データに同じ数を足すと、 全部が平行移動するだけで「散らばり」は変わらない。
$$ \text{Var}(aX) = a^2 \cdot \text{Var}(X) $$
2倍すると分散は4倍、 3倍すると分散は9倍。 ばらつきも2乗で広がる。
$$ \text{Var}(X + Y) = \text{Var}(X) + \text{Var}(Y) \quad (X, Y \text{ 独立}) $$
独立な変数の和の分散は、 それぞれの分散の和。 大数の法則の根拠でもあります。
$$ \text{Var}(X + Y) = \text{Var}(X) + \text{Var}(Y) + 2 \text{Cov}(X, Y) $$
独立でない場合、 共分散の項が追加されます。 ポートフォリオ理論や分散分析の基礎。
$$ \text{Var}(\bar{X}) = \frac{\sigma^2}{n} $$
サンプルサイズを n 倍にすると、 平均のばらつきは 1/n に減る。 これが「サンプルを多く取れば平均が安定する」の理論的根拠。
分散の平方根が標準偏差(standard deviation):
$$ \sigma = \sqrt{\sigma^2}, \quad s = \sqrt{s^2} $$
分散は単位が「元の単位の2乗」(千円² など)になるため、 解釈しにくいことがあります。 平方根を取った標準偏差は元のデータと同じ単位を持つので、 直感的。
| 統計量 | 単位 | 直感性 | 数学的扱いやすさ |
|---|---|---|---|
| 分散 σ² | 元の単位の二乗(千円²) | 低い | 高い(線形性、 加法性) |
| 標準偏差 σ | 元の単位(千円) | 高い | 低い(加法性なし) |
分散の最大の応用が分散分析(Analysis of Variance)。 全体の分散を「群間の差による分散」と「群内の偶然の分散」に分けて、 「群差は本物か?」を検定します。
$$ \text{総分散} = \text{群間分散} + \text{群内分散} $$
$$ \sum_i (x_i - \bar{x})^2 = \sum_g n_g (\bar{x}_g - \bar{x})^2 + \sum_g \sum_i (x_{gi} - \bar{x}_g)^2 $$
$$ F = \frac{\text{群間分散} / df_1}{\text{群内分散} / df_2} $$
F が大きい → 群間差が大きい → 群差は有意。 t検定の多群版とも言えます。
機械学習モデルの予測誤差は3つに分解されます:
$$ E[(y - \hat{f}(x))^2] = \text{Bias}^2 + \text{Variance} + \sigma^2_\epsilon $$
過学習=Variance が大(複雑モデルは学習データに敏感)、 過小学習=Bias が大。
「分散を最大化する方向」を順に見つけ、 データの主要な変動を捉える次元削減手法。 分散がそのまま「情報量」として使われる。
分散がほぼゼロの特徴量(全データで値が同じ)は予測に寄与しないので除外する前処理。
このコードでやること: 3 特徴量のうち分散が threshold=0.01 以下の列を自動除外する sklearn の VarianceThreshold の最小動作例。
📥 入力データ例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # ── この抜粋で使うデータを用意します ── import numpy as np import pandas as pd from sklearn.feature_selection import VarianceThreshold import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年の 47 都道府県 # 総人口・65歳以上人口・消費支出を、桁を揃えて 3 列の行列にする X = np.column_stack([ df['A1101'].astype(float).values / 1e4, # 総人口(万人) df['A1303'].astype(float).values / 1e4, # 65歳以上人口(万人) df['L3221'].astype(float).values / 1e3]) # 消費支出(千円) selector = VarianceThreshold(threshold=0.01) X_filtered = selector.fit_transform(X) print('各列の分散 :', np.round(selector.variances_, 3)) print('残った列の数 :', X_filtered.shape[1], '/', X.shape[1]) |
💬 分散が 0.01 以下の特徴量(全サンプルでほぼ同じ値)は予測に寄与しないため自動除去される。 前処理で不要な特徴量を削る標準的な手順。
各層の出力を「平均0、 分散1」に標準化する深層学習の必須技術。 「分散」が出てくるたびに必要なのが正規化。
分散の計算で最初に詰まるのが「分母を n にするか n-1 にするか」問題。 NumPy / pandas / SciPy で ddof (Delta Degrees Of Freedom) という引数で制御する。 既定値が NumPy=0、 pandas=1 と異なるため、 同じデータでも違う値が出るのが要注意ポイント。
標本分散の定義は s² = Σ(xᵢ - x̄)² / (n - ddof)。 数式を言葉で読み解くと、 「観測値とその平均との差を二乗して足し、 自由度で割る」。 ここで自由度とは「自由に動ける情報の数」のこと。 標本平均 x̄ を計算するのに 1 個分の情報を使っているため、 残りの「真に独立な情報」は n - 1 個になる。 ddof=1 (= n-1 で割る) とすると、 推定された分散の期待値が母分散 σ² と一致する (不偏推定量)。 一方 ddof=0 では系統的に過小評価される。
| 関数 | 既定 ddof | 既定の意味 | 変更方法 |
|---|---|---|---|
numpy.var(x) | 0 | 標本分散 (n で割る) | ddof=1 |
pandas.Series.var() | 1 | 不偏分散 (n-1 で割る) | ddof=0 |
statistics.variance(x) | 1 | 不偏分散 | statistics.pvariance |
scipy.stats.tvar(x) | 1 | 不偏分散 | なし (固定) |
Excel VAR.S | 1 | 不偏分散 | VAR.P で標本分散 |
分散 σ² = E[(X − μ)²] の各記号を日本語に翻訳する。
分散の式は「データが平均からどれだけ広がっているか」を二乗距離の平均で測る。 SSDSE-B-2026 A1101 では分散 ≈ 7.7 × 104 (万人²)、 標準偏差 ≈ 277 万人で「47 県の人口は平均 265 万人 ± 277 万人」と要約される。
母分散 vs 不偏分散の使い分け:
var(), pandas の .var() はデフォルト n−1| 都道府県 | 食料費 xᵢ | 偏差 (xᵢ - x̄) | 偏差の二乗 (xᵢ - x̄)² |
|---|---|---|---|
| 青森県 | 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 |
| 合計 | 484.944 | ≈ 0 | 40.4382 |
平均 x̄ = 80.824 千円。
$$ s^2_n = \frac{1}{n} \sum_{i=1}^{n} (x_i - \bar{x})^2 $$
計算:40.4382 ÷ 6 = 6.7397
$$ s^2 = \frac{1}{n - 1} \sum_{i=1}^{n} (x_i - \bar{x})^2 $$
計算:40.4382 ÷ 5 = 8.0876
東北6県の食料費の分散は約 6.74〜8.09 (千円²)。 平方根を取れば標準偏差 ≈ 2.84 千円。
「ばらつきを n 個で割って平均すれば、 1個あたりのばらつきになる」が直感的。 でも統計学ではn-1 で割るのが標準。 なぜでしょうか。
「÷n」で計算した標本分散 s²_n は、 母集団全体の分散 σ²より小さくなる傾向があります。
$$ \mathbb{E}[s^2_n] = \frac{n - 1}{n} \sigma^2 \quad < \sigma^2 $$
つまり「÷n」だと、 平均的に母分散より (n-1)/n 倍だけ過小評価します。 これを是正するため、 (n-1)/n の逆数 n/(n-1) を掛けて補正:
$$ s^2 = \frac{n}{n-1} \cdot s^2_n = \frac{1}{n - 1} \sum (x_i - \bar{x})^2 $$
これが不偏分散。 期待値が母分散 σ² に一致する(不偏性)。
上の図は1000回のサンプリングで分散を計算した平均値。 赤線(÷n)は常に真値より下にあり、 緑線(÷(n-1))は真値に正しく一致。
n 個のデータがあって、 平均 x̄ を計算すると1つの「制約」ができます(偏差の合計がゼロ)。 残りの「自由に動ける情報の数」は n-1 個。 これが自由度と呼ばれる概念。
自由度で割ることで、 「情報の量に合わせた平均」になります。
StandardScaler や PCA も ÷n)np.var(x) は ÷n、 ddof=1 で ÷(n-1)df.var() は ÷(n-1) — 推論用SSDSE-B-2026 の主要 6 変数で、 ① 標本分散、 ② 不偏分散、 ③ 標準偏差、 ④ 変動係数(CV)、 ⑤ Welford のオンライン計算 を実演する。
このコードでやること: SSDSE-B-2026 の 47 都道府県データ(2023 年)から「総人口・15歳未満人口・65歳以上人口・合計特殊出生率・年平均気温・消費支出」6 変数について、母分散・不偏分散・標準偏差・変動係数を一括計算する。
📥 入力データ(SSDSE-B-2026、2023 年 抜粋):
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 # 先頭列名は "SSDSE-B-2026"(=年度)。2 行目の日本語ラベルは skiprows=[1] で除外し、 # コード列名(A1101 等)で読み込んでから 2023 年だけを抽出する。 df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # (コード, 表示名, 単位変換) 人口系は万人、消費支出は千円に換算して比較する feats = [('A1101', '総人口(万人)', 1e4), ('A1301', '15歳未満人口(万人)', 1e4), ('A1303', '65歳以上人口(万人)', 1e4), ('A4103', '合計特殊出生率', 1), ('B4101', '年平均気温(℃)', 1), ('L3221', '消費支出(千円)', 1e3)] for code, name, u in feats: x = df[code].astype(float).values / u mu, sd = x.mean(), x.std(ddof=1) print(f'{name:<16} 平均={mu:8.2f} σ²={x.var(ddof=0):10.2f} ' f's²={x.var(ddof=1):10.2f} SD={sd:7.2f} CV={sd/mu:6.3f}') |
💬 消費支出の CV ≈ 0.082(世帯あたり支出は全国的に均質)に対し、総人口の CV ≈ 1.057(東京都が突出して大きい)と最大。「ばらつきを比較する」には絶対値の分散ではなく、単位無次元の CV が有効。
典型的な観察例: 総人口の CV は 1.0 を超え(東京都がずば抜けて大きい)、 消費支出の CV は 0.08 程度と均質。 「ばらつきを比較する」には絶対値の分散ではなく、 単位無次元の CV を使うのが定石。 また ddof=0(母分散)と ddof=1(不偏分散)の差は n=47 では約 2.2% で実用上ほぼ無視できるが、 教科書通り「サンプルから母数を推定」する文脈では必ず ddof=1 を使う。
このコードでやること: SSDSE-B-2026(2023 年)の消費支出を Welford アルゴリズムで計算し、numpy の一括計算と完全一致することを確認する。
📥 入力データ(SSDSE-B-2026 消費支出、47 県分):
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 df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] x = df['L3221'].astype(float).values / 1e3 # 消費支出(二人以上の世帯)を千円に def welford(xs): n, mean, M2 = 0, 0.0, 0.0 for v in xs: n += 1 delta = v - mean mean += delta / n M2 += delta * (v - mean) return mean, M2/n, M2/(n-1) # 母分散, 不偏分散 mu, var_pop, var_samp = welford(x) print(f'Welford : μ={mu:.2f}, σ²={var_pop:.2f}, s²={var_samp:.2f}') print(f'numpy : μ={x.mean():.2f}, σ²={x.var(ddof=0):.2f}, ' f's²={x.var(ddof=1):.2f}') |
💬 Welford アルゴリズムの μ=295.86、σ²=570.53、s²=582.94 が numpy と完全一致。 ストリーミング計算でも numpy の一括計算と同じ結果が得られる。
このコードでやること: SSDSE-B-2026 の「15歳未満人口」と「65歳以上人口」は相関があるため Var(a+b) ≠ Var(a)+Var(b) となる。共分散項の補正がなければ分散の加法性が成立しないことを実データで確認する。
📥 入力データ(SSDSE-B-2026 抜粋):
1 2 3 4 5 6 7 8 9 10 11 | # 15歳未満 + 65歳以上 = 「非生産年齢人口」とすると Var の加法性は崩れる # (両者は同じ県内のサンプルなので相関がある) a = df['A1301'].astype(float) / 1e4 b = df['A1303'].astype(float) / 1e4 print(f'Var(a) = {a.var(ddof=1):.2f}') print(f'Var(b) = {b.var(ddof=1):.2f}') print(f'Var(a+b) = {(a+b).var(ddof=1):.2f}') print(f'2*Cov(a,b) = {2 * a.cov(b):.2f}') print(f'分散の加法性チェック: ' f'Var(a)+Var(b)+2Cov(a,b) = ' f'{a.var(ddof=1) + b.var(ddof=1) + 2*a.cov(b):.2f}') |
💬 Var(a)+Var(b) = 5787.70 に対し Var(a+b) = 10065.49。 差は 2×Cov(a,b) = 4277.79 で完全一致。 15歳未満と65歳以上は都市部で共に多い傾向があり、強い正の共分散を持つため加法性が単純には成立しない。
このコードでやること: SSDSE-B-2026 の 47 県人口について、 ddof=0 (標本分散) と ddof=1 (不偏分散) の差を実値で示し、 同じデータでも値がどう変わるかを確認する。
📥 入力データ (SSDSE-B-2026 抜粋):
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]) pop = df.groupby('Prefecture')['A1101'].first() / 1e4 n = len(pop) mean = pop.mean() ss = ((pop - mean) ** 2).sum() # 偏差平方和 print(f'n = {n}') print(f'mean = {mean:.3f}') print(f'Σ(x-x̄)² = {ss:.1f}') print() print(f'np.var (ddof=0, n で割る) = {np.var(pop, ddof=0):.2f} → σ̂² (バイアス有)') print(f'np.var (ddof=1, n-1 で割る) = {np.var(pop, ddof=1):.2f} → s² (不偏)') print(f'pandas .var() (既定 ddof=1) = {pop.var():.2f}') print(f'pandas .var(ddof=0) = {pop.var(ddof=0):.2f}') print(f'比 ddof1/ddof0 = {np.var(pop,ddof=1)/np.var(pop,ddof=0):.6f} (= n/(n-1) = {n/(n-1):.6f})') |
📤 実行例:
💬 結果の読み方: 同じデータでも ddof=0 と ddof=1 で 1665 (約 2.2%) の差が出る。 比は n/(n-1) = 47/46 ≒ 1.0217 という単純な比例関係。 N が大きくなるとこの差はゼロに収束するため、 ビッグデータでは無視できる。 ただし「47 都道府県は標本ではなく母集団そのもの」という見方を取るなら ddof=0 が正しく、 「47 県は何らかの母集団からの標本」と見るなら ddof=1。 設定で意味が変わる典型例。
分散には「分解できる」という強力な性質がある。 任意のグループ分けに対し、 全分散 = 群内分散の加重平均 + 群間分散 という関係 (分散分解定理) が成立する。 これは ANOVA (分散分析) や混合効果モデルの基礎であり、 R² (決定係数) の意味も「全分散のうちモデルが説明する分散の割合」として理解できる。
数式を言葉で読み解くと、 「全分散は『各グループ内のばらつきの平均』と『各グループの平均同士のばらつき』の和」。 前者を「群内分散 (within-group variance)」、 後者を「群間分散 (between-group variance)」と呼ぶ。 この分解は、 グループ分けが「データの違いをどれだけ説明するか」を 1 つの指標で測れることを意味する。 群間 / 全 = R² (1 元配置 ANOVA の場合) となる。
このコードでやること: SSDSE-B-2026 の都道府県人口を 8 地方ブロックに分け、 全分散・群内分散・群間分散の 3 つを分解計算し、 「地方の違いが人口のばらつきをどれだけ説明するか」を R² 風指標で出す。
📥 入力データ(SSDSE-B-2026 抜粋):
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 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) pop = (df.groupby('Prefecture')['A1101'].first() / 1e4).reset_index() region_map = {'北海道':'北海道', '青森県':'東北','岩手県':'東北','宮城県':'東北','秋田県':'東北','山形県':'東北','福島県':'東北', '茨城県':'関東','栃木県':'関東','群馬県':'関東','埼玉県':'関東','千葉県':'関東','東京都':'関東','神奈川県':'関東', '新潟県':'中部','富山県':'中部','石川県':'中部','福井県':'中部','山梨県':'中部','長野県':'中部','岐阜県':'中部','静岡県':'中部','愛知県':'中部', '三重県':'近畿','滋賀県':'近畿','京都府':'近畿','大阪府':'近畿','兵庫県':'近畿','奈良県':'近畿','和歌山県':'近畿', '鳥取県':'中国','島根県':'中国','岡山県':'中国','広島県':'中国','山口県':'中国', '徳島県':'四国','香川県':'四国','愛媛県':'四国','高知県':'四国', '福岡県':'九州沖縄','佐賀県':'九州沖縄','長崎県':'九州沖縄','熊本県':'九州沖縄','大分県':'九州沖縄','宮崎県':'九州沖縄','鹿児島県':'九州沖縄','沖縄県':'九州沖縄', } pop['region'] = pop['Prefecture'].map(region_map) total_mean = pop['A1101'].mean() ss_total = ((pop['A1101'] - total_mean) ** 2).sum() # 群内 (within) と 群間 (between) の平方和 ss_within = 0.0 ss_between = 0.0 for r, sub in pop.groupby('region'): ss_within += ((sub['A1101'] - sub['A1101'].mean()) ** 2).sum() ss_between += len(sub) * (sub['A1101'].mean() - total_mean) ** 2 print(f'SS_total = {ss_total:>12.1f}') print(f'SS_within = {ss_within:>12.1f}') print(f'SS_between = {ss_between:>12.1f}') print(f'within + between = {ss_within + ss_between:>12.1f}') print(f'R² (between/total) = {ss_between/ss_total:.4f}') |
📤 実行例:
💬 結果の読み方: 全分散 3,600,095 を 2,261,919 (群内) + 1,338,177 (群間) に綺麗に分解できた (完全に一致)。 R² ≒ 0.37 は、 「47 県人口のばらつきのうち約 37% が地方ブロックの違いで説明できる」と解釈する。 残り 63% は「同じ地方の中での県間のばらつき」(例: 東京と神奈川の差) によるもの。 グルーピングが「強い説明力を持つか」を 1 つの数字で示せる強力な道具。
t 検定や ANOVA の前提のひとつが「群間で分散が等しい (等分散性)」。 これを確かめる検定が Levene 検定 (頑健、 非正規でも使える) と Bartlett 検定 (正規前提、 検出力が高い)。 帰無仮説はどちらも「全群の分散が等しい」。
このコードでやること: SSDSE 47 県人口を 8 地方ブロックに分け、 各ブロック内分散が等しいかを Levene 検定と Bartlett 検定で検証する。
📥 入力データ(SSDSE-B-2026 抜粋):
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 | import pandas as pd from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) pop = (df.groupby('Prefecture')['A1101'].first() / 1e4).reset_index() region_map = {'北海道':'北海道', '青森県':'東北','岩手県':'東北','宮城県':'東北','秋田県':'東北','山形県':'東北','福島県':'東北', '茨城県':'関東','栃木県':'関東','群馬県':'関東','埼玉県':'関東','千葉県':'関東','東京都':'関東','神奈川県':'関東', '新潟県':'中部','富山県':'中部','石川県':'中部','福井県':'中部','山梨県':'中部','長野県':'中部','岐阜県':'中部','静岡県':'中部','愛知県':'中部', '三重県':'近畿','滋賀県':'近畿','京都府':'近畿','大阪府':'近畿','兵庫県':'近畿','奈良県':'近畿','和歌山県':'近畿', '鳥取県':'中国','島根県':'中国','岡山県':'中国','広島県':'中国','山口県':'中国', '徳島県':'四国','香川県':'四国','愛媛県':'四国','高知県':'四国', '福岡県':'九州沖縄','佐賀県':'九州沖縄','長崎県':'九州沖縄','熊本県':'九州沖縄','大分県':'九州沖縄','宮崎県':'九州沖縄','鹿児島県':'九州沖縄','沖縄県':'九州沖縄', } pop['region'] = pop['Prefecture'].map(region_map) # サンプルサイズ 2 以上の群だけ抽出 (北海道は 1 県のみで除外) groups = [g['A1101'].values for r, g in pop.groupby('region') if len(g) >= 2] group_names = [r for r, g in pop.groupby('region') if len(g) >= 2] # 群ごとの分散表 for name, g in zip(group_names, groups): print(f'{name:>6} n={len(g):>2} var(ddof=1)={g.var(ddof=1):>10.1f}') print() W, p_l = stats.levene(*groups, center='median') print(f'Levene W = {W:.3f}, p = {p_l:.4f} (center=median, Brown-Forsythe)') T, p_b = stats.bartlett(*groups) print(f'Bartlett T = {T:.3f}, p = {p_b:.4f}') |
📤 実行例:
💬 結果の読み方: 群ごとの分散が 834 (四国) から 201,705 (関東) まで 240 倍以上の差。 Levene 検定 p=0.024、 Bartlett 検定 p<0.001 でいずれも「等分散ではない」が示される。 → この後 ANOVA するなら Welch ANOVA (stats.f_oneway ではなく pingouin.welch_anova) を使うのが妥当。 t 検定なら Welch t を選ぶ。 「分散が違うときに通常の t/F を使うと第一種の過誤率が膨らむ」のがポイント。
このコードでやること: SSDSE-B-2026 の東北6県(青森・岩手・宮城・秋田・山形・福島)の食料費(千円)を使い、 数式 → 実数値代入 → Step ごとの展開 → Python 再現 → 一致確認を完全に示す。
数式(不偏分散):
$$ s^2 = \frac{1}{n-1} \sum_{i=1}^{n} (x_i - \bar{x})^2 $$
📥 入力データ(SSDSE-B-2026 東北6県 食料費 単位:千円):
東北6県食料費(千円)を Python リスト形式で表すと: [77.899, 81.997, 83.835, 78.124, 84.105, 78.984](青森・岩手・宮城・秋田・山形・福島の順)。
Step 1: 平均 x̄ を計算する
Step 2: 各偏差 (xᵢ − x̄) と偏差の二乗 (xᵢ − x̄)² を計算する
Step 3: 偏差の二乗和 Σ(xᵢ − x̄)² を求める
Step 4: 不偏分散(÷ n−1 = ÷5)と標本分散(÷ n = ÷6)を算出する
このコードでやること: 上記の手計算 Step 1〜4 を numpy で再現し、結果が完全一致することを確認する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import numpy as np # SSDSE-B-2026 東北6県 食料費(千円) x = np.array([77.899, 81.997, 83.835, 78.124, 84.105, 78.984]) # Step 1: 平均 print(f'Step1 x̄ = {x.mean():.3f}') # 80.824 # Step 2: 偏差の二乗和 ss = np.sum((x - x.mean()) ** 2) print(f'Step2 Σ(x-x̄)² = {ss:.4f}') # 40.4382 # Step 3: 不偏分散・標本分散・標準偏差 print(f'Step3 不偏分散 s² = {x.var(ddof=1):.4f}') # 8.0876 print(f'Step3 標本分散 σ̂² = {x.var(ddof=0):.4f}') # 6.7397 print(f'Step3 標準偏差 s = {x.std(ddof=1):.3f}') # 2.843 |
📤 実行例:
💬 手計算 Step 1〜4 と Python 出力が完全一致。 「食料費のばらつき」は標準偏差 ≈ 2.84 千円 — 東北各県の食料費は平均 80.8 千円から ±2.84 千円の範囲でばらついていることが分かる。
このコードでやること: numpy と pandas の分散計算(ddof=0/1 の違い)、行列の列ごと分散、共分散行列の対角成分取得を実演する。
📥 入力データ(東北6県 食料費 SSDSE-B-2026 抜粋):
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 np.random.seed(0) # 実行のたびに同じ結果が出るようにする # numpy のデフォルトは ÷n(標本分散) arr = np.array([77.90, 82.00, 83.83, 78.12, 84.11, 78.98]) print(np.var(arr)) # 標本分散(÷n) print(np.var(arr, ddof=1)) # 不偏分散(÷(n-1)) # pandas のデフォルトは ÷(n-1)(不偏分散) s = pd.Series(arr) print(s.var()) # 不偏分散 print(s.var(ddof=0)) # 標本分散 # 行列の分散(軸指定) mat = np.random.randn(100, 5) print(np.var(mat, axis=0)) # 各列の分散 # 共分散行列(分散は対角成分) cov_mat = np.cov(mat, rowvar=False) diag = np.diag(cov_mat) # 各列の分散 |
💬 numpy のデフォルト(ddof=0)と pandas のデフォルト(ddof=1)が異なる点が最重要。 東北6県データでは標本分散 6.74、不偏分散 8.09 と約 20% の差が出る(n=6 と小さいため)。
データを1個ずつ受け取る場合の安定アルゴリズム:
このコードでやること: データをオンラインで 1 個ずつ受け取りながら分散を数値安定に計算する Welford アルゴリズムの実装と動作確認。
📥 入力データ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class StreamingVariance: def __init__(self): self.n = 0 self.mean = 0.0 self.M2 = 0.0 def update(self, x): self.n += 1 delta = x - self.mean self.mean += delta / self.n delta2 = x - self.mean self.M2 += delta * delta2 def variance(self, unbiased=True): if self.n < 2: return float('nan') return self.M2 / (self.n - 1 if unbiased else self.n) # 使用例 sv = StreamingVariance() for x in [1, 2, 3, 4, 5]: sv.update(x) print(sv.variance()) # 2.5(÷(n-1)) |
💬 Welford アルゴリズムで [1,2,3,4,5] の不偏分散 2.5 が得られた(np.var([1,2,3,4,5], ddof=1) と完全一致)。 一括計算不要でメモリ効率が高く、数値的にも安定している。
numpy のデフォルトと pandas のデフォルトが違う点に注意。 ddof(delta degrees of freedom)パラメータで明示的に指定するのが安全。
分散は元の単位の二乗。 「分散 = 500千円²」は直感的でない。 解釈するときは標準偏差(√500 ≈ 22千円)に変換すべき。
2乗するため、 外れ値1個が分散を大きく押し上げます。 外れ値ありデータでは MAD(中央絶対偏差)や IQR を併用するとよい。
身長(cm)と体重(kg)の分散を直接比較するのは無意味。 変動係数 (CV = σ/μ) で無次元化するのが標準。
n=5 程度では分散の推定値は大きくブレます。 信頼区間(χ²分布ベース)を計算するか、 ブートストラップで分布を見るのが安全。
分散は単なる記述統計を超え、 推論・予測・最適化など現代統計学の中核に。
このコードでやること: numpy と pandas の var() 関数のデフォルト ddof の違いを最小例で確認する。
📥 入力データ: x = [1, 2, 3, 4, 5](不偏分散の真値 = 2.5、母分散 = 2.0)
1 2 3 4 5 6 7 | import numpy as np import pandas as pd x = np.array([1, 2, 3, 4, 5]) print('numpy.var ddof=0:', np.var(x)) # 2.0 (母分散) print('numpy.var ddof=1:', np.var(x, ddof=1)) # 2.5 (不偏分散) print('pandas .var() :', pd.Series(x).var()) # 2.5 (既定 ddof=1) print('pandas .var(ddof=0):', pd.Series(x).var(ddof=0)) # 2.0 |
💬 numpy のデフォルトは ddof=0(母分散 2.0)、pandas のデフォルトは ddof=1(不偏分散 2.5)で異なる。 ライブラリを混在させるときは必ず ddof を明示すること。
このコードでやること: SSDSE-B-2026 の総人口データで、両端 10% をトリムした頑健な分散と MAD を計算する。
📥 入力データ: df['A1101'].values/1e4(47 都道府県、万人単位)
1 2 3 4 5 6 7 8 9 10 11 12 13 | import numpy as np import pandas as pd from scipy import stats # このブロックだけで完結させる(上のブロックの df に依存しない) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年の 47 都道府県 x = df['A1101'].astype(float).values / 1e4 # 万人単位 # 両端 10% をトリムした分散 print('トリム分散 :', stats.tvar(x, limits=(np.percentile(x, 10), np.percentile(x, 90)))) print('MAD :', stats.median_abs_deviation(x)) print('MAD→SD換算:', stats.median_abs_deviation(x) * 1.4826) |
💬 通常の SD≈280 万人に対し MAD を SD 換算すると 92 万人。 東京都の外れ値が通常の分散/SD を 3 倍近くに膨らませていることが確認できる。
このコードでやること: 各都道府県の消費支出を総人口で重み付けして、全国の重み付き分散を計算する。人口の大きい県に多くの重みを置いた全国加重平均に相当する。
📥 入力データ: df['L3221'].values(消費支出)と df['A1101'].values(総人口=重み)
1 2 3 4 5 6 7 8 9 10 11 12 13 | import pandas as pd from statsmodels.stats.weightstats import DescrStatsW df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] cons = df['L3221'].astype(float).values / 1e3 # 消費支出(千円) pop = df['A1101'].astype(float).values / 1e4 # 総人口(万人、重み) ds = DescrStatsW(cons, weights=pop, ddof=1) print('重み付き平均:', round(ds.mean, 2)) print('重み付き分散:', round(ds.var, 2)) print('重み付き SD :', round(ds.std, 2)) print('単純平均 :', round(cons.mean(), 2), ' 単純分散:', round(cons.var(ddof=1), 2)) |
💬 人口加重平均 304.16 千円は単純平均 295.86 千円より高い。消費支出が多い都市部の県は人口も多いため、加重すると全国平均が上がる。重み付き分散 603.80 で「人口按分した真の全国格差」が計算できる。
このコードでやること: SSDSE-B-2026 の「総人口・65歳以上人口・消費支出」3 変数の分散共分散行列と相関行列を計算し、分散が対角成分に現れることを確認する。
📥 入力データ: df[['A1101','A1303','L3221']](47 県 × 3 変数、人口は万人・消費支出は千円に換算)
1 2 3 4 5 6 7 8 9 10 11 12 | import pandas as pd, numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] X = np.column_stack([ df['A1101'].astype(float).values / 1e4, # 総人口(万人) df['A1303'].astype(float).values / 1e4, # 65歳以上人口(万人) df['L3221'].astype(float).values / 1e3]) # 消費支出(千円) S = np.cov(X.T, ddof=1) print('分散共分散行列:'); print(np.round(S, 1)) print('相関行列 :'); print(np.round(np.corrcoef(X.T), 3)) |
💬 分散共分散行列の対角成分([0,0]=78262.9 が総人口 s²、[2,2]=582.9 が消費支出 s²)が各変数の不偏分散と一致している。相関行列は分散で標準化したもので、総人口と65歳以上人口は r=0.991 と強く相関する一方、消費支出との相関は r≈0.33 と弱い。
このコードでやること: scipy.stats.bootstrap で消費支出の分散の 95% 信頼区間を経験的に推定する。n=47 と小さいため、χ² 分布の仮定が怪しい場面でのロバストな代替手段。
📥 入力データ: df['L3221'].values(47 件、不偏分散 ≈ 582.94 千円²)
1 2 3 4 5 6 7 8 9 10 11 12 13 | import numpy as np, pandas as pd from scipy.stats import bootstrap df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] x = df['L3221'].astype(float).values / 1e3 # 消費支出(千円) def var_unbiased(a, axis=0): return np.var(a, axis=axis, ddof=1) res = bootstrap((x,), var_unbiased, n_resamples=5000, confidence_level=0.95) print(f'点推定 不偏分散 = {var_unbiased(x):.2f}') print(f'分散の 95%CI = {res.confidence_interval}') |
💬 ブートストラップ 5000 回で得た分散の 95% 信頼区間は [393, 965](千円²)。点推定 582.94 を中心に非対称に広がる。n=47 と小さいため χ² 分布前提の区間推定より頑健で、非正規データや小標本では scipy.stats.bootstrap が安全な代替手段。
このコードでやること: WelfordVariance クラスを定義し、SSDSE-B-2026(2023 年)の消費支出データを 1 件ずつ update() で逐次処理することで、一括計算と同じ不偏分散が得られることを確認する。メモリに全データを載せられないストリーミング処理に対応した数値安定アルゴリズムの実装例。
📥 入力データ: df['L3221'].values(SSDSE-B-2026、47 件、不偏分散 ≈ 582.94 千円²)
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 df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] class WelfordVariance: def __init__(self): self.n = 0 self.mean = 0.0 self.M2 = 0.0 def update(self, x): self.n += 1 delta = x - self.mean self.mean += delta / self.n self.M2 += delta * (x - self.mean) @property def variance(self): return self.M2 / (self.n - 1) if self.n > 1 else float('nan') w = WelfordVariance() for v in df['L3221'].astype(float).values / 1e3: # 消費支出(千円) w.update(v) print(round(w.variance, 2)) |
💬 WelfordVariance クラスで消費支出 47 件を逐次処理した結果 582.94 は、np.var(df['L3221']/1e3, ddof=1) = 582.94 と完全一致。ストリーミング処理でもバッチ計算と同じ精度が得られることを確認できる。
調査票や行政統計では「単純無作為標本」ではなく「層化抽出 (例: 都道府県別、 年齢層別)」を行うことが多い。 このとき「層内分散の加重平均」が真の母分散の良い推定値となる。 通常の np.var はサンプリング設計を考慮しないため、 過大評価することがある。
このコードでやること: SSDSE 47 県人口を 8 地方ブロックに層化したとみなし、 単純分散と層別分散 (= 群内分散の加重平均) を比較する。 「群間のばらつきを除いた純粋な層内ばらつき」が層別分散だ。
📥 入力データ(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 22 23 24 25 26 27 28 29 30 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) pop = (df.groupby('Prefecture')['A1101'].first() / 1e4).reset_index() region_map = {'北海道':'北海道', '青森県':'東北','岩手県':'東北','宮城県':'東北','秋田県':'東北','山形県':'東北','福島県':'東北', '茨城県':'関東','栃木県':'関東','群馬県':'関東','埼玉県':'関東','千葉県':'関東','東京都':'関東','神奈川県':'関東', '新潟県':'中部','富山県':'中部','石川県':'中部','福井県':'中部','山梨県':'中部','長野県':'中部','岐阜県':'中部','静岡県':'中部','愛知県':'中部', '三重県':'近畿','滋賀県':'近畿','京都府':'近畿','大阪府':'近畿','兵庫県':'近畿','奈良県':'近畿','和歌山県':'近畿', '鳥取県':'中国','島根県':'中国','岡山県':'中国','広島県':'中国','山口県':'中国', '徳島県':'四国','香川県':'四国','愛媛県':'四国','高知県':'四国', '福岡県':'九州沖縄','佐賀県':'九州沖縄','長崎県':'九州沖縄','熊本県':'九州沖縄','大分県':'九州沖縄','宮崎県':'九州沖縄','鹿児島県':'九州沖縄','沖縄県':'九州沖縄', } pop['region'] = pop['Prefecture'].map(region_map) simple = pop['A1101'].var(ddof=0) # 層別分散 = Σ (n_h / N) * s_h² N = len(pop) strat = 0.0 for r, sub in pop.groupby('region'): if len(sub) >= 2: strat += (len(sub)/N) * sub['A1101'].var(ddof=0) print(f'単純分散 (全 47 県を 1 群と見たとき) = {simple:.1f}') print(f'層別分散 (8 地方ブロックを層化抽出と見たとき) = {strat:.1f}') print(f'比 strat / simple = {strat/simple:.3f}') print(f'差 simple - strat (= 群間分散 / N) = {simple - strat:.1f}') |
📤 実行例:
💬 結果の読み方: 層別分散は単純分散の約 63 %。 つまり「地方ブロックで層化すると、 群間分散 (28472) を除いた純粋な層内ばらつきだけが残る」。 サンプリング設計上、 層化抽出を行うと推定値の分散が小さくなり、 同じ精度を少ないサンプル数で達成できる (層化抽出の効率性)。 これは社会調査・市場調査でしばしば「層別抽出の標本サイズ計算」として用いられる重要な計算だ。
「分散」と一口に言っても、 母分散 / 標本分散 / 不偏分散 / 群内・群間分散 と多義語的に使われる。 ここでは 分散の本質と現場での使い分け を 5 問で確認する。
解答の要点(自己採点用)
🛠 5 分でできる自分で確かめる課題
SSDSE-B-2026 の「消費支出(二人以上の世帯)」を 47 都道府県分とりだし、 (1) NumPy np.var(x, ddof=0) と np.var(x, ddof=1) の差を計算、 (2) 8 地方ブロックでグループ化した groupby().var() を表示、 (3) 層内分散の平均と層間分散を計算し、 全体分散 ≈ その合計になることを確認してみよう。 数式の分散分解が 実データで成立する ことを体感できる。
numpy.var() の既定は ddof=0(母分散)、 pandas Series.var() の既定は ddof=1(不偏分散)と、 主要ライブラリでデフォルト値が違う。 これに気づかず numpy と pandas を混在させると、 nが小さいデータで結果が 5〜10% 単位でズレる。 学術論文や検定で使うのは「サンプルから母数を推定する」目的なので ddof=1(n-1 で割る)が正しい。 必ず明示する習慣をつけ、 既定任せにしない。
「身長(cm)」の分散は cm² であり、 元データと単位が違う。 そのため分散の絶対値は直感的に解釈しにくく、 報告は標準偏差(SD = √分散、 単位は元と同じ)で行うのが原則。 「年収のばらつきが分散 1.2 × 10⁹ 円²」と書くより「SD ≈ 35,000 円」の方がずっと意味が分かる。 査読でも SD で報告するよう要求されることが多い。
分散は偏差を二乗するため、 外れ値 1 個で大きく動く。 47 都道府県で東京を含めると総人口の SD が約 280 万人、 外すと約 224 万人、 と大きく変わる。 ロバストな散布度として IQR(四分位範囲)、 MAD(中央絶対偏差)が代替に使える。 MAD = median(|x - median(x)|) を SD に変換するなら ×1.4826(正規分布前提)。 外れ値の処理を明示せずに分散を比較しない。
「Var(X+Y) = Var(X) + Var(Y)」は X と Y が独立(または無相関)のときだけ成立。 相関がある場合は Var(X+Y) = Var(X) + Var(Y) + 2·Cov(X,Y) が正しい。 共分散項を忘れて足し算するとポートフォリオのリスクを誤算する。 SSDSE データでも「15歳未満人口 + 65歳以上人口」は強い正の相関を持ち、 共分散項を無視した単純加算では合わない。 リスク管理・ファイナンスでは共分散項が本質。
分散はデータのばらつきを測るが、 推定量の精度を測るのは「標準誤差(SE = SD/√n)」。 SE = SD ではない。 サンプルサイズ n を増やせば SE は √n に反比例して下がるが、 SD(母集団の真のばらつき)は変わらない。 「分散が大きい / 小さい」と「推定が不確実 / 確実」は別概念で、 両者を混同するのは初学者の典型ミス。
「総人口の分散」と「失業率の分散」を直接比較しても意味がない(単位が違う)。 単位無次元の比較には変動係数 CV = SD/Mean を使う。 ただし平均が 0 に近い変数(収益率など)では CV が爆発するので、 z-スコア化(標準化)して比較するか、 ロバストな統計(中央値・MAD)を使う方が安全。 PCA や Lasso 等の機械学習でスケーリングが必須なのも同じ理由。
分散 がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 統計・データサイエンス › 記述統計 › ばらつき › 分散
「分散」を中心に、前提・派生・応用の手法系譜を静的 SVG で示す。
中心に 分散 を置き、 そこから 平均・標準偏差・共分散・R²・PCA・相関係数 など 計 14 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語とあとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。
大きな円が小さな円を包含する Circle Packing 図。 「分散」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「分散」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは 分散 の隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス → ばらつき → 分散 という入れ子の位置を示します。 「ばらつきには他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。
「分散」は単独で完結する指標ではなく、 隣接する手法・概念と連携することで真価を発揮する。
| 方向 | 手法・概念 | 接続の意味 |
|---|---|---|
| 前提 (上流) | 平均値・代表値 | 分散の計算には平均 x̄ が必要。 平均を理解していないと偏差の意味が取れない。 |
| 並列 (横) | 標準偏差・IQR・MAD | 同じ「散布度」ファミリー。 分散は 2乗単位で数学的扱いやすさ最優先。 外れ値に頑健にしたいなら IQR・MAD を使う。 |
| 発展 (下流) | 標準偏差 = √分散 | 単位を元に戻すだけで直感的になる。 報告・可視化では標準偏差が標準形式。 |
| 応用1 | 共分散・相関係数 | 「2変数の分散の掛け算」が共分散。 それを各変数の標準偏差で割ると相関係数 r ∈ [−1,1] になる。 |
| 応用2 | 分散分析 ANOVA | 全分散を群内・群間に分解して F 比を計算。 「分散の分解」がアルゴリズムの核。 |
| 応用3 | 主成分分析 PCA | 「分散を最大化する方向」を逐次的に求める次元削減手法。 分散が「情報量」として直接使われる。 |
| 応用4 | バイアス・バリアンス分解 | モデル予測誤差の「Variance」成分 = モデルが学習データに依存してぶれる度合い。 過学習の定量指標。 |
| 応用5 | R²(決定係数) | R² = 1 − 残差分散/全分散。 回帰モデルが「全分散のうち何割を説明したか」を示す。 |
| 応用6 | 標準化(z-スコア) | 「(値 − 平均) / 標準偏差」で平均0・分散1に変換する前処理。 機械学習のスケール問題を解決する。 |
💡 分散を起点にすると「相関 → 回帰 → PCA → ANOVA → 機械学習」という統計学の大きな流れが1本の糸で繋がる。 分散こそが現代統計の基礎概念と言える。
「データのばらつきを測りたい」という状況で何を選ぶかを、 条件ごとに整理する。
| 状況・条件 | 推奨手法 | 理由 |
|---|---|---|
| 正規分布に近い連続データ、 外れ値なし | 標準偏差(不偏分散の√) | 単位が元データと同じで直感的。 最も普及している報告形式 |
| 外れ値が含まれる、 歪んだ分布 | IQR または MAD | 分散は偏差を2乗するため外れ値に過敏。 IQR・MAD は中央値ベースで頑健 |
| 単位の異なる複数変数を比較 | 変動係数 CV = σ/μ | 無次元化された相対的ばらつき。 「人口」と「失業率」の散布度を同じ軸で比較できる |
| 母集団の分散を標本から推定する(推論統計) | 不偏分散(ddof=1) | ÷n だと系統的に過小評価(バイアス)。 ÷(n-1) で不偏推定量になる |
| 標本そのものを要約する(記述統計) | 標本分散(ddof=0) | 集めたデータそのものの散布度を示す。 機械学習の最尤推定もこちら |
| グループ間のばらつきと群内のばらつきを分離 | ANOVA(分散分解) | 全分散 = 群間 + 群内 の分解。 F 検定で「群差は有意か」を判断 |
| 複数変数間のばらつきの相互関係も知りたい | 分散共分散行列 | 対角成分が各変数の分散、 非対角成分が共分散。 PCA の入力行列 |
| 大量データのストリーミング処理で分散を計算 | Welford アルゴリズム | 1 パスで数値安定に分散を更新できる。 一括計算より桁落ちに強い |
| 分散の信頼区間を求めたい(n が小さい) | χ² 分布 または ブートストラップ | 正規分布前提なら (n-1)s²/σ² が χ²(n-1) に従う。 非正規ならブートストラップが安全 |
💡 実務の鉄則: 報告書・論文では「分散」ではなく「平均 ± SD(標準偏差)」の形で示す。 外れ値があるなら「中央値 (IQR)」に切り替える。 単位が異なる変数を比べるなら CV。 この3つを使い分けるだけで散布度の表現力が格段に上がる。
ここまでのセクションは分散の定義と解釈(偏差二乗の平均・n−1・外れ値感度)を扱った。 この追補では角度を変えて、 恒等式「二乗の平均 − 平均の二乗」を軸に、 分散をコンピュータで実際に計算するときに何が起きるかを SSDSE-B-2026 の実測値で確かめる。 群間・群内の分解やσ収束は 散布度、 68-95-99.7 則やチェビシェフの不等式は 標準偏差 のページで扱っているため、 ここでは重複させない。
計算用の別形式 $$ s^2_n = \overline{x^2} - \bar{x}^2 $$ を、 「式変形の結果」ではなく意味として読んでみる。 二乗の平均 $\overline{x^2}$ には「データの大きさ(水準)」と「ばらつき」の両方が混ざっている。 そこから水準だけの成分 $\bar{x}^2$ を差し引くと、 純粋な「ばらつき」が残る——これが分散。
実測(SSDSE-B-2026、 2023 年・47 都道府県、 消費支出 L3221〔二人以上の世帯・円〕):
| 量 | 値(実測) | 読み方 |
|---|---|---|
| 平均 $\bar{x}$ | 295,856.0 円 | 水準(最大: 埼玉県 344,092 円、 最小: 愛媛県 223,423 円) |
| 二乗の平均 $\overline{x^2}$ | 88,101,317,933 円² | 水準+ばらつきの混合 |
| 平均の二乗 $\bar{x}^2$ | 87,530,785,326 円² | 水準だけの成分 |
| 差=母分散 $s^2_n$ | 570,532,607 円² | 純粋なばらつき(不偏分散 s² = 582,935,490 円²、 SD ≈ 24,144 円) |
注目すべきは比率:ばらつき成分は $\overline{x^2}$ のわずか 0.65% しかない。 つまり「二乗の平均」の 99.3% 以上は平均(水準)の寄与で、 分散は巨大な 2 つの数のごく僅かな差として得られている。 この構造が、 次の「落とし穴」の伏線になる。
「二乗の平均 − 平均の二乗」は 1 パスで計算できて便利だが、 上で見たとおりほぼ等しい巨大な数同士の引き算である。 浮動小数点では、 近い数を引くと上位の桁が打ち消し合い有効桁が失われる(桁落ち・catastrophic cancellation)。
var() が 2 パス相当で実装されているのは、 まさにこの罠を避けるため。💡 教訓:数式として等価でも計算手順として等価とは限らない。 ショートカット公式は「手計算・厳密計算」用、 コンピュータでは定義式(2 パス)か次の Welford 法を使う。
「2 パスは安定だがデータを 2 回読む必要がある。 ストリーミングでは 1 回しか読めない」——この両立を解くのが Welford のアルゴリズム(1962)。 平均 m と偏差平方和 M2 を 1 件ずつ更新する:
実測: 消費支出 L3221 の 47 件を Welford 法で 1 パス処理すると不偏分散 582,935,490.2 円²—— numpy.var(ddof=1) と完全に一致する。 巨大な数同士の引き算が現れないため桁落ちが起きない。