論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
サンプルサイズ
Sample Size (n)
観測したデータの個数。nが大きいほど統計量の精度が上がり、小さな効果でも有意になりやすい。
推測統計n標本サイズn数サンプル数

🔖 キーワード索引(補強)

サンプルサイズと検出力に関する主要概念チップ集。

n 検出力 α(第一種の誤り) β(第二種の誤り) 効果量 Cohen's d 事前パワー解析 事後パワー 標準誤差 $1/\sqrt{n}$ A/Bテスト 逐次検定 適応的設計 バイアス 代表性 確証バイアス 非劣性試験 同等性試験 クラスター n デザインエフェクト

💡 30秒で分かる結論

🍰 まずはやさしく

データの個数のことです。

分析の正確さを決めるために使います。

アンケートに答えた人の数のようなものです。

個数を増やすと精度が上がる仕組みを読みます。

📖 もっと詳しく

サンプルサイズ 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が大きいほど統計量の精度が上がり、小さな効果でも有意になりやすい。

📍 サンプルサイズ設計チェックリスト(研究計画書テンプレート)

  1. 研究目的:何を検出したいか(平均差、 相関、 オッズ比、 分類精度)を 1 文で言語化
  2. 主要評価項目:1 つに絞る(複数なら α 補正)
  3. 効果量目標:過去研究やパイロットから根拠付き設定。 推測なら理由を明記
  4. α と power:α=0.05, power=0.8 が標準。 重大領域は power=0.9
  5. 計算ツール:G*Power / statsmodels / R pwr。 SQL のような場当たり計算は避ける
  6. 脱落・欠損率:医療なら 15-20% 上乗せ、 アンケートなら回答率を考慮
  7. 多重検定:副次評価項目数を数え、 必要なら Bonferroni / Holm / BH-FDR
  8. 事前登録:osf.io や AsPredicted で登録 → post-hoc 変更の温床を防ぐ
  9. 感度分析:σ や効果量が ±20% ずれたら n がどう変わるか
  10. 停止規則:A/B テストや臨床試験では事前に「peeking しない」ルールを文書化

📌 このチェックリストは 研究計画書 (study protocol)事前登録の必須項目とほぼ同じ。 サンプルサイズ設計を済ませることが、 そのまま「再現性の高い研究」になる。

📍 SSDSE-B-2026 で n=47 をどう扱うか ─ 3 つの戦略

📌 教材としては 戦略 A + B の組み合わせが安全。 「47 サンプルだから何でもできる」ではなく「何ができて何ができないか」を理解させるのが、 実践的な統計教育。

🎨 直感で掴む

🍰 まずはやさしく

データの量というイメージです。

結果のばらつきを抑えるために使います。

少人数の意見より大人数の意見の方が安定します。

量が増えると結果がどう変わるかを見ます。

サンプルサイズ
n=5 と n=100 の信頼区間幅の比較。 n を増やすと CI は劇的に狭くなる。

🎨 Cohen の効果量分類と実例

指標実例
Cohen's d (平均差)0.20.50.8男女の身長差 d≈1.5
相関係数 r0.100.300.50SSDSE 人口 vs 出生数 r≈0.99
$\eta^2$ (分散説明率)0.010.060.14教育水準 vs 学習時間 η²≈0.10
Cohen's w (χ²)0.100.300.50アンケート集計の偏り
オッズ比 OR1.52.54.3疫学・症例対照研究

📌 「効果量」は事前に決めるべきで、 後から「結果を見て」決めるのは循環論法。 過去研究のメタ解析や予備実験で見積もる。

📐 数式

🍰 まずはやさしく

数式で表したデータの個数です。

必要なデータの数を計算するために使います。

部活の平均点などを正確に出したい時に役立ちます。

精度と個数の関係を数式で詳しく読みます。

【標本平均の標準誤差】
$$SE(\bar{x}) = \frac{\sigma}{\sqrt{n}}$$
平均の精度は n の平方根に反比例して向上する

📐 検出力分析 — 必要 n を導く 4 つの量

サンプルサイズは 4 つの量が相互依存する。 3 つ決めれば残り 1 つが決まる。

