標本抽出の偏りと相関
同じ母集団から抽出方法を変え、平均の偏りと相関から判断できる範囲を調べます。
説明
母集団は知りたい対象全体、標本はそこから観測した一部です。標本が多くても、選ばれ方が偏っていれば全体の性質を正しく推定できません。無作為抽出はその偏りを抑える方法ですが、個々の標本には偶然の差が残ります。
処理時間の異なる二つの拠点を例に、先頭だけの抽出、無作為抽出、拠点比率をそろえた抽出を比較します。後半では負荷が二つの測定値を同時に変える例から、相関だけで原因を特定できないことを確認します。
1全体の構成
拠点Aは80件で各10ミリ秒、拠点Bは20件で各50ミリ秒とします。例を単純にするため拠点内の値は一定です。
import statistics as st; import random平均と抽出; population = [('A',10)]*80 + [('B',50)]*20拠点と処理時間; st.mean(value for site,value in population)母集団平均全100件の平均は18ミリ秒です。この教材では全体が既知なので、抽出結果とのずれを直接比較できます。実際の標本調査では通常、全体の値は分かりません。
2並び順の先頭だけを採る
記録が拠点順に並んでいるとき、先頭20件だけを取得します。
head = population[:20]先頭20件を抽出; {site for site,value in head}, st.mean(value for site,value in head)拠点と平均Aしか含まれず平均10です。標本数20という情報だけでは、Bを一件も含まない選び方の偏りを見抜けません。
3無作為に20件を採る
全100件から重複なく20件を無作為抽出します。seedを固定して同じ例を追えるようにします。
rng = random.Random(2026)乱数器; sample = rng.sample(population,20)重複なしの無作為抽出; sum(site == 'B' for site,value in sample), st.mean(value for site,value in sample)Bの件数と標本平均Bが何件入るかは抽出ごとに揺れます。無作為抽出で偏りを抑えることと、この一回の平均が必ず18になることは別です。
4同じ抽出を繰り返す
独立した抽出を1000回行い、標本平均の分布を調べます。
means = [st.mean(value for site,value in rng.sample(population,20)) for _ in range(1000)]1000回の標本平均; min(means), max(means), st.mean(means)範囲と中心標本平均には範囲があり、平均を何度も取り直すとその中心が母集団平均付近になります。一方、先頭20件の取得を繰り返すだけでは常に10で、抽出の偏りは解消しません。
5拠点ごとの比率を保つ
Aから16件、Bから4件を採ります。この例では拠点内の値が一定なので、比率をそろえると全体平均に一致します。
stratified = rng.sample(population[:80],16) + rng.sample(population[80:],4)拠点比率に合わせて抽出; st.mean(value for site,value in stratified)層化した標本の平均層化抽出の例です。実データに拠点内のばらつきがあれば、比率をそろえても標本誤差は残ります。層の情報自体が正しいことも必要です。
6拠点ごとに同数を抽出し、構成比で重み付けする
各拠点10件ずつを測ると、標本内の比率は50対50です。全体の80対20へ重みを戻して集計します。
equal_sample = population[:10] + population[80:90]各拠点10件; st.mean(value for site,value in equal_sample)同じ重みの平均, 0.8*10 + 0.2*50母集団比率で重み付け単純平均は30、構成比を戻した平均は18です。標本の平均と母集団の推定平均を同じものとして扱うと、抽出設計による重みを見落とします。
7共通の原因で二つの値が増える
負荷が上がるとCPU使用率と待ち時間が両方増えるモデルを作ります。CPU使用率を直接待ち時間の式には使っていません。
load = [1,2,3,4,5]共通の負荷; cpu = [10*x for x in load]; wait = [2*x+3 for x in load]各測定値を負荷から計算; list(zip(load,cpu,wait)), st.correlation(cpu,wait)対応表と相関係数相関係数は1です。しかしこの例では両方を負荷から計算しています。観測された相関だけでは、CPU使用率そのものが待ち時間を増やしたという因果関係を証明できません。
8相関係数が0でも関係がある場合
xとxの二乗の関係を調べます。正負が対称なので直線的な相関が打ち消されます。
x = [-2,-1,0,1,2]; y = [v*v for v in x]二次関数の値; list(zip(x,y)), st.correlation(x,y)対応表と直線的相関相関係数は0ですが、yはxの二乗で完全に決まっています。Pearsonの相関係数は直線的な関係を表す指標であり、0を無関係と読み替えることはできません。
まとめ
標本数だけでなく、どの対象がどのように選ばれたかを確認します。
母集団と異なる比率で抽出した標本では、目的に応じた重み付けが必要です。
相関は因果の証明ではなく、直線的相関0も関係がない証明にはなりません。
操作履歴と解説を振り返れます。
Python 3
import statistics as st; import random; population = [('A',10)]*80 + [('B',50)]*20; st.mean(value for site,value in population)18
head = population[:20]; {site for site,value in head}, st.mean(value for site,value in head)({'A'}, 10)rng = random.Random(2026); sample = rng.sample(population,20); sum(site == 'B' for site,value in sample), st.mean(value for site,value in sample)(5, 20)
means = [st.mean(value for site,value in rng.sample(population,20)) for _ in range(1000)]; min(means), max(means), st.mean(means)(10, 28, 17.9)
stratified = rng.sample(population[:80],16) + rng.sample(population[80:],4); st.mean(value for site,value in stratified)18
equal_sample = population[:10] + population[80:90]; st.mean(value for site,value in equal_sample), 0.8*10 + 0.2*50(30, 18.0)
load = [1,2,3,4,5]; cpu = [10*x for x in load]; wait = [2*x+3 for x in load]; list(zip(load,cpu,wait)), st.correlation(cpu,wait)([(1, 10, 5), (2, 20, 7), (3, 30, 9), (4, 40, 11), (5, 50, 13)], 1.0)
x = [-2,-1,0,1,2]; y = [v*v for v in x]; list(zip(x,y)), st.correlation(x,y)([(-2, 4), (-1, 1), (0, 0), (1, 1), (2, 4)], 0.0)
演習完了