この回のコードは,すべて tidyverse
を読み込んだ状態で動きます。
RStudioを起動したら,まずこれを実行してください。
毎回必要です。読み込まないまま
filter()やggplot()を使うと, 「関数が見つかりません」というエラーになります。
ここまでの流れを整理しておきます。
| 回 | 何と何の関係を見るか | 使う手法 |
|---|---|---|
| 第8回 | 量 と 量(身長と体重のような) | 相関分析 |
| 第9回(今日) | 分類 と 分類(性別と購買の有無のような) | カイ二乗検定 |
| 第10・11回 | グループ と 量(男女で平均点が違うか) | t検定 |
今日のデータは,これまでと性質が違います。平均が計算できません。 「男性と女性の平均」には意味がありませんし,「生存した人の平均」も意味をなしません。 数えること,つまり度数(件数)でしか扱えないのです。
行動科学研究法を履修している人へ
カイ二乗検定は,研究法では1月に扱われる予定の内容です。 つまり今日が初めてになります。考え方のところから丁寧に進めます。 一方,帰無仮説やp値の枠組みは1学期に学んだとおりで,そこは変わりません。
カテゴリデータ(名義・順序尺度):数値ではなく,グループや分類を表すデータ
| カテゴリデータの例 | 連続データとの違い |
|---|---|
| 性別(男・女) | 平均が計算できない |
| 学部(文・理・医…) | 「文学部の平均」は意味をなさない |
| 回答(はい・いいえ) | 頻度(件数)で分析する |
2つのカテゴリ変数の組み合わせごとの件数を表にしたものです。
クロス集計表ができると,つい割合を見比べて「差がある」と言いたくなります。 ところが,割合だけ見ても結論は出せません。
次の2つの表を見てください。
small <- matrix(c(16, 4, 10, 10), nrow = 2, byrow = TRUE,
dimnames = list(c("A群", "B群"), c("はい", "いいえ")))
small## はい いいえ
## A群 16 4
## B群 10 10
## はい いいえ
## A群 80 20
## B群 50 50
A群は80%,B群は50%。かなり違って見えます。では,この表をそのまま5倍にしてみます。
## はい いいえ
## A群 80 20
## B群 50 50
## はい いいえ
## A群 80 20
## B群 50 50
割合は1%も変わっていません。 ところが検定の結果は変わります。
## 小さい表 大きい表
## 9.742169e-02 1.713801e-05
小さい表では \(p > .05\),大きい表では \(p < .001\) です。
同じ割合なのに結論が逆になるのは,「その差が偶然でも起こりうるか」はデータの量によって変わるからです。20人で8割対5割なら偶然の範囲ですが,100人で同じ差が出たら偶然とは考えにくい。この判断を目分量ではなく手続きで行うのが検定です。
逆に言えば,\(p\) が小さいことは「差が大きい」ことを意味しません。 差の大きさは5節の効果量で別に測ります。
「性別と生存率は独立(無関係)か,それとも関連があるか?」
期待度数(H₀が正しいとしたときの理論上の頻度)と観測度数の差から計算します。
\[\chi^2 = \sum \frac{(観測度数 - 期待度数)^2}{期待度数}\]
ここが,この検定が独立性の検定と呼ばれるゆえんです。
2つの変数が独立であるとは,同時に起こる確率が,それぞれの確率の積で書けることでした。
\[P(A \cap B) = P(A) \times P(B)\]
いま \(A\) を「男性である」,\(B\) を「死亡した」とします。表から読める割合は次の2つです。
\[P(\text{男性}) = \frac{\text{男性の行合計}}{N}, \qquad P(\text{死亡}) = \frac{\text{死亡の列合計}}{N}\]
もし性別と生存が独立なら,両方に当てはまる人の割合は,この2つの積になるはずです。
\[P(\text{男性} \cap \text{死亡}) = \frac{\text{行合計}}{N} \times \frac{\text{列合計}}{N}\]
期待される人数は,この割合に総数 \(N\) を掛けたものです。
\[E = N \times \frac{\text{行合計}}{N} \times \frac{\text{列合計}}{N} = \frac{\text{行合計} \times \text{列合計}}{N}\]
\(N\) が1つ約分されて消え,見慣れた形になりました。
数値で確かめる:タイタニックの表では \(N = 2201\),男性の行合計 \(1731\),死亡の列合計 \(1490\) なので
\[E_{\text{男性・死亡}} = \frac{1731 \times 1490}{2201} = 1171.83\]
chisq.test(tab)$expected
が返す値と一致します。4つのセルの期待度数は次のとおりです。
| 死亡 | 生存 | 行合計 | |
|---|---|---|---|
| 男性 | 1171.83 | 559.17 | 1731 |
| 女性 | 318.17 | 151.83 | 470 |
| 列合計 | 1490 | 711 | 2201 |
観測値(男性の死亡は \(1364\) 人)はこれより大きく,\(E\) から離れています。期待度数は「独立だったらこうなるはずの表」であり,カイ二乗検定はそこからのズレを測っているのです。
使った数学:独立の定義(確率の積)と,割合に総数を掛けて人数に戻す操作。
ズレ \(O - E\) をそのまま全セル足すと,必ず 0 になります。
数値で確かめる:タイタニックの4セルのズレは
| 死亡 | 生存 | |
|---|---|---|
| 男性 | +192.17 | −192.17 |
| 女性 | −192.17 | +192.17 |
で,合計は \(0\) です。行合計と列合計が観測値と一致するように \(E\) を作ったので,プラスとマイナスが必ず打ち消し合います。これは第3回で見た「偏差をそのまま足すと 0」と同じ事情です。
そこで二乗して符号を消します。ここまでは分散のときと同じ考え方です。
残るのは「なぜ \(E\) で割るのか」です。同じ大きさのズレでも,期待される規模が違えば意味が違うからです。
| 期待度数 \(E\) | ズレ \(O-E\) | \((O-E)^2/E\) |
|---|---|---|
| 10 | 5 | 2.5 |
| 1000 | 5 | 0.025 |
10人しか来ないはずのところに5人多いのは大事件ですが,1000人来るところで5人多いのは誤差のうちです。\(E\) で割ることで,ズレを期待される規模に対する相対的な大きさに直しています。
数値で確かめる:4セルとも \(|O-E| = 192.17\) ですが,\(E\) が小さいセルほど寄与が大きくなり,合計は \(\chi^2 = 456.87\) になります。
本文の出力
X-squared = 454.5と少しずれるのはなぜか。 R は 2×2 の表に対して既定でイェーツの連続性補正を掛けます(出力の1行目にwith Yates' continuity correctionと書かれています)。補正なしの値が \(456.87\),補正後が \(454.50\) です。chisq.test(tab, correct = FALSE)とすると補正なしの値が得られます。結論は変わりません。
使った数学:偏差の和が 0 になること,二乗で符号を消すこと,相対化のための割り算。
## Survived
## Sex No Yes
## Male 1364 367
## Female 126 344
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tab
## X-squared = 454.5, df = 1, p-value < 2.2e-16
Pearson's Chi-squared test with Yates' continuity correction
X-squared = 454.5, df = 1, p-value < 2.2e-16
| 項目 | 意味 |
|---|---|
X-squared |
カイ二乗統計量 χ² |
df |
自由度(= (行数-1)×(列数-1)) |
p-value |
p値 |
p < .05 ならば「性別と生存は独立でない」(関連がある)と結論できます。
出力の「Yates’ continuity correction」とは。
2×2 の表のとき,R は既定でイェーツの連続性補正を適用します。 カイ二乗検定は「とびとびの度数」を「なめらかな分布」で近似しているので,そのズレを少し埋め合わせる調整です。 \(\chi^2\) がわずかに小さくなり,\(p\) 値は大きめ,つまり慎重な側に出ます。
今回は補正あり \(454.5\),補正なし \(456.9\) で,結論は変わりません。 外すときは
chisq.test(tab, correct = FALSE)と書きます。2×2 以外の表では,そもそも適用されません。
カイ二乗検定は近似を使っています。その近似は,各セルに十分な人数が期待されるときにしか成り立ちません。
目安は「期待度数が5未満のセルが全体の20%を超えないこと」です。満たさない場合,Rは警告を出します。
sparse <- matrix(c(8, 2, 3, 7), nrow = 2, byrow = TRUE,
dimnames = list(c("A群", "B群"), c("はい", "いいえ")))
chisq.test(sparse)## Warning in chisq.test(sparse): カイ自乗近似は不正確かもしれません
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: sparse
## X-squared = 3.2323, df = 1, p-value = 0.0722
期待度数を確認してみます。
## はい いいえ
## A群 5.5 4.5
## B群 5.5 4.5
5を下回るセルがあります。このようなときは,近似を使わず正確に確率を計算するフィッシャーの正確確率検定を使います。
##
## Fisher's Exact Test for Count Data
##
## data: sparse
## p-value = 0.06978
## alternative hypothesis: true odds ratio is not equal to 1
## 95 percent confidence interval:
## 0.8821175 127.0558418
## sample estimates:
## odds ratio
## 8.153063
実務上の注意:警告が出たまま結果を報告しないこと。 期待度数を確認し,小さければ
fisher.test()に切り替えます。 サンプルサイズが小さい研究ではよく起こります。
2×2の表なら「関連がある」で十分ですが,3×2以上の表では「どこが効いているのか」が分かりません。 そこで調整済み残差を見ます。
## Survived
## Class No Yes
## 1st 122 203
## 2nd 167 118
## 3rd 528 178
## Crew 673 212
##
## Pearson's Chi-squared test
##
## data: tab_class
## X-squared = 190.4, df = 3, p-value < 2.2e-16
## Survived
## Class No Yes
## 1st -12.59 12.59
## 2nd -3.52 3.52
## 3rd 4.89 -4.89
## Crew 6.87 -6.87
残差が正なら期待より多い,負なら期待より少ないことを表します。絶対値がおおむね2を超えるセルに注目します。
この表では1等が生存側に大きく正,3等と乗員が生存側に負で,「等級が高いほど生存しやすかった」という中身まで読み取れます。検定は「関連の有無」しか教えてくれません。中身は残差を見て初めて分かります。
p値は「統計的に有意かどうか」を示しますが, 「効果の大きさ」は別途,効果量で表します。
\[V = \sqrt{\frac{\chi^2}{n \cdot (k-1)}}\]
(n = 総度数,k = 行数・列数の小さい方)
# 効果量の計算(手動)
# 効果量は「関連の強さ」なので,連続性補正を外した χ² を使います
chi2 <- unname(chisq.test(tab, correct = FALSE)$statistic) # unname() で「X-squared」という名前を外す
n <- sum(tab)
k <- min(nrow(tab), ncol(tab))
V <- sqrt(chi2 / (n * (k - 1)))
round(V, 3)## [1] 0.456
なぜ
correct = FALSEなのか。 イェーツ補正は,\(p\) 値を慎重な側に寄せるための調整でした。 一方 \(V\) が表したいのは「関連がどれくらい強いか」であって,偶然かどうかの判定ではありません。 目的が違うので,効果量は補正を外した \(\chi^2\) から計算するのが一般的です。今回は補正あり \(V = 0.454\),補正なし \(V = 0.456\) で解釈は変わりませんが, セルの度数が小さい表では差が開きます。
| V の値 | 効果の大きさ |
|---|---|
| 0.1〜0.3 | 小 |
| 0.3〜0.5 | 中 |
| 0.5〜 | 大 |
まず自由度から。 カイ二乗検定では,行合計と列合計は観測された表のものに固定されています。すると,自由に決められるセルはごくわずかしかありません。
2×2 の表で確かめます。左上(男性・死亡)を \(1364\) と決めた瞬間,残りの3つは引き算で自動的に決まります。
つまり自由に動けるのは1つだけです。これが \(df = (2-1)(2-1) = 1\) の正体です。
一般には,各行で最後の1つが行合計から決まり,各列で最後の1つが列合計から決まるので,自由に決められるのは \((\text{行数}-1) \times (\text{列数}-1)\) 個になります。
次に \(V\) です。 \(\chi^2\) には困った性質があります。同じ関連の強さでも,データを増やすだけで大きくなるのです。全セルを \(m\) 倍すると,\((O-E)^2\) は \(m^2\) 倍,\(E\) は \(m\) 倍なので,比は \(m\) 倍になります。
\[\chi^2 \ \longrightarrow \ m\,\chi^2\]
一方 \(V\) の定義は
\[V = \sqrt{\frac{\chi^2}{n(k-1)}}\]
で,分子の \(\chi^2\) も分母の \(n\) も同じ \(m\) 倍になるため,約分されて \(V\) は変わりません。
数値で確かめる(補正なしの \(\chi^2\) で計算):
| データの量 | \(n\) | \(\chi^2\) | \(V\) | \(p\) |
|---|---|---|---|---|
| そのまま | 2,201 | 456.87 | 0.4556 | \(2 \times 10^{-101}\) |
| 2倍 | 4,402 | 913.75 | 0.4556 | \(1 \times 10^{-200}\) |
| 5倍 | 11,005 | 2284.37 | 0.4556 | ほぼ 0 |
| 10倍 | 22,010 | 4568.74 | 0.4556 | ほぼ 0 |
\(\chi^2\) と \(p\) はいくらでも動かせるのに,\(V\) は \(0.4556\) から動きません。
「有意である」と「関連が強い」は,別のことを言っています。 \(p\) は \(n\) を増やせば小さくできます。\(V\) は関連の強さそのものなので,\(n\) では動きません。だから本文7節のように \(\chi^2\)・\(p\)・\(V\) を並べて報告します。
なお,上の表も本文5節も,どちらも補正なしの \(\chi^2\) から \(V\) を計算しています(\(V = 0.4556\))。補正項は \(n\) に依存するため,補正を入れたまま倍率を変えると \(V\) がわずかに動いてしまい,「\(V\) は \(n\) に振り回されない」という性質が見えにくくなるからです。参考までに,補正ありで計算すると \(V = 0.454\) です。
使った数学:数え上げ(自由度),および比を取ると共通の倍率が消えること。
titanic_pct <- titanic_summary |>
group_by(Sex) |>
mutate(pct = Freq / sum(Freq) * 100)
ggplot(titanic_pct, aes(x = Sex, y = pct, fill = Survived)) +
geom_col() +
scale_fill_manual(values = c("No" = "#D95F02", "Yes" = "#1B9E77"),
labels = c("No" = "死亡", "Yes" = "生存")) +
labs(title = "タイタニック:性別と生存率",
x = "性別", y = "割合(%)", fill = "生存") +
theme_bw()論文・レポートでの記述例:
性別と生存の独立性を検定するためにカイ二乗検定を実施した。 その結果,性別と生存の間には有意な関連が認められた, χ²(1, N = 2201) = 454.5, p < .001, V = .46。
\(\chi^2\) と \(p\) は
chisq.test()の既定(イェーツ補正あり)の値, \(V\) は補正を外して計算した値です。検定と効果量で目的が違うためで,食い違いではありません。
mtcars
データを使って,シリンダー数(cyl)とトランスミッション(am)の
クロス集計表を作成してください。
演習1のクロス集計表を使って,カイ二乗検定を実施し,結果を解釈してください。
chisq.test() を実行する⚠ この表では警告が出ます
実行すると 「カイ自乗近似は不正確かもしれません」という警告が出ます。 期待度数を見ると,6セルのうち3セル(50%)が5未満です。 4節の目安「5未満のセルが全体の20%を超えないこと」を満たしていません。
警告が出たまま報告してはいけません。 フィッシャーの正確確率検定に切り替えてください。
この例では,カイ二乗検定が \(p\) = .013,フィッシャーが \(p\) = .009 で, どちらも有意という結論は変わりません。 結論が変わらないことを確かめたうえで,フィッシャーの結果を報告します。
mtcars の cyl(シリンダー数)と
am(0=オートマ, 1=マニュアル)の
関係を積み上げ棒グラフで表現してください。
mtcars |>
mutate(
am = factor(am, labels = c("オートマ", "マニュアル")),
cyl = factor(cyl, labels = c("4気筒", "6気筒", "8気筒"))
) |>
group_by(cyl, am) |>
summarise(n = n(), .groups = "drop") |>
group_by(cyl) |>
mutate(pct = n / sum(n) * 100) |>
ggplot(aes(x = cyl, y = pct, fill = am)) +
geom_col() +
scale_fill_brewer(palette = "Set2") +
labs(title = "シリンダー数とトランスミッションの関係",
x = "シリンダー数", y = "割合(%)", fill = "トランスミッション") +
theme_bw()table() / xtabs()
でクロス集計表を作成chisq.test() で独立性を検定fisher.test()
に切り替える