1 Bagian 1: Definisi Analisis Data Kategori


1.1 Pengertian Analisis Data Kategori

Analisis data kategori (categorical data analysis) adalah cabang statistika yang mempelajari metode-metode untuk mengumpulkan, merangkum, mendeskripsikan, dan menarik inferensi dari data yang nilainya berupa kategori atau label — bukan besaran numerik kontinu. Tujuan utamanya adalah memahami distribusi frekuensi suatu variabel kategori dan menguji ada tidaknya asosiasi (hubungan) antara dua atau lebih variabel kategori dalam suatu populasi.

Secara historis, analisis data kategori berkembang pesat sejak Karl Pearson memperkenalkan Uji Chi-Square pada tahun 1900 sebagai alat untuk menguji kecocokan distribusi frekuensi. Sejak itu, berbagai metode berkembang mulai dari tabel kontingensi, odds ratio, regresi logistik, hingga model log-linear untuk tabel multidimensional.

Yang membedakan analisis data kategori dari statistika konvensional adalah sifat datanya: nilai-nilai dalam data kategori tidak dapat diaritmetikakan secara bermakna. Tidak ada konsep “rata-rata agama” atau “selisih antara Merah dan Biru”. Oleh karena itu, diperlukan pendekatan yang berfokus pada frekuensi, proporsi, dan peluang kemunculan setiap kategori.


1.2 Karakteristik Variabel Kategori

Variabel kategori memiliki sejumlah karakteristik yang membedakannya dari variabel numerik:

No. Karakteristik Penjelasan Contoh
1 Nilai berupa label Data hanya berupa nama atau kode, bukan angka sejati “Laki-laki”, “Perempuan”; “Positif”, “Negatif”
2 Saling eksklusif Setiap observasi hanya dapat masuk ke satu kategori Seseorang tidak bisa sekaligus “lulus” dan “tidak lulus”
3 Exhaustive Seluruh kemungkinan nilai sudah tercakup dalam kategori yang ada Kategori “Ya / Tidak” mencakup semua kemungkinan jawaban
4 Tidak memiliki jarak yang terdefinisi Pada skala nominal, tidak ada urutan; pada ordinal ada urutan tapi jarak tidak terdefinisi “SMP < SMA < S1” tapi selisih antar jenjang tidak sama
5 Direpresentasikan sebagai frekuensi Analisis berfokus pada jumlah/proporsi observasi per kategori 60 laki-laki, 40 perempuan dari 100 responden

1.2.1 Tipe-Tipe Skala Variabel Kategori

Variabel kategori dibagi menjadi tiga tipe utama berdasarkan ada tidaknya urutan dan jumlah kategori:

Tipe Skala Deskripsi Lengkap Jumlah Kategori Contoh Variabel Ukuran Statistik yang Tepat
Nominal Kategori murni tanpa urutan alami. Label hanya berfungsi sebagai pembeda, bukan peringkat. ≥ 2 Jenis kelamin, golongan darah, kota asal, agama, warna Modus, Chi-Square, Cramér’s V, Phi
Ordinal Kategori memiliki urutan yang bermakna, namun jarak antarkategori tidak terdefinisi secara numerik. ≥ 3 Tingkat pendidikan (SD/SMP/SMA/PT), skala Likert (1–5), status sosial (rendah/menengah/tinggi) Median, persentil, Spearman, Gamma
Dikotomis Kasus khusus nominal dengan tepat dua kategori yang saling eksklusif dan exhaustive. = 2 Lulus/Tidak Lulus, Sakit/Sehat, Hadir/Absen, Ya/Tidak Phi, Odds Ratio, Point-Biserial

💡 Catatan: Variabel dikotomis adalah kasus khusus dari variabel nominal. Karena hanya dua kategori, ukuran asosiasi seperti Phi dan Odds Ratio dapat dihitung lebih langsung dan diinterpretasikan lebih intuitif dibandingkan pada data nominal dengan banyak kategori.


1.3 Mengapa Diperlukan Metode Khusus?

Banyak mahasiswa bertanya: mengapa tidak menggunakan saja mean atau korelasi Pearson untuk data kategori? Jawabannya terletak pada asumsi dasar yang dilanggar jika metode numerik diterapkan pada data kategori:

  1. Mean tidak bermakna: Rata-rata dari kode “1 = Laki-laki” dan “2 = Perempuan” adalah 1.5 — angka yang tidak merepresentasikan kategori apa pun.
  2. Normalitas tidak terpenuhi: Metode parametrik (uji-t, ANOVA) mengasumsikan distribusi normal pada data. Data kategori mengikuti distribusi Binomial atau Multinomial, bukan Normal.
  3. Homogenitas variansi tidak relevan: Konsep variansi tidak berlaku pada skala nominal.
  4. Korelasi Pearson mensyaratkan linearitas: Hubungan linear antarvariabel kategori tidak terdefinisi.

Karena itu, statistika mengembangkan metode khusus seperti yang dirangkum berikut:

Metode Fungsi Utama Jenis Data
Tabel Kontingensi Merangkum distribusi bersama dua variabel kategori Nominal, Ordinal
Uji Chi-Square (\(\chi^2\)) Menguji independensi statistik dua variabel kategori Nominal, Ordinal
Odds Ratio (OR) Mengukur kekuatan dan arah asosiasi pada tabel 2×2 Nominal (dikotomis)
Relative Risk (RR) Membandingkan risiko relatif antardua kelompok Nominal (dikotomis)
Cramér’s V Mengukur kekuatan asosiasi pada tabel \(r \times c\) Nominal
Korelasi Spearman / Gamma Mengukur asosiasi pada variabel ordinal Ordinal
Regresi Logistik Memodelkan peluang kejadian variabel respons dikotomis Campuran
Fisher’s Exact Test Alternatif Chi-Square untuk sampel kecil (\(E_{ij} < 5\)) Nominal

1.4 Contoh Penerapan dalam Penelitian

Analisis data kategori digunakan secara luas di berbagai bidang penelitian:

No. Bidang Pertanyaan Penelitian Variabel Metode
1 Epidemiologi Apakah merokok meningkatkan risiko kanker paru-paru? Merokok (Ya/Tidak) × Kanker (Ya/Tidak) Odds Ratio, Chi-Square
2 Kesehatan Masyarakat Apakah vaksinasi mengurangi insiden infeksi? Status vaksin (Vaksin/Tidak) × Status infeksi (Terinfeksi/Tidak) Relative Risk, Chi-Square
3 Pendidikan Apakah gender berpengaruh terhadap kelulusan tepat waktu? Jenis kelamin × Status kelulusan Chi-Square, Cramér’s V
4 Sosiologi Apakah tingkat pendidikan berkaitan dengan preferensi politik? Pendidikan × Pilihan partai Chi-Square, Cramér’s V
5 Psikologi Apakah perlakuan terapi A lebih efektif daripada terapi B? Jenis terapi × Respons pasien Chi-Square, Odds Ratio
6 Pemasaran Apakah jenis iklan berpengaruh terhadap keputusan pembelian? Jenis iklan × Pembelian (Ya/Tidak) Chi-Square, Cramér’s V

2 Bagian 2: Tabel Kontingensi


2.1 Definisi Tabel Kontingensi

Tabel kontingensi (contingency table), juga dikenal sebagai cross-tabulation atau crosstab, adalah tabel berbentuk matriks yang menyajikan distribusi frekuensi bersama dari dua atau lebih variabel kategori secara simultan. Setiap sel dalam tabel menunjukkan berapa banyak observasi yang memiliki kombinasi nilai tertentu dari variabel-variabel tersebut.

Nama “kontingensi” berasal dari kata Latin contingere yang berarti “bergantung pada” — karena tabel ini memungkinkan kita melihat apakah distribusi satu variabel bergantung pada (atau berubah sesuai dengan) nilai variabel lain. Jika distribusinya tidak berubah, kedua variabel dikatakan independen atau tidak berasosiasi.

Tabel kontingensi pertama kali diperkenalkan oleh Karl Pearson pada akhir abad ke-19 dan hingga kini tetap menjadi alat analisis eksplorasi yang paling mendasar dalam statistika kategori.


2.2 Struktur Tabel Kontingensi

2.2.1 Tabel Kontingensi Umum \(r \times c\)

Untuk dua variabel kategori \(X\) (dengan \(r\) kategori baris) dan \(Y\) (dengan \(c\) kategori kolom), struktur tabelnya adalah:

\(Y_1\) \(Y_2\) \(\cdots\) \(Y_c\) Total Baris
\(X_1\) \(n_{11}\) \(n_{12}\) \(\cdots\) \(n_{1c}\) \(n_{1\cdot}\)
\(X_2\) \(n_{21}\) \(n_{22}\) \(\cdots\) \(n_{2c}\) \(n_{2\cdot}\)
\(\vdots\) \(\vdots\) \(\vdots\) \(\ddots\) \(\vdots\) \(\vdots\)
\(X_r\) \(n_{r1}\) \(n_{r2}\) \(\cdots\) \(n_{rc}\) \(n_{r\cdot}\)
Total Kolom \(n_{\cdot1}\) \(n_{\cdot2}\) \(\cdots\) \(n_{\cdot c}\) \(n\)

Notasi penting:

Simbol Nama Rumus / Keterangan
\(n_{ij}\) Frekuensi sel Jumlah observasi dengan \(X = i\) dan \(Y = j\)
\(n_{i\cdot}\) Marginal baris ke-\(i\) \(\displaystyle\sum_{j=1}^{c} n_{ij}\) — total baris ke-\(i\)
\(n_{\cdot j}\) Marginal kolom ke-\(j\) \(\displaystyle\sum_{i=1}^{r} n_{ij}\) — total kolom ke-\(j\)
\(n\) Total keseluruhan \(\displaystyle\sum_{i=1}^{r}\sum_{j=1}^{c} n_{ij}\)
\(r\) Jumlah baris Banyaknya kategori variabel \(X\)
\(c\) Jumlah kolom Banyaknya kategori variabel \(Y\)

2.2.2 Tabel Kontingensi 2×2 (Kasus Khusus)

Tabel 2×2 adalah bentuk paling sederhana dan paling sering digunakan, terutama untuk dua variabel dikotomis. Ia memiliki bentuk baku sebagai berikut:

\(Y = 1\) (Positif) \(Y = 0\) (Negatif) Total
\(X = 1\) (Terekspos) \(a = n_{11}\) \(b = n_{12}\) \(a + b = n_{1\cdot}\)
\(X = 0\) (Tidak Terekspos) \(c = n_{21}\) \(d = n_{22}\) \(c + d = n_{2\cdot}\)
Total \(a + c = n_{\cdot1}\) \(b + d = n_{\cdot2}\) \(n\)

📌 Konvensi label sel \(a, b, c, d\) ini sangat umum digunakan dalam epidemiologi dan akan dipakai sepanjang dokumen ini. Hafalkan posisinya karena rumus Odds Ratio dan Relative Risk diturunkan dari notasi ini.


2.3 Konsep Joint Distribution (Distribusi Bersama)

Distribusi bersama (joint distribution) dari dua variabel \(X\) dan \(Y\) adalah distribusi yang menggambarkan peluang kemunculan setiap kombinasi nilai \(X\) dan \(Y\) secara bersamaan dalam satu observasi. Dinotasikan sebagai \(P(X = i, Y = j)\) atau \(P(X = i \cap Y = j)\).

\[P(X = i,\ Y = j) = \frac{n_{ij}}{n}, \quad \text{untuk semua } i = 1, \ldots, r \text{ dan } j = 1, \ldots, c\]

Sifat distribusi bersama: \[\sum_{i=1}^{r} \sum_{j=1}^{c} P(X = i, Y = j) = 1\]

Ilustrasi dengan contoh konkret:

Misalkan dari 200 mahasiswa diperoleh tabel berikut:

Lulus (Y=1) Tidak Lulus (Y=0) Total
Laki-laki (X=1) 60 50 110
Perempuan (X=2) 63 27 90
Total 123 77 200

Maka distribusi bersama:

\(P(Y=1)\) \(P(Y=0)\) Total
\(P(X=1)\) \(P(X=1, Y=1) = 60/200 = 0.30\) \(P(X=1, Y=0) = 50/200 = 0.25\) \(0.55\)
\(P(X=2)\) \(P(X=2, Y=1) = 63/200 = 0.315\) \(P(X=2, Y=0) = 27/200 = 0.135\) \(0.45\)
Total \(0.615\) \(0.385\) \(1.00\)