意味典型値
$\alpha$(有意水準)第 1 種の過誤率(FP)0.05
$1 - \beta$(検出力)真に差があるとき発見する確率0.80
$\delta$ or $d$(効果量)検出したい差の大きさ小 0.2 / 中 0.5 / 大 0.8 (Cohen)
$n$(サンプルサイズ)必要観測数これを求める

2 群平均差検定 (t-test) の必要 n

$$ n_{\mathrm{group}} \;=\; \frac{(z_{1-\alpha/2} + z_{1-\beta})^2 \cdot 2 \sigma^2}{\delta^2} \;=\; \frac{2 (z_{1-\alpha/2} + z_{1-\beta})^2}{d^2} $$

🔬 数式を言葉で読み解く

相関係数の検定の必要 n(Fisher z 変換)

$$ n \;=\; \left(\frac{z_{1-\alpha/2} + z_{1-\beta}}{\frac{1}{2} \ln\frac{1+r}{1-r}}\right)^2 + 3 $$

割合の差検定の必要 n

$$ n_{\mathrm{group}} \;=\; \frac{(z_{1-\alpha/2}\sqrt{2 \bar{p}(1-\bar{p})} + z_{1-\beta}\sqrt{p_1(1-p_1)+p_2(1-p_2)})^2}{(p_1 - p_2)^2} $$

🔬 数式を言葉で読み解く

📐 有限母集団修正 (Finite Population Correction, FPC)

母集団サイズ $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 変数)10k20k条件指数も確認
ロジスティック回帰10k / 少数クラス20k / 少数クラスEPV (events per variable)
決定木 / RF数百数千〜木の深さで調整可能
XGBoost / LightGBM1k数万〜早期終了 + 正則化
SVM数百数千大データで遅い
深層学習 (画像)数千数十万〜転移学習で削減可
LLM ファインチューン数百数千〜LoRA で更に削減可
PCA / 因子分析100300+KMO 検定で適性確認

📌 SSDSE-B-2026 (n=47) は 線形回帰の k≤4ロジスティック回帰の少数クラス k≤2決定木は深さ≤3 が現実的。 ランダムフォレストは min_samples_leaf を大きく取って過学習防止。

📐 信頼区間幅と n の関係

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 固定):

MOE 目標 n 必要 ± 50,000 12,027 ± 100,000 3,007 ± 250,000 482 ± 500,000 121 ±1,000,000 31 ±2,000,000 8

💬 47 県データの実 MOE は 1.96 × 408,065 ≈ ± 80 万人。 これで「平均 264 万人 ± 80 万」と推定するイメージ。 もっと狭い CI(±10 万人)が欲しければ n=3,000 必要 → 都道府県より細かい単位(市区町村)で検討。

🎮 触って理解する

スライダーやドラッグで サンプルサイズ n を動かすと、 標準誤差 $\sigma/\sqrt{n}$ と 95% 信頼区間の幅がどう縮むかがリアルタイムに変わります。 グラフを直接ドラッグ(マウス/指)しても n を変えられます。 「n を 4 倍にすると誤差は半分」という 平方根の逓減を体感してください。

標準誤差 SE = σ/√n
誤差の半幅 MOE = z·SE
信頼区間の幅(全幅 2·MOE)

n を 4 倍にすると…

推定対象:
必要サンプルサイズ n
使用した z 値

許容誤差を半分にすると必要 n は 4 倍に。

🧠 直感 — なぜ √n の逓減なのか

⚠️ よくある落とし穴

🚀 発展 — 検出力分析(power analysis)へ

上の逆算は「推定の精度(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 で実値計算 — サンプルサイズの考察

SSDSE-B-2026 は 47都道府県 = n=47 の典型的な「小〜中規模パネル」。 サンプルサイズに関連する具体計算を実行します。

例1:statsmodels で必要サンプルサイズと検出力を計算

 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}')

🧮 SSDSE-B-2026 で「n=47 で何が分かるか」を実値計算

47 都道府県は「標本」というより全国データの「母集団」に近いが、 統計的推論を行う場合の必要 n と現状 47 の比較は学習素材として有益。

事前情報(実データ検証済)

必要 n の手計算(平均差を 10% で検出)

「来年の平均人口が今年と 10%(=$\delta$)以上変わったか」を $\alpha=0.05$, power=0.8 で検出するための n:

