サンプルサイズと検出力に関する主要概念チップ集。
🍰 まずはやさしく
データの個数のことです。
分析の正確さを決めるために使います。
アンケートに答えた人の数のようなものです。
個数を増やすと精度が上がる仕組みを読みます。
サンプルサイズ n は 「データの個数」 です。 47都道府県データなら n=47、 1000人のアンケートなら n=1000。 単純な数字ですが、 n は分析結果の精度・検出力・解釈の全てを支配する重要パラメータです。
n の効果:n が大きいほど、 (i) 推定値のばらつき(標準誤差)が小さくなる、 (ii) 信頼区間が狭くなる、 (iii) 検定の検出力(小さな効果も発見できる確率)が上がる。 $\sqrt{n}$ 則:標準誤差は $1/\sqrt{n}$ で減るので、 精度を2倍にしたければ n を4倍にする必要がある。
n が小さすぎる弊害:(i) 検定の検出力不足で「効果あり」を見逃す、 (ii) 推定値が不安定で再現できない、 (iii) 外れ値の影響を受けやすい。
n が大きすぎる弊害:(i) 実用上無視できる小さな差でも p<0.001 になり、 「有意」が氾濫する、 (ii) 計算コストが上がる。
都道府県データ n=47 は中規模。 重回帰では n ≥ 10×(説明変数の数) が経験則なので、 n=47 だと説明変数は4〜5個までが目安。 多変量分析(PCA、 クラスタリング)も実行可能だが、 結果の安定性に注意。
🍰 まずはやさしく
データの数を示す数字です。
結果がどれくらい信頼できるか判断します。
都道府県の数でデータを集めるような例です。
計画を立てる時に気をつける点を確認します。
論文の冒頭で「n = 47(47都道府県)」と書かれる数字。 ほぼ全ての統計量の信頼性を左右する基本要素。
サンプルサイズ とは:観測したデータの個数。nが大きいほど統計量の精度が上がり、小さな効果でも有意になりやすい。
📌 このチェックリストは 研究計画書 (study protocol) や 事前登録の必須項目とほぼ同じ。 サンプルサイズ設計を済ませることが、 そのまま「再現性の高い研究」になる。
📌 教材としては 戦略 A + B の組み合わせが安全。 「47 サンプルだから何でもできる」ではなく「何ができて何ができないか」を理解させるのが、 実践的な統計教育。
🍰 まずはやさしく
データの量というイメージです。
結果のばらつきを抑えるために使います。
少人数の意見より大人数の意見の方が安定します。
量が増えると結果がどう変わるかを見ます。