Distribusi bersama memberikan gambaran lengkap tentang bagaimana kedua variabel berperilaku secara simultan dalam populasi.


2.4 Konsep Marginal Distribution (Distribusi Marginal)

Distribusi marginal adalah distribusi peluang dari satu variabel saja, diperoleh dengan menjumlahkan distribusi bersama atas semua nilai variabel yang lain. Distribusi marginal mengabaikan informasi tentang variabel lainnya.

Marginal distribusi \(X\) (baris): \[P(X = i) = \sum_{j=1}^{c} P(X = i, Y = j) = \frac{n_{i\cdot}}{n}\]

Marginal distribusi \(Y\) (kolom): \[P(Y = j) = \sum_{i=1}^{r} P(X = i, Y = j) = \frac{n_{\cdot j}}{n}\]

Mengapa disebut “marginal”? Karena nilainya ditempatkan di margin (tepi/pinggir) tabel kontingensi — yaitu pada baris total paling bawah dan kolom total paling kanan.

Melanjutkan contoh di atas:

Variabel Kategori Frekuensi Peluang Marginal
Jenis Kelamin (\(X\)) Laki-laki \(n_{1\cdot} = 110\) \(P(X=1) = 110/200 = 0.55\)
Jenis Kelamin (\(X\)) Perempuan \(n_{2\cdot} = 90\) \(P(X=2) = 90/200 = 0.45\)
Status Lulus (\(Y\)) Lulus \(n_{\cdot1} = 123\) \(P(Y=1) = 123/200 = 0.615\)
Status Lulus (\(Y\)) Tidak Lulus \(n_{\cdot2} = 77\) \(P(Y=0) = 77/200 = 0.385\)

Distribusi marginal berguna untuk mengetahui karakteristik masing-masing variabel secara terpisah, tanpa mempertimbangkan hubungannya dengan variabel lain.


2.5 Konsep Conditional Probability (Peluang Bersyarat)

Peluang bersyarat (conditional probability) \(P(Y = j \mid X = i)\) adalah peluang bahwa variabel \(Y\) bernilai \(j\), diberikan bahwa variabel \(X\) sudah diketahui bernilai \(i\). Peluang bersyarat hanya mempertimbangkan observasi dalam subkelompok \(X = i\), bukan keseluruhan sampel.

\[P(Y = j \mid X = i) = \frac{P(X = i, Y = j)}{P(X = i)} = \frac{n_{ij}}{n_{i\cdot}}\]

\[P(X = i \mid Y = j) = \frac{P(X = i, Y = j)}{P(Y = j)} = \frac{n_{ij}}{n_{\cdot j}}\]

Mengapa peluang bersyarat penting? Karena ia menangkap inti dari konsep asosiasi: jika \(P(Y = j \mid X = 1) \neq P(Y = j \mid X = 2)\), artinya distribusi \(Y\) berbeda tergantung pada nilai \(X\) — dengan kata lain, ada asosiasi antara \(X\) dan \(Y\).

Sebaliknya, jika \(P(Y = j \mid X = i) = P(Y = j)\) untuk semua \(i\) dan \(j\), maka kedua variabel independen — mengetahui nilai \(X\) tidak memberikan informasi apapun tentang \(Y\).

Kondisi independensi secara formal: \[X \perp Y \iff P(X = i, Y = j) = P(X = i) \times P(Y = j) \quad \forall i, j\]

Ilustrasi peluang bersyarat dari contoh:

Lulus \(P(Y=1 \mid X)\) Tidak Lulus \(P(Y=0 \mid X)\) Total
Laki-laki \(60/110 = 0.545\) \(50/110 = 0.455\) \(1.00\)
Perempuan \(63/90 = 0.700\) \(27/90 = 0.300\) \(1.00\)

Perhatikan: \(P(Y=1 \mid X=\text{Laki-laki}) = 0.545 \neq P(Y=1 \mid X=\text{Perempuan}) = 0.700\). Karena berbeda, ada indikasi asosiasi antara jenis kelamin dan kelulusan.


3 Bagian 3: Ukuran Asosiasi


3.1 Pengantar: Mengapa Perlu Ukuran Asosiasi?

Ukuran asosiasi (measures of association) adalah nilai numerik yang merangkum kekuatan dan/atau arah hubungan antara dua variabel kategori dalam satu angka yang mudah dikomunikasikan. Uji Chi-Square hanya menjawab pertanyaan “apakah ada asosiasi?” (ya/tidak), tetapi tidak memberitahu seberapa kuat atau seberapa besar asosiasi tersebut secara praktis.

Ukuran asosiasi menjawab pertanyaan yang lebih informatif:

  • “Seberapa besar kemungkinan seseorang yang merokok terkena kanker dibanding yang tidak merokok?”
  • “Berapa kali lipat risiko terinfeksi bagi yang tidak divaksin?”

3.2 Odds (Peluang Relatif)

3.2.1 Definisi Odds

Odds adalah perbandingan antara peluang suatu kejadian terjadi dengan peluang kejadian tersebut tidak terjadi. Odds berbeda dari peluang biasa: peluang adalah \(p\), sedangkan odds adalah \(p/(1-p)\).

\[\text{Odds} = \frac{p}{1 - p} = \frac{\text{Peluang kejadian terjadi}}{\text{Peluang kejadian tidak terjadi}}\]

Atau dalam konteks tabel 2×2, odds kejadian \(Y=1\) pada kelompok \(X=1\) (baris pertama):

\[\text{Odds}_1 = \frac{a / (a+b)}{b / (a+b)} = \frac{a}{b}\]

Dan odds pada kelompok \(X=0\) (baris kedua):

\[\text{Odds}_2 = \frac{c / (c+d)}{d / (c+d)} = \frac{c}{d}\]

Contoh interpretasi Odds:

Jika peluang lulus = \(p = 0.7\), maka: \[\text{Odds} = \frac{0.7}{0.3} = 2.333\] Artinya: untuk setiap 1 mahasiswa yang tidak lulus, ada 2.333 mahasiswa yang lulus. Atau lebih mudah: peluang lulus 2.333 kali lebih besar daripada peluang tidak lulus.

Nilai Odds Interpretasi
\(< 1\) Kejadian lebih kecil peluangnya daripada tidak terjadi (\(p < 0.5\))
\(= 1\) Peluang terjadi sama dengan peluang tidak terjadi (\(p = 0.5\))
\(> 1\) Kejadian lebih besar peluangnya daripada tidak terjadi (\(p > 0.5\))

3.3 Odds Ratio (OR)

3.3.1 Definisi dan Rumus

Odds Ratio (OR) adalah perbandingan odds pada dua kelompok berbeda. OR menjawab pertanyaan: “Berapa kali lipat odds kejadian pada kelompok terekspos dibandingkan odds pada kelompok tidak terekspos?” OR merupakan ukuran asosiasi utama dalam studi case-control dan sangat populer di epidemiologi.

Untuk tabel 2×2 dengan sel \(a, b, c, d\):

\[\boxed{OR = \frac{a/b}{c/d} = \frac{ad}{bc}}\]

Di mana: - \(a\) = terekspos & outcome positif - \(b\) = terekspos & outcome negatif - \(c\) = tidak terekspos & outcome positif - \(d\) = tidak terekspos & outcome negatif

Confidence Interval 95% untuk OR:

\[CI_{95\%} = \left[\exp\!\left(\ln\widehat{OR} - 1.96 \cdot SE\right),\ \exp\!\left(\ln\widehat{OR} + 1.96 \cdot SE\right)\right]\]

\[\text{dengan} \quad SE = \sqrt{\frac{1}{a} + \frac{1}{b} + \frac{1}{c} + \frac{1}{d}}\]

3.3.2 Interpretasi Odds Ratio

Nilai OR Interpretasi
\(OR = 1\) Tidak ada asosiasi; odds sama pada kedua kelompok
\(OR > 1\) Kelompok terekspos memiliki odds lebih tinggi untuk outcome positif
\(OR < 1\) Kelompok terekspos memiliki odds lebih rendah untuk outcome positif (bersifat protektif)
\(OR = 2\) Odds outcome pada kelompok terekspos 2 kali lipat dibanding tidak terekspos
\(OR = 0.5\) Odds outcome pada kelompok terekspos hanya setengah dari yang tidak terekspos

📌 Signifikansi OR: Jika confidence interval 95% CI mencakup nilai 1, maka OR tidak berbeda signifikan dari 1 pada \(\alpha = 0.05\), artinya tidak ada bukti asosiasi yang signifikan secara statistik.


3.4 Relative Risk (RR)

3.4.1 Definisi dan Rumus

Relative Risk (RR), atau Risk Ratio, adalah perbandingan peluang langsung (bukan odds) dari outcome pada dua kelompok. RR lebih intuitif daripada OR karena membandingkan probabilitas secara langsung, bukan rasio odds. RR paling tepat digunakan pada studi cohort (prospektif) di mana proporsi kejadian dapat diestimasi secara langsung.

\[\boxed{RR = \frac{p_1}{p_2} = \frac{a / (a+b)}{c / (c+d)}}\]

Di mana: - \(p_1 = a/(a+b)\) = peluang outcome pada kelompok terekspos (baris 1) - \(p_2 = c/(c+d)\) = peluang outcome pada kelompok tidak terekspos (baris 2)

Confidence Interval 95% untuk RR:

\[CI_{95\%} = \left[\exp\!\left(\ln\widehat{RR} - 1.96 \cdot SE\right),\ \exp\!\left(\ln\widehat{RR} + 1.96 \cdot SE\right)\right]\]

\[\text{dengan} \quad SE = \sqrt{\frac{b}{a(a+b)} + \frac{d}{c(c+d)}}\]

3.4.2 Interpretasi Relative Risk

Nilai RR Interpretasi
\(RR = 1\) Risiko sama pada kedua kelompok; tidak ada asosiasi
\(RR > 1\) Kelompok terekspos memiliki risiko lebih tinggi daripada tidak terekspos
\(RR < 1\) Paparan bersifat protektif — menurunkan risiko outcome
\(RR = 3\) Risiko outcome pada kelompok terekspos 3 kali lebih besar daripada tidak terekspos

3.5 Perbandingan OR vs RR

Aspek Odds Ratio (OR) Relative Risk (RR)
Definisi Rasio odds antar kelompok Rasio peluang langsung antar kelompok
Cocok untuk Studi case-control, regresi logistik Studi cohort, uji klinis (RCT)
Intuisi Kurang intuitif Lebih intuitif dan langsung
Nilai saat outcome langka Mendekati RR (rare disease assumption) Nilai langsung
Syarat perhitungan Selalu dapat dihitung dari tabel 2×2 Hanya valid jika proporsi dapat diestimasi secara langsung

💡 Aturan praktis: Ketika prevalensi outcome sangat kecil (< 10%), OR dan RR memberikan nilai yang hampir sama. Namun ketika prevalensi besar, OR selalu melebih-lebihkan kekuatan asosiasi dibanding RR. Dalam kasus seperti itu, gunakan RR bila memungkinkan.


4 Bagian 4: Contoh Perhitungan Manual


4.1 Kasus: Hubungan Merokok dan Kanker Paru-Paru

Latar Belakang Kasus: Seorang peneliti epidemiologi melakukan studi case-control untuk menyelidiki apakah kebiasaan merokok berkaitan dengan kejadian kanker paru-paru. Sebanyak 200 subjek direkrut, terdiri dari 100 pasien terdiagnosis kanker paru-paru (case) dan 100 orang sehat sebagai pembanding (control). Setiap subjek ditanyakan riwayat merokoknya.

Variabel penelitian: - \(X\): Status merokok (Merokok / Tidak Merokok) - \(Y\): Diagnosis kanker paru (Kanker / Tidak Kanker)


4.1.1 Langkah 1: Membuat Tabel Kontingensi

Data yang dikumpulkan peneliti adalah sebagai berikut: dari 200 subjek, ditemukan bahwa 90 perokok terdiri dari 70 orang yang mengidap kanker paru dan 20 orang sehat; sementara 110 bukan perokok terdiri dari 30 orang yang mengidap kanker paru dan 80 orang sehat.