z_α/2 = 1.96 z_β = 0.8416 (β = 1 - 0.8) σ = 2,797,551 δ = 0.10 × 2,645,808 = 264,581 n = (1.96 + 0.8416)² × 2,797,551² / 264,581² = (2.8016)² × 7.826e12 / 7.000e10 = 7.849 × 111.799 ≈ 877.5 → 必要 n ≈ 878 (47 の約 19 倍)

💬 「47 都道府県」では 10% 差を統計的に検出するのは厳しい。 逆に、 47 県で検出できる効果量を逆算してみる:

n=47, σ=2.797M で 80% 検出力を得る δ: δ = √( (1.96+0.8416)² × 2 × σ² / 47 ) = √( 7.849 × 2 × 7.826e12 / 47 ) ≈ 1,617,000 人 (= 61% の差) → 47 県では「平均差 61% 以上」しか確実に検出できない。 これは現実的にあり得ない大きさ。 つまり 47 県は「点推定にはよいが検出力検定には不足」。

🧮 power analysis ── 「N をいくつにすれば良いか」を逆算する

サンプルサイズ設計の王道は「事後 (集めてから検出力を語る)」ではなく 事前 (検出したい効果量と検出力を決めて 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.2small394× (不可能)
0.3small-medium176×
0.5medium64×
0.8large26 (やっと検出可能)
1.2very large12

🎯 このコードでやること: SSDSE-B-2026 の「東日本 (n=22) vs 西日本 (n=25)」の出生数 (A4101) で実際の Cohen d を計算し、 statsmodels.stats.power.TTestIndPower で逆算した「必要 N」を比較する。

📥 入力: SSDSE-B-2026 47 行 (2023 年度) と「東日本 = 北海道〜静岡 (Code ≤ R22100, 22 県)」分類フラグ。

SSDSE-B-2026 Prefecture region A4101 (出生数, 人) R01000 北海道 east 24430 R13000 東京都 east 86348 R27000 大阪府 west 55292 R47000 沖縄県 west 12549 ... (全 47 県、 east=22, west=25)
 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}")

📤 実行結果:

観測された Cohen d = 0.253 必要 N per group = 246.9, 現在の検出力 = 0.135

💬 結果の読み方: d=0.253 (small) を α=0.05 / 1-β=0.8 で検出するには 1 群あたり約 247 県が必要。 SSDSE-B では各群 22/25 県しかなく 検出力は 0.135 ── 「差が無い」のではなく 「差を検出できる体力が無い」状態。 結論を出すには (a) 市区町村レベルに細分化、 (b) 複数年度をプール、 (c) 「効果が大きいなら見える」と限定的に解釈、 のいずれかが必要。 これが 「事前 power analysis を回さずに t 検定を打つ」のが危険な理由。

⚠️ sample-size 設計の固有落とし穴

🖼️ サンプルサイズ設計の可視化と理解度チェック

SSDSE-B-2026 の県別データで「サンプルサイズと検出力」 の関係を可視化し、 学習者がポイントを再確認できる理解度チェックを追加する。

📊 図1: 検出力曲線 (Power curve)

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% 検出力に必要。

効果量別の検出力曲線

📊 図2: 有意性と検出力のトレードオフ

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

有意性と検出力のトレードオフ

🧪 理解度チェック

  1. 問1: α=0.05, 1−β=0.8 で Cohen d=0.5 を検出したい。 1 群あたり必要 N は約何件か?
    : 約 64 件 (両側 t 検定)。 SSDSE-B の 47 県だと N=23/24 程度なので、 d=0.5 すら検出力 80% で確実に拾えない。
  2. 問2: 47 県のサブグループ (例: 関東 vs 関西) で平均差検定を行うとき、 効果量 d を推定するにはどうすべきか?
    : 過去文献の 最小値・保守的下限を使う。 自分のデータで事後に推定すると「post-hoc power の罠」 に陥る。
  3. 問3: Bonferroni 補正で α を 10 検定に分けると α=0.005 になる。 同じ検出力を保つには N をどう変える必要があるか?
    : α が 1/10 になると N は 1.5〜2 倍程度増やす必要がある (正確な値は statsmodels の TTestIndPower で確認)。
  4. 問4: SSDSE-B-2026 のような 47 県のデータで、 都道府県差を t 検定で検出するときの本質的限界は何か?
    : N が固定 (47) で増やせないこと。 大きな効果量しか拾えないので、 「都道府県差なし」 と結論しても「検出力不足で見えない」 可能性を必ず併記する。

