Tabel Kontingensi 2×2
Teori, Distribusi Peluang, dan Ukuran Asosiasi
📘 Tentang E-Book Ini
E-Book ini dirancang sebagai panduan komprehensif untuk memahami
tabel kontingensi 2×2 secara mendalam — mulai dari
definisi, distribusi peluang (joint, marginal, kondisional), hingga
berbagai ukuran asosiasi. Setiap konsep dilengkapi derivasi matematis
dalam format \(\LaTeX\) dan
implementasi langsung menggunakan R.
Target pembaca: mahasiswa statistika, epidemiologi, kedokteran, dan
ilmu sosial tingkat menengah hingga lanjut.
Dalam penelitian ilmiah, kita sering kali mengamati dua variabel kategorikal pada unit yang sama dan ingin mengetahui: apakah ada hubungan di antara keduanya? Pertanyaan ini mendasari hampir seluruh analisis data kategorik.
Tabel kontingensi (contingency table atau cross-tabulation table) adalah alat statistik utama untuk menjawab pertanyaan tersebut. Tabel ini merangkum distribusi bersama dari dua atau lebih variabel kategorikal ke dalam bentuk matriks frekuensi yang mudah dibaca dan dianalisis.
Bentuk paling sederhana — dan paling sering digunakan — adalah tabel kontingensi 2×2, yakni tabel yang terbentuk ketika kedua variabel masing-masing hanya memiliki dua kategori. Meskipun tampak sederhana, tabel 2×2 menyimpan kekayaan analitik yang luar biasa dan menjadi fondasi dari banyak metode statistik yang lebih kompleks.
E-Book ini mencakup:
| No. | Topik | Keterangan |
|---|---|---|
| 1 | Definisi Tabel Kontingensi | Pengertian, notasi, struktur |
| 2 | Contoh Tabel Kontingensi | Kasus nyata dari berbagai bidang |
| 3 | Distribusi Peluang | Joint, Marginal, Kondisional |
| 4 | Ukuran Asosiasi | OR, RR, \(\phi\), Cramer’s V, dll. |
| 5 | Perhitungan Manual | Derivasi lengkap dengan \(\LaTeX\) |
| 6 | Implementasi R | Kode lengkap dengan data simulasi |
Definisi (Tabel Kontingensi):
Tabel kontingensi adalah representasi tabular dari distribusi frekuensi
bersama dua atau lebih variabel kategorikal. Setiap sel dalam tabel
menyimpan frekuensi observasi yang memenuhi kombinasi kategori dari
variabel-variabel tersebut.
Secara formal, misalkan \(X\) dan \(Y\) adalah dua variabel acak diskret dengan ruang sampel:
\[X \in \{x_1, x_2, \ldots, x_r\} \quad \text{dan} \quad Y \in \{y_1, y_2, \ldots, y_c\}\]
Tabel kontingensi \(r \times c\) memiliki \(r\) baris (kategori \(X\)) dan \(c\) kolom (kategori \(Y\)), sehingga membentuk \(r \times c\) sel.
Untuk tabel 2×2, \(r = c = 2\), sehingga:
\[X \in \{0, 1\} \quad \text{dan} \quad Y \in \{0, 1\}\]
Struktur umum tabel kontingensi 2×2 dengan notasi \(n_{ij}\) (frekuensi observasi pada sel baris \(i\), kolom \(j\)):
\[ \begin{array}{c|cc|c} & Y = 1 & Y = 0 & \text{Total} \\ \hline X = 1 & n_{11} & n_{10} & n_{1\cdot} \\ X = 0 & n_{01} & n_{00} & n_{0\cdot} \\ \hline \text{Total} & n_{\cdot 1} & n_{\cdot 0} & n \\ \end{array} \]
Di mana:
Dalam epidemiologi dan penelitian klinis, tabel 2×2 sering dituliskan dengan notasi huruf a, b, c, d:
\[ \begin{array}{c|cc|c} & \textbf{Outcome (+)} & \textbf{Outcome (−)} & \textbf{Total} \\ \hline \textbf{Exposed (+)} & a & b & a+b \\ \textbf{Exposed (−)} & c & d & c+d \\ \hline \textbf{Total} & a+c & b+d & n \\ \end{array} \]
Interpretasi sel:
| Sel | Makna |
|---|---|
| \(a\) | Terpapar dan mengalami outcome (kasus terpapar) |
| \(b\) | Terpapar tetapi tidak mengalami outcome |
| \(c\) | Tidak terpapar tetapi mengalami outcome |
| \(d\) | Tidak terpapar dan tidak mengalami outcome |
Penting untuk dipahami bahwa struktur pengambilan sampel memengaruhi interpretasi tabel 2×2:
| Desain Penelitian | Margin yang Tetap | Metode Sampling |
|---|---|---|
| Cross-sectional | Hanya \(n\) | Sampel acak tunggal |
| Kohort / Eksperimental | Total baris (\(n_{1\cdot}, n_{0\cdot}\)) | Dua sampel independen berdasarkan paparan |
| Kasus-Kontrol | Total kolom (\(n_{\cdot 1}, n_{\cdot 0}\)) | Dua sampel independen berdasarkan outcome |
| Double Dichotomy | Semua margin | Uji Fisher Exact |
⚠️ Catatan Penting:
Desain penelitian memengaruhi ukuran asosiasi mana yang
valid untuk dihitung. Misalnya, Risk Ratio
hanya valid pada desain kohort atau cross-sectional, bukan
kasus-kontrol.
Sebuah studi kohort dilakukan selama 10 tahun untuk menyelidiki hubungan antara kebiasaan merokok dan kejadian kanker paru. Dari 800 perokok dan 1200 bukan perokok yang diamati, diperoleh data sebagai berikut:
\[ \begin{array}{c|cc|c} & \textbf{Kanker Paru (+)} & \textbf{Kanker Paru (−)} & \textbf{Total} \\ \hline \textbf{Merokok (+)} & 120 & 680 & 800 \\ \textbf{Merokok (−)} & 40 & 1160 & 1200 \\ \hline \textbf{Total} & 160 & 1840 & 2000 \\ \end{array} \]
# ── Membuat tabel kontingensi ──────────────────────────────────────────
ct1 <- matrix(c(120, 680, 40, 1160),
nrow = 2, byrow = TRUE,
dimnames = list(
Merokok = c("Ya", "Tidak"),
Kanker = c("Ya", "Tidak")
))
kable(ct1, caption = "Tabel 1. Rokok vs Kanker Paru (n = 2000)") |>
kable_styling(bootstrap_options = c("striped", "hover", "bordered"),
full_width = FALSE) |>
add_header_above(c(" " = 1, "Kanker Paru" = 2)) |>
column_spec(1, bold = TRUE, background = "#D6EAF8")| Ya | Tidak | |
|---|---|---|
| Ya | 120 | 680 |
| Tidak | 40 | 1160 |
Sebuah uji diagnostik cepat (rapid antigen test) diuji terhadap baku emas PCR pada 500 pasien yang dicurigai terinfeksi COVID-19:
\[ \begin{array}{c|cc|c} & \textbf{PCR (+)} & \textbf{PCR (−)} & \textbf{Total} \\ \hline \textbf{Rapid Test (+)} & 185 & 25 & 210 \\ \textbf{Rapid Test (−)} & 15 & 275 & 290 \\ \hline \textbf{Total} & 200 & 300 & 500 \\ \end{array} \]
ct2 <- matrix(c(185, 25, 15, 275),
nrow = 2, byrow = TRUE,
dimnames = list(
`Rapid Test` = c("(+)", "(−)"),
`PCR` = c("(+)", "(−)")
))
kable(ct2, caption = "Tabel 2. Uji Diagnostik Rapid Test vs PCR (n = 500)") |>
kable_styling(bootstrap_options = c("striped", "hover", "bordered"),
full_width = FALSE) |>
add_header_above(c(" " = 1, "Hasil PCR (Baku Emas)" = 2)) |>
column_spec(1, bold = TRUE, background = "#D5F5E3")| (+) | (−) | |
|---|---|---|
| (+) | 185 | 25 |
| (−) | 15 | 275 |
Survei terhadap 400 mahasiswa untuk menganalisis hubungan gender dengan preferensi karier (swasta vs pemerintah):
ct3 <- matrix(c(110, 90, 80, 120),
nrow = 2, byrow = TRUE,
dimnames = list(
Gender = c("Perempuan", "Laki-laki"),
Karier = c("Swasta", "Pemerintah")
))
kable(ct3, caption = "Tabel 3. Gender vs Preferensi Karier (n = 400)") |>
kable_styling(bootstrap_options = c("striped", "hover", "bordered"),
full_width = FALSE) |>
add_header_above(c(" " = 1, "Preferensi Karier" = 2)) |>
column_spec(1, bold = TRUE, background = "#FDEBD0")| Swasta | Pemerintah | |
|---|---|---|
| Perempuan | 110 | 90 |
| Laki-laki | 80 | 120 |
Definisi (Joint Probability):
Peluang bersama \(P(X = i, Y = j)\)
adalah peluang bahwa variabel \(X\)
mengambil nilai \(i\) dan
secara simultan \(Y\)
mengambil nilai \(j\).
Estimasi dari data observasi:
\[\hat{p}_{ij} = P(X = i, Y = j) = \frac{n_{ij}}{n}\]
Tabel peluang bersama (dengan \(n\) sebagai pembagi):
\[ \begin{array}{c|cc|c} & Y=1 & Y=0 & \text{Total} \\ \hline X=1 & \hat{p}_{11} = n_{11}/n & \hat{p}_{10} = n_{10}/n & \hat{p}_{1\cdot} \\ X=0 & \hat{p}_{01} = n_{01}/n & \hat{p}_{00} = n_{00}/n & \hat{p}_{0\cdot} \\ \hline \text{Total} & \hat{p}_{\cdot 1} & \hat{p}_{\cdot 0} & 1 \\ \end{array} \]
Sifat-sifat: - \(\hat{p}_{ij} \geq 0\) untuk semua \(i, j\) - \(\sum_{i}\sum_{j} \hat{p}_{ij} = 1\)
Definisi (Marginal Probability):
Distribusi marginal \(P(X = i)\) adalah
distribusi peluang dari satu variabel saja, tanpa
memperhatikan nilai variabel lainnya. Diperoleh dengan
menjumlahkan peluang bersama sepanjang satu dimensi.
\[\hat{p}_{i\cdot} = P(X = i) = \sum_{j} P(X=i, Y=j) = \frac{n_{i\cdot}}{n}\]
\[\hat{p}_{\cdot j} = P(Y = j) = \sum_{i} P(X=i, Y=j) = \frac{n_{\cdot j}}{n}\]
Secara intuitif, peluang marginal adalah frekuensi relatif yang tercantum di “pinggir” (margin) tabel.
Definisi (Conditional Probability):
Peluang kondisional \(P(Y = j \mid X =
i)\) adalah peluang bahwa \(Y =
j\) diberikan bahwa \(X = i\) telah diketahui. Ini membagi
distribusi bersama dengan distribusi marginal dari variabel kondisi.
Dari definisi peluang kondisional:
\[P(Y = j \mid X = i) = \frac{P(X = i, Y = j)}{P(X = i)} = \frac{n_{ij}}{n_{i\cdot}}\]
Demikian pula:
\[P(X = i \mid Y = j) = \frac{P(X = i, Y = j)}{P(Y = j)} = \frac{n_{ij}}{n_{\cdot j}}\]
Properti kunci: \[\sum_{j} P(Y = j \mid X = i) = 1 \quad \text{untuk setiap } i\]
Dua variabel \(X\) dan \(Y\) dikatakan saling independen jika dan hanya jika:
\[P(X = i, Y = j) = P(X = i) \cdot P(Y = j) \quad \forall \; i, j\]
Yang ekuivalen dengan:
\[P(Y = j \mid X = i) = P(Y = j) \quad \forall \; i, j\]
Artinya, mengetahui nilai \(X\) tidak memberikan informasi tambahan tentang nilai \(Y\).
# ── Data simulasi utama ────────────────────────────────────────────────
set.seed(2025)
n_total <- 1000
# Simulasi: Paparan (X) dan Outcome (Y) dengan asosiasi positif
paparan <- rbinom(n_total, 1, 0.45) # P(X=1) = 0.45
outcome <- ifelse(paparan == 1,
rbinom(n_total, 1, 0.40), # P(Y=1|X=1) = 0.40
rbinom(n_total, 1, 0.15)) # P(Y=1|X=0) = 0.15
df_sim <- data.frame(
Paparan = factor(paparan, levels = c(1,0), labels = c("Terpapar","Tidak Terpapar")),
Outcome = factor(outcome, levels = c(1,0), labels = c("Sakit","Tidak Sakit"))
)
# ── Tabel Frekuensi ───────────────────────────────────────────────────
tbl_freq <- table(df_sim$Paparan, df_sim$Outcome)
cat("=== TABEL FREKUENSI ===\n")#> === TABEL FREKUENSI ===
#>
#> Sakit Tidak Sakit Sum
#> Terpapar 179 272 451
#> Tidak Terpapar 93 456 549
#> Sum 272 728 1000
# ── Joint Probability ─────────────────────────────────────────────────
tbl_joint <- prop.table(tbl_freq)
cat("\n=== DISTRIBUSI PELUANG BERSAMA (Joint) ===\n")#>
#> === DISTRIBUSI PELUANG BERSAMA (Joint) ===
#>
#> Sakit Tidak Sakit Sum
#> Terpapar 0.179 0.272 0.451
#> Tidak Terpapar 0.093 0.456 0.549
#> Sum 0.272 0.728 1.000
# ── Marginal Probability ──────────────────────────────────────────────
cat("\n=== PELUANG MARGINAL BARIS P(Paparan) ===\n")#>
#> === PELUANG MARGINAL BARIS P(Paparan) ===
#>
#> Terpapar Tidak Terpapar
#> 0.451 0.549
#>
#> === PELUANG MARGINAL KOLOM P(Outcome) ===
#>
#> Sakit Tidak Sakit
#> 0.272 0.728
# ── Conditional Probability ───────────────────────────────────────────
tbl_cond_row <- prop.table(tbl_freq, margin = 1) # kondisi pada baris
tbl_cond_col <- prop.table(tbl_freq, margin = 2) # kondisi pada kolom
cat("\n=== DISTRIBUSI KONDISIONAL P(Outcome | Paparan) ===\n")#>
#> === DISTRIBUSI KONDISIONAL P(Outcome | Paparan) ===
#>
#> Sakit Tidak Sakit
#> Terpapar 0.3969 0.6031
#> Tidak Terpapar 0.1694 0.8306
#>
#> === DISTRIBUSI KONDISIONAL P(Paparan | Outcome) ===
#>
#> Sakit Tidak Sakit
#> Terpapar 0.6581 0.3736
#> Tidak Terpapar 0.3419 0.6264
# ── Visualisasi distribusi peluang ────────────────────────────────────
# 1. Mosaic plot
par(mfrow = c(1,2))
mosaicplot(tbl_freq,
main = "Mosaic Plot: Paparan vs Outcome",
color = c("#2980B9","#E74C3C"),
las = 1, cex.axis = 0.85,
xlab = "Paparan", ylab = "Outcome")
# 2. Grouped bar: conditional probability
cond_df <- as.data.frame(tbl_cond_row)
colnames(cond_df) <- c("Paparan","Outcome","Prob")
barplot_data <- matrix(c(tbl_cond_row[,"Sakit"], tbl_cond_row[,"Tidak Sakit"]),
nrow = 2, byrow = TRUE,
dimnames = list(c("Sakit","Tidak Sakit"),
c("Terpapar","Tidak Terpapar")))
barplot(barplot_data,
beside = FALSE,
col = c("#E74C3C","#2980B9"),
main = "P(Outcome | Paparan) — Stacked Bar",
ylab = "Peluang", xlab = "Paparan",
legend.text = c("Sakit","Tidak Sakit"),
args.legend = list(x = "topright", bty = "n"))# ── Tabel ringkasan estetis ───────────────────────────────────────────
df_joint <- as.data.frame(round(tbl_joint, 4))
colnames(df_joint) <- c("Paparan", "Outcome", "P(X,Y)")
kable(df_joint,
caption = "Distribusi Peluang Bersama (Joint Probability)") |>
kable_styling(bootstrap_options = c("striped","hover","bordered"),
full_width = FALSE)| Paparan | Outcome | P(X,Y) |
|---|---|---|
| Terpapar | Sakit | 0.179 |
| Tidak Terpapar | Sakit | 0.093 |
| Terpapar | Tidak Sakit | 0.272 |
| Tidak Terpapar | Tidak Sakit | 0.456 |
df_cond <- as.data.frame(round(tbl_cond_row, 4))
colnames(df_cond) <- c("Paparan", "Outcome", "P(Y|X)")
kable(df_cond,
caption = "Distribusi Peluang Kondisional P(Outcome | Paparan)") |>
kable_styling(bootstrap_options = c("striped","hover","bordered"),
full_width = FALSE)| Paparan | Outcome | P(Y|X) |
|---|---|---|
| Terpapar | Sakit | 0.3969 |
| Tidak Terpapar | Sakit | 0.1694 |
| Terpapar | Tidak Sakit | 0.6031 |
| Tidak Terpapar | Tidak Sakit | 0.8306 |
Setelah membentuk tabel kontingensi, pertanyaan berikutnya adalah: seberapa kuat hubungan antara kedua variabel? Ukuran asosiasi (measures of association) menjawab pertanyaan ini secara kuantitatif.
Proporsi risiko (risk atau prevalence) mengukur peluang mengalami outcome pada masing-masing kelompok:
\[R_1 = P(Y=1 \mid X=1) = \frac{n_{11}}{n_{1\cdot}} = \frac{a}{a+b}\]
\[R_0 = P(Y=1 \mid X=0) = \frac{n_{01}}{n_{0\cdot}} = \frac{c}{c+d}\]
Risk Ratio (RR) mengukur berapa kali lipat risiko outcome pada kelompok terpapar dibandingkan kelompok tidak terpapar.
\[\text{RR} = \frac{R_1}{R_0} = \frac{a/(a+b)}{c/(c+d)}\]
Interpretasi:
| Nilai RR | Makna |
|---|---|
| \(\text{RR} = 1\) | Tidak ada asosiasi |
| \(\text{RR} > 1\) | Paparan meningkatkan risiko (risk factor) |
| \(\text{RR} < 1\) | Paparan menurunkan risiko (protective factor) |
Confidence Interval 95% untuk ln(RR):
\[\text{SE}[\ln(\widehat{\text{RR}})] = \sqrt{\frac{1}{a} - \frac{1}{a+b} + \frac{1}{c} - \frac{1}{c+d}}\]
\[\text{95% CI: } \exp\!\left(\ln\widehat{\text{RR}} \pm 1.96 \cdot \text{SE}[\ln\widehat{\text{RR}}]\right)\]
Odds Ratio (OR) membandingkan odds terjadinya outcome pada kelompok terpapar dengan kelompok tidak terpapar. OR valid di semua desain penelitian, termasuk kasus-kontrol.
Odds pada kelompok terpapar:
\[\text{Odds}_1 = \frac{P(Y=1 \mid X=1)}{P(Y=0 \mid X=1)} = \frac{a/({a+b})}{b/({a+b})} = \frac{a}{b}\]
Odds pada kelompok tidak terpapar:
\[\text{Odds}_0 = \frac{P(Y=1 \mid X=0)}{P(Y=0 \mid X=0)} = \frac{c}{d}\]
Odds Ratio:
\[\text{OR} = \frac{\text{Odds}_1}{\text{Odds}_0} = \frac{a/b}{c/d} = \frac{ad}{bc}\]
Perhatikan bahwa OR dapat dihitung sebagai rasio silang (cross-product ratio) \(\frac{ad}{bc}\).
Standard Error dan CI untuk ln(OR):
\[\text{SE}[\ln(\widehat{\text{OR}})] = \sqrt{\frac{1}{a} + \frac{1}{b} + \frac{1}{c} + \frac{1}{d}}\]
\[\text{95% CI: } \exp\!\left(\ln\widehat{\text{OR}} \pm 1.96 \cdot \text{SE}[\ln\widehat{\text{OR}}]\right)\]
\[\text{RD} = R_1 - R_0 = \frac{a}{a+b} - \frac{c}{c+d}\]
SE dan CI:
\[\text{SE}(\widehat{\text{RD}}) = \sqrt{\frac{R_1(1-R_1)}{n_{1\cdot}} + \frac{R_0(1-R_0)}{n_{0\cdot}}}\]
\[\text{95% CI: } \widehat{\text{RD}} \pm 1.96 \cdot \text{SE}(\widehat{\text{RD}})\]
Untuk tabel 2×2, koefisien phi adalah ukuran asosiasi berbasis korelasi:
\[\phi = \frac{ad - bc}{\sqrt{(a+b)(c+d)(a+c)(b+d)}}\]
Atau dalam notasi statistik chi-square:
\[\phi = \sqrt{\frac{\chi^2}{n}}\]
Nilai: \(-1 \leq \phi \leq 1\). Nilai \(|\phi|\) mendekati 1 menunjukkan asosiasi kuat.
Untuk tabel \(r \times c\) umum, Cramer’s V adalah generalisasi dari \(\phi\):
\[V = \sqrt{\frac{\chi^2}{n \cdot \min(r-1, c-1)}}\]
Untuk tabel 2×2, \(V = |\phi|\).
Uji ini menguji hipotesis: - \(H_0\): \(X\) dan \(Y\) saling independen - \(H_1\): \(X\) dan \(Y\) tidak independen
Frekuensi harapan di bawah \(H_0\):
\[E_{ij} = \frac{n_{i\cdot} \cdot n_{\cdot j}}{n}\]
Statistik uji:
\[\chi^2 = \sum_{i}\sum_{j} \frac{(O_{ij} - E_{ij})^2}{E_{ij}} \sim \chi^2_{(r-1)(c-1)}\]
Untuk tabel 2×2, \(df = (2-1)(2-1) = 1\).
Rumus ringkas untuk tabel 2×2:
\[\chi^2 = \frac{n(ad-bc)^2}{(a+b)(c+d)(a+c)(b+d)}\]
| Ukuran | Formula | Keterangan |
|---|---|---|
| Sensitivitas | \(\text{Se} = a/(a+c)\) | P(Tes+ | Sakit) |
| Spesifisitas | \(\text{Sp} = d/(b+d)\) | P(Tes− | Tidak Sakit) |
| PPV | \(\text{PPV} = a/(a+b)\) | P(Sakit | Tes+) |
| NPV | \(\text{NPV} = d/(c+d)\) | P(Tidak Sakit | Tes−) |
| Akurasi | \((a+d)/n\) | Proporsi klasifikasi benar |
Kita akan menggunakan data simulasi berikut. Sebuah studi kohort pada 500 individu mengamati hubungan antara konsumsi alkohol (Ya/Tidak) dan hipertensi (Ya/Tidak):
\[ \begin{array}{c|cc|c} & \textbf{Hipertensi (Y=1)} & \textbf{Tidak Hipertensi (Y=0)} & \textbf{Total} \\ \hline \textbf{Alkohol (X=1)} & a = 80 & b = 120 & a+b = 200 \\ \textbf{Tidak Alkohol (X=0)} & c = 50 & d = 250 & c+d = 300 \\ \hline \textbf{Total} & a+c = 130 & b+d = 370 & n = 500 \\ \end{array} \]
\[\hat{p}_{11} = \frac{a}{n} = \frac{80}{500} = 0.160\]
\[\hat{p}_{10} = \frac{b}{n} = \frac{120}{500} = 0.240\]
\[\hat{p}_{01} = \frac{c}{n} = \frac{50}{500} = 0.100\]
\[\hat{p}_{00} = \frac{d}{n} = \frac{250}{500} = 0.500\]
Verifikasi: \(0.160 + 0.240 + 0.100 + 0.500 = 1.000\) ✓
\[P(X=1) = \hat{p}_{1\cdot} = \frac{a+b}{n} = \frac{200}{500} = 0.400\]
\[P(X=0) = \hat{p}_{0\cdot} = \frac{c+d}{n} = \frac{300}{500} = 0.600\]
\[P(Y=1) = \hat{p}_{\cdot 1} = \frac{a+c}{n} = \frac{130}{500} = 0.260\]
\[P(Y=0) = \hat{p}_{\cdot 0} = \frac{b+d}{n} = \frac{370}{500} = 0.740\]
\[P(Y=1 \mid X=1) = \frac{a}{a+b} = \frac{80}{200} = 0.400\]
\[P(Y=1 \mid X=0) = \frac{c}{c+d} = \frac{50}{300} = 0.1\overline{6} \approx 0.167\]
Interpretasi: Prevalensi hipertensi pada peminum alkohol (40%) jauh lebih tinggi dibandingkan bukan peminum (16.7%).
Jika \(X\) dan \(Y\) independen, maka:
\[P(Y=1 \mid X=1) \overset{?}{=} P(Y=1)\]
\[0.400 \neq 0.260\]
Karena \(P(Y=1 \mid X=1) \neq P(Y=1)\), terdapat indikasi ketidakindependenan (asosiasi positif).
\[\widehat{\text{RR}} = \frac{P(Y=1 \mid X=1)}{P(Y=1 \mid X=0)} = \frac{a/(a+b)}{c/(c+d)} = \frac{80/200}{50/300} = \frac{0.4000}{0.1667} = 2.400\]
Standard Error:
\[\text{SE}[\ln(\widehat{\text{RR}})] = \sqrt{\frac{1}{a} - \frac{1}{a+b} + \frac{1}{c} - \frac{1}{c+d}}\]
\[= \sqrt{\frac{1}{80} - \frac{1}{200} + \frac{1}{50} - \frac{1}{300}}\]
\[= \sqrt{0.01250 - 0.00500 + 0.02000 - 0.00333}\]
\[= \sqrt{0.02417} = 0.1555\]
95% Confidence Interval:
\[\ln(\widehat{\text{RR}}) = \ln(2.400) = 0.8755\]
\[\text{Lower: } \exp(0.8755 - 1.96 \times 0.1555) = \exp(0.5707) = 1.769\]
\[\text{Upper: } \exp(0.8755 + 1.96 \times 0.1555) = \exp(1.1803) = 3.254\]
\[\boxed{\widehat{\text{RR}} = 2.40 \quad (95\%\ \text{CI: } 1.77 - 3.25)}\]
Interpretasi: Peminum alkohol memiliki risiko hipertensi 2.40 kali lebih tinggi dibandingkan bukan peminum, dan hubungan ini secara statistik signifikan (CI tidak mencakup 1).
\[\widehat{\text{OR}} = \frac{ad}{bc} = \frac{80 \times 250}{120 \times 50} = \frac{20000}{6000} = 3.\overline{3} \approx 3.333\]
Standard Error:
\[\text{SE}[\ln(\widehat{\text{OR}})] = \sqrt{\frac{1}{a} + \frac{1}{b} + \frac{1}{c} + \frac{1}{d}}\]
\[= \sqrt{\frac{1}{80} + \frac{1}{120} + \frac{1}{50} + \frac{1}{250}}\]
\[= \sqrt{0.01250 + 0.00833 + 0.02000 + 0.00400}\]
\[= \sqrt{0.04483} = 0.2117\]
95% Confidence Interval:
\[\ln(\widehat{\text{OR}}) = \ln(3.333) = 1.2040\]
\[\text{Lower: } \exp(1.2040 - 1.96 \times 0.2117) = \exp(0.7891) = 2.202\]
\[\text{Upper: } \exp(1.2040 + 1.96 \times 0.2117) = \exp(1.6189) = 5.048\]
\[\boxed{\widehat{\text{OR}} = 3.33 \quad (95\%\ \text{CI: } 2.20 - 5.05)}\]
\[\widehat{\text{RD}} = R_1 - R_0 = 0.400 - 0.167 = 0.233\]
\[\text{SE}(\widehat{\text{RD}}) = \sqrt{\frac{0.4 \times 0.6}{200} + \frac{0.167 \times 0.833}{300}} = \sqrt{0.001200 + 0.000464} = \sqrt{0.001664} = 0.0408\]
\[\text{95% CI: } 0.233 \pm 1.96 \times 0.0408 = (0.153,\ 0.313)\]
\[\boxed{\widehat{\text{RD}} = 0.233 \quad (95\%\ \text{CI: } 0.153 - 0.313)}\]
Frekuensi harapan:
\[E_{11} = \frac{(a+b)(a+c)}{n} = \frac{200 \times 130}{500} = 52.0\]
\[E_{10} = \frac{(a+b)(b+d)}{n} = \frac{200 \times 370}{500} = 148.0\]
\[E_{01} = \frac{(c+d)(a+c)}{n} = \frac{300 \times 130}{500} = 78.0\]
\[E_{00} = \frac{(c+d)(b+d)}{n} = \frac{300 \times 370}{500} = 222.0\]
Statistik Chi-Square:
\[\chi^2 = \frac{(80-52)^2}{52} + \frac{(120-148)^2}{148} + \frac{(50-78)^2}{78} + \frac{(250-222)^2}{222}\]
\[= \frac{784}{52} + \frac{784}{148} + \frac{784}{78} + \frac{784}{222}\]
\[= 15.077 + 5.297 + 10.051 + 3.532 = 33.957\]
\[\chi^2 = 33.957 \quad \text{dengan } df = 1, \quad p\text{-value} < 0.0001\]
\[\boxed{\chi^2 = 33.96, \quad df = 1, \quad p < 0.001}\]
\[\phi = \frac{ad - bc}{\sqrt{(a+b)(c+d)(a+c)(b+d)}}\]
\[= \frac{(80)(250) - (120)(50)}{\sqrt{(200)(300)(130)(370)}}\]
\[= \frac{20000 - 6000}{\sqrt{200 \times 300 \times 130 \times 370}}\]
\[= \frac{14000}{\sqrt{2{,}886{,}000{,}000}} = \frac{14000}{53721.5} = 0.2606\]
\[\boxed{\phi = 0.261}\]
Atau menggunakan relasi dengan chi-square:
\[\phi = \sqrt{\frac{\chi^2}{n}} = \sqrt{\frac{33.957}{500}} = \sqrt{0.06791} = 0.261 \quad \checkmark\]
# ────────────────────────────────────────────────────────────────────────
# DATA SIMULASI: Alkohol vs Hipertensi
# ────────────────────────────────────────────────────────────────────────
set.seed(2025)
n <- 500
# Tentukan paparan: 200 terpapar, 300 tidak terpapar
alkohol <- c(rep(1, 200), rep(0, 300))
# Simulasi outcome berdasarkan probabilitas kondisional
hipertensi <- c(
rbinom(200, 1, 0.40), # P(Y=1 | X=1) = 0.40
rbinom(300, 1, 0.167) # P(Y=1 | X=0) = 0.167
)
df <- data.frame(
Alkohol = factor(alkohol, levels = c(1,0), labels = c("Ya","Tidak")),
Hipertensi = factor(hipertensi, levels = c(1,0), labels = c("Ya","Tidak"))
)
cat("Dimensi data:", dim(df), "\n")#> Dimensi data: 500 2
#> Distribusi Alkohol:
#>
#> Ya Tidak
#> 200 300
#>
#> Preview data:
#> Alkohol Hipertensi
#> 1 Ya Ya
#> 2 Ya Tidak
#> 3 Ya Tidak
#> 4 Ya Tidak
#> 5 Ya Ya
#> 6 Ya Tidak
#> 7 Ya Ya
#> 8 Ya Tidak
#> 9 Ya Ya
#> 10 Ya Tidak
# ── Tabel kontingensi dari data simulasi ─────────────────────────────
ct_sim <- table(Alkohol = df$Alkohol, Hipertensi = df$Hipertensi)
cat("=== TABEL KONTINGENSI ===\n")#> === TABEL KONTINGENSI ===
#> Hipertensi
#> Alkohol Ya Tidak Sum
#> Ya 89 111 200
#> Tidak 52 248 300
#> Sum 141 359 500
kable(addmargins(ct_sim),
caption = "Tabel Kontingensi: Alkohol vs Hipertensi (Simulasi, n=500)") |>
kable_styling(bootstrap_options = c("striped","hover","bordered"),
full_width = FALSE) |>
column_spec(1, bold = TRUE) |>
row_spec(3, bold = TRUE, background = "#D6EAF8")| Ya | Tidak | Sum | |
|---|---|---|---|
| Ya | 89 | 111 | 200 |
| Tidak | 52 | 248 | 300 |
| Sum | 141 | 359 | 500 |
a <- ct_sim["Ya","Ya"]; b <- ct_sim["Ya","Tidak"]
c <- ct_sim["Tidak","Ya"]; d <- ct_sim["Tidak","Tidak"]
n <- sum(ct_sim)
cat("=== SEL TABEL: a =", a, ", b =", b, ", c =", c, ", d =", d, ", n =", n, "\n\n")#> === SEL TABEL: a = 89 , b = 111 , c = 52 , d = 248 , n = 500
#> --- JOINT PROBABILITY ---
#> Hipertensi
#> Alkohol Ya Tidak Sum
#> Ya 0.178 0.222 0.400
#> Tidak 0.104 0.496 0.600
#> Sum 0.282 0.718 1.000
#>
#> --- MARGINAL PROBABILITY ---
#> P(Alkohol = Ya) = 0.4
#> P(Alkohol = Tidak) = 0.6
#> P(Hipertensi = Ya) = 0.282
#> P(Hipertensi = Tidak) = 0.718
#>
#> --- CONDITIONAL PROBABILITY P(Hipertensi | Alkohol) ---
#> Hipertensi
#> Alkohol Ya Tidak
#> Ya 0.4450 0.5550
#> Tidak 0.1733 0.8267
# ── Fungsi perhitungan manual ─────────────────────────────────────────
hitung_asosiasi <- function(a, b, c, d) {
n <- a + b + c + d
R1 <- a / (a + b)
R0 <- c / (c + d)
# Risk Ratio
RR <- R1 / R0
se_lnRR <- sqrt(1/a - 1/(a+b) + 1/c - 1/(c+d))
ci_RR <- exp(log(RR) + c(-1,1) * 1.96 * se_lnRR)
# Odds Ratio
OR <- (a * d) / (b * c)
se_lnOR <- sqrt(1/a + 1/b + 1/c + 1/d)
ci_OR <- exp(log(OR) + c(-1,1) * 1.96 * se_lnOR)
# Risk Difference
RD <- R1 - R0
se_RD <- sqrt(R1*(1-R1)/(a+b) + R0*(1-R0)/(c+d))
ci_RD <- RD + c(-1,1) * 1.96 * se_RD
# Chi-Square
E11 <- (a+b)*(a+c)/n; E10 <- (a+b)*(b+d)/n
E01 <- (c+d)*(a+c)/n; E00 <- (c+d)*(b+d)/n
chi2 <- (a-E11)^2/E11 + (b-E10)^2/E10 +
(c-E01)^2/E01 + (d-E00)^2/E00
p_val <- pchisq(chi2, df = 1, lower.tail = FALSE)
# Phi coefficient
phi <- (a*d - b*c) / sqrt((a+b)*(c+d)*(a+c)*(b+d))
list(
Prevalensi_Terpapar = round(R1, 4),
Prevalensi_TidakTerpapar = round(R0, 4),
RR = round(RR, 4), CI_RR = round(ci_RR, 4),
OR = round(OR, 4), CI_OR = round(ci_OR, 4),
RD = round(RD, 4), CI_RD = round(ci_RD, 4),
Chi2 = round(chi2, 4), p_value = signif(p_val, 3),
Phi = round(phi, 4)
)
}
hasil <- hitung_asosiasi(a, b, c, d)
cat("========================================\n")#> ========================================
#> RINGKASAN UKURAN ASOSIASI
#> ========================================
cat(sprintf(" Prevalensi (Terpapar) : %.4f (%.1f%%)\n",
hasil$Prevalensi_Terpapar, hasil$Prevalensi_Terpapar*100))#> Prevalensi (Terpapar) : 0.4450 (44.5%)
cat(sprintf(" Prevalensi (Tidak Terpapar): %.4f (%.1f%%)\n",
hasil$Prevalensi_TidakTerpapar, hasil$Prevalensi_TidakTerpapar*100))#> Prevalensi (Tidak Terpapar): 0.1733 (17.3%)
#> ----------------------------------------
cat(sprintf(" Risk Ratio (RR) : %.4f [95%% CI: %.4f – %.4f]\n",
hasil$RR, hasil$CI_RR[1], hasil$CI_RR[2]))#> Risk Ratio (RR) : 2.5673 [95% CI: 1.9180 – 3.4365]
cat(sprintf(" Odds Ratio (OR) : %.4f [95%% CI: %.4f – %.4f]\n",
hasil$OR, hasil$CI_OR[1], hasil$CI_OR[2]))#> Odds Ratio (OR) : 3.8240 [95% CI: 2.5408 – 5.7553]
cat(sprintf(" Risk Difference : %.4f [95%% CI: %.4f – %.4f]\n",
hasil$RD, hasil$CI_RD[1], hasil$CI_RD[2]))#> Risk Difference : 0.2717 [95% CI: 0.1906 – 0.3528]
#> ----------------------------------------
#> Chi-Square (χ²) : 43.7402 (df = 1)
#> p-value : 3.75e-11
#> Phi Coefficient : NA
#> ========================================
epitools dan vcd# ── Menggunakan paket epitools ─────────────────────────────────────────
if (requireNamespace("epitools", quietly = TRUE)) {
cat("=== VERIFIKASI DENGAN epitools ===\n\n")
# riskratio membutuhkan matriks dengan exposed di baris ke-1
ct_ep <- matrix(c(a, c, b, d), nrow = 2,
dimnames = list(c("Exposed","Unexposed"), c("Cases","NonCases")))
rr_res <- epitools::riskratio(ct_ep, method = "wald")
or_res <- epitools::oddsratio(ct_ep, method = "wald")
cat("Risk Ratio:\n")
print(rr_res$measure)
cat("\nOdds Ratio:\n")
print(or_res$measure)
}#> === VERIFIKASI DENGAN epitools ===
#>
#> Risk Ratio:
#> NA
#> risk ratio with 95% C.I. estimate lower upper
#> Exposed 1.000000 NA NA
#> Unexposed 1.489489 1.302065 1.703892
#>
#> Odds Ratio:
#> NA
#> odds ratio with 95% C.I. estimate lower upper
#> Exposed 1.000000 NA NA
#> Unexposed 3.823978 2.540779 5.755245
# ── Uji Chi-Square bawaan R ───────────────────────────────────────────
cat("=== UJI CHI-SQUARE (stats::chisq.test) ===\n")#> === UJI CHI-SQUARE (stats::chisq.test) ===
#>
#> Pearson's Chi-squared test
#>
#> data: ct_sim
#> X-squared = 43.74, df = 1, p-value = 3.75e-11
#>
#> === FREKUENSI HARAPAN ===
#> Hipertensi
#> Alkohol Ya Tidak
#> Ya 56.4 143.6
#> Tidak 84.6 215.4
# ── Fisher's Exact Test ──────────────────────────────────────────────
cat("\n=== FISHER'S EXACT TEST ===\n")#>
#> === FISHER'S EXACT TEST ===
#>
#> Fisher's Exact Test for Count Data
#>
#> data: ct_sim
#> p-value = 8.606e-11
#> alternative hypothesis: true odds ratio is not equal to 1
#> 95 percent confidence interval:
#> 2.490956 5.883355
#> sample estimates:
#> odds ratio
#> 3.812619
# ── Forest plot ukuran asosiasi ───────────────────────────────────────
ukuran_df <- data.frame(
Ukuran = c("Risk Ratio (RR)", "Odds Ratio (OR)"),
Estimasi = c(hasil$RR, hasil$OR),
Lower = c(hasil$CI_RR[1], hasil$CI_OR[1]),
Upper = c(hasil$CI_RR[2], hasil$CI_OR[2])
)
ggplot(ukuran_df, aes(x = Estimasi, y = Ukuran)) +
geom_vline(xintercept = 1, linetype = "dashed", color = "gray50", linewidth = 0.8) +
geom_errorbarh(aes(xmin = Lower, xmax = Upper),
height = 0.2, color = "#2980B9", linewidth = 1) +
geom_point(aes(size = 3), color = "#E74C3C", shape = 18) +
geom_text(aes(label = sprintf("%.2f (%.2f–%.2f)", Estimasi, Lower, Upper)),
hjust = -0.1, size = 3.8, color = "#2c3e50") +
scale_x_continuous(limits = c(0.5, 7), breaks = c(1, 2, 3, 4, 5)) +
labs(title = "Forest Plot: Ukuran Asosiasi Alkohol → Hipertensi",
x = "Estimasi (skala linear)", y = NULL) +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold", color = "#1a5276"),
legend.position = "none",
panel.grid.minor = element_blank())# ── Bar chart: Prevalensi per kelompok ────────────────────────────────
prev_df <- data.frame(
Kelompok = c("Peminum Alkohol", "Bukan Peminum"),
Prevalensi = c(hasil$Prevalensi_Terpapar, hasil$Prevalensi_TidakTerpapar),
Lower = c(hasil$Prevalensi_Terpapar - 1.96*sqrt(hasil$Prevalensi_Terpapar*(1-hasil$Prevalensi_Terpapar)/sum(a,b)),
hasil$Prevalensi_TidakTerpapar - 1.96*sqrt(hasil$Prevalensi_TidakTerpapar*(1-hasil$Prevalensi_TidakTerpapar)/sum(c,d))),
Upper = c(hasil$Prevalensi_Terpapar + 1.96*sqrt(hasil$Prevalensi_Terpapar*(1-hasil$Prevalensi_Terpapar)/sum(a,b)),
hasil$Prevalensi_TidakTerpapar + 1.96*sqrt(hasil$Prevalensi_TidakTerpapar*(1-hasil$Prevalensi_TidakTerpapar)/sum(c,d)))
)
ggplot(prev_df, aes(x = Kelompok, y = Prevalensi, fill = Kelompok)) +
geom_col(width = 0.5, alpha = 0.85) +
geom_errorbar(aes(ymin = Lower, ymax = Upper), width = 0.15, linewidth = 1) +
geom_text(aes(label = scales::percent(Prevalensi, accuracy = 0.1)),
vjust = -1.8, size = 4, fontface = "bold") +
scale_fill_manual(values = c("#E74C3C", "#2980B9")) +
scale_y_continuous(labels = scales::percent, limits = c(0, 0.55)) +
labs(title = "Prevalensi Hipertensi Berdasarkan Status Konsumsi Alkohol",
subtitle = sprintf("RR = %.2f, OR = %.2f | χ² = %.2f, p < 0.001",
hasil$RR, hasil$OR, hasil$Chi2),
x = NULL, y = "Prevalensi Hipertensi (%)",
caption = "Error bar: 95% Confidence Interval") +
theme_minimal(base_size = 12) +
theme(legend.position = "none",
plot.title = element_text(face = "bold", color = "#1a5276"),
plot.subtitle = element_text(color = "gray40"))# ── Tabel ringkasan hasil analisis ───────────────────────────────────
df_hasil <- data.frame(
`Ukuran Asosiasi` = c(
"Risk Ratio (RR)",
"Odds Ratio (OR)",
"Risk Difference (RD)",
"Chi-Square (χ²)",
"p-value",
"Phi Coefficient (φ)"
),
`Estimasi` = c(
sprintf("%.3f", hasil$RR),
sprintf("%.3f", hasil$OR),
sprintf("%.3f", hasil$RD),
sprintf("%.3f", hasil$Chi2),
as.character(hasil$p_value),
sprintf("%.3f", hasil$Phi)
),
`95% CI` = c(
sprintf("[%.3f – %.3f]", hasil$CI_RR[1], hasil$CI_RR[2]),
sprintf("[%.3f – %.3f]", hasil$CI_OR[1], hasil$CI_OR[2]),
sprintf("[%.3f – %.3f]", hasil$CI_RD[1], hasil$CI_RD[2]),
"df = 1", "—", "—"
),
`Interpretasi` = c(
"Risiko 2.4× lebih tinggi pada peminum",
"Odds 3.3× lebih tinggi pada peminum",
"Selisih risiko 23.3 poin persentase",
"Signifikan (p < 0.001)",
"Tolak H₀ independensi",
"Asosiasi sedang positif"
),
check.names = FALSE
)
kable(df_hasil,
caption = "Tabel Ringkasan Ukuran Asosiasi: Alkohol vs Hipertensi (n = 500)") |>
kable_styling(bootstrap_options = c("striped","hover","bordered"),
full_width = TRUE) |>
column_spec(1, bold = TRUE, background = "#D6EAF8") |>
column_spec(4, italic = TRUE) |>
row_spec(0, bold = TRUE, color = "white", background = "#2980B9")| Ukuran Asosiasi | Estimasi | 95% CI | Interpretasi |
|---|---|---|---|
| Risk Ratio (RR) | 2.567 | [1.918 – 3.437] | Risiko 2.4× lebih tinggi pada peminum |
| Odds Ratio (OR) | 3.824 | [2.541 – 5.755] | Odds 3.3× lebih tinggi pada peminum |
| Risk Difference (RD) | 0.272 | [0.191 – 0.353] | Selisih risiko 23.3 poin persentase |
| Chi-Square (χ²) | 43.740 | df = 1 | Signifikan (p < 0.001) |
| p-value | 3.75e-11 | — | Tolak H₀ independensi |
| Phi Coefficient (φ) | NA | — | Asosiasi sedang positif |
Tabel kontingensi 2×2 merupakan alat analisis yang sangat fundamental dalam statistika kategorikal. Berikut adalah poin-poin kunci yang telah kita pelajari:
1. Definisi dan Struktur
Tabel 2×2 terbentuk dari dua variabel biner dan menghasilkan empat sel
(\(a, b, c, d\)) dengan total marginal
baris, kolom, dan grand total \(n\).
2. Distribusi Peluang
Tiga jenis distribusi peluang yang dapat diekstrak dari tabel 2×2:
3. Ukuran Asosiasi
Empat ukuran utama beserta konteks penggunaannya:
| Ukuran | Validitas Desain | Nilai Null | Interpretasi |
|---|---|---|---|
| RR | Kohort, Cross-sectional | RR = 1 | Rasio risiko langsung |
| OR | Semua desain | OR = 1 | Rasio odds (mendekati RR bila rare) |
| RD | Kohort, Cross-sectional | RD = 0 | Selisih risiko absolut |
| φ | Semua desain | φ = 0 | Kekuatan asosiasi (−1 hingga 1) |
4. Prinsip Desain Penelitian
Pemilihan ukuran asosiasi harus selalu mempertimbangkan desain
penelitian. Khususnya, RR tidak dapat dihitung secara langsung
pada desain kasus-kontrol.
📌 Catatan Reproduksibilitas:
Seluruh analisis dalam E-Book ini dapat direproduksi secara penuh
menggunakan R dengan set.seed(2025). Pastikan semua paket
yang diperlukan telah terinstal: ggplot2,
dplyr, knitr, kableExtra,
epitools, vcd, scales.
E-Book ini dibuat menggunakan R Markdown • 02 March 2026 16:37