Tabel Kontingensi: Status Merokok × Diagnosis Kanker Paru

Kanker Paru (\(Y=1\)) Tidak Kanker (\(Y=0\)) Total
Merokok (\(X=1\)) \(a = 70\) \(b = 20\) \(a+b = 90\)
Tidak Merokok (\(X=0\)) \(c = 30\) \(d = 80\) \(c+d = 110\)
Total \(a+c = 100\) \(b+d = 100\) \(n = 200\)

Dari tabel di atas, kita dapat langsung melihat secara deskriptif bahwa dari 90 perokok, 70 (77.8%) mengidap kanker, sedangkan dari 110 bukan perokok, hanya 30 (27.3%) yang mengidap kanker. Perbedaan yang sangat mencolok ini adalah sinyal awal adanya asosiasi yang kuat.


4.1.2 Langkah 2: Menghitung Peluang Bersyarat

Peluang bersyarat dihitung dengan membagi frekuensi sel dengan marginal baris yang bersesuaian:

Peluang kanker pada perokok: \[P(Y=1 \mid X=1) = \frac{a}{a+b} = \frac{70}{90} = 0.7\overline{7} \approx \mathbf{0.7778}\]

Peluang kanker pada bukan perokok: \[P(Y=1 \mid X=0) = \frac{c}{c+d} = \frac{30}{110} = 0.2\overline{72} \approx \mathbf{0.2727}\]

Peluang tidak kanker pada perokok: \[P(Y=0 \mid X=1) = \frac{b}{a+b} = \frac{20}{90} = 0.2\overline{2} \approx \mathbf{0.2222}\]

Peluang tidak kanker pada bukan perokok: \[P(Y=0 \mid X=0) = \frac{d}{c+d} = \frac{80}{110} = 0.7\overline{27} \approx \mathbf{0.7273}\]

Rangkuman peluang bersyarat:

Kelompok \(P(\text{Kanker} \mid \text{Kelompok})\) \(P(\text{Tidak Kanker} \mid \text{Kelompok})\) Total
Merokok \(70/90 = 0.7778\) \(20/90 = 0.2222\) \(1.0000\)
Tidak Merokok \(30/110 = 0.2727\) \(80/110 = 0.7273\) \(1.0000\)

Perbandingan \(P(\text{Kanker} \mid \text{Merokok}) = 0.7778\) vs \(P(\text{Kanker} \mid \text{Tidak Merokok}) = 0.2727\) menunjukkan perbedaan yang sangat besar — mahasiswa yang merokok memiliki peluang kanker yang jauh lebih tinggi.


4.1.3 Langkah 3: Menghitung Odds

Odds dihitung sebagai rasio peluang kejadian terhadap peluang ketidakjadian, atau secara langsung sebagai \(a/b\) dan \(c/d\):

Odds kanker pada kelompok perokok (\(X=1\)): \[\text{Odds}_{\text{Merokok}} = \frac{a}{b} = \frac{70}{20} = \mathbf{3.5000}\]

Artinya: Pada perokok, untuk setiap 1 orang yang tidak kanker, terdapat 3.5 orang yang kanker.

Odds kanker pada kelompok tidak merokok (\(X=0\)): \[\text{Odds}_{\text{Tidak Merokok}} = \frac{c}{d} = \frac{30}{80} = \mathbf{0.3750}\]

Artinya: Pada bukan perokok, untuk setiap 1 orang yang kanker, terdapat \(1/0.375 = 2.667\) orang yang tidak kanker.

Perbandingan Odds:

Kelompok Rumus Nilai Odds Interpretasi
Merokok \(70 / 20\) \(3.5000\) Perokok lebih besar peluang kankernya daripada tidak kanker
Tidak Merokok \(30 / 80\) \(0.3750\) Bukan perokok lebih kecil peluang kankernya daripada tidak kanker

4.1.4 Langkah 4: Menghitung Odds Ratio

Odds Ratio dihitung dengan membagi odds kelompok terekspos dengan odds kelompok tidak terekspos:

\[OR = \frac{\text{Odds}_{\text{Merokok}}}{\text{Odds}_{\text{Tidak Merokok}}} = \frac{a/b}{c/d} = \frac{ad}{bc}\]

\[OR = \frac{70 \times 80}{20 \times 30} = \frac{5600}{600} = \mathbf{9.3333}\]

Menghitung Confidence Interval 95%:

\[SE = \sqrt{\frac{1}{a} + \frac{1}{b} + \frac{1}{c} + \frac{1}{d}} = \sqrt{\frac{1}{70} + \frac{1}{20} + \frac{1}{30} + \frac{1}{80}}\]

\[SE = \sqrt{0.01429 + 0.05000 + 0.03333 + 0.01250} = \sqrt{0.11012} = 0.33184\]

\[\ln(\widehat{OR}) = \ln(9.3333) = 2.2336\]

\[CI_{\text{bawah}} = \exp(2.2336 - 1.96 \times 0.33184) = \exp(1.5832) = \mathbf{4.8703}\]

\[CI_{\text{atas}} = \exp(2.2336 + 1.96 \times 0.33184) = \exp(2.8840) = \mathbf{17.8964}\]

\[\therefore \quad OR = 9.333 \quad [95\% \ CI: 4.870,\ 17.896]\]

Menghitung Relative Risk sebagai perbandingan:

\[RR = \frac{a/(a+b)}{c/(c+d)} = \frac{70/90}{30/110} = \frac{0.7778}{0.2727} = \mathbf{2.8519}\]

Tabel Ringkasan Perhitungan Manual:

Ukuran Rumus Substitusi Hasil
Odds (Merokok) \(a / b\) \(70 / 20\) \(3.5000\)
Odds (Tidak Merokok) \(c / d\) \(30 / 80\) \(0.3750\)
Odds Ratio \(ad / bc\) \((70 \times 80)/(20 \times 30)\) \(9.3333\)
95% CI (bawah) \(\exp(\ln OR - 1.96 \cdot SE)\) \(\exp(2.2336 - 0.6504)\) \(4.8703\)
95% CI (atas) \(\exp(\ln OR + 1.96 \cdot SE)\) \(\exp(2.2336 + 0.6504)\) \(17.8964\)
Relative Risk \([a/(a+b)] / [c/(c+d)]\) \((70/90) / (30/110)\) \(2.8519\)

5 Bagian 5: Analisis Menggunakan R


5.1 Persiapan: Memuat Paket

# ── Memuat paket yang dibutuhkan ───────────────────────────────────────────
library(vcd)          # Mosaic plot dan ukuran asosiasi
library(DescTools)    # OddsRatio, RelRisk, CramerV, dll.
library(ggplot2)      # Visualisasi tingkat lanjut
library(dplyr)        # Manipulasi data
library(knitr)        # Render tabel
library(kableExtra)   # Styling tabel HTML
library(scales)       # Format angka dan persen

5.2 Langkah 1: Membuat Tabel Kontingensi

# ── Input data sesuai kasus merokok vs kanker paru ─────────────────────────
# Matriks 2x2: baris = Merokok/Tidak, kolom = Kanker/Tidak Kanker

tabel_kont <- matrix(
  c(70, 20,   # baris 1: Merokok    → Kanker=70, Tidak Kanker=20
    30, 80),  # baris 2: Tidak Merokok → Kanker=30, Tidak Kanker=80
  nrow = 2,
  byrow = TRUE,
  dimnames = list(
    "Status Merokok" = c("Merokok", "Tidak Merokok"),
    "Kanker Paru"    = c("Kanker", "Tidak Kanker")
  )
)

# Simpan total
n_total <- sum(tabel_kont)

# Tampilkan tabel dengan marginal
kable(
  addmargins(tabel_kont),
  caption = "Tabel 6. Tabel Kontingensi: Status Merokok × Diagnosis Kanker Paru",
  align   = "c"
) |>
  kable_styling(
    bootstrap_options = c("bordered", "hover"),
    full_width        = TRUE
  ) |>
  add_header_above(c(" " = 1, "Diagnosis Kanker Paru" = 2, " " = 1)) |>
  row_spec(0, bold = TRUE, background = "#1a5c5a", color = "white") |>
  row_spec(nrow(addmargins(tabel_kont)),
           bold = TRUE, background = "#d4edec") |>
  column_spec(1, bold = TRUE, background = "#eef7f6") |>
  column_spec(ncol(addmargins(tabel_kont)),
              bold = TRUE, background = "#d4edec")
Tabel 6. Tabel Kontingensi: Status Merokok × Diagnosis Kanker Paru
Diagnosis Kanker Paru
Kanker Tidak Kanker Sum
Merokok 70 20 90
Tidak Merokok 30 80 110
Sum 100 100 200
# ── Tabel proporsi bersyarat (per baris) ───────────────────────────────────
prop_baris <- prop.table(tabel_kont, margin = 1)

kable(
  round(prop_baris, 4),
  caption = "Tabel 7. Distribusi Peluang Bersyarat P(Kanker Paru | Status Merokok)",
  align   = "c"
) |>
  kable_styling(
    bootstrap_options = c("bordered", "hover", "striped"),
    full_width        = FALSE,
    position          = "center"
  ) |>
  row_spec(0, bold = TRUE, background = "#1a5c5a", color = "white") |>
  column_spec(2, bold = TRUE, color = "#8b3a1e")
Tabel 7. Distribusi Peluang Bersyarat P(Kanker Paru | Status Merokok)
Kanker Tidak Kanker
Merokok 0.7778 0.2222
Tidak Merokok 0.2727 0.7273

5.3 Langkah 2: Menghitung Odds Ratio

# ── Ekstrak nilai sel ───────────────────────────────────────────────────────
a <- tabel_kont[1, 1]  # Merokok & Kanker
b <- tabel_kont[1, 2]  # Merokok & Tidak Kanker
c_val <- tabel_kont[2, 1]  # Tidak Merokok & Kanker
d <- tabel_kont[2, 2]  # Tidak Merokok & Tidak Kanker

# ── Hitung Odds masing-masing kelompok ─────────────────────────────────────
odds_merokok      <- a / b
odds_tidak_merokok <- c_val / d

cat("══ ODDS ════════════════════════════════════════════════════════════\n")
#> ══ ODDS ════════════════════════════════════════════════════════════
cat(sprintf("  Odds (Merokok)      = %d / %d = %.4f\n", a, b, odds_merokok))
#>   Odds (Merokok)      = 70 / 20 = 3.5000
cat(sprintf("  Odds (Tidak Merokok) = %d / %d = %.4f\n",
            c_val, d, odds_tidak_merokok))
#>   Odds (Tidak Merokok) = 30 / 80 = 0.3750
# ── Hitung OR secara manual ─────────────────────────────────────────────────
OR_manual <- (a * d) / (b * c_val)
log_OR    <- log(OR_manual)
SE_log    <- sqrt(1/a + 1/b + 1/c_val + 1/d)
CI_low    <- exp(log_OR - 1.96 * SE_log)
CI_high   <- exp(log_OR + 1.96 * SE_log)

cat("\n══ ODDS RATIO ══════════════════════════════════════════════════════\n")
#> 
#> ══ ODDS RATIO ══════════════════════════════════════════════════════
cat(sprintf("  OR  = (%d × %d) / (%d × %d)\n", a, d, b, c_val))
#>   OR  = (70 × 80) / (20 × 30)
cat(sprintf("      = %d / %d\n", a*d, b*c_val))
#>       = 5600 / 600
cat(sprintf("      = %.4f\n", OR_manual))
#>       = 9.3333
cat(sprintf("  SE(ln OR) = %.4f\n", SE_log))
#>   SE(ln OR) = 0.3318
cat(sprintf("  95%% CI    = [%.4f, %.4f]\n", CI_low, CI_high))
#>   95% CI    = [4.8704, 17.8857]
# ── Hitung OR menggunakan fungsi R (verifikasi) ─────────────────────────────
OR_r <- OddsRatio(tabel_kont, conf.level = 0.95)
cat("\n══ VERIFIKASI DENGAN FUNGSI R (DescTools::OddsRatio) ═══════════════\n")
#> 
#> ══ VERIFIKASI DENGAN FUNGSI R (DescTools::OddsRatio) ═══════════════
print(OR_r)
#> odds ratio     lwr.ci     upr.ci 
#>   9.333333   4.870488  17.885501
# ── Menghitung Relative Risk ────────────────────────────────────────────────
p1   <- a / (a + b)          # peluang kanker pada perokok
p2   <- c_val / (c_val + d)  # peluang kanker pada bukan perokok
RR   <- p1 / p2
SE_RR <- sqrt(b / (a * (a+b)) + d / (c_val * (c_val+d)))
CI_RR_low  <- exp(log(RR) - 1.96 * SE_RR)
CI_RR_high <- exp(log(RR) + 1.96 * SE_RR)