💬 SSDSE-B-2026 で「県別の差」 を語るときには、 α, β, d, N の 4 つを必ず明示 する習慣をつけたい。 これが 仮説検定 を「結論」 でなく「証拠の強度」 として正しく扱う基礎となる。

🧮 数式に値を入れて手で計算する: 必要サンプル数

SSDSE-B-2026 から「全国の有業者率」を許容誤差 3% で推定する世論調査設計を想定し、 必要サンプルサイズ n を計算する。

Step 1: パラメータ

許容誤差 e = 0.03 (3%) 信頼水準 95% → z = 1.96 母比率 p = 0.5 (最大分散)

Step 2: 公式

n = z²·p·(1-p)/e² = (1.96)²·0.5·0.5/0.03² = 3.8416·0.25/0.0009 ≈ 1067

🐍 Python で再現

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)}")

📤 実行結果

n = 1068

💬 手計算 (Step 2) ≈1067 と Python 出力が一致。

🐍 Python 実装①:statsmodels で必要サンプル数を求める

🎯 このコードでやること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}')

📤 実行結果

σ = 2,797,551 μ = 2,645,808 d n_per_group total_n 0.2 393.4 786.8 0.3 175.4 350.8 0.5 63.8 127.5 0.8 25.5 51.0 1.0 16.7 33.4 ---------------------------------------- n=47 で power=0.8 を満たす最小 d = 0.584 これは絶対差 ≈ 1,633,888 人 (= 61.8% of mean) n=47, d=0.3 のときの power = 0.302

💬 n=47 で d=0.3 の検出力は 30%。 真に効果があっても 70% 見逃す。 「中効果量を確実に拾う」には d=0.5 で n=64/群、 計 128 必要。 SSDSE-B-2026 47 県は「中央値・回帰係数の点推定」には十分だが、 「小〜中の差の検出」には市区町村レベル(n=1741)への展開を検討すべき。

🐍 Python 実装②:power curve(検出力曲線)を描く

🎯 このコードでやること:横軸 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}')

📤 実行結果

n=47, d=0.2: power = 0.160 n=47, d=0.5: power = 0.669 n=47, d=0.8: power = 0.970 (画像は power_curve.png に保存)

💬 SSDSE-B-2026 (n=47) は 大効果量 (d=0.8) なら 97% 検出中 (d=0.5) で 67%小 (d=0.2) で 16% しか発見できない。 power curve はこの「足りない領域」を一目で示せる、 研究計画書に必須の図。

🐍 Python 実装③:相関 r を検出するための n(Fisher z 変換)

🎯 このコードでやること:相関係数の有意性を検出するための必要 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}')

📤 実行結果

r = 0.9954 p = 1.529e-47 r = 0.10 → 必要 n ≈ 782.7 r = 0.20 → 必要 n ≈ 194.0 r = 0.30 → 必要 n ≈ 84.9 r = 0.50 → 必要 n ≈ 29.0 r = 0.70 → 必要 n ≈ 13.4 r = 0.97 → 必要 n ≈ 4.8

💬 SSDSE-B-2026 の総人口×出生数の相関 r=0.995 は p=1.5e-47 と圧倒的有意。 これほど強い相関なら n=5 でも検出可能(必要 n≈4.8)。 逆に「小相関 r=0.1」を確実に検出するには n=783 必要。 「47 県で多変量分析する」のは強い構造があれば成立、 微妙な効果には不適。

🐍 Python 実装④:A/B テスト設計(比率差検出)

🎯 このコードでやること:「現状 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))

📤 実行結果

p_control p_treat lift_pp h_cohen n_per_arm 0.05 0.06 1.0 -0.044 8143.0 0.10 0.12 2.0 -0.064 3835.0 0.20 0.25 5.0 -0.120 1092.0 0.50 0.55 5.0 -0.100 1565.0

💬 「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 でピークを取り、 ばらつきが最大になるため。

🐍 Python 実装⑤:ブートストラップで SSDSE-B-2026 の標準誤差を実測

🎯 このコードでやること:「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}')

