library(tidyverse)クロス集計・χ2検定・順位相関係数
カテゴリー変数の二変量統計について学びます。
パッケージの読み込み
クロス集計
データの準備
学生 200 人を対象とした調査(性別・スマートフォン OS・満足度)を想定する。
set.seed(42)
n <- 200
df <- tibble(
gender = sample(c("男", "女"), n, replace = TRUE),
os = sample(
c("iPhone", "Android"), n,
replace = TRUE, prob = c(0.55, 0.45)
),
satisfaction = ordered(
sample(1:5, n, replace = TRUE),
labels = c("非常に不満", "不満", "普通", "満足", "非常に満足")
)
)
head(df)# A tibble: 6 × 3
gender os satisfaction
<chr> <chr> <ord>
1 男 Android 満足
2 男 iPhone 非常に満足
3 男 Android 満足
4 男 iPhone 非常に満足
5 女 iPhone 満足
6 女 iPhone 普通
satisfaction を ordered() で「順序型」データにしておくと,後の順位相関でそのまま使える。
xtabs() によるクロス集計
tbl <- xtabs(~ gender + os, data = df)
tbl os
gender Android iPhone
女 37 74
男 37 52
xtabs() は「式(あるいはモデル)」(~ 行変数 + 列変数)を引数にとるので、データフレームと相性が良い。
addmargins() で周辺度数を追加
addmargins(tbl) os
gender Android iPhone Sum
女 37 74 111
男 37 52 89
Sum 74 126 200
proportions() で割合表に変換
margin 引数で「どの方向を 100% にするか」を指定する。
# 行方向:性別ごとの OS 比率
proportions(tbl, margin = 1) |> round(3) os
gender Android iPhone
女 0.333 0.667
男 0.416 0.584
# 列方向:OS ごとの性別比率
proportions(tbl, margin = 2) |> round(3) os
gender Android iPhone
女 0.500 0.587
男 0.500 0.413
# 総計基準:全体構成比
proportions(tbl) |> round(3) os
gender Android iPhone
女 0.185 0.370
男 0.185 0.260
margin |
基準 | 問い |
|---|---|---|
1 |
行合計 = 1 | 性別ごとに,OS の選択比率はどう違うか? |
2 |
列合計 = 1 | OS ごとに,性別の構成はどう違うか? |
| 省略 | 総計 = 1 | 全体に占める各セルの割合は? |
周辺度数付きで確認するには,割合変換後に再度 addmargins() をかける。
proportions(tbl) |> round(3) |> addmargins() os
gender Android iPhone Sum
女 0.185 0.370 0.555
男 0.185 0.260 0.445
Sum 0.370 0.630 1.000
χ2検定(独立性の検定)
2 変数が互いに独立か否かを検定する。
- H0(帰無仮説):性別と OS の選択は独立である
- H1(対立仮説):性別と OS の選択に関連がある(α = 0.05)
検定の実施
result_chi <- chisq.test(tbl)
result_chi
Pearson's Chi-squared test with Yates' continuity correction
data: tbl
X-squared = 1.1069, df = 1, p-value = 0.2928
結果は、χ2値が1.1069、p値が0.2928となった。 0.2928 > 0.05なので、H0を棄却できず、有意な関連があるとはいえない。
補足:Fisher の正確検定
期待度数が小さなのセルがあるときには「カイ自乗近似は不正確かもしれません」というメッセージが出ることがある。 そのような場合には、fisher.test() を使うとよい。
small_tbl <- matrix(
c(8, 2, 1, 9), nrow = 2,
dimnames = list(c("男", "女"), c("iPhone", "Android"))
)
fisher.test(small_tbl)
Fisher's Exact Test for Count Data
data: small_tbl
p-value = 0.005477
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
2.057999 1740.081669
sample estimates:
odds ratio
27.32632
順位相関係数
ピアソンの積率相関係数とスピアマンの順位相関係数
アンケートの満足度評価(1〜5 点)のような順序尺度データ, あるいは外れ値が大きく正規性が期待できない場合は, ピアソンの積率相関係数(いわゆる相関係数)ではなくスピアマンの順位相関係数 \(\rho\) を使う。
\[ \rho = 1 - \frac{6 \sum d_i^2}{n(n^2 - 1)} \]
\(d_i\):各観測におけるランクの差
| データの性質 | 推奨される相関係数 |
|---|---|
| 連続変数・正規性あり・外れ値なし | ピアソン(method = "pearson") |
| 順序尺度,または非正規・外れ値あり | スピアマン(method = "spearman") |
| 同順位が非常に多い順序データ | ケンドール(method = "kendall") |
データの確認
先ほど作った df の satisfaction(順序付き因子)と os(ダミー化)の関係を見る。 ここでは数値に変換して使う。
df2 <- df |>
mutate(
sat_num = as.integer(satisfaction), # 1〜5 の整数
os_num = as.integer(os == "iPhone") # iPhone = 1, Android = 0
)
head(df2[, c("gender", "os", "satisfaction", "sat_num", "os_num")])# A tibble: 6 × 5
gender os satisfaction sat_num os_num
<chr> <chr> <ord> <int> <int>
1 男 Android 満足 4 0
2 男 iPhone 非常に満足 5 1
3 男 Android 満足 4 0
4 男 iPhone 非常に満足 5 1
5 女 iPhone 満足 4 1
6 女 iPhone 普通 3 1
cor() によるスピアマン相関
cor(df2$sat_num, df2$os_num, method = "spearman")[1] -0.00558782
cor.test() による有意性検定
result_cor <- cor.test(
df2$sat_num, df2$os_num,
method = "spearman",
exact = FALSE # n が大きいとき(厳密計算は重い)
)
result_cor
Spearman's rank correlation rho
data: df2$sat_num and df2$os_num
S = 1340750, p-value = 0.9374
alternative hypothesis: true rho is not equal to 0
sample estimates:
rho
-0.00558782
0.9374073 > 0.05なので、有意な相関があるとはいえない。
複数変数の相関行列
df2 |>
select(sat_num, os_num) |>
cor(method = "spearman") |>
round(3) sat_num os_num
sat_num 1.000 -0.006
os_num -0.006 1.000
まとめ
| 関数 | 役割 |
|---|---|
| xtabs(~ 行 + 列, data) | クロス集計表の作成 |
| addmargins(tbl) | 周辺度数(行計・列計・総計)の追加 |
| proportions(tbl, margin = 1) | 行合計 = 1 の割合表 |
| proportions(tbl, margin = 2) | 列合計 = 1 の割合表 |
| chisq.test(tbl) | 独立性の χ² 検定 |
| fisher.test(tbl) | 独立性の Fisher 正確検定(小標本) |
| cor(…, method = ‘spearman’) | スピアマン順位相関係数の計算 |
| cor.test(…, method = ‘spearman’) | スピアマン相関の有意性検定 |