cat("══ RELATIVE RISK ═══════════════════════════════════════════════════\n")
#> ══ RELATIVE RISK ═══════════════════════════════════════════════════
cat(sprintf("  p1 (Merokok)      = %d / %d = %.4f\n", a, a+b, p1))
#>   p1 (Merokok)      = 70 / 90 = 0.7778
cat(sprintf("  p2 (Tidak Merokok) = %d / %d = %.4f\n", c_val, c_val+d, p2))
#>   p2 (Tidak Merokok) = 30 / 110 = 0.2727
cat(sprintf("  RR  = %.4f / %.4f = %.4f\n", p1, p2, RR))
#>   RR  = 0.7778 / 0.2727 = 2.8519
cat(sprintf("  95%% CI = [%.4f, %.4f]\n", CI_RR_low, CI_RR_high))
#>   95% CI = [2.0615, 3.9452]
# ── Tabel ringkasan OR dan RR ───────────────────────────────────────────────
ringkasan_or <- data.frame(
  Ukuran  = c("Odds (Merokok)", "Odds (Tidak Merokok)",
              "Odds Ratio (OR)", "Relative Risk (RR)"),
  Rumus   = c("a/b", "c/d", "ad/bc", "p₁/p₂"),
  Nilai   = c(round(odds_merokok, 4), round(odds_tidak_merokok, 4),
              round(OR_manual, 4), round(RR, 4)),
  CI_95   = c("—", "—",
              paste0("[", round(CI_low,3), ", ", round(CI_high,3), "]"),
              paste0("[", round(CI_RR_low,3), ", ", round(CI_RR_high,3), "]"))
)

kable(
  ringkasan_or,
  col.names = c("Ukuran", "Rumus", "Nilai", "95% CI"),
  caption   = "Tabel 8. Ringkasan Odds, Odds Ratio, dan Relative Risk",
  align     = c("l", "c", "c", "c")
) |>
  kable_styling(
    bootstrap_options = c("bordered", "hover", "striped"),
    full_width        = TRUE
  ) |>
  row_spec(0, bold = TRUE, background = "#1a5c5a", color = "white") |>
  row_spec(3, bold = TRUE, background = "#fff5d4") |>
  row_spec(4, bold = TRUE, background = "#fff5d4") |>
  column_spec(3, bold = TRUE, color = "#1a5c5a")
Tabel 8. Ringkasan Odds, Odds Ratio, dan Relative Risk
Ukuran Rumus Nilai 95% CI
Odds (Merokok) a/b 3.5000
Odds (Tidak Merokok) c/d 0.3750
Odds Ratio (OR) ad/bc 9.3333 [4.87, 17.886]
Relative Risk (RR) p₁/p₂ 2.8519 [2.061, 3.945]

5.4 Langkah 3: Uji Chi-Square

# ── Uji Chi-Square (tanpa koreksi Yates) ───────────────────────────────────
hasil_chi2 <- chisq.test(tabel_kont, correct = FALSE)

# Ekstrak komponen penting
chi2_val    <- hasil_chi2$statistic
df_val      <- hasil_chi2$parameter
p_val       <- hasil_chi2$p.value
E_mat       <- hasil_chi2$expected
chi2_kritis <- qchisq(0.95, df = df_val)

cat("══ UJI CHI-SQUARE ══════════════════════════════════════════════════\n")
#> ══ UJI CHI-SQUARE ══════════════════════════════════════════════════
print(hasil_chi2)
#> 
#>  Pearson's Chi-squared test
#> 
#> data:  tabel_kont
#> X-squared = 50.505, df = 1, p-value = 1.189e-12
cat("\n── Frekuensi Ekspektasi E_ij ───────────────────────────────────────\n")
#> 
#> ── Frekuensi Ekspektasi E_ij ───────────────────────────────────────
print(round(E_mat, 4))
#>                Kanker Paru
#> Status Merokok  Kanker Tidak Kanker
#>   Merokok           45           45
#>   Tidak Merokok     55           55
cat(sprintf("\n── Nilai Kritis (df=%d, α=0.05): %.4f\n", df_val, chi2_kritis))
#> 
#> ── Nilai Kritis (df=1, α=0.05): 3.8415
cat(sprintf("── Keputusan: χ²_hitung (%.4f) %s χ²_kritis (%.4f) → %s\n",
            chi2_val,
            ifelse(chi2_val > chi2_kritis, ">", "≤"),
            chi2_kritis,
            ifelse(chi2_val > chi2_kritis, "TOLAK H₀", "GAGAL TOLAK H₀")))
#> ── Keputusan: χ²_hitung (50.5051) > χ²_kritis (3.8415) → TOLAK H₀
# ── Tabel detail Chi-Square per sel ────────────────────────────────────────
O_mat     <- tabel_kont
kontrib   <- (O_mat - E_mat)^2 / E_mat
sel_names <- c("Merokok | Kanker", "Tidak Merokok | Kanker",
                "Merokok | Tidak Kanker", "Tidak Merokok | Tidak Kanker")

detail_chi2 <- data.frame(
  Sel         = c("Merokok | Kanker", "Merokok | Tidak Kanker",
                  "Tidak Merokok | Kanker", "Tidak Merokok | Tidak Kanker"),
  O           = as.vector(t(O_mat)),
  E           = round(as.vector(t(E_mat)), 4),
  `O-E`       = round(as.vector(t(O_mat - E_mat)), 4),
  `(O-E)^2/E` = round(as.vector(t(kontrib)), 4)
)

kable(
  detail_chi2,
  col.names = c("Sel (i, j)", "O", "E", "O − E", "(O−E)² / E"),
  caption   = "Tabel 9. Kontribusi Tiap Sel terhadap Statistik Chi-Square",
  align     = c("l", "c", "c", "c", "c")
) |>
  kable_styling(
    bootstrap_options = c("bordered", "hover", "striped"),
    full_width        = TRUE
  ) |>
  row_spec(0, bold = TRUE, background = "#1a5c5a", color = "white") |>
  column_spec(5, bold = TRUE, color = "#8b3a1e")
Tabel 9. Kontribusi Tiap Sel terhadap Statistik Chi-Square
Sel (i, j) O E O − E (O−E)² / E
Merokok &#124; Kanker 70 45 25 13.8889
Merokok &#124; Tidak Kanker 20 45 -25 13.8889
Tidak Merokok &#124; Kanker 30 55 -25 11.3636
Tidak Merokok &#124; Tidak Kanker 80 55 25 11.3636

5.5 Visualisasi

# ── Bar chart proporsi bersyarat ────────────────────────────────────────────
# as.data.frame.table() mengubah ke long format: Var1, Var2, Freq
df_plot <- as.data.frame.table(prop.table(tabel_kont, margin = 1))
colnames(df_plot) <- c("Merokok", "Kanker_Paru", "Proporsi")

ggplot(df_plot, aes(x = Merokok, y = Proporsi, fill = Kanker_Paru)) +
  geom_col(position = "dodge", width = 0.6, alpha = 0.92, color = "white") +
  geom_text(aes(label = percent(Proporsi, accuracy = 0.1)),
            position = position_dodge(0.6), vjust = -0.5,
            size = 4.5, fontface = "bold") +
  scale_fill_manual(
    values = c("Kanker" = "#8b3a1e", "Tidak Kanker" = "#1a5c5a"),
    name   = "Diagnosis"
  ) +
  scale_y_continuous(labels = percent, limits = c(0, 0.95),
                     expand = c(0, 0)) +
  labs(
    title    = "Proporsi Kanker Paru berdasarkan Status Merokok",
    subtitle = bquote(chi^2 ~ "=" ~ .(round(chi2_val, 2)) ~
                      ", p < 0.001" ~
                      ", OR =" ~ .(round(OR_manual, 2))),
    x        = "Status Merokok",
    y        = "Proporsi (%)",
    caption  = "Catatan: Proporsi dihitung dalam masing-masing kelompok merokok"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title    = element_text(face = "bold", color = "#1a5c5a", size = 14),
    plot.subtitle = element_text(color = "#555", size = 11),
    plot.caption  = element_text(color = "#888", face = "italic", size = 10),
    legend.position = "top",
    panel.grid.major.x = element_blank(),
    panel.grid.minor   = element_blank()
  )
Gambar 1. Proporsi Kanker Paru berdasarkan Status Merokok

Gambar 1. Proporsi Kanker Paru berdasarkan Status Merokok

# ── Mosaic plot dengan shade residual Pearson ───────────────────────────────
mosaic(
  tabel_kont,
  shade   = TRUE,
  legend  = TRUE,
  main    = "Mosaic Plot: Status Merokok × Kanker Paru",
  sub     = paste0("OR = ", round(OR_manual, 3),
                   "  |  χ² = ", round(chi2_val, 3),
                   "  |  p < 0.001")
)
Gambar 2. Mosaic Plot: Status Merokok × Kanker Paru

Gambar 2. Mosaic Plot: Status Merokok × Kanker Paru


5.6 Interpretasi Hasil Analisis

5.6.1 Interpretasi Statistik

Hasil Uji Chi-Square:

Diperoleh nilai statistik uji \(\chi^2(1) = 50.505\) dengan \(p\text{-value} = 1.19e-12\). Karena \(\chi^2_{\text{hitung}} = 50.505 > \chi^2_{\text{kritis}} = 3.841\) dan \(p\text{-value} < 0.001\), maka:

Keputusan: TOLAK H₀ pada taraf signifikansi \(\alpha = 0.05\) (bahkan pada \(\alpha = 0.001\)).

Terdapat asosiasi yang signifikan secara statistik antara kebiasaan merokok dan kejadian kanker paru-paru (\(p < 0.001\)).


Kekuatan Asosiasi (Odds Ratio):

\[OR = 9.3333 \quad [95\% \ CI: 4.87,\ 17.886]\]

Karena seluruh interval kepercayaan berada jauh di atas 1 (batas bawah CI = 4.87), OR ini signifikan secara statistik dan menunjukkan asosiasi positif yang sangat kuat.


Relative Risk:

\[RR = 2.8519 \quad [95\% \ CI: 2.061,\ 3.945]\]


5.6.2 Interpretasi Substantif dalam Konteks Kasus

1. Tentang Odds Ratio (\(OR = 9.333\)):

Odds terkena kanker paru pada kelompok perokok adalah 9.333 kali lebih tinggi dibandingkan odds pada kelompok bukan perokok (95% CI: 4.87 hingga 17.89). Ini berarti: dalam studi ini, perokok memiliki kemungkinan relatif terkena kanker paru yang jauh lebih besar secara praktis, bukan hanya secara statistik.

2. Tentang Relative Risk (\(RR = 2.852\)):

Peluang terkena kanker paru pada perokok (\(77.8\%\)) adalah 2.852 kali lebih besar dibandingkan pada bukan perokok (\(27.3\%\)). RR lebih kecil dari OR karena prevalensi outcome cukup tinggi dalam data ini (~50%) — OR melebih-lebihkan kekuatan asosiasi pada kondisi seperti ini.

3. Catatan Kausalitas dan Keterbatasan:

  • Asosiasi ≠ Kausalitas. Studi ini menunjukkan asosiasi yang kuat, namun untuk menyimpulkan kausalitas, diperlukan studi kohort prospektif jangka panjang dengan kontrol terhadap faktor perancu (usia, jenis pekerjaan, riwayat keluarga, paparan zat kimia lain).
  • Desain case-control memungkinkan perhitungan OR, tetapi RR yang dihitung dari studi case-control tidak valid secara langsung jika sampling dilakukan berdasarkan status penyakit (bukan secara acak dari populasi).
  • Variabel perancu seperti usia, lama merokok, jumlah rokok per hari, dan faktor lingkungan lain tidak dikontrol dalam analisis bivariat ini.
  • Data simulasi — angka-angka dalam contoh ini bersifat ilustratif dan tidak merepresentasikan studi epidemiologi nyata.