📤 実行結果

n = 47 σ = 2,797,551 SE (理論) = σ/√n = 408,065 SE (ブート) = 401,690 差 = 1.56% 平均の 95%CI = [1,927,700, 3,517,038] n= 47: SE = 408,065 n= 100: SE = 279,755 n= 500: SE = 125,110 n= 1000: SE = 88,466 n= 5000: SE = 39,563

💬 ブートストラップ実測 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 県の点推定が指し示す精度の限界。

🐍 Python 実装⑥:重回帰のサンプルサイズルール(10×k)を実証

🎯 このコードでやること:説明変数の数 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))

📤 実行結果

k 10k_rule_n 満たすか 係数 SD 平均 2 20 ✅ 418,403 4 40 ✅ 238,809 6 60 ❌ 243,999 8 80 ❌ 197,953 10 100 ❌ 167,515

💬 「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 に依存し変動する)。

🐍 Python 実装⑦:EPV(Events Per Variable)で実必要 n を逆算

🎯 このコードでやること:不均衡な二値分類の必要 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) なら可能')

📤 実行結果

全体 n = 47 陽性 (人口 ≥ 500 万) = 9 陰性 (人口 < 500 万) = 38 陽性率 = 19.1% ---------------------------------------- k=1 変数モデル: ❌ 不足 (要 10, 実 9) k=2 変数モデル: ❌ 不足 (要 20, 実 9) k=3 変数モデル: ❌ 不足 (要 30, 実 9) k=4 変数モデル: ❌ 不足 (要 40, 実 9) k=5 変数モデル: ❌ 不足 (要 50, 実 9) ---------------------------------------- k=5 を支えるなら陽性 50 件 → 全体 ≈ 262 件必要 → 都道府県(47)では到底不足、 市区町村 (n=1741) なら可能

💬 SSDSE 47 県の「500 万以上」は 9 県(北海道・埼玉・東京・愛知・大阪等の大都市圏)。 k=1 変数すら EPV 10 を満たさない。 ロジスティック回帰は厳密には不適、 アンサンブル決定木で対応するか、 閾値を変えて陽性率 50% 近辺にすべき。 これが「分類タスクは陽性側の絶対数で決まる」の実例。

🐍 Python 実装⑧:世論調査の「許容誤差 ± 3%」から必要 n

🎯 このコードでやること:「政党支持率を ± 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}')

📤 実行結果

信頼水準 95%、 p=0.5 の最悪ケース: margin_of_error n_required (p=0.5) ±1% 9604.0 ±2% 2401.0 ±3% 1068.0 ±5% 385.0 ±10% 97.0 ---------------------------------------- moe ±3%: 無限母集団 n=1068, N=1億で n=1068 moe ±5%: 無限母集団 n= 385, N=1億で n= 385

💬 世論調査の「全国 1,068 人」は ±3% の精度から逆算された数字。 N=1 億のような巨大母集団では FPC はほぼ無効化し、 必要 n はほぼ無限母集団と同じ。 「日本全体」「米国全体」「世界全体」で必要 n が変わらないのは多くの人が直感に反するが、 これが標本誤差の理論。

🧪 深掘り FAQ(10 問)

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) シミュレーションで 結論の頑健性を示す。

Q10. SSDSE で学ぶ次は? A. 効果量信頼区間多重検定。 サンプルサイズはこれら 3 つと不可分。

🐍 Python 実装⑨:多重検定補正後の必要 n(Bonferroni)

🎯 このコードでやること:「同時に 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))

📤 実行結果

k_tests alpha n_per_group inflation_vs_k1 1 0.05000 63.8 1.00 5 0.01000 95.1 1.49 10 0.00500 108.5 1.70 20 0.00250 121.8 1.91 50 0.00125 139.3 2.18

💬 検定 1 個なら n=64、 50 個なら n=140。 1.5〜2.2 倍の n インフレを見込む必要がある。 「探索的に大量の変数を投げる」分析は p-hacking のリスクと表裏一体 → 事前登録と FDR (False Discovery Rate) 補正で代替を検討。

🐍 Python 実装⑩:モンテカルロで検出力を実測(SSDSE 風シナリオ)

🎯 このコードでやること:理論式に頼らず、 「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))

📤 実行結果