| 指標 | 小 | 中 | 大 | 実例 |
|---|---|---|---|---|
| Cohen's d (平均差) | 0.2 | 0.5 | 0.8 | 男女の身長差 d≈1.5 |
| 相関係数 r | 0.10 | 0.30 | 0.50 | SSDSE 人口 vs 出生数 r≈0.99 |
| $\eta^2$ (分散説明率) | 0.01 | 0.06 | 0.14 | 教育水準 vs 学習時間 η²≈0.10 |
| Cohen's w (χ²) | 0.10 | 0.30 | 0.50 | アンケート集計の偏り |
| オッズ比 OR | 1.5 | 2.5 | 4.3 | 疫学・症例対照研究 |
📌 「効果量」は事前に決めるべきで、 後から「結果を見て」決めるのは循環論法。 過去研究のメタ解析や予備実験で見積もる。
🍰 まずはやさしく
数式で表したデータの個数です。
必要なデータの数を計算するために使います。
部活の平均点などを正確に出したい時に役立ちます。
精度と個数の関係を数式で詳しく読みます。
サンプルサイズは 4 つの量が相互依存する。 3 つ決めれば残り 1 つが決まる。
| 量 | 意味 | 典型値 |
|---|---|---|
| $\alpha$(有意水準) | 第 1 種の過誤率(FP) | 0.05 |
| $1 - \beta$(検出力) | 真に差があるとき発見する確率 | 0.80 |
| $\delta$ or $d$(効果量) | 検出したい差の大きさ | 小 0.2 / 中 0.5 / 大 0.8 (Cohen) |
| $n$(サンプルサイズ) | 必要観測数 | これを求める |
母集団サイズ $N$ が有限で、 標本抽出率 $n/N$ が無視できないとき(典型的に $n/N \ge 0.05$)、 標準誤差を補正する:
$$ \mathrm{SE}_{\mathrm{FPC}} = \frac{\sigma}{\sqrt{n}} \cdot \sqrt{\frac{N - n}{N - 1}} $$📌 例:N=1741 市区町村のうち n=200 を抽出する場合、 FPC 因子 = √((1741-200)/(1741-1)) = √0.886 ≈ 0.941。 SE は 5.9% 小さくなる。
統計検定と機械学習では n の感覚が違う。 経験則を表にまとめる:
| 手法 | 最低 n | 推奨 n | 注意 |
|---|---|---|---|
| 線形回帰 (k 変数) | 10k | 20k | 条件指数も確認 |
| ロジスティック回帰 | 10k / 少数クラス | 20k / 少数クラス | EPV (events per variable) |
| 決定木 / RF | 数百 | 数千〜 | 木の深さで調整可能 |
| XGBoost / LightGBM | 1k | 数万〜 | 早期終了 + 正則化 |
| SVM | 数百 | 数千 | 大データで遅い |
| 深層学習 (画像) | 数千 | 数十万〜 | 転移学習で削減可 |
| LLM ファインチューン | 数百 | 数千〜 | LoRA で更に削減可 |
| PCA / 因子分析 | 100 | 300+ | KMO 検定で適性確認 |
📌 SSDSE-B-2026 (n=47) は 線形回帰の k≤4、 ロジスティック回帰の少数クラス k≤2、 決定木は深さ≤3 が現実的。 ランダムフォレストは min_samples_leaf を大きく取って過学習防止。
95% 信頼区間の半幅 (margin of error, MOE) は:
$$ \mathrm{MOE} = z_{0.975} \cdot \frac{\sigma}{\sqrt{n}} = 1.96 \cdot \frac{\sigma}{\sqrt{n}} $$逆に、 MOE を目標値 $m$ にする必要 n は:
$$ n = \left(\frac{1.96 \, \sigma}{m}\right)^2 $$SSDSE-B-2026 の人口平均で MOE 別の必要 n($\sigma$=2,797,551 固定):
💬 47 県データの実 MOE は 1.96 × 408,065 ≈ ± 80 万人。 これで「平均 264 万人 ± 80 万」と推定するイメージ。 もっと狭い CI(±10 万人)が欲しければ n=3,000 必要 → 都道府県より細かい単位(市区町村)で検討。
スライダーやドラッグで サンプルサイズ n を動かすと、 標準誤差 $\sigma/\sqrt{n}$ と 95% 信頼区間の幅がどう縮むかがリアルタイムに変わります。 グラフを直接ドラッグ(マウス/指)しても n を変えられます。 「n を 4 倍にすると誤差は半分」という 平方根の逓減を体感してください。
n を 4 倍にすると…
許容誤差を半分にすると必要 n は 4 倍に。
上の逆算は「推定の精度(CI 幅)」からの n。 一方 検定の設計では、 有意水準 $\alpha$・検出力 $1-\beta$・効果量 $d$ の 3 つを決めて n を逆算する 検出力分析を使う(2 群平均差なら $n_\text{group}=2(z_{1-\alpha/2}+z_{1-\beta})^2/d^2$)。 詳しくは 検出力・検定力分析・効果量・有意水準 の各ページへ。 精度側の帰結は 標準誤差・信頼区間 を参照。
数式の記号・要素を言葉で説明する。
前節の数式に含まれる記号を、 日本語の意味に翻訳する。
sample size の数式は、 これらの記号を組み合わせて「データから未知量を推定する」あるいは「データの構造を要約する」プロセスを記述している。
SSDSE-B-2026 は 47都道府県 = n=47 の典型的な「小〜中規模パネル」。 サンプルサイズに関連する具体計算を実行します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from statsmodels.stats.power import TTestIndPower analysis = TTestIndPower() # 必要なサンプルサイズを計算 n_required = analysis.solve_power( effect_size=0.5, # 中程度の効果量(Cohen's d) alpha=0.05, power=0.80, ratio=1.0 # 2群が同じサイズ ) print(f'各群に必要なサンプルサイズ: {n_required:.0f}') # 与えられたnでの検出力 power = analysis.solve_power( effect_size=0.3, nobs1=50, alpha=0.05) print(f'検出力: {power:.3f}') |
47 都道府県は「標本」というより全国データの「母集団」に近いが、 統計的推論を行う場合の必要 n と現状 47 の比較は学習素材として有益。
「来年の平均人口が今年と 10%(=$\delta$)以上変わったか」を $\alpha=0.05$, power=0.8 で検出するための n:
💬 「47 都道府県」では 10% 差を統計的に検出するのは厳しい。 逆に、 47 県で検出できる効果量を逆算してみる:
サンプルサイズ設計の王道は「事後 (集めてから検出力を語る)」ではなく 事前 (検出したい効果量と検出力を決めて N を逆算する)。 これを power analysis と呼ぶ。 必要なのは 4 つの数値: (1) 効果量 $d$、 (2) 有意水準 $\alpha$、 (3) 検出力 $1-\beta$、 (4) 検定の片側 / 両側。 SSDSE-B-2026 で「東日本 vs 西日本の出生数平均に差があるか」を 5% 水準で 80% の検出力で見つけたい場合、 d=0.8 (large) なら n=26 per group で足りるが、 d=0.3 (small) では n=176 per group が必要 ── つまり 47 県では検出不能。
数式を言葉で読み解く: Cohen の d は $d = \dfrac{\bar{x}_1 - \bar{x}_2}{s_{\text{pooled}}}$ ── 群間の差を プールされた標準偏差で割って正規化した量。 d=0.2 が「小」、 0.5 が「中」、 0.8 が「大」(Cohen 1988)。 必要 N の近似式は $n \approx \dfrac{2(z_{1-\alpha/2}+z_{1-\beta})^2}{d^2}$ ── 効果量の二乗に 反比例するため、 検出したい差が半分になると必要 N は 4 倍に膨らむ。
| Cohen d | 解釈 | 必要 N (per group, α=0.05 両側, 1-β=0.8) | SSDSE-B (n=47/2≈24) で検出可能? |
|---|---|---|---|
| 0.2 | small | 394 | × (不可能) |
| 0.3 | small-medium | 176 | × |
| 0.5 | medium | 64 | × |
| 0.8 | large | 26 | ○ (やっと検出可能) |
| 1.2 | very large | 12 | ◎ |
🎯 このコードでやること: SSDSE-B-2026 の「東日本 (n=22) vs 西日本 (n=25)」の出生数 (A4101) で実際の Cohen d を計算し、 statsmodels.stats.power.TTestIndPower で逆算した「必要 N」を比較する。
📥 入力: SSDSE-B-2026 47 行 (2023 年度) と「東日本 = 北海道〜静岡 (Code ≤ R22100, 22 県)」分類フラグ。
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 from statsmodels.stats.power import TTestIndPower df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 東日本 = 都道府県コード R22100(静岡)以下の 22 県 df['region'] = np.where(df['Code'] <= 'R22100', 'east', 'west') east = df[df.region=='east']['A4101'].values west = df[df.region=='west']['A4101'].values pooled_sd = np.sqrt(((len(east)-1)*east.var(ddof=1) + (len(west)-1)*west.var(ddof=1)) / (len(east)+len(west)-2)) d = (east.mean() - west.mean()) / pooled_sd print(f"観測された Cohen d = {d:.3f}") analysis = TTestIndPower() n_required = analysis.solve_power(effect_size=abs(d), alpha=0.05, power=0.8, alternative='two-sided') power_now = analysis.power(effect_size=abs(d), nobs1=len(east), alpha=0.05, ratio=len(west)/len(east), alternative='two-sided') print(f"必要 N per group = {n_required:.1f}, 現在の検出力 = {power_now:.3f}") |
📤 実行結果:
💬 結果の読み方: d=0.253 (small) を α=0.05 / 1-β=0.8 で検出するには 1 群あたり約 247 県が必要。 SSDSE-B では各群 22/25 県しかなく 検出力は 0.135 ── 「差が無い」のではなく 「差を検出できる体力が無い」状態。 結論を出すには (a) 市区町村レベルに細分化、 (b) 複数年度をプール、 (c) 「効果が大きいなら見える」と限定的に解釈、 のいずれかが必要。 これが 「事前 power analysis を回さずに t 検定を打つ」のが危険な理由。
SSDSE-B-2026 の県別データで「サンプルサイズと検出力」 の関係を可視化し、 学習者がポイントを再確認できる理解度チェックを追加する。
→ sample_size_power.png は効果量 d=0.2/0.5/0.8 のときの N と検出力 (1−β) の関係。 効果量が小さいほど必要 N が急増することが見て取れる。 d=0.2 なら N≈400、 d=0.5 なら N≈64、 d=0.8 なら N≈26 が 80% 検出力に必要。