6 Bagian 6: Tugas 6 Inferensi Tabel Kontingensi Dua Arah - Anolius Laia


6.1 Pendahuluan

Tugas ini menerapkan metode inferensi statistika pada dua kasus tabel kontingensi: Kasus 1 mengkaji hubungan antara kebiasaan merokok dan kanker paru-paru menggunakan tabel 2×2, dan Kasus 2 mengkaji hubungan antara gender dan identifikasi partai politik menggunakan tabel 2×3. Analisis mencakup estimasi proporsi, ukuran asosiasi, berbagai uji hipotesis, dan interpretasi substantif.


7 Kasus 1: Tabel Kontingensi 2×2 — Merokok dan Kanker Paru


7.1 1.1 Penyusunan Tabel Kontingensi 2×2

# ── Data Kasus 1 ─────────────────────────────────────────────────────────
k1 <- matrix(
  c(688, 650,   # Smoker:     Cancer(+)=688, Control(-)=650
     21,  59),  # Non-Smoker: Cancer(+)=21,  Control(-)=59
  nrow = 2, byrow = TRUE,
  dimnames = list(
    "Status Merokok" = c("Smoker", "Non-Smoker"),
    "Diagnosis"      = c("Cancer (+)", "Control (-)")
  )
)

# Tampilkan dengan marginal
kable(
  addmargins(k1),
  caption = "Tabel K1-1. Tabel Kontingensi 2×2: Status Merokok × Diagnosis Kanker Paru",
  align   = "c"
) |>
  kable_styling(bootstrap_options = c("bordered","hover"), full_width = TRUE) |>
  add_header_above(c(" " = 1, "Diagnosis" = 2, " " = 1)) |>
  row_spec(0, bold = TRUE, background = "#1a5c5a", color = "white") |>
  row_spec(3, bold = TRUE, background = "#d4edec") |>
  column_spec(1, bold = TRUE, background = "#eef7f6") |>
  column_spec(4, bold = TRUE, background = "#d4edec")
Tabel K1-1. Tabel Kontingensi 2×2: Status Merokok × Diagnosis Kanker Paru
Diagnosis
Cancer (+) Control (-) Sum
Smoker 688 650 1338
Non-Smoker 21 59 80
Sum 709 709 1418

Keterangan data: Total sampel \(n = 1418\), dengan desain matched case-control (709 kasus kanker, 709 kontrol sehat). Perokok berjumlah 1338 orang dan non-perokok 80 orang.


7.2 1.2 Estimasi Titik Proporsi Kejadian Kanker Paru

# ── Ekstrak sel ──────────────────────────────────────────────────────────
a1 <- k1[1,1]; b1 <- k1[1,2]   # Smoker
c1 <- k1[2,1]; d1 <- k1[2,2]   # Non-Smoker
n1 <- sum(k1)

# ── Proporsi kanker per kelompok ─────────────────────────────────────────
p_smoker    <- a1 / (a1 + b1)
p_nonsmoker <- c1 / (c1 + d1)

cat("══ ESTIMASI TITIK PROPORSI ═════════════════════════════════════════\n")
#> ══ ESTIMASI TITIK PROPORSI ═════════════════════════════════════════
cat(sprintf("  p̂(Kanker | Smoker)     = %d / %d = %.4f  (%.2f%%)\n",
            a1, a1+b1, p_smoker, p_smoker*100))
#>   p̂(Kanker | Smoker)     = 688 / 1338 = 0.5142  (51.42%)
cat(sprintf("  p̂(Kanker | Non-Smoker) = %d / %d = %.4f  (%.2f%%)\n",
            c1, c1+d1, p_nonsmoker, p_nonsmoker*100))
#>   p̂(Kanker | Non-Smoker) = 21 / 80 = 0.2625  (26.25%)
cat(sprintf("\n  Selisih proporsi       = %.4f - %.4f = %.4f\n",
            p_smoker, p_nonsmoker, p_smoker - p_nonsmoker))
#> 
#>   Selisih proporsi       = 0.5142 - 0.2625 = 0.2517

Interpretasi: Proporsi kejadian kanker paru pada kelompok Smoker adalah \(\hat{p}_1 = 0.5142\) (51.42%), sedangkan pada kelompok Non-Smoker adalah \(\hat{p}_2 = 0.2625\) (26.25%). Perokok memiliki proporsi kanker paru yang jauh lebih tinggi dibandingkan non-perokok.


7.3 1.3 Interval Kepercayaan 95%

7.3.1 CI Proporsi Masing-Masing Kelompok

# ── CI proporsi dengan metode Wald ──────────────────────────────────────
ci_prop <- function(x, n, conf = 0.95) {
  p   <- x / n
  z   <- qnorm(1 - (1 - conf) / 2)
  se  <- sqrt(p * (1 - p) / n)
  c(p = p, lower = p - z*se, upper = p + z*se)
}

ci_s  <- ci_prop(a1, a1 + b1)
ci_ns <- ci_prop(c1, c1 + d1)

cat("══ CI 95% PROPORSI ════════════════════════════════════════════════\n")
#> ══ CI 95% PROPORSI ════════════════════════════════════════════════
cat(sprintf("  Smoker:     p̂ = %.4f  [%.4f, %.4f]\n",
            ci_s["p"], ci_s["lower"], ci_s["upper"]))
#>   Smoker:     p̂ = 0.5142  [0.4874, 0.5410]
cat(sprintf("  Non-Smoker: p̂ = %.4f  [%.4f, %.4f]\n",
            ci_ns["p"], ci_ns["lower"], ci_ns["upper"]))
#>   Non-Smoker: p̂ = 0.2625  [0.1661, 0.3589]

7.3.2 CI untuk Risk Difference (RD), Risk Ratio (RR), dan Odds Ratio (OR)

# ── Risk Difference (RD) ────────────────────────────────────────────────
RD   <- p_smoker - p_nonsmoker
SE_RD <- sqrt(p_smoker*(1-p_smoker)/(a1+b1) +
              p_nonsmoker*(1-p_nonsmoker)/(c1+d1))
CI_RD <- c(RD - 1.96*SE_RD, RD + 1.96*SE_RD)

# ── Relative Risk (RR) ──────────────────────────────────────────────────
RR1    <- p_smoker / p_nonsmoker
SE_lnRR <- sqrt(b1/(a1*(a1+b1)) + d1/(c1*(c1+d1)))
CI_RR   <- exp(log(RR1) + c(-1,1)*1.96*SE_lnRR)

# ── Odds Ratio (OR) ─────────────────────────────────────────────────────
OR1    <- (a1 * d1) / (b1 * c1)
SE_lnOR <- sqrt(1/a1 + 1/b1 + 1/c1 + 1/d1)
CI_OR   <- exp(log(OR1) + c(-1,1)*1.96*SE_lnOR)

cat("══ UKURAN ASOSIASI DAN CI 95% ═════════════════════════════════════\n")
#> ══ UKURAN ASOSIASI DAN CI 95% ═════════════════════════════════════
cat(sprintf("  Risk Difference (RD) = %.4f  [%.4f, %.4f]\n",
            RD, CI_RD[1], CI_RD[2]))
#>   Risk Difference (RD) = 0.2517  [0.1516, 0.3518]
cat(sprintf("  Relative Risk  (RR)  = %.4f  [%.4f, %.4f]\n",
            RR1, CI_RR[1], CI_RR[2]))
#>   Relative Risk  (RR)  = 1.9589  [1.3517, 2.8387]
cat(sprintf("  Odds Ratio     (OR)  = %.4f  [%.4f, %.4f]\n",
            OR1, CI_OR[1], CI_OR[2]))
#>   Odds Ratio     (OR)  = 2.9738  [1.7867, 4.9495]
# ── Tabel ringkasan ──────────────────────────────────────────────────────
df_asosiasi <- data.frame(
  Ukuran = c("Risk Difference (RD)", "Relative Risk (RR)", "Odds Ratio (OR)"),
  Nilai  = round(c(RD, RR1, OR1), 4),
  CI_Bawah = round(c(CI_RD[1], CI_RR[1], CI_OR[1]), 4),
  CI_Atas  = round(c(CI_RD[2], CI_RR[2], CI_OR[2]), 4)
)

kable(df_asosiasi,
      col.names = c("Ukuran Asosiasi", "Nilai Estimasi",
                    "CI 95% Bawah", "CI 95% Atas"),
      caption = "Tabel K1-2. Estimasi Titik dan Interval Kepercayaan 95% Ukuran Asosiasi",
      align = c("l","c","c","c")) |>
  kable_styling(bootstrap_options = c("bordered","hover","striped"),
                full_width = TRUE) |>
  row_spec(0, bold = TRUE, background = "#1a5c5a", color = "white") |>
  column_spec(2, bold = TRUE, color = "#1a5c5a")
Tabel K1-2. Estimasi Titik dan Interval Kepercayaan 95% Ukuran Asosiasi
Ukuran Asosiasi Nilai Estimasi CI 95% Bawah CI 95% Atas
Risk Difference (RD) 0.2517 0.1516 0.3518
Relative Risk (RR) 1.9589 1.3517 2.8387
Odds Ratio (OR) 2.9738 1.7867 4.9495

Interpretasi CI:

  • RD = 0.2517 [CI: 0.1516, 0.3518]: Perokok memiliki risiko absolut lebih tinggi sebesar 25.17 poin persentase. CI tidak mencakup 0 → signifikan.
  • RR = 1.9589 [CI: 1.3517, 2.8387]: Risiko kanker pada perokok 1.9589 kali lipat non-perokok. CI tidak mencakup 1 → signifikan.
  • OR = 2.9738 [CI: 1.7867, 4.9495]: Odds kanker pada perokok 2.9738 kali lipat non-perokok. CI tidak mencakup 1 → signifikan.

7.4 1.4 Uji Dua Proporsi

# ── Uji dua proporsi (Z-test) ─────────────────────────────────────────
# H0: p_smoker = p_nonsmoker
# H1: p_smoker ≠ p_nonsmoker

n_s  <- a1 + b1  # total Smoker
n_ns <- c1 + d1  # total Non-Smoker

p_pool <- (a1 + c1) / n1   # proporsi gabungan di bawah H0

Z_stat <- (p_smoker - p_nonsmoker) /
          sqrt(p_pool * (1 - p_pool) * (1/n_s + 1/n_ns))
p_two  <- 2 * pnorm(-abs(Z_stat))

cat("══ UJI DUA PROPORSI (Z-TEST) ══════════════════════════════════════\n")
#> ══ UJI DUA PROPORSI (Z-TEST) ══════════════════════════════════════
cat(sprintf("  H₀: p_Smoker = p_Non-Smoker\n"))
#>   H₀: p_Smoker = p_Non-Smoker
cat(sprintf("  H₁: p_Smoker ≠ p_Non-Smoker  (dua arah)\n\n"))
#>   H₁: p_Smoker ≠ p_Non-Smoker  (dua arah)
cat(sprintf("  p̂ gabungan    = (%.0f + %.0f) / %.0f = %.4f\n",
            a1, c1, n1, p_pool))
#>   p̂ gabungan    = (688 + 21) / 1418 = 0.5000
cat(sprintf("  Z-statistik   = %.4f\n", Z_stat))
#>   Z-statistik   = 4.3737
cat(sprintf("  p-value       = %.6f\n", p_two))
#>   p-value       = 0.000012
cat(sprintf("  Nilai kritis  = ±%.4f  (α = 0.05, dua arah)\n", qnorm(0.975)))
#>   Nilai kritis  = ±1.9600  (α = 0.05, dua arah)
cat(sprintf("  Keputusan     : %s\n",
            ifelse(p_two < 0.05, "TOLAK H₀ — proporsi berbeda signifikan",
                                  "GAGAL TOLAK H₀")))