n d power (MC) power (理論) 差 47 0.5 0.694 0.669 0.025 47 0.8 0.957 0.970 0.013 100 0.5 0.940 0.940 0.000 200 0.5 0.999 0.999 0.000

💬 1,000 回モンテカルロの実測 power と理論 power は 3% 未満の差で一致(N=1,000 の二項ゆらぎの範囲内)。 公式が正しく動いている確認になり、 同時に「もし正規性が崩れたら」をシミュレーションで素早く検証する設計の出発点にもなる。

⚠️ よくある落とし穴

❌ 「n が大きい = 良い研究」ではない
偏ったサンプル(バイアス)の場合、 n を増やしても誤った結論に近づくだけ。 サンプルの代表性 がまず重要。 1000人の偏ったサンプルより、 100人の代表サンプルの方が信頼できる。
❌ 統計的有意性に依存しすぎる
n=10万 のビッグデータでは、 r=0.02 でも p<0.001 になる。 「統計的有意」と「実質的重要」は別物。 必ず効果量も見る。
✅ 事前パワー分析
実験を計画するときは、 「検出したい効果量」「α」「目標 power」 から必要な n を逆算するのが推奨。 Python なら statsmodels.stats.power

🔗 「標本サイズ」と他の概念の関係を深掘り

① 4要素の相互関係

n、 α、 検出力(1-β)、 効果量(d)の4つは互いに連動。 3つ決まれば残り1つが決まる:

② 多変量解析での必要 n

手法 経験則(最低)
単回帰n ≥ 30
重回帰(変数 k)n ≥ 10k + 50(Tabachnick)
ロジスティック回帰最小カテゴリで n ≥ 10k(EPV ルール)
因子分析n ≥ 5 × 項目数
構造方程式モデリングn ≥ 200
機械学習(教師あり)数千〜数十万
深層学習数万〜数億

③ サブグループ分析での注意

「全体で n=100」でも、 サブグループ別では n=20-30 になることが。 サブグループでの検定はサンプルが不足しがち。

④ アンケート調査の標本設計

全国調査での代表性確保:

⑤ A/Bテストでのサンプルサイズ

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}')

✅ 実務チェックリスト — 推測統計を使う前に

1. データの確認

2. 検定・推定の設計

3. 結果の報告

4. 解釈の注意

⚠️ さらに深い落とし穴 ─ 7 つの実例

  1. 事後検出力(post-hoc power)の罠 ─ 実験後に観測した効果量から「検出力 0.7 だった」と計算しても無意味。 検出力分析は事前に行うべき。 事後 power は p 値と数学的に等価で新情報なし(Hoenig & Heisey 2001)。
  2. 効果量設計を「希望」で決める ─ 「d=0.5 を見たい」ではなく 「過去研究のメタ解析で d=0.3 が報告」を根拠に。 願望はサンプル不足を生む。
  3. 多重検定の補正忘れ ─ k 個の検定なら Bonferroni で α/k に。 k=10 で α=0.05 → 0.005 になり、 必要 n は約 1.5 倍に。
  4. クラスタリングサンプル ─ 「47 県」が独立観測でなく、 学校 (n=200) や生徒 (n=8000) のように入れ子なら、 ICC を考慮した有効サンプルサイズ $n_\mathrm{eff} = n / [1 + (m-1) \cdot \mathrm{ICC}]$ を使う。
  5. 不均衡データ ─ 二値分類で陽性 1% なら、 n=10000 でも陽性は 100 件。 ロジスティック回帰の EPV ルールでは 陽性側 ≥ 10×k が必要、 過半数クラスのサイズは目安にならない。
  6. n を増やせば「有意」が氾濫 ─ 大規模 EC データ(n=100万)では、 月変換率 0.001% の差すら p<0.001。 効果量(β、 リフト幅)と実用的閾値を併記すべき。
  7. 逐次解析(peeking) ─ A/B テスト中に「もう有意かな」と毎日 p を見ると、 第 1 種過誤率がインフレ。 α=0.05 のまま毎日 10 日見ると実質 α≈0.20。 Bayesian や sequential design で対処。

🗺️ 概念マップ — 3つの視点で体系を理解する

サンプルサイズ がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。

📍 体系階層のパス

🌐 統計・データサイエンス推測統計推定標本サイズ