→ significance_power.png は α (有意水準) と β (第2種の誤り) のトレードオフ。 α を厳しくすると検出力が落ち、 検出力を上げるには N を増やすしかない。 この三角関係 (α, β, N, d) のうち 3 つを固定すれば残り 1 つが決まる ── これが power analysis の核心。

💬 SSDSE-B-2026 で「県別の差」 を語るときには、 α, β, d, N の 4 つを必ず明示 する習慣をつけたい。 これが 仮説検定 を「結論」 でなく「証拠の強度」 として正しく扱う基礎となる。
SSDSE-B-2026 から「全国の有業者率」を許容誤差 3% で推定する世論調査設計を想定し、 必要サンプルサイズ n を計算する。
1 2 3 4 5 6 | import math z = 1.96 p = 0.5 e = 0.03 n = z**2 * p * (1-p) / e**2 print(f"n = {math.ceil(n)}") |
💬 手計算 (Step 2) ≈1067 と Python 出力が一致。
🎯 このコードでやること:statsmodels.stats.power で 2 群 t 検定の必要 n を、 効果量・α・power を変えながら計算する。 SSDSE-B-2026 の実際の σ も使う。
📥 入力データ: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 | import pandas as pd import numpy as np from statsmodels.stats.power import TTestIndPower df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) pop23 = df[df['SSDSE-B-2026']==2023]['A1101'].astype(float) sigma = pop23.std(ddof=1) mean = pop23.mean() print(f'σ = {sigma:,.0f}') print(f'μ = {mean:,.0f}') # 効果量 d を変えながら必要 n ap = TTestIndPower() rows = [] for d in [0.2, 0.3, 0.5, 0.8, 1.0]: n = ap.solve_power(effect_size=d, alpha=0.05, power=0.8) rows.append({'d': d, 'n_per_group': round(n, 1), 'total_n': round(n*2, 1)}) print(pd.DataFrame(rows).to_string(index=False)) # n=47 のとき検出できる効果量 d47 = ap.solve_power(effect_size=None, alpha=0.05, power=0.8, nobs1=47) print('-' * 40) print(f'n=47 で power=0.8 を満たす最小 d = {d47:.3f}') print(f' これは絶対差 ≈ {d47*sigma:,.0f} 人 (= {d47*sigma/mean*100:.1f}% of mean)') # n=47 で d=0.3 だと power はいくら? p47 = ap.solve_power(effect_size=0.3, alpha=0.05, nobs1=47) print(f'n=47, d=0.3 のときの power = {p47:.3f}') |
📤 実行結果:
💬 n=47 で d=0.3 の検出力は 30%。 真に効果があっても 70% 見逃す。 「中効果量を確実に拾う」には d=0.5 で n=64/群、 計 128 必要。 SSDSE-B-2026 47 県は「中央値・回帰係数の点推定」には十分だが、 「小〜中の差の検出」には市区町村レベル(n=1741)への展開を検討すべき。
🎯 このコードでやること:横軸 n、 縦軸 power の曲線を 3 つの効果量(d=0.2, 0.5, 0.8)で重ねて描く。 SSDSE-B-2026 の n=47 線を引いて、 現状の検出力を視覚的に確認。
📥 入力データ:効果量 d の配列と n の配列だけ(実データ不要、 解析的計算)。
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 | import numpy as np import matplotlib.pyplot as plt from statsmodels.stats.power import TTestIndPower ap = TTestIndPower() n_grid = np.arange(5, 300, 5) ds = [0.2, 0.5, 0.8] plt.figure(figsize=(8, 5)) for d in ds: pw = [ap.solve_power(effect_size=d, alpha=0.05, nobs1=n) for n in n_grid] plt.plot(n_grid, pw, label=f'd={d}') plt.axvline(47, color='red', linestyle='--', label='SSDSE-B-2026 n=47') plt.axhline(0.8, color='gray', linestyle=':', label='target power = 0.8') plt.xlabel('Sample size per group n') plt.ylabel('Statistical power (1 - β)') plt.title('Power curve (α = 0.05, 2-sample t-test)') plt.legend() plt.grid(alpha=0.3) plt.tight_layout() plt.savefig('power_curve.png', dpi=110) # 47 における各 d の power for d in ds: pw47 = ap.solve_power(effect_size=d, alpha=0.05, nobs1=47) print(f'n=47, d={d}: power = {pw47:.3f}') |
📤 実行結果:
💬 SSDSE-B-2026 (n=47) は 大効果量 (d=0.8) なら 97% 検出、 中 (d=0.5) で 67%、 小 (d=0.2) で 16% しか発見できない。 power curve はこの「足りない領域」を一目で示せる、 研究計画書に必須の図。
🎯 このコードでやること:相関係数の有意性を検出するための必要 n を、 Fisher z 変換ベースの公式で求める。 SSDSE-B-2026 で観測された強相関 r=0.99 は n=47 で十分か検証。
📥 入力データ:SSDSE-B-2026 から総人口(A1101)と出生数(A4101)の相関を実測。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import numpy as np import pandas as pd from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023] pop = d23['A1101'].astype(float) births = d23['A4101'].astype(float) r, p = stats.pearsonr(pop, births) print(f'r = {r:.4f} p = {p:.4g}') # 任意の r を α=0.05, power=0.8 で検出する必要 n def n_for_correlation(r_target, alpha=0.05, power=0.8): z_a = stats.norm.ppf(1 - alpha/2) z_b = stats.norm.ppf(power) z_r = 0.5 * np.log((1 + r_target) / (1 - r_target)) return ((z_a + z_b) / z_r) ** 2 + 3 for r0 in [0.10, 0.20, 0.30, 0.50, 0.70, 0.97]: n = n_for_correlation(r0) print(f'r = {r0:.2f} → 必要 n ≈ {n:6.1f}') |
📤 実行結果:
💬 SSDSE-B-2026 の総人口×出生数の相関 r=0.995 は p=1.5e-47 と圧倒的有意。 これほど強い相関なら n=5 でも検出可能(必要 n≈4.8)。 逆に「小相関 r=0.1」を確実に検出するには n=783 必要。 「47 県で多変量分析する」のは強い構造があれば成立、 微妙な効果には不適。
🎯 このコードでやること:「現状 CTR 5%、 新施策で 6% に上がるか?」を α=0.05, power=0.8 で検出するための n を、 statsmodels の比率差検出力で計算する。 実務のグロース施策設計でよく使う。
📥 入力データ:仮想の現状 CTR と新施策 CTR の対。 SSDSE は入力に使わないが、 SSDSE 規模との比較に使う。
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 | import pandas as pd from statsmodels.stats.proportion import proportion_effectsize from statsmodels.stats.power import NormalIndPower def n_for_ab(p1, p2, alpha=0.05, power=0.8): es = proportion_effectsize(p1, p2) # Cohen's h ap = NormalIndPower() return ap.solve_power(effect_size=es, alpha=alpha, power=power) scenarios = [ (0.05, 0.06), # +1pp lift on low CTR (0.10, 0.12), (0.20, 0.25), (0.50, 0.55), ] rows = [] for p1, p2 in scenarios: n = n_for_ab(p1, p2) rows.append({ 'p_control': p1, 'p_treat': p2, 'lift_pp': round((p2-p1)*100, 1), 'h_cohen': round(proportion_effectsize(p1, p2), 3), 'n_per_arm': round(n, 0), }) print(pd.DataFrame(rows).to_string(index=False)) |
📤 実行結果:
💬 「CTR 5%→6%」を確実に検出するには 8,143/群 = 16,286 必要。 SSDSE n=47 とは桁が 2 つ違う。 A/B テストは「桁違いの n を 1 日で集められる Web 計測の世界だから成立する」。 「割合差 5pp(0.20→0.25、 n=1,092)」より「絶対差は同じだが基底値 0.5(0.50→0.55、 n=1,565)」の方が n が多く必要になるのは、 二項分布の分散 $p(1-p)$ が p=0.5 でピークを取り、 ばらつきが最大になるため。
🎯 このコードでやること:「n=47 で標本平均はどれくらいバラつくか」をブートストラップで実測し、 $\sigma/\sqrt{n}$ の理論値と比較する。 理論と実測の一致を可視化。
📥 入力データ:SSDSE-B-2026 2023 年の 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 31 32 | import numpy as np import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) pop = df[df['SSDSE-B-2026']==2023]['A1101'].astype(float).values # 理論値 sigma = pop.std(ddof=1) se_theory = sigma / np.sqrt(len(pop)) print(f'n = {len(pop)}') print(f'σ = {sigma:,.0f}') print(f'SE (理論) = σ/√n = {se_theory:,.0f}') # ブートストラップで実測 rng = np.random.default_rng(0) B = 10_000 boot_means = np.array([ rng.choice(pop, size=len(pop), replace=True).mean() for _ in range(B) ]) se_boot = boot_means.std(ddof=1) print(f'SE (ブート) = {se_boot:,.0f}') print(f'差 = {abs(se_theory-se_boot)/se_theory*100:.2f}%') # 95% CI ci_low, ci_high = np.percentile(boot_means, [2.5, 97.5]) print(f'平均の 95%CI = [{ci_low:,.0f}, {ci_high:,.0f}]') # n を仮に大きくしたときの SE for n_new in [47, 100, 500, 1000, 5000]: print(f'n={n_new:5d}: SE = {sigma/np.sqrt(n_new):,.0f}') |
📤 実行結果:
💬 ブートストラップ実測 SE (40.2 万) と理論 SE (40.8 万) はほぼ一致 (1.6% 差)。 $\sigma/\sqrt{n}$ 公式が n=47 の小標本でも正確に動く確認。 n を 100 倍にすると SE は 1/10 になる($\sqrt{n}$ 則)。 95% CI [1.93M, 3.52M] は意外と広い ─ 47 県の点推定が指し示す精度の限界。
🎯 このコードでやること:説明変数の数 k を増やしながら回帰係数の安定性を見る。 SSDSE-B-2026 の 47 県データで「10×k ルール」がなぜ必要かを実証。
📥 入力データ:SSDSE-B-2026 (2023 年, 47 行) から k=2,4,6,8,10 個の特徴を選び、 ブートストラップで係数の標準誤差を測る。
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 34 35 36 | import numpy as np import pandas as pd from sklearn.linear_model import LinearRegression from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023].copy() y = d23['A1101'].astype(float).values # 総人口 # 候補特徴 feat_cols = ['G7101', 'F3101', 'A1301', 'A1302', 'A4101', 'A5101', 'E1101', 'E2101', 'B4101', 'B4102'] rng = np.random.default_rng(0) rows = [] for k in [2, 4, 6, 8, 10]: cols = feat_cols[:k] X = StandardScaler().fit_transform( d23[cols].astype(float).values ) # ブートストラップ 500 回、 係数の SD coefs = [] for _ in range(500): idx = rng.choice(len(X), size=len(X), replace=True) coefs.append(LinearRegression().fit(X[idx], y[idx]).coef_) coefs = np.array(coefs) sd_mean = coefs.std(0).mean() rows.append({ 'k': k, '10k_rule_n': 10*k, '満たすか': '✅' if len(X) >= 10*k else '❌', '係数 SD 平均': f'{sd_mean:,.0f}', }) print(pd.DataFrame(rows).to_string(index=False)) |
📤 実行結果:
💬 「10×k ルール」は n ≥ 10×(説明変数の数) を満たすかの目安。 47 県では k≤4 なら満たす(47≥40)が、 k≥6 では満たさない(満たすか列の ❌)。 SSDSE で重回帰するならk ≤ 4が目安。
📝 より正確な分析:上のコードを同一 seed で実測すると、 係数 SD 平均は k=2 の 418,403 が最大で、 k=10 では 167,515 とむしろ低下し、 k に対して単調増加はしない。 これは「係数 SD 平均」が全係数の SD を平均した指標で、 標準化後も各説明変数のスケールや目的変数との関係の強弱に左右されるうえ、 平均操作でばらつきが均されるためである。 10×k ルールが警告する真の危険(少数サンプルでの係数の不安定化・過学習)は、 このように平均した一指標の単調な上昇としては必ずしも現れず、 個々の係数の分散や検証データでの再現性に現れる。 したがって 10×k は絶対基準ではなく目安として扱い、 安定性はブートストラップや交差検証で都度検証するのが妥当(数値はデータ・seed に依存し変動する)。
🎯 このコードでやること:不均衡な二値分類の必要 n を、 少数クラス側の event 数で計算する。 SSDSE-B-2026 で「人口 500 万以上の県」を分類するなら陽性は何件か、 そして k 変数の予測モデルに何 n 必要かを示す。
📥 入力データ: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 22 23 24 25 26 27 28 29 30 31 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023] pop = d23['A1101'].astype(float) # 二値分類:人口 ≥ 500万 を 1 y = (pop >= 5_000_000).astype(int) n_pos = int(y.sum()) n_neg = int((1 - y).sum()) print(f'全体 n = {len(y)}') print(f'陽性 (人口 ≥ 500 万) = {n_pos}') print(f'陰性 (人口 < 500 万) = {n_neg}') print(f'陽性率 = {n_pos/len(y)*100:.1f}%') # EPV (events per variable) ルール:少数側 ≥ 10×k print('-' * 40) for k in [1, 2, 3, 4, 5]: enough = n_pos >= 10 * k msg = '✅ OK' if enough else f'❌ 不足 (要 {10*k}, 実 {n_pos})' print(f'k={k} 変数モデル: {msg}') # 何件あれば k=5 を 10×k で支えられるか? need_pos = 10 * 5 need_total = need_pos / (n_pos/len(y)) print('-' * 40) print(f'k=5 を支えるなら陽性 {need_pos} 件 → ' f'全体 ≈ {need_total:.0f} 件必要') print(' → 都道府県(47)では到底不足、 市区町村 (n=1741) なら可能') |
📤 実行結果:
💬 SSDSE 47 県の「500 万以上」は 9 県(北海道・埼玉・東京・愛知・大阪等の大都市圏)。 k=1 変数すら EPV 10 を満たさない。 ロジスティック回帰は厳密には不適、 アンサンブル決定木で対応するか、 閾値を変えて陽性率 50% 近辺にすべき。 これが「分類タスクは陽性側の絶対数で決まる」の実例。
🎯 このコードでやること:「政党支持率を ± 3% 以内の精度で測りたい」など、 比率推定の margin of error から逆算して n を求める。 メディア報道で見る「全国 1,000 人調査」の根拠を再現。
📥 入力データ:許容誤差と信頼水準だけ(実データ不要)。
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 | import pandas as pd from scipy import stats def n_for_proportion(moe, p=0.5, alpha=0.05): """比率推定で margin of error が ±moe になる n""" z = stats.norm.ppf(1 - alpha/2) return (z**2 * p * (1-p)) / moe**2 rows = [] for moe in [0.01, 0.02, 0.03, 0.05, 0.10]: n = n_for_proportion(moe) rows.append({ 'margin_of_error': f'±{moe*100:.0f}%', 'n_required (p=0.5)': round(n, 0), }) print('信頼水準 95%、 p=0.5 の最悪ケース:') print(pd.DataFrame(rows).to_string(index=False)) # 有限母集団修正あり print('-' * 40) N_pop = 100_000_000 # 日本の人口規模 for moe in [0.03, 0.05]: n_inf = n_for_proportion(moe) n_fpc = n_inf / (1 + (n_inf - 1) / N_pop) print(f'moe ±{moe*100:.0f}%: 無限母集団 n={n_inf:.0f}, ' f'N=1億で n={n_fpc:.0f}') |
📤 実行結果:
💬 世論調査の「全国 1,068 人」は ±3% の精度から逆算された数字。 N=1 億のような巨大母集団では FPC はほぼ無効化し、 必要 n はほぼ無限母集団と同じ。 「日本全体」「米国全体」「世界全体」で必要 n が変わらないのは多くの人が直感に反するが、 これが標本誤差の理論。
Q1. SSDSE-B-2026 で「n=47」は十分? A. 強い相関(r>0.5)や大効果量(d>0.8)には十分。 小相関(r<0.2)や小差の検出には不足。 重回帰なら k≤4、 分類は陽性 9 件で EPV 不足。
Q2. 「n が大きいほど良い」は本当? A. 精度・検出力は上がるが、 実用上無意味な小差まで「有意」になる。 効果量や CI 幅を併記すべき。
Q3. 必要 n の事前計算は誰がやる? A. 研究計画段階の統計家・分析リード。 IRB(倫理委員会)や事前登録(pre-registration)で必須項目。
Q4. パイロット研究で σ を測ってから n を決めるのは? A. 良いプラクティス。 ただしパイロットの σ 推定誤差が大きいので、 1.2-1.5 倍の余裕を持って n を設計。
Q5. ベイズ統計ならサンプルサイズの考え方は? A. 事前分布が情報を持つほど必要 n は小さくなる。 ベイズの実用基準は「事後分布の HDI 幅 ≤ ROPE」。
Q6. 質的研究のサンプルサイズは? A. インタビュー研究では「飽和(saturation)」が基準。 新情報が出なくなる時点でサンプル停止、 典型 20-30 人。
Q7. 機械学習で「データを増やすほど精度が上がる」のはどこまで? A. 学習曲線(learning curve)でプラトーに達したら頭打ち。 Scaling laws(Kaplan 2020)は LLM 領域での経験則。
Q8. 検出力 0.8 は絶対? A. 業界慣習。 医学・心理学では 0.8、 創薬や安全性は 0.9 以上を要求。 0.7 でも「探索的」として許容される場合あり。
Q9. n が「足りない」とき何をすべき? A. (1) 効果量目標を上げる、 (2) 内部検証(CV)で過学習を防ぐ、 (3) ベイズ事前で情報補強、 (4) シミュレーションで 結論の頑健性を示す。
🎯 このコードでやること:「同時に k 個の検定をする場合、 Bonferroni 補正で α が α/k に縮む。 必要 n はどう変わるか」を示す。 SSDSE-B-2026 で 10 個の相関を一気に検定する想定。
📥 入力データ:効果量と検定数のみ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import pandas as pd from statsmodels.stats.power import TTestIndPower ap = TTestIndPower() d = 0.5 # 中効果量 rows = [] for k in [1, 5, 10, 20, 50]: alpha_corrected = 0.05 / k n = ap.solve_power(effect_size=d, alpha=alpha_corrected, power=0.8) rows.append({ 'k_tests': k, 'alpha': round(alpha_corrected, 5), 'n_per_group': round(n, 1), 'inflation_vs_k1': round(n / 63.766, 2), }) print(pd.DataFrame(rows).to_string(index=False)) |
📤 実行結果:
💬 検定 1 個なら n=64、 50 個なら n=140。 1.5〜2.2 倍の n インフレを見込む必要がある。 「探索的に大量の変数を投げる」分析は p-hacking のリスクと表裏一体 → 事前登録と FDR (False Discovery Rate) 補正で代替を検討。
🎯 このコードでやること:理論式に頼らず、 「SSDSE-B-2026 と同じ分散構造を持つ 2 群の差を t 検定で 1000 回シミュレート」し、 実測検出力を求める。 公式の妥当性も同時に確認できる。
📥 入力データ:SSDSE 由来の σ と仮定する δ、 サンプルサイズ n。
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 34 | import numpy as np import pandas as pd from scipy import stats from statsmodels.stats.power import TTestIndPower df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) pop23 = df[df['SSDSE-B-2026']==2023]['A1101'].astype(float).values sigma = pop23.std(ddof=1) mean = pop23.mean() ap = TTestIndPower() rng = np.random.default_rng(0) N_SIM = 1000 rows = [] for n, d in [(47, 0.5), (47, 0.8), (100, 0.5), (200, 0.5)]: delta = d * sigma sig_count = 0 for _ in range(N_SIM): g1 = rng.normal(mean, sigma, n) g2 = rng.normal(mean + delta, sigma, n) _, p = stats.ttest_ind(g1, g2, equal_var=True) if p < 0.05: sig_count += 1 power_mc = sig_count / N_SIM power_th = ap.solve_power(effect_size=d, alpha=0.05, nobs1=n) rows.append({ 'n': n, 'd': d, 'power (MC)': round(power_mc, 3), 'power (理論)': round(power_th, 3), '差': round(abs(power_mc - power_th), 3), }) print(pd.DataFrame(rows).to_string(index=False)) |
📤 実行結果:
💬 1,000 回モンテカルロの実測 power と理論 power は 3% 未満の差で一致(N=1,000 の二項ゆらぎの範囲内)。 公式が正しく動いている確認になり、 同時に「もし正規性が崩れたら」をシミュレーションで素早く検証する設計の出発点にもなる。
statsmodels.stats.power。n、 α、 検出力(1-β)、 効果量(d)の4つは互いに連動。 3つ決まれば残り1つが決まる:
| 手法 | 経験則(最低) |
|---|---|
| 単回帰 | n ≥ 30 |
| 重回帰(変数 k) | n ≥ 10k + 50(Tabachnick) |
| ロジスティック回帰 | 最小カテゴリで n ≥ 10k(EPV ルール) |
| 因子分析 | n ≥ 5 × 項目数 |
| 構造方程式モデリング | n ≥ 200 |
| 機械学習(教師あり) | 数千〜数十万 |
| 深層学習 | 数万〜数億 |
「全体で n=100」でも、 サブグループ別では n=20-30 になることが。 サブグループでの検定はサンプルが不足しがち。
全国調査での代表性確保:
1 2 3 4 5 6 7 8 | # 比率の差を検出するサンプルサイズ import statsmodels.stats.proportion as smp # A群: 5% conversion, B群: 6% conversion を検出したい effect = smp.proportion_effectsize(0.06, 0.05) n = smp.samplesize_proportions_2indep_onetail( diff=0.01, prop2=0.05, power=0.80, alpha=0.05) print(f'各群に必要なサンプル: {n:.0f}') |
サンプルサイズ がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 統計・データサイエンス › 推測統計 › 推定 › 標本サイズ
中心に サンプルサイズ を置き、 そこから 標準誤差・有意水準・信頼区間・回帰設計・t検定・標準偏差 など 計 13 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語とあとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。
大きな円が小さな円を包含する Circle Packing 図。 「サンプルサイズ」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「サンプルサイズ」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは 標本サイズ の隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス → 推定 → 標本サイズ という入れ子の位置を示します。 「推定には他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。
「サンプルサイズ」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。
「何人集めれば差を検出できるか」を 事前に 決めることが、 「データが少なすぎて結論が出ない」「データが多すぎて瑣末な差まで有意」を避ける研究設計の出発点である。
「sample size」を含む手法選択は、 データの性質・分析目的・運用制約の 3 軸で決まる。 以下に典型シナリオと対応する手法の組合せを示す。
| シナリオ | 重視する観点 | 候補手法 |
|---|---|---|
| データが大規模 (n が多い、 高次元) | 計算コスト / メモリ / 並列化が必要 | G*Power 等 |
| 外れ値が多い / ノイズあり | 頑健性 / 外れ値除去 / 中央値ベース | statsmodels.stats.power 等 |
| 解釈性を重視する | 線形 / 木構造 / ルールベース | pwr 等 |
| 予測精度を最優先する | アンサンブル / ハイパラ調整 / 交差検証 | PowerAndSampleSize.com 等 |
このページの各所で「n=47 では検出力が足りない」と述べた。 すると自然に「SSDSE-B-2026 は 2012〜2023 年の 12 年分あるから、 47 × 12 = 564 行をプールすれば n=564 になるのでは?」というアイデアが浮かぶ。 結論から言うと ならない。 ここでは「n はデータの行数ではなく独立な情報の個数である」という、 サンプルサイズ理解の最後のピースを、 SSDSE-B-2026 の実測値で確かめる。
アンケートで 1 人に同じ質問を 12 回して 12 行のデータを作っても、 「独立な回答者」は 1 人のままだ。 都道府県パネルも同じで、 ある県の 2013 年の値は、 同じ県の 2012 年の値とほぼ同じ。 実際、 SSDSE-B-2026 の総人口(A1101)で県内の隣接年の相関(ラグ 1 自己相関)を 47 県で平均すると 0.986、 さらに 11 年離れた 2012 年と 2023 年の県別総人口の相関ですら r = 0.999 ある。 つまり 2023 年の列は 2012 年の列の「ほぼコピー」であり、 年を足しても新しい情報はほとんど増えない。 標準誤差の公式 $SE = \sigma/\sqrt{n}$ が成り立つのは「n 個が互いに独立」のときだけ── この前提こそが、 行数 n を「実質的な n」に読み替える鍵になる。
総人口 A1101 の 564 行(2012〜2023 年 × 47 県)をあたかも独立標本のように扱うと、 標準誤差は次のように「見かけ上」小さくなる:
ナイーブな SE(±11 万人)は、 実際の情報量に見合う SE(±40 万人)を 約 3.5 倍(≈ √12)過小評価している。 この状態で t 検定や回帰の p 値を計算すると、 本当は有意でないものが大量に「有意」と判定される(第 1 種の過誤の膨張)。 「行を増やしたのに結論が甘くなる」という、 サンプルサイズの直感に反する現象である。 どれだけ情報が「圧縮」されているかは、 県というクラスター内の似通い度合い=級内相関係数 ICC(intraclass correlation)で測れる:
| 列(SSDSE-B-2026 実測) | ICC | デザインエフェクト DEFF = 1+(m−1)·ICC | 有効 neff = 564/DEFF |
|---|---|---|---|
| A1101 総人口 | 0.9995 | 11.99 | 47.0 |
| A4101 出生数 | 0.9793 | 11.77 | 47.9 |
| A4200 死亡数 | 0.9806 | 11.79 | 47.8 |
📌 3 列とも neff ≈ 47。 つまり 12 年分 564 行をプールしても、 独立情報はほぼ「47 県分」のままである。 「n=47 の壁」は年数を足す方向では破れない── 破るなら市区町村(1,741 自治体)などクラスター数そのものを増やす方向、 という本文の結論がここで定量的に裏付けられる。
クラスターあたり m 個の観測、 級内相関 $\rho$ のとき、 有効サンプルサイズは
$$ n_{\mathrm{eff}} \;=\; \frac{n}{1 + (m-1)\,\rho} $$で近似できる(分母がデザインエフェクト DEFF)。 $\rho=0$(完全独立)なら neff=n、 $\rho=1$(クラスター内が完全コピー)なら neff=クラスター数、 になる。 SSDSE-B-2026 は $\rho \approx 0.98$〜$1.0$ なのでほぼ後者の極限であった。 同じ構造は「1 人の患者から複数回測定」「1 学校から複数の生徒」「1 ユーザーの複数ログ」などあらゆる階層データに現れ、 実務ではクラスターロバスト標準誤差や混合効果モデル(マルチレベルモデル)で対処する。 なお、 このページの範囲を超えるが、 独立性ではなく抽出の偏りが原因で実質 n が激減する現象もある(Meng 2018 の「ビッグデータの逆説」: 偏った巨大標本は、 小さな無作為標本に精度で負けることがある)。 いずれの場合も教訓は同じ── 「n はいくつか?」と問う前に「独立で偏りのない観測はいくつか?」と問う。 チェックリストに 1 行足すなら「行数 n とは別に neff を見積もったか」である。
※ 級内相関係数(ICC)とデザインエフェクトの個別解説ページは本用語集には未収録。 本節の実測値は data/raw/SSDSE-B-2026.csv(564 行 = 47 都道府県 × 2012〜2023 年)から一元配置分散分析ベースの ICC で算出した。