#>   Keputusan     : TOLAK H₀ — proporsi berbeda signifikan
# Verifikasi dengan fungsi bawaan R
cat("\n── Verifikasi dengan prop.test() ───────────────────────────────────\n")
#> 
#> ── Verifikasi dengan prop.test() ───────────────────────────────────
hasil_prop <- prop.test(c(a1, c1), c(n_s, n_ns), correct = FALSE)
print(hasil_prop)
#> 
#>  2-sample test for equality of proportions without continuity correction
#> 
#> data:  c(a1, c1) out of c(n_s, n_ns)
#> X-squared = 19.129, df = 1, p-value = 1.222e-05
#> alternative hypothesis: two.sided
#> 95 percent confidence interval:
#>  0.1516343 0.3517663
#> sample estimates:
#>    prop 1    prop 2 
#> 0.5142003 0.2625000

7.5 1.5 Uji Chi-Square Independensi

# ── Uji Chi-Square (tanpa koreksi Yates) ─────────────────────────────
hasil_chi_k1 <- chisq.test(k1, correct = FALSE)
chi2_k1  <- hasil_chi_k1$statistic
df_k1    <- hasil_chi_k1$parameter
pval_k1  <- hasil_chi_k1$p.value
E_k1     <- hasil_chi_k1$expected
kritis_k1 <- qchisq(0.95, df = df_k1)

cat("══ UJI CHI-SQUARE INDEPENDENSI ════════════════════════════════════\n")
#> ══ UJI CHI-SQUARE INDEPENDENSI ════════════════════════════════════
cat(sprintf("  H₀: Status merokok dan kanker paru INDEPENDEN\n"))
#>   H₀: Status merokok dan kanker paru INDEPENDEN
cat(sprintf("  H₁: Ada asosiasi antara status merokok dan kanker paru\n\n"))
#>   H₁: Ada asosiasi antara status merokok dan kanker paru
cat(sprintf("  χ² statistik = %.4f\n", chi2_k1))
#>   χ² statistik = 19.1292
cat(sprintf("  df           = %d\n", df_k1))
#>   df           = 1
cat(sprintf("  p-value      = %.6f\n", pval_k1))
#>   p-value      = 0.000012
cat(sprintf("  χ² kritis    = %.4f  (df=1, α=0.05)\n", kritis_k1))
#>   χ² kritis    = 3.8415  (df=1, α=0.05)
cat(sprintf("  Keputusan    : %s\n",
            ifelse(pval_k1 < 0.05, "TOLAK H₀", "GAGAL TOLAK H₀")))
#>   Keputusan    : TOLAK H₀
cat("\n── Frekuensi Harapan (E_ij) ────────────────────────────────────────\n")
#> 
#> ── Frekuensi Harapan (E_ij) ────────────────────────────────────────
print(round(E_k1, 4))
#>               Diagnosis
#> Status Merokok Cancer (+) Control (-)
#>     Smoker            669         669
#>     Non-Smoker         40          40
# Kontribusi per sel
kontrib_k1 <- (k1 - E_k1)^2 / E_k1
cat("\n── Kontribusi per Sel [(O-E)²/E] ──────────────────────────────────\n")
#> 
#> ── Kontribusi per Sel [(O-E)²/E] ──────────────────────────────────
print(round(kontrib_k1, 4))
#>               Diagnosis
#> Status Merokok Cancer (+) Control (-)
#>     Smoker         0.5396      0.5396
#>     Non-Smoker     9.0250      9.0250
cat(sprintf("  Total χ² = %.4f ✓\n", sum(kontrib_k1)))
#>   Total χ² = 19.1292 ✓

7.6 1.6 Uji Likelihood Ratio (G²)

# ── G² (Likelihood Ratio Chi-Square) ────────────────────────────────
G2_k1 <- 2 * sum(k1 * log(k1 / E_k1))
p_G2_k1 <- pchisq(G2_k1, df = df_k1, lower.tail = FALSE)

cat("══ UJI LIKELIHOOD RATIO G² ════════════════════════════════════════\n")
#> ══ UJI LIKELIHOOD RATIO G² ════════════════════════════════════════
cat(sprintf("  G² = 2 × Σ O_ij × ln(O_ij / E_ij)\n"))
#>   G² = 2 × Σ O_ij × ln(O_ij / E_ij)
cat(sprintf("  G² = %.4f\n", G2_k1))
#>   G² = 19.8780
cat(sprintf("  df = %d\n", df_k1))
#>   df = 1
cat(sprintf("  p-value = %.6f\n", p_G2_k1))
#>   p-value = 0.000008
cat(sprintf("  Keputusan: %s\n",
            ifelse(p_G2_k1 < 0.05, "TOLAK H₀", "GAGAL TOLAK H₀")))
#>   Keputusan: TOLAK H₀
# Detail per sel
cat("\n── Kontribusi G² per Sel [2 × O × ln(O/E)] ─────────────────────────\n")
#> 
#> ── Kontribusi G² per Sel [2 × O × ln(O/E)] ─────────────────────────
kontrib_G2 <- 2 * k1 * log(k1 / E_k1)
print(round(kontrib_G2, 4))
#>               Diagnosis
#> Status Merokok Cancer (+) Control (-)
#>     Smoker        38.5346    -37.4552
#>     Non-Smoker   -27.0630     45.8616
cat(sprintf("  Total G² = %.4f ✓\n", sum(kontrib_G2)))
#>   Total G² = 19.8780 ✓

7.7 1.7 Fisher Exact Test

# ── Fisher Exact Test ────────────────────────────────────────────────
hasil_fisher_k1 <- fisher.test(k1)

cat("══ FISHER EXACT TEST ══════════════════════════════════════════════\n")
#> ══ FISHER EXACT TEST ══════════════════════════════════════════════
cat(sprintf("  H₀: OR = 1 (tidak ada asosiasi)\n"))
#>   H₀: OR = 1 (tidak ada asosiasi)
cat(sprintf("  H₁: OR ≠ 1 (ada asosiasi)\n\n"))
#>   H₁: OR ≠ 1 (ada asosiasi)
print(hasil_fisher_k1)
#> 
#>  Fisher's Exact Test for Count Data
#> 
#> data:  k1
#> p-value = 1.476e-05
#> alternative hypothesis: true odds ratio is not equal to 1
#> 95 percent confidence interval:
#>  1.755611 5.210711
#> sample estimates:
#> odds ratio 
#>   2.971634
cat(sprintf("\n  OR (exact)  = %.4f\n", hasil_fisher_k1$estimate))
#> 
#>   OR (exact)  = 2.9716
cat(sprintf("  95%% CI      = [%.4f, %.4f]\n",
            hasil_fisher_k1$conf.int[1], hasil_fisher_k1$conf.int[2]))
#>   95% CI      = [1.7556, 5.2107]
cat(sprintf("  p-value     = %.6f\n", hasil_fisher_k1$p.value))
#>   p-value     = 0.000015
cat(sprintf("  Keputusan   : %s\n",
            ifelse(hasil_fisher_k1$p.value < 0.05,
                   "TOLAK H₀ — ada asosiasi signifikan",
                   "GAGAL TOLAK H₀")))
#>   Keputusan   : TOLAK H₀ — ada asosiasi signifikan

7.8 1.8 Perbandingan Hasil Keempat Uji

df_banding <- data.frame(
  Uji = c("Uji Dua Proporsi (Z)",
           "Chi-Square (χ²)",
           "Likelihood Ratio (G²)",
           "Fisher Exact Test"),
  Hipotesis = c("H₀: p₁ = p₂",
                "H₀: Independen",
                "H₀: Independen",
                "H₀: OR = 1"),
  Statistik = c(round(Z_stat, 4), round(chi2_k1, 4),
                round(G2_k1, 4), "—"),
  P_Value   = c(formatC(p_two,  digits=6, format="f"),
                formatC(pval_k1, digits=6, format="f"),
                formatC(p_G2_k1, digits=6, format="f"),
                formatC(hasil_fisher_k1$p.value, digits=6, format="f")),
  Keputusan = rep("TOLAK H₀", 4),
  Interpretasi = c("Proporsi berbeda nyata",
                   "Ada asosiasi",
                   "Ada asosiasi",
                   "OR ≠ 1, ada asosiasi")
)

kable(df_banding,
      col.names = c("Metode Uji", "Hipotesis Nol", "Statistik Uji",
                    "p-value", "Keputusan", "Interpretasi"),
      caption = "Tabel K1-3. Perbandingan Hasil Keempat Metode Uji (α = 0.05)",
      align   = c("l","l","c","c","c","l")) |>
  kable_styling(bootstrap_options = c("bordered","hover","striped"),
                full_width = TRUE) |>
  row_spec(0, bold = TRUE, background = "#1a5c5a", color = "white") |>
  column_spec(5, bold = TRUE, color = "#8b3a1e") |>
  footnote(general = "Semua uji menggunakan α = 0.05 (dua arah).",
           general_title = "Catatan:")
Tabel K1-3. Perbandingan Hasil Keempat Metode Uji (α = 0.05)
Metode Uji Hipotesis Nol Statistik Uji p-value Keputusan Interpretasi
Uji Dua Proporsi (Z) H₀: p₁ = p₂ 4.3737 0.000012 TOLAK H₀ Proporsi berbeda nyata
Chi-Square (χ²) H₀: Independen 19.1292 0.000012 TOLAK H₀ Ada asosiasi
Likelihood Ratio (G²) H₀: Independen 19.878 0.000008 TOLAK H₀ Ada asosiasi
Fisher Exact Test H₀: OR = 1 0.000015 TOLAK H₀ OR ≠ 1, ada asosiasi
Catatan:
Semua uji menggunakan α = 0.05 (dua arah).

Perbandingan substantif keempat metode:

  • Uji Dua Proporsi dan Chi-Square pada tabel 2×2 ekuivalen secara aljabar: \(Z^2 = \chi^2\). Keduanya menguji perbedaan proporsi secara asimtotik.
  • Likelihood Ratio (G²) memberikan hasil yang sangat dekat dengan Chi-Square, terutama pada sampel besar. G² memiliki keunggulan dalam partisi tabel yang lebih besar.
  • Fisher Exact Test merupakan uji yang paling tepat (exact), tidak bergantung pada asumsi asimtotik. Pada sampel besar seperti ini (\(n = 1418\)), semua metode memberikan kesimpulan yang sama.

7.9 1.9 Visualisasi Kasus 1

df_k1_plot <- data.frame(
  Kelompok    = c("Smoker", "Non-Smoker"),
  Proporsi    = c(p_smoker, p_nonsmoker),
  n           = c(a1+b1, c1+d1)
)

ggplot(df_k1_plot, aes(x = Kelompok, y = Proporsi, fill = Kelompok)) +
  geom_col(width = 0.55, alpha = 0.9, color = "white", size = 0.8) +
  geom_errorbar(
    aes(ymin = Proporsi - 1.96*sqrt(Proporsi*(1-Proporsi)/n),
        ymax = Proporsi + 1.96*sqrt(Proporsi*(1-Proporsi)/n)),
    width = 0.15, size = 0.9, color = "#333"
  ) +
  geom_text(aes(label = percent(Proporsi, accuracy = 0.1)),
            vjust = -0.8, size = 5, fontface = "bold") +
  scale_fill_manual(values = c("Smoker" = "#8b3a1e", "Non-Smoker" = "#1a5c5a")) +
  scale_y_continuous(labels = percent, limits = c(0, 0.85),
                     expand = c(0, 0)) +
  labs(
    title    = "Proporsi Kejadian Kanker Paru berdasarkan Status Merokok",
    subtitle = bquote(chi^2 ~ "=" ~ .(round(chi2_k1,2)) ~
                      "  |  p < 0.001" ~
                      "  |  OR =" ~ .(round(OR1,2)) ~
                      "  |  RR =" ~ .(round(RR1,2))),
    x = "Status Merokok", y = "Proporsi Kanker Paru (%)",
    caption  = "Error bar menunjukkan 95% CI proporsi"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title    = element_text(face = "bold", color = "#1a5c5a"),
    plot.subtitle = element_text(color = "#555"),
    legend.position = "none",
    panel.grid.major.x = element_blank(),
    panel.grid.minor   = element_blank()
  )
Gambar K1. Proporsi Kanker Paru berdasarkan Status Merokok

Gambar K1. Proporsi Kanker Paru berdasarkan Status Merokok

mosaic(k1, shade = TRUE, legend = TRUE,
       main = "Mosaic Plot: Status Merokok × Kanker Paru",
       sub  = paste0("OR = ", round(OR1,3),
                     "  |  χ² = ", round(chi2_k1,3),
                     "  |  p < 0.001"))