① 🔗 関係マップ — 「他の手法とどう繋がっているか」

中心に サンプルサイズ を置き、 そこから 標準誤差・有意水準・信頼区間・回帰設計・t検定・標準偏差 など 計 13 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語あとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。

凡例:現在の用語上位カテゴリ兄弟(並列)前提発展形応用先2階層先

② ⭕ 包含マップ — 「どのカテゴリに含まれているか」

大きな円が小さな円を包含する Circle Packing 図。 「サンプルサイズ」は緑色でハイライト

📍現在地:統計・データサイエンス

③ 🌳 ツリーマップ — 「面積で見るボリューム比較」

長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「サンプルサイズ」は緑色でハイライト

🎯 3つのマップの使い分け

マップ 分かること こんな時に見る
🔗 関係マップ手法間の横の関係(前提→発展→応用)「次に何を学べばよい?」 学習順序の判断
⭕ 包含マップ分類体系の入れ子構造(上位⊃下位)「この手法はどんなジャンルに属する?」
🌳 ツリーマップ分野の規模比較(面積=ボリューム)「データサイエンス全体の俯瞰像」

💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは 標本サイズ隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス推定 → 標本サイズ という入れ子の位置を示します。 「推定には他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。

🔗 隣接手法への橋渡し

「サンプルサイズ」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。

「何人集めれば差を検出できるか」を 事前に 決めることが、 「データが少なすぎて結論が出ない」「データが多すぎて瑣末な差まで有意」を避ける研究設計の出発点である。

🌳 手法選択フロー

「sample size」を含む手法選択は、 データの性質・分析目的・運用制約の 3 軸で決まる。 以下に典型シナリオと対応する手法の組合せを示す。

典型シナリオ別の手法選択

シナリオ重視する観点候補手法
データが大規模 (n が多い、 高次元)計算コスト / メモリ / 並列化が必要G*Power
外れ値が多い / ノイズあり頑健性 / 外れ値除去 / 中央値ベースstatsmodels.stats.power
解釈性を重視する線形 / 木構造 / ルールベースpwr
予測精度を最優先するアンサンブル / ハイパラ調整 / 交差検証PowerAndSampleSize.com

選んだ後の検証ステップ

  1. 前処理確認: 標準化 / 欠損処理 / カテゴリ変数のエンコード が適切か
  2. ハイパラ調整: 交差検証で安定する値を選ぶ
  3. 性能評価: タスクに応じた指標 (RMSE / Accuracy / F1 / AUC / シルエット等) を複数併用
  4. 頑健性チェック: 別手法 / 別シードで結果が大きく違わないか確認
  5. 解釈: 結果を分野知識と照らし合わせ、 意味のある発見になっているか検討

🔍 解説深化 — 「行数の n」と「有効サンプルサイズ neff」:564 行あっても情報は 47 個

このページの各所で「n=47 では検出力が足りない」と述べた。 すると自然に「SSDSE-B-2026 は 2012〜2023 年の 12 年分あるから、 47 × 12 = 564 行をプールすれば n=564 になるのでは?」というアイデアが浮かぶ。 結論から言うと ならない。 ここでは「n はデータの行数ではなく独立な情報の個数である」という、 サンプルサイズ理解の最後のピースを、 SSDSE-B-2026 の実測値で確かめる。

💡 直感 — 同じ人に 12 回聞いても、 回答者は 1 人

アンケートで 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」に読み替える鍵になる。

⚠️ 落とし穴(重要) — 12 年プールしても SE は 1/√12 にならない(実測)

総人口 A1101 の 564 行(2012〜2023 年 × 47 県)をあたかも独立標本のように扱うと、 標準誤差は次のように「見かけ上」小さくなる:

SSDSE-B-2026 総人口 A1101(実測) 564 行プールの標準偏差 s = 2,730,951 ナイーブ SE = s/√564 = 114,994 ← 見かけの精度 2023 年単年 (n=47) の SE = 408,065 ← 実際の精度の目安 級内相関で補正した SE = 398,259 ← ナイーブの約 3.5 倍

ナイーブな 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.999511.9947.0
A4101 出生数0.979311.7747.9
A4200 死亡数0.980611.7947.8

📌 3 列とも neff47。 つまり 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 で算出した。