層別と集計の罠|記述統計と標本
このページはプロモーション(広告)を含みます。
記述統計と標本(中級・読む30分+演習40分)
この授業のゴール
- 群別の率と全体の率を、件数の重みを使った加重平均として計算し、両者の関係を説明できる
- 全体では不利な群が、すべての層では有利になる逆転(シンプソンのパラドックス)を数値で作り、原因を構成比の違いとして説明できる
- 共通の構成比で比べる標準化を計算し、層別の結果と全体の結果のどちらを採るかの判断材料を述べられる
- 集計の前後で、分母・欠損・代表性・単位を検証するチェックリストを使える
仕事でどう使うか
同じデータから、集計の仕方だけで正反対の結論が出ることがあります。会議で『全体ではB案が高い』と言われたとき、群ごとに分けて見直せるかどうかが、判断を左右します。
| 路線 | この授業の使いどころ |
|---|---|
| DS(データサイエンティスト) | A/Bテストや施策評価で、全体の率だけでなく、顧客層・デバイス・時期などで層別して確認する。レポートに層別表を付けます |
| ML(機械学習エンジニア) | モデルの精度が全体では良くても、特定の群で悪いことがある。評価を群別に出し、学習・評価データの構成比のずれも確認します |
| DX(DX推進・AI企画) | 部署別・拠点別のKPIを合算するときの分母のずれを防ぐ。『平均の平均』にしない集計仕様を、KPI定義書に書きます |
| RS(研究者) | 観察データでは、群の構成が違うことで見かけの差が生じる。層別、標準化、そして原因構造の検討を、解析計画に含めます |
この授業は、ST01 の総仕上げです。分母・欠損・代表性・単位の4点を、集計の前後で確認する習慣を作ります。
前提
次の言葉を使います。
- 割合と分母、パーセントポイント → 比率・割合・パーセントポイント
- 加重平均(件数で重みを付けた平均) → 代表値と散らばり
- 標本と母集団、代表性 → 母集団と標本
- 外れ値・別集団の混入 → 外れ値と頑健性
コードは pandas の groupby(グループごとの集計)と pivot を使います。
身近な状況:クーポンの比較で、全体と群別の結論が逆になる
架空のネットショップが、2種類のクーポン配布方法 A と B を試しました。それぞれ1,000人に配り、購入した人数を数えました。
| 配布方法 | 配布人数 | 購入者 | 購入率 |
|---|---|---|---|
| A | 1,000 | 230 | 23.0% |
| B | 1,000 | 424 | 42.4% |
全体では B が圧倒的に高く見えます。そこで、顧客を『新規客』と『既存客』に分けて見直しました。
| 顧客層 | A(配布人数 / 購入者 / 購入率) | B(配布人数 / 購入者 / 購入率) |
|---|---|---|
| 新規客 | 800 / 120 / 15% | 200 / 24 / 12% |
| 既存客 | 200 / 110 / 55% | 800 / 400 / 50% |
新規客でも既存客でも、A のほうが購入率が高い(15%対12%、55%対50%)のに、全体では B のほうが高い。計算ミスではありません。このような逆転をシンプソンのパラドックスといいます。
どちらを信じればよいのでしょうか。この授業では、(1) なぜ逆転するのか、(2) どう比べれば公平か、(3) どちらを採用するかをどう判断するか、を順に確認します。
直感的な説明:混ぜ方が違う2つのカゴ
果物のカゴで考えます。カゴAには、安いみかん(1個15円)が多く、高いメロン(1個55円)が少し入っています。カゴBには、メロンが多く、みかんが少し入っています。みかんもメロンも、Aのほうが少し高い値段(A:15円・55円、B:12円・50円)で売れたとします。それでも、カゴ全体の平均価格はBのほうが高くなります。Bのほうが高いメロンの割合が大きいからです。
全体の平均(率)は、『各群の値』を『各群の人数の割合』で重み付けして平均したものです。
- Aは新規客80%、既存客20%。購入率の低い新規客が多く入っています。
- Bは新規客20%、既存客80%。購入率の高い既存客が多く入っています。
つまり、全体の差は『方法の効果』と『顧客層の構成の違い』が混ざったものです。層別(群に分けて見る)ことで、2つを切り分けられます。
注意:層別すれば必ず正しい、というわけではありません。どの切り口で分けるべきかは、データがどのように生まれたかで決まります(発展で扱います)。
正確な定義:加重平均・層別・標準化
層(群)を $g=1,\dots,G$ とし、層 $g$ の人数を $n_g$(人)、購入者を $b_g$(人)、購入率を $p_g=b_g\div n_g$ とします。全体の人数は $N=\sum_g n_g$、全体の購入率は次の式です。
$$P=\frac{\sum_g b_g}{\sum_g n_g}=\sum_{g}w_g\,p_g,\qquad w_g=\frac{n_g}{N}$$
$w_g$ は層 $g$ の構成比(全体に占める人数の割合)で、$\sum_g w_g=1$ です。全体の率は、層ごとの率を構成比で重み付けした平均です。数値を代入します。
- A:$w=(0.8,\,0.2)$、$p=(0.15,\,0.55)$ なので $P_A=0.8\times0.15+0.2\times0.55=0.12+0.11=0.23$(23%)。
- B:$w=(0.2,\,0.8)$、$p=(0.12,\,0.50)$ なので $P_B=0.2\times0.12+0.8\times0.50=0.024+0.40=0.424$(42.4%)。
シンプソンのパラドックスとは、すべての層で $p_{A,g}>p_{B,g}$ なのに、全体では $P_A<P_B$ となる現象です。原因は、A と B で構成比 $w_g$ が違うことです。
標準化(直接標準化)は、どちらの方法にも同じ構成比 $w_g^{\ast}$ を当てはめて比べる方法です。2群の全配布人数を合算した構成比を使います(新規 1,000人、既存 1,000人なので、各0.5)。
$$P_A^{\ast}=0.5\times0.15+0.5\times0.55=0.35,\qquad P_B^{\ast}=0.5\times0.12+0.5\times0.50=0.31$$
標準化した率は A が 35%、B が 31%。差は 4パーセントポイント(35−31、割合の差であって『4%の差』ではありません)で、A が高い。
集計の前後で確認する4点を、チェックリストにします。
| 確認点 | 問い |
|---|---|
| 分母 | 率の分母は何か。合算するとき、率の平均ではなく『分子の合計÷分母の合計』になっているか |
| 欠損 | 欠損は何件か。分母に入れたか、除いたか。0と混同していないか |
| 代表性 | その集計は誰を表すか。群ごとに集め方や構成が違わないか |
| 単位 | 集計前後で単位(円と千円、日次と月次、人と件)が揃っているか |
段階付き例題:逆転を計算で再現し、標準化まで行う
ステップ1:全体の率を出す。 A:230÷1,000=23.0%、B:424÷1,000=42.4%。
ステップ2:層ごとの率を出す。 新規客 A=120÷800=15%、B=24÷200=12%。既存客 A=110÷200=55%、B=400÷800=50%。どちらの層でも A が高い(差はそれぞれ +3、+5 パーセントポイント)。
ステップ3:構成比の違いを確認する。 A の新規客の割合は 800÷1,000=80%、B は 200÷1,000=20%。A は購入率の低い新規客に大きく偏って配られていました。
ステップ4:標準化する。 共通の構成比(新規0.5、既存0.5)で A=35%、B=31%。
次のコードで、全体・層別・標準化を一度に確認します。groupby('method')[['n','buy']].sum() は方法ごとに人数と購入者を合計し、set_index('segment') は層の名前を行の見出しにして、構成比と層の名前で掛け算を揃えます。
import pandas as pd
df = pd.DataFrame({
'method': ['A', 'A', 'B', 'B'],
'segment': ['新規', '既存', '新規', '既存'],
'n': [800, 200, 200, 800],
'buy': [120, 110, 24, 400]})
tot = df.groupby('method')[['n', 'buy']].sum()
tot['rate'] = tot['buy'] / tot['n']
print("全体:", {m: round(r, 3) for m, r in tot['rate'].items()})
df['rate'] = df['buy'] / df['n']
for seg in ['新規', '既存']:
d = df[df['segment'] == seg].set_index('method')['rate']
print(seg, "A:", d['A'], " B:", d['B'])
w = df.groupby('segment')['n'].sum() / df['n'].sum() # 共通の構成比
print("構成比:", w.to_dict())
for m in ['A', 'B']:
d = df[df['method'] == m].set_index('segment')
print("標準化", m, round((d['rate'] * w).sum(), 3))
出力は次のとおりです。
- 全体:
{'A': 0.23, 'B': 0.424} - 新規 A: 0.15 B: 0.12、既存 A: 0.55 B: 0.5
- 構成比:
{'新規': 0.5, '既存': 0.5} - 標準化 A 0.35、標準化 B 0.31
ステップ5:結果の読み方。 配布が無作為で、構成比がたまたま違ったのなら、層別・標準化の結果(Aが有利)を採るのが自然です。しかし『Aは新規客に配る』という運用ルールで決まっていたなら、全体の23%対42.4%は『Aという運用』の結果でもあります。何を比べたいのか(運用全体か、クーポン自体の効果か)を最初に決めることが、判断の出発点です。
操作して理解する:構成比を動かすと全体の率はどう動くか
A の層別の購入率(新規15%、既存55%)は変えずに、A の新規客の割合 $s$ だけを動かして、A の全体の購入率を見ます。B は新規客20%のまま固定です。
rate_new, rate_old = 0.15, 0.55
for s in (0.8, 0.5, 0.2):
overall = s * rate_new + (1 - s) * rate_old
print(f"Aの新規割合 {s:.0%} → Aの全体購入率 {overall:.1%}")
print("Bの全体購入率 (新規20%):", f"{0.2 * 0.12 + 0.8 * 0.50:.1%}")
出力は次のとおりです。
| Aの新規割合 | Aの全体購入率 |
|---|---|
| 80% | 23.0% |
| 50% | 35.0% |
| 20% | 47.0% |
Bの全体購入率は 42.4% です。
- 層ごとの率が同じでも、構成比を変えるだけで、A の全体の率は 23% から 47% まで動きます。
- A の新規割合が約31%を下回ると、全体でも A が B を上回ります($55-40s>42.4$ を解くと $s<0.315$)。逆転は構成比のずれの大きさで決まります。
- 配布を無作為にして、A も B も新規50%・既存50%にそろえれば、全体の率は A=35%、B=31% となり、層別の結論と一致します。
試してみましょう。(1) rate_new を 0.10 に変えると、逆転が起きる条件はどう動くでしょう。(2) B の新規割合を 50% にして全体の率を計算してみましょう(0.5×0.12+0.5×0.50=31.0%)。(3) 3つ目の層『休眠客』を加えるときは、構成比の合計が1になっているかを検算します。
発展:どちらの集計を採るべきか。因果の構造を考える
『層別した結果が常に正しい』とは限りません。次の2つの状況は、データの数字だけを見ると同じ形に見えますが、結論は逆になります。
状況1(交絡):新規客か既存客かが、クーポンの配られ方と購入率の両方に影響しています(新規客にAを多く配った、新規客は購入率が低い)。クーポンの効果だけを知りたいなら、顧客層で層別または標準化するのが適切です。
状況2(媒介):クーポンを配った結果『アプリを開く回数』が増え、その結果として購入が増えるなら、『アプリを開いた回数』はクーポンの効果の通り道です。この回数で層別すると、クーポンの効果の一部を取り除いてしまい、効果を過小評価します。この場合は層別しないほうが適切です。
どちらの状況かは、データ分析だけでは決まりません。割付の方法(無作為だったか)、変数が生じた時間的順序、業務の知識で判断します。因果の検討は 実験計画・標本抽出(有料版) で、より詳しく扱います。
そのほか、集計の罠はいくつもあります。
- 平均の平均:店舗ごとの平均客単価を単純平均すると、全体の客単価とずれる。
- 生存者バイアス:残ったデータだけを集計して、消えたものを見落とす。
- 生態学的誤謬:地域ごとの集計の関係を、個人の関係と取り違える。
- 多層の群:層を増やすと、各層の件数が少なくなり、率が不安定になる。層別の数と件数のバランスを考える必要があります。
よくある失敗
失敗1:全体の率だけを見て施策を比較する
誤った例:クーポンAとBの全体の購入率(23.0%と42.4%)だけを見て『Bのほうが約19パーセントポイント良い。Bを採用する』と判断する。
誤りの理由:新規客でも既存客でもAが高く、全体の差は顧客層の構成の違いで生じています。構成比をそろえると A=35%、B=31% で、Aが4パーセントポイント高い。Bを採用すると、効果の高い施策を捨てる可能性があります。
直し方:比較の前に、群の構成比が揃っているかを確認する。層別の表を作り、全体の結果と一致するか確認する。逆転していれば、標準化の結果と、データが生まれた仕組み(割付)を併記して報告する。
失敗2:率の単純平均を全体の率にする
誤った例:店舗1は10人中2人(20%)、店舗2は300人中90人(30%)が購入した。全体の購入率を (20+30)÷2=25% と報告する。
rates = [2 / 10, 90 / 300]
print("率の単純平均:", sum(rates) / len(rates))
print("分子の合計÷分母の合計:", round((2 + 90) / (10 + 300), 4))
出力は『率の単純平均: 0.25』『分子の合計÷分母の合計: 0.2968』です。
誤りの理由:店舗1の10人と店舗2の300人を同じ重さで扱っています。全体の率は 92÷310≒29.7% です。
直し方:率を合算するときは、必ず分子の合計÷分母の合計(または件数で重み付けした加重平均)。KPI定義書に分母を明記する。
失敗3:欠損の扱いで分母がずれた平均を比べる
誤った例:店舗A・Bの日次売上(千円)を比べる。A店は4日中2日が空欄で、平均が150。B店は4日とも入力されていて平均100。『A店のほうが売上が高い』と報告する。
import numpy as np
import pandas as pd
s = pd.DataFrame({'store': ['A'] * 4 + ['B'] * 4,
'sales': [100, 200, np.nan, np.nan, 90, 110, 100, 100]})
print("欠損を除く平均:", s.groupby('store')['sales'].mean().to_dict())
print("空欄を0にした平均:", s.fillna({'sales': 0}).groupby('store')['sales'].mean().to_dict())
出力は『欠損を除く平均: {'A': 150.0, 'B': 100.0}』『空欄を0にした平均: {'A': 75.0, 'B': 100.0}』です。
誤りの理由:A店の空欄が『休業日』(売上0)なのか『入力漏れ』(不明)なのかで、平均の分母が2日か4日か変わります。pandas の mean() は既定で欠損を除くので、欠損の意味を確認しないと比較できません。
直し方:空欄の意味を確認する。休業日なら0、入力漏れなら欠損のまま除き『回答2日分』と明記する。集計表には、平均とともに分母(日数)を併記する。
まとめ
- 全体の率は、層ごとの率を構成比で重み付けした加重平均(分子の合計÷分母の合計)。率の単純平均は誤り。
- すべての層でAが高いのに全体でBが高くなる逆転(シンプソンのパラドックス)は、群の構成比の違いで起こる。
- 標準化は、共通の構成比で比べる方法。差は『パーセントポイント』で表す。
- 層別と全体のどちらを採るかは、データの生まれた仕組み(割付、変数の因果の順序)で決まる。数字だけでは決まらない。
- 集計の前後で、分母・欠損・代表性・単位を確認する。
用語
- 層別(stratification)
データを属性(顧客層、地域など)で群に分けて集計すること。
- シンプソンのパラドックス(Simpson's paradox)
すべての層で優位な群が、全体では劣位になる現象。構成比の違いで起こる。
- 構成比(composition ratio)
全体のうち各層が占める割合。全体の率は層の率を構成比で重み付けした平均になる。
- 標準化(standardization)
比べる群に同じ構成比を当てはめて、構成比の違いの影響を取り除く方法。
- パーセントポイント(percentage point)
率どうしの差の単位。35%と31%の差は4パーセントポイント。
よくある質問
シンプソンのパラドックスは、現実のデータでよく起こるのですか。
構成比の違いがあるデータでは起こり得ます。特に観察データ(無作為に割り付けていないデータ)で、群の構成が偏るときです。起きていなくても、層別で確認する習慣が大切です。実際の事例は、薬の効果の比較や入試の合格率などで報告されています。
層を細かく分けるほど正確になりますか。
いいえ。層を増やすと各層の件数が少なくなり、率が不安定になります。層別は『結果を左右しそうな要因』に絞り、各層に十分な件数があるか(分母が小さくないか)を確認します。
標準化と加重平均は同じですか。
どちらも構成比を使った平均ですが目的が違います。加重平均は『実際の構成での全体の値』を出します。標準化は『比べたい2群に同じ構成比を当てはめた値』を出して、構成比の違いの影響を取り除きます。
『どの切り口で層別するか』は、どう決めますか。
施策の割付や結果に影響しそうな変数(顧客層、時期、地域、デバイス)を、業務知識から挙げます。割付の後に変わる変数(媒介変数)では層別しません。迷うときは、複数の層別を並べて結果が安定しているか確認します。
無作為割付をしていれば、この問題は起きませんか。
構成比がそろうので、起きにくくなります。ただし標本が小さいと、たまたま偏ることはあります。割付後に群ごとの構成を確認し、必要なら層別または標準化を併用します(実験計画・標本抽出(有料版))。
実務でのレポートには、何を載せればよいですか。
全体の結果、層別の結果、群の構成比、標準化した結果の4点と、分母・欠損・単位の注記です。『全体と層別で結論が違う』場合は、その理由を一文で説明し、採用する結論と根拠(割付の方法)を書きます。
確認問題
問1 すべての層でAの率がBより高いのに、全体ではAの率がBより低くなる現象の主な原因はどれか。
- ① 計算ミスが必ず含まれている
- ② AとBで層の構成比が異なること
- ③ 標本サイズが大きすぎること
- ④ 層別をしたことで率が変わること
解答と解説
正解:②
全体の率は、層ごとの率を構成比で重み付けした平均です。構成比が違えば、層ごとの順位が全体では逆になることがあります(シンプソンのパラドックス)。
問2 店舗1が10人中2人購入(20%)、店舗2が300人中90人購入(30%)。2店舗全体の購入率として正しいのはどれか。
- ① 25%(率の単純平均)
- ② 50%(20%+30%)
- ③ 29.7%(92÷310)
- ④ 30%(大きい方の率)
解答と解説
正解:③
全体の率は分子の合計÷分母の合計=(2+90)÷(10+300)≒29.7%。人数の多い店舗2の影響が大きくなります。
問3 クーポンAは新規客80%・既存客20%、Bは新規客20%・既存客80%に配った。新規客の購入率はA15%、B12%、既存客はA55%、B50%。標準化(新規・既存を50%ずつ)したAの購入率はいくらか。
- ① 35%
- ② 23%
- ③ 42.4%
- ④ 55%
解答と解説
正解:①
0.5×15%+0.5×55%=35%。23%は元の構成比(80:20)での全体の率です。
問4 層別集計の結果と全体の集計の結果が食い違ったとき、どちらを採るべきかの判断として最も適切なのはどれか。
- ① 常に層別の結果を採る
- ② 常に全体の結果を採る
- ③ データが生まれた仕組み(割付・変数の因果の順序)を確認して決める
- ④ 好ましい結果が出たほうを採る
解答と解説
正解:③
層別すべきか(交絡の調整)、層別すべきでないか(媒介変数で層別すると効果を取り除く)は、数字だけでは決まらず、データの生まれ方で決まります。
問5 A店の日次売上は4日中2日が空欄で、pandasの mean() で平均150千円となった。B店は4日とも入力済みで平均100千円。比較する前に最優先で確認すべきことは何か。
- ① グラフの色
- ② B店の平均を150にそろえること
- ③ 標準偏差の分母
- ④ A店の空欄が『休業日(0)』か『入力漏れ(不明)』か
解答と解説
正解:④
空欄の意味で平均の分母が変わります。休業日なら0にして平均75、入力漏れなら欠損のまま『2日分の平均』と明記します。
問6 全体の購入率の差が19パーセントポイント(42.4%−23.0%)あった。この表現として最も適切なのはどれか。
- ① Bは19%高い
- ② Bは19パーセントポイント高い
- ③ Bは1.9倍の19%
- ④ AとBの差は19%の人数
解答と解説
正解:②
率どうしの差はパーセントポイントで表します。『19%高い』は相対的な増加率(42.4÷23.0−1≒84%)と取り違えやすい表現です。
次に学ぶこと
これで ST01 の6授業が終わりました。次は ST01 の総合テストと自力課題で、群別集計と全体集計が逆転するデータを自分の言葉で説明できるかを確認します(記述統計と標本)。戻るなら、分母と割合は 比率・割合・パーセントポイント、加重平均は 代表値と散らばり です。
この授業の確認問題だけで習得とはしません。進む先は、確率の基礎 確率・条件付き確率・独立(有料版)、推定と信頼区間 標本分布・推定・信頼区間(有料版)、標本抽出と実験計画 実験計画・標本抽出(有料版) です。
キャリア学習:データサイエンティスト・機械学習エンジニア・DX推進・研究者を目指す人の学習アプリ。164モジュール・984授業を、ブラウザで動くSQLとPythonの演習で。基礎と各分野の最初のモジュールは無料。全部は2,980円の買い切り。
アプリを無料で開く有料版と無料版の違い