Gambar K1-2. Mosaic Plot: Status Merokok × Kanker Paru

Gambar K1-2. Mosaic Plot: Status Merokok × Kanker Paru


7.10 1.10 Kesimpulan Kasus 1

Kesimpulan Akhir Kasus 1: Hubungan Merokok dan Kanker Paru-Paru

Berdasarkan data tabel kontingensi 2×2 dengan \(n = 1418\) subjek:

  1. Estimasi proporsi: Proporsi kanker paru pada perokok (51.42%) jauh lebih tinggi dibandingkan non-perokok (26.25%).

  2. Ukuran asosiasi:

    • \(RD = 0.2517\) → perokok memiliki risiko absolut 25.17 poin persentase lebih tinggi
    • \(RR = 1.9589\) → risiko kanker perokok 1.96 kali lebih besar
    • \(OR = 2.9738\) → odds kanker perokok 2.97 kali lebih besar
  3. Keempat uji hipotesis (Uji dua proporsi, Chi-Square, Likelihood Ratio G², Fisher Exact Test) secara konsisten menghasilkan p-value < 0.001 dan menolak H₀ pada \(\alpha = 0.05\).

  4. Kesimpulan substantif: Terdapat asosiasi yang sangat kuat dan signifikan secara statistik antara kebiasaan merokok dan kejadian kanker paru-paru. Perokok memiliki risiko yang jauh lebih tinggi untuk menderita kanker paru. Seluruh CI 95% untuk RD, RR, dan OR tidak mencakup nilai netral (0, 1, dan 1), mempertegas signifikansi statistik.


8 Kasus 2: Tabel Kontingensi 2×3 — Gender dan Identifikasi Partai Politik


8.1 2.1 Penyusunan Tabel Kontingensi 2×3

# ── Data Kasus 2 ─────────────────────────────────────────────────────────
k2 <- matrix(
  c(495, 272, 590,   # Female: Democrat, Republican, Independent
    330, 265, 498),  # Male:   Democrat, Republican, Independent
  nrow = 2, byrow = TRUE,
  dimnames = list(
    "Gender" = c("Female", "Male"),
    "Partai" = c("Democrat", "Republican", "Independent")
  )
)

kable(
  addmargins(k2),
  caption = "Tabel K2-1. Tabel Kontingensi 2×3: Gender × Identifikasi Partai Politik",
  align   = "c"
) |>
  kable_styling(bootstrap_options = c("bordered","hover"), full_width = TRUE) |>
  add_header_above(c(" " = 1, "Identifikasi Partai Politik" = 3, " " = 1)) |>
  row_spec(0, bold = TRUE, background = "#1a5c5a", color = "white") |>
  row_spec(3, bold = TRUE, background = "#d4edec") |>
  column_spec(1, bold = TRUE, background = "#eef7f6") |>
  column_spec(5, bold = TRUE, background = "#d4edec")
Tabel K2-1. Tabel Kontingensi 2×3: Gender × Identifikasi Partai Politik
Identifikasi Partai Politik
Democrat Republican Independent Sum
Female 495 272 590 1357
Male 330 265 498 1093
Sum 825 537 1088 2450

8.2 2.2 Frekuensi Harapan

# ── Uji Chi-Square untuk mendapat E_ij ──────────────────────────────────
hasil_chi_k2 <- chisq.test(k2, correct = FALSE)
E_k2 <- hasil_chi_k2$expected

cat("══ FREKUENSI HARAPAN E_ij ════════════════════════════════════════\n")
#> ══ FREKUENSI HARAPAN E_ij ════════════════════════════════════════
cat("  Rumus: E_ij = (n_i. × n_.j) / n\n\n")
#>   Rumus: E_ij = (n_i. × n_.j) / n
print(round(E_k2, 4))
#>         Partai
#> Gender   Democrat Republican Independent
#>   Female  456.949   297.4322    602.6188
#>   Male    368.051   239.5678    485.3812
# Tabel perbandingan O vs E
df_oe <- data.frame(
  Sel         = c("Female|Democrat","Female|Republican","Female|Independent",
                  "Male|Democrat","Male|Republican","Male|Independent"),
  O           = as.vector(t(k2)),
  E           = round(as.vector(t(E_k2)), 4),
  Selisih     = round(as.vector(t(k2 - E_k2)), 4),
  Kontribusi  = round(as.vector(t((k2 - E_k2)^2 / E_k2)), 4)
)

kable(df_oe,
      col.names = c("Sel (i,j)", "O (Obs.)", "E (Harap.)",
                    "O − E", "(O−E)²/E"),
      caption = "Tabel K2-2. Frekuensi Observasi, Harapan, dan Kontribusi Chi-Square",
      align   = c("l","c","c","c","c")) |>
  kable_styling(bootstrap_options = c("bordered","hover","striped"),
                full_width = TRUE) |>
  row_spec(0, bold = TRUE, background = "#1a5c5a", color = "white") |>
  column_spec(5, bold = TRUE, color = "#8b3a1e")
Tabel K2-2. Frekuensi Observasi, Harapan, dan Kontribusi Chi-Square
Sel (i,j) O (Obs.) E (Harap.) O − E (O−E)²/E
Female&#124;Democrat 495 456.9490 38.0510 3.1686
Female&#124;Republican 272 297.4322 -25.4322 2.1746
Female&#124;Independent 590 602.6188 -12.6188 0.2642
Male&#124;Democrat 330 368.0510 -38.0510 3.9339
Male&#124;Republican 265 239.5678 25.4322 2.6999
Male&#124;Independent 498 485.3812 12.6188 0.3281
cat(sprintf("\n  Semua E_ij > 5: %s — asumsi Chi-Square terpenuhi ✓\n",
            ifelse(all(E_k2 >= 5), "YA", "TIDAK")))
#> 
#>   Semua E_ij > 5: YA — asumsi Chi-Square terpenuhi ✓

8.3 2.3 Uji Chi-Square Independensi Keseluruhan

chi2_k2   <- hasil_chi_k2$statistic
df_k2     <- hasil_chi_k2$parameter
pval_k2   <- hasil_chi_k2$p.value
kritis_k2 <- qchisq(0.95, df = df_k2)

cat("══ UJI CHI-SQUARE KESELURUHAN (2×3) ══════════════════════════════\n")
#> ══ UJI CHI-SQUARE KESELURUHAN (2×3) ══════════════════════════════
cat(sprintf("  H₀: Gender dan identifikasi partai politik INDEPENDEN\n"))
#>   H₀: Gender dan identifikasi partai politik INDEPENDEN
cat(sprintf("  H₁: Ada asosiasi antara Gender dan identifikasi partai\n\n"))
#>   H₁: Ada asosiasi antara Gender dan identifikasi partai
cat(sprintf("  χ² statistik = %.4f\n", chi2_k2))
#>   χ² statistik = 12.5693
cat(sprintf("  df           = (r-1)(c-1) = (2-1)(3-1) = %d\n", df_k2))
#>   df           = (r-1)(c-1) = (2-1)(3-1) = 2
cat(sprintf("  p-value      = %.6f\n", pval_k2))
#>   p-value      = 0.001865
cat(sprintf("  χ² kritis    = %.4f  (df=2, α=0.05)\n", kritis_k2))
#>   χ² kritis    = 5.9915  (df=2, α=0.05)
cat(sprintf("\n  Keputusan    : %s\n",
            ifelse(pval_k2 < 0.05,
                   "TOLAK H₀ — ada asosiasi signifikan antara Gender dan Partai",
                   "GAGAL TOLAK H₀")))
#> 
#>   Keputusan    : TOLAK H₀ — ada asosiasi signifikan antara Gender dan Partai
# Cramér's V
n2  <- sum(k2)
V_k2 <- sqrt(chi2_k2 / (n2 * min(nrow(k2)-1, ncol(k2)-1)))
cat(sprintf("\n  Cramér's V   = %.4f  (kekuatan asosiasi)\n", V_k2))
#> 
#>   Cramér's V   = 0.0716  (kekuatan asosiasi)
cat(sprintf("  Interpretasi : %s\n",
            ifelse(V_k2 < 0.1, "Sangat lemah",
            ifelse(V_k2 < 0.3, "Lemah",
            ifelse(V_k2 < 0.5, "Sedang", "Kuat")))))
#>   Interpretasi : Sangat lemah

8.4 2.4 Residual Pearson dan Standardized Residual

# ── Residual Pearson ─────────────────────────────────────────────────────
res_pearson <- (k2 - E_k2) / sqrt(E_k2)

# ── Standardized Residual (Adjusted) ─────────────────────────────────────
# Formula: r_ij = (O_ij - E_ij) / sqrt(E_ij * (1 - p_i.) * (1 - p_.j))
n2   <- sum(k2)
p_row <- rowSums(k2) / n2
p_col <- colSums(k2) / n2

res_std <- matrix(NA, nrow = 2, ncol = 3,
                  dimnames = dimnames(k2))
for (i in 1:2) {
  for (j in 1:3) {
    denom <- sqrt(E_k2[i,j] * (1 - p_row[i]) * (1 - p_col[j]))
    res_std[i,j] <- (k2[i,j] - E_k2[i,j]) / denom
  }
}

cat("══ RESIDUAL PEARSON ═══════════════════════════════════════════════\n")
#> ══ RESIDUAL PEARSON ═══════════════════════════════════════════════
print(round(res_pearson, 4))
#>         Partai
#> Gender   Democrat Republican Independent
#>   Female   1.7801    -1.4747     -0.5140
#>   Male    -1.9834     1.6431      0.5728
cat("\n══ STANDARDIZED (ADJUSTED) RESIDUAL ══════════════════════════════\n")
#> 
#> ══ STANDARDIZED (ADJUSTED) RESIDUAL ══════════════════════════════
print(round(res_std, 4))
#>         Partai
#> Gender   Democrat Republican Independent
#>   Female   3.2724    -2.4986     -1.0322
#>   Male    -3.2724     2.4986      1.0322
cat("\n  Nilai |r_std| > 1.96 menunjukkan sel berkontribusi signifikan (α=0.05)\n")
#> 
#>   Nilai |r_std| > 1.96 menunjukkan sel berkontribusi signifikan (α=0.05)
# Tabel interpretasi residual
df_resid <- data.frame(
  Sel          = c("Female|Democrat","Female|Republican","Female|Independent",
                   "Male|Democrat","Male|Republican","Male|Independent"),
  O            = as.vector(t(k2)),
  E            = round(as.vector(t(E_k2)), 2),
  Res_Pearson  = round(as.vector(t(res_pearson)), 4),
  Res_Std      = round(as.vector(t(res_std)), 4),
  Signifikan   = ifelse(abs(as.vector(t(res_std))) > 1.96, "✔ YA", "✗ Tidak")
)

kable(df_resid,
      col.names = c("Sel", "O", "E", "Residual Pearson",
                    "Std. Residual", "Sig. (|r|>1.96)"),
      caption = "Tabel K2-3. Residual Pearson dan Standardized Residual",
      align   = c("l","c","c","c","c","c")) |>
  kable_styling(bootstrap_options = c("bordered","hover","striped"),
                full_width = TRUE) |>
  row_spec(0, bold = TRUE, background = "#1a5c5a", color = "white") |>
  row_spec(which(abs(df_resid$Res_Std) > 1.96),
           bold = TRUE, background = "#fff5d4") |>
  column_spec(6, bold = TRUE, color = "#8b3a1e")
Tabel K2-3. Residual Pearson dan Standardized Residual
Sel O E Residual Pearson Std. Residual Sig. (&#124;r&#124;>1.96)
Female&#124;Democrat 495 456.95 1.7801 3.2724 ✔ YA
Female&#124;Republican 272 297.43 -1.4747 -2.4986 ✔ YA
Female&#124;Independent 590 602.62 -0.5140 -1.0322 ✗ Tidak
Male&#124;Democrat 330 368.05 -1.9834 -3.2724 ✔ YA
Male&#124;Republican 265 239.57 1.6431 2.4986 ✔ YA
Male&#124;Independent 498 485.38 0.5728 1.0322 ✗ Tidak

Interpretasi Standardized Residual:

Sel dengan |residual standar| > 1.96 menunjukkan penyimpangan yang signifikan dari ekspektasi di bawah H₀ independensi. Sel bertanda positif menunjukkan frekuensi observasi lebih tinggi dari harapan, sedangkan negatif berarti lebih rendah.


8.5 2.5 Partisi Chi-Square

8.5.1 Partisi 1: Democrat vs Republican

# ── Subtabel: Democrat vs Republican ─────────────────────────────────────
k2_p1 <- k2[, c("Democrat", "Republican")]

chi_p1 <- chisq.test(k2_p1, correct = FALSE)
G2_p1  <- 2 * sum(k2_p1 * log(k2_p1 / chi_p1$expected))

cat("══ PARTISI 1: Democrat vs Republican ══════════════════════════════\n")
#> ══ PARTISI 1: Democrat vs Republican ══════════════════════════════
cat(sprintf("  χ² = %.4f,  df = %d,  p = %.6f\n",
            chi_p1$statistic, chi_p1$parameter, chi_p1$p.value))
#>   χ² = 11.5545,  df = 1,  p = 0.000676
cat(sprintf("  G² = %.4f\n", G2_p1))
#>   G² = 11.5357
cat(sprintf("  Keputusan: %s\n",
            ifelse(chi_p1$p.value < 0.05, "TOLAK H₀", "GAGAL TOLAK H₀")))
#>   Keputusan: TOLAK H₀
print(k2_p1)
#>         Partai
#> Gender   Democrat Republican
#>   Female      495        272
#>   Male        330        265

8.5.2 Partisi 2: (Democrat + Republican) vs Independent

# ── Subtabel: (Dem+Rep) vs Independent ────────────────────────────────────
k2_p2 <- cbind(
  "Dem+Rep"     = rowSums(k2[, c("Democrat","Republican")]),
  "Independent" = k2[, "Independent"]
)

chi_p2 <- chisq.test(k2_p2, correct = FALSE)
G2_p2  <- 2 * sum(k2_p2 * log(k2_p2 / chi_p2$expected))

cat("══ PARTISI 2: (Democrat+Republican) vs Independent ════════════════\n")
#> ══ PARTISI 2: (Democrat+Republican) vs Independent ════════════════
cat(sprintf("  χ² = %.4f,  df = %d,  p = %.6f\n",
            chi_p2$statistic, chi_p2$parameter, chi_p2$p.value))
#>   χ² = 1.0654,  df = 1,  p = 0.301979
cat(sprintf("  G² = %.4f\n", G2_p2))
#>   G² = 1.0652
cat(sprintf("  Keputusan: %s\n",
            ifelse(chi_p2$p.value < 0.05, "TOLAK H₀", "GAGAL TOLAK H₀")))
#>   Keputusan: GAGAL TOLAK H₀
print(k2_p2)
#>        Dem+Rep Independent
#> Female     767         590
#> Male       595         498

8.5.3 Perbandingan Partisi vs Keseluruhan

df_partisi <- data.frame(
  Komponen = c("Keseluruhan (2×3)",
               "Partisi 1: Dem vs Rep",
               "Partisi 2: (Dem+Rep) vs Ind",
               "Jumlah Partisi"),
  Chi2     = round(c(chi2_k2,
                     chi_p1$statistic,
                     chi_p2$statistic,
                     chi_p1$statistic + chi_p2$statistic), 4),
  df       = c(df_k2, chi_p1$parameter, chi_p2$parameter,
               chi_p1$parameter + chi_p2$parameter),
  P_value  = c(formatC(pval_k2, digits=6, format="f"),
               formatC(chi_p1$p.value, digits=6, format="f"),
               formatC(chi_p2$p.value, digits=6, format="f"),
               "—"),
  Keputusan = c(
    ifelse(pval_k2 < 0.05, "TOLAK H₀","GAGAL TOLAK H₀"),
    ifelse(chi_p1$p.value < 0.05, "TOLAK H₀","GAGAL TOLAK H₀"),
    ifelse(chi_p2$p.value < 0.05, "TOLAK H₀","GAGAL TOLAK H₀"),
    "—"
  )
)

kable(df_partisi,
      col.names = c("Komponen Uji", "χ²", "df", "p-value", "Keputusan"),
      caption   = "Tabel K2-4. Partisi Chi-Square: Keseluruhan vs Komponen",
      align     = c("l","c","c","c","c")) |>
  kable_styling(bootstrap_options = c("bordered","hover","striped"),
                full_width = TRUE) |>
  row_spec(0, bold = TRUE, background = "#1a5c5a", color = "white") |>
  row_spec(1, bold = TRUE, background = "#eef7f6") |>
  row_spec(4, bold = TRUE, background = "#fff5d4") |>
  footnote(general = "Jumlah χ² partisi ≈ χ² keseluruhan karena partisi orthogonal.",
           general_title = "Catatan:")
Tabel K2-4. Partisi Chi-Square: Keseluruhan vs Komponen
Komponen Uji χ² df p-value Keputusan
Keseluruhan (2×3) 12.5693 2 0.001865 TOLAK H₀
Partisi 1: Dem vs Rep 11.5545 1 0.000676 TOLAK H₀
Partisi 2: (Dem+Rep) vs Ind 1.0654 1 0.301979 GAGAL TOLAK H₀
Jumlah Partisi 12.6200 2
Catatan:
Jumlah χ² partisi ≈ χ² keseluruhan karena partisi orthogonal.

Perbandingan Partisi vs Keseluruhan:

Jumlah \(\chi^2\) dari Partisi 1 dan Partisi 2 seharusnya mendekati \(\chi^2\) keseluruhan (12.5693), mengonfirmasi bahwa partisi bersifat additif (orthogonal). Hal ini menunjukkan:

  • Partisi 1 menguji apakah gender membedakan preferensi antara Democrat dan Republican.
  • Partisi 2 menguji apakah gender membedakan pilihan antara kandidat dari dua partai besar versus Independent.

8.6 2.6 Visualisasi Kasus 2

# ── Proporsi bersyarat per gender ────────────────────────────────────────
prop_k2 <- prop.table(k2, margin = 1)
df_k2_plot <- as.data.frame.table(prop_k2)
colnames(df_k2_plot) <- c("Gender","Partai","Proporsi")

ggplot(df_k2_plot, aes(x = Partai, y = Proporsi, fill = Gender)) +
  geom_col(position = "dodge", width = 0.6, alpha = 0.9, color = "white") +
  geom_text(aes(label = percent(Proporsi, accuracy = 0.1)),
            position = position_dodge(0.6), vjust = -0.5,
            size = 4, fontface = "bold") +
  scale_fill_manual(values = c("Female" = "#6a3fa0", "Male" = "#1a5c5a")) +
  scale_y_continuous(labels = percent, limits = c(0, 0.55),
                     expand = c(0, 0)) +
  labs(
    title    = "Distribusi Identifikasi Partai Politik berdasarkan Gender",
    subtitle = bquote(chi^2 ~ "=" ~ .(round(chi2_k2,3)) ~
                      ", df = 2, p =" ~ .(formatC(pval_k2, digits=4, format="f")) ~
                      ", Cramér's V =" ~ .(round(V_k2,4))),
    x = "Identifikasi Partai", y = "Proporsi (%)",
    fill = "Gender",
    caption = "Proporsi dihitung dalam masing-masing kelompok gender"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title    = element_text(face = "bold", color = "#1a5c5a"),
    plot.subtitle = element_text(color = "#555"),
    legend.position = "top",
    panel.grid.major.x = element_blank(),
    panel.grid.minor   = element_blank()
  )
Gambar K2-1. Distribusi Identifikasi Partai Politik berdasarkan Gender

Gambar K2-1. Distribusi Identifikasi Partai Politik berdasarkan Gender

mosaic(k2, shade = TRUE, legend = TRUE,
       main = "Mosaic Plot: Gender × Identifikasi Partai Politik",
       sub  = paste0("χ² = ", round(chi2_k2,3),
                     "  |  df = 2  |  p = ",
                     formatC(pval_k2, digits=4, format="f"),
                     "  |  Cramér's V = ", round(V_k2,4)))
Gambar K2-2. Mosaic Plot: Gender × Identifikasi Partai Politik

Gambar K2-2. Mosaic Plot: Gender × Identifikasi Partai Politik

# ── Heatmap standardized residual ─────────────────────────────────────────
df_resid_plot <- as.data.frame.table(round(res_std, 3))
colnames(df_resid_plot) <- c("Gender","Partai","Residual")

ggplot(df_resid_plot, aes(x = Partai, y = Gender, fill = Residual)) +
  geom_tile(color = "white", size = 1.2) +
  geom_text(aes(label = sprintf("%.3f", Residual)),
            size = 5, fontface = "bold",
            color = ifelse(abs(df_resid_plot$Residual) > 2, "white","black")) +
  scale_fill_gradient2(
    low = "#8b3a1e", mid = "white", high = "#1a5c5a",
    midpoint = 0, name = "Std.\nResidual"
  ) +
  labs(
    title   = "Heatmap Standardized Residual",
    subtitle = "Nilai > 1.96 atau < −1.96 → kontribusi signifikan (α=0.05)",
    x = "Identifikasi Partai", y = "Gender"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title    = element_text(face = "bold", color = "#1a5c5a"),
    plot.subtitle = element_text(color = "#555"),
    panel.grid    = element_blank()
  )
Gambar K2-3. Heatmap Standardized Residual

Gambar K2-3. Heatmap Standardized Residual


8.7 2.7 Kesimpulan Kasus 2

Kesimpulan Akhir Kasus 2: Hubungan Gender dan Identifikasi Partai Politik

Berdasarkan data tabel kontingensi 2×3 dengan \(n = 2450\) responden:

  1. Uji Chi-Square keseluruhan: \(\chi^2(2) = 12.5693\), \(p = 0.001865\). Tolak H₀ → terdapat asosiasi signifikan antara gender dan identifikasi partai politik.

  2. Kekuatan asosiasi: Cramér’s \(V = 0.0716\), menunjukkan asosiasi yang lemah secara praktis meski signifikan secara statistik (ukuran sampel besar).

  3. Residual standar: Sel yang berkontribusi paling besar adalah pada kategori Democrat dan Republican — perempuan cenderung lebih banyak mengidentifikasi diri sebagai Democrat dan lebih sedikit sebagai Republican dibandingkan ekspektasi, sementara pola sebaliknya terlihat pada laki-laki.

  4. Partisi chi-square:

    • Partisi 1 (Dem vs Rep): \(\chi^2 = 11.5545\), \(p =`r formatC(chi_p1\)p.value, digits=6, format=“f”)`$ — gender membedakan preferensi Demokrat vs Republik.
    • Partisi 2 ((Dem+Rep) vs Ind): \(\chi^2 = 1.0654\), \(p =`r formatC(chi_p2\)p.value, digits=6, format=“f”)`$ — gender tidak secara signifikan membedakan antara pemilih dua partai besar vs Independen.
  5. Kesimpulan substantif: Kategori yang paling membedakan gender adalah Democrat vs Republican — perempuan cenderung lebih condong ke Democrat, sedangkan laki-laki lebih merata antara Democrat, Republican, dan Independent. Perbedaan antara pemilih partai besar (Dem+Rep) dan Independent tidak berbeda nyata antar gender.


9 Referensi

No. Penulis Tahun Judul Penerbit/Jurnal
1 Agresti, A. 2013 Categorical Data Analysis, 3rd ed. Wiley
2 Friendly, M. 2000 Visualizing Categorical Data SAS Institute
3 Hosmer, D. W. & Lemeshow, S. 2013 Applied Logistic Regression, 3rd ed. Wiley
4 Rothman, K. J. 2012 Epidemiology: An Introduction, 2nd ed. Oxford University Press
5 R Core Team 2024 R: A Language and Environment for Statistical Computing R Foundation
6 Meyer, D., Zeileis, A., & Hornik, K. 2023 vcd: Visualizing Categorical Data R Package
7 Stokes, M. E., Davis, C. S., & Koch, G. G. 2000 Categorical Data Analysis Using the SAS System, 2nd ed. SAS Institute

:::

Tugas 6 — Inferensi Tabel Kontingensi Dua Arah  ·  Analisis Data Kategori
Dibuat dengan R Markdown  ·  10 April 2026