Uji Chi-Square

Uji kebaikan suai dan uji kebebasan pada tabel kontingensi.

Daftar isi

Data hasil penghitungan kategori menuntut perlakuan yang berbeda dari data pengukuran, karena rata-rata atas label tidak menyatakan apa pun. Topik ini membahas uji chi-square untuk data frekuensi dalam dua bentuknya, yaitu uji kebaikan suai (goodness-of-fit test) untuk satu variabel kategorikal dan uji kebebasan (test of independence) untuk dua variabel kategorikal pada tabel kontingensi (contingency table). Setiap bentuk dikerjakan melalui dua jalur, pertama dengan simulasi Monte Carlo agar intuisinya terbangun, kemudian dengan fungsi resmi scipy.stats.chisquare dan scipy.stats.chi2_contingency. Pembahasan ditutup dengan syarat frekuensi harapan (expected frequency) yang wajib dipenuhi sebelum hasil uji ini dipercaya.

Dua wajah uji chi-square#

Uji chi-square membandingkan frekuensi amatan dengan frekuensi harapan pada setiap sel, lalu meringkas seluruh selisihnya menjadi satu angka. Angka tersebut besar apabila data menyimpang jauh dari yang ditetapkan hipotesis nol, dan kecil apabila data menempel pada harapan. Bentuk pertama, uji kebaikan suai, memeriksa satu variabel kategorikal, misalnya apakah 120 lemparan dadu seimbang pada enam matanya. Bentuk kedua, uji kebebasan, memeriksa dua variabel kategorikal sekaligus, misalnya apakah jalur transportasi siswa berhubungan dengan angkatannya. Kedua bentuk menggunakan statistik uji yang sama.

χ2=∑(O−E)2E \chi^2 = \sum \frac{(O - E)^2}{E}

Pada rumus tersebut, OO adalah frekuensi amatan dan EE adalah frekuensi harapan pada setiap sel. Nilai EE ditetapkan oleh hipotesis nol, sedangkan nilai OO datang dari data. Sel dengan selisih besar menyumbang suku yang besar karena selisihnya dikuadratkan, sehingga satu sel yang menyimpang sudah cukup mendorong χ2\chi^2 naik. Distribusi acuan statistik ini adalah distribusi chi-square dengan derajat kebebasan tertentu, sehingga p-value dibaca dari ekor distribusi tersebut. Diagram berikut merangkum kapan masing-masing bentuk digunakan.

Satu variabel kategorikaldaftar frekuensi tiap kategoriUji kebaikan suaiscipy.stats.chisquareDua variabel kategorikaltabel kontingensiUji kebebasanscipy.stats.chi2_contingency
Dua bentuk uji chi-square menurut banyaknya variabel kategorikal

Uji kebaikan suai lewat simulasi dan rumus#

Urutan yang digunakan sepanjang jalur ini menempatkan simulasi sebelum rumus. Program berikut membangkitkan 120 lemparan dadu digital yang peluang matanya tidak seragam, yaitu mata 5 dan 6 diberi peluang dua kali lipat mata lainnya, lalu mengujinya terhadap dadu seimbang dengan frekuensi harapan 20 untuk setiap mata. Simulasi Monte Carlo menghasilkan 100.000 tabel frekuensi di bawah hipotesis nol dadu seimbang, menghitung χ2\chi^2 pada setiap tabel acak, dan menetapkan p-value sebagai proporsi tabel acak yang seekstrem data amatan.

python kebaikan-suai.py
import numpy as np
from scipy import stats

# 120 lemparan dadu digital yang peluang matanya tidak seragam
# (mata 5 dan 6 diberi peluang dua kali lipat mata lainnya)
rng = np.random.default_rng(42)
peluang_asli = np.array([0.125, 0.125, 0.125, 0.125, 0.25, 0.25])
lemparan = rng.choice(np.arange(1, 7), size=120, p=peluang_asli)
amatan = np.bincount(lemparan, minlength=7)[1:]
print(f"Frekuensi amatan   : {amatan}")

# Uji kebaikan suai terhadap dadu seimbang, harapan 20 untuk setiap mata
harapan = np.full(6, 120 / 6)
chi2_manual = float(np.sum((amatan - harapan) ** 2 / harapan))
formal = stats.chisquare(amatan, f_exp=harapan)
print(f"chi-square manual  : {chi2_manual:.4f}")
print(f"SciPy chisquare    : statistik = {formal.statistic:.4f}, p-value = {formal.pvalue:.4f}")

# Simulasi Monte Carlo: 100.000 tabel frekuensi dadu seimbang di bawah H0
rng_mc = np.random.default_rng(43)
simulasi = rng_mc.multinomial(120, np.full(6, 1 / 6), size=100_000)
chi2_sim = np.sum((simulasi - 20.0) ** 2 / 20.0, axis=1)
p_mc = (np.count_nonzero(chi2_sim >= chi2_manual) + 1) / 100_001
print(f"p-value Monte Carlo: {p_mc:.4f}")
text Keluaran
Frekuensi amatan   : [12 17 14 19 29 29]
chi-square manual  : 13.6000
SciPy chisquare    : statistik = 13.6000, p-value = 0.0184
p-value Monte Carlo: 0.0184

Ketiga jalur memberi jawaban yang sama. Statistik uji hasil hitungan manual bernilai 13.6000 dan identik dengan keluaran chisquare, karena fungsi tersebut menerapkan rumus yang sama. p-value Monte Carlo 0.0184 berhimpit dengan p-value distribusi chi-square 0.0184, sebuah kesepakatan yang wajar karena frekuensi harapan per sel berukuran 20 sehingga aproksimasinya akurat. Karena p-value berada di bawah 0.05, hipotesis nol dadu seimbang ditolak, dan kesimpulan itu sesuai dengan cara data dibangkitkan.

Uji kebebasan pada tabel kontingensi#

Uji kebebasan menanyakan apakah dua variabel kategorikal bergerak sendiri-sendiri. Tabel kontingensi pada program berikut merangkum jalur transportasi 200 siswa menurut angkatan, dan pertanyaannya adalah apakah perubahan angkatan disertai perubahan pola jalur yang dipilih. Frekuensi harapan dihitung dengan asumsi kebebasan, yaitu frekuensi baris dikalikan frekuensi kolom, kemudian dibagi total keseluruhan.

Eij=(total baris i)×(total kolom j)n E_{ij} = \frac{(\text{total baris } i) \times (\text{total kolom } j)}{n}

Program berikut menghitung frekuensi harapan tersebut secara manual, menjalankan chi2_contingency, lalu memverifikasinya dengan permutasi Monte Carlo. Permutasi hanya memindahkan label angkatan antarsiswa, sehingga jumlah setiap baris dan setiap kolom tidak berubah dan struktur tabel tetap terjaga.

python kebebasan-angkatan.py
import numpy as np
from scipy import stats

# Tabel kontingensi: jalur transportasi 200 siswa menurut angkatan
# baris = jalur, kolom = angkatan (2024, 2025)
jalur = ["jalan kaki", "sepeda", "angkutan umum"]
tabel = np.array([[48, 32],
                  [22, 38],
                  [30, 30]])

# Frekuensi harapan dihitung manual: total baris x total kolom / total keseluruhan
total_baris = tabel.sum(axis=1, keepdims=True)
total_kolom = tabel.sum(axis=0, keepdims=True)
harapan = total_baris @ total_kolom / tabel.sum()
for i, nama in enumerate(jalur):
    print(f"{nama:14s}: amatan = {tabel[i, 0]:2d} dan {tabel[i, 1]:2d},"
          f" harapan = {harapan[i, 0]:.4f} dan {harapan[i, 1]:.4f}")

# Uji kebebasan formal
stat, p, df, _ = stats.chi2_contingency(tabel)
print(f"chi-square = {stat:.4f}, df = {df}, p-value = {p:.4f}")

# Simulasi permutasi: label angkatan diacak, margin baris dan kolom tetap
jalur_kode = np.repeat(np.arange(3), total_baris.ravel())
angkatan = np.concatenate([np.repeat([0, 1], baris) for baris in tabel])
rng = np.random.default_rng(42)
acak = rng.permuted(np.tile(angkatan, (10_000, 1)), axis=1)
satu_panjang = np.eye(3)[jalur_kode]
hitung_kolom_1 = satu_panjang.T @ (acak == 1).T
harapan_k0 = total_baris.ravel() * tabel[:, 0].sum() / tabel.sum()
harapan_k1 = total_baris.ravel() * tabel[:, 1].sum() / tabel.sum()
hitung_kolom_0 = total_baris.ravel()[:, None] - hitung_kolom_1
chi2_sim = np.sum((hitung_kolom_0 - harapan_k0[:, None]) ** 2 / harapan_k0[:, None], axis=0)
chi2_sim = chi2_sim + np.sum((hitung_kolom_1 - harapan_k1[:, None]) ** 2
                             / harapan_k1[:, None], axis=0)
p_perm = (np.count_nonzero(chi2_sim >= stat) + 1) / 10_001
print(f"p-value permutasi Monte Carlo : {p_perm:.4f}")
text Keluaran
jalan kaki    : amatan = 48 dan 32, harapan = 40.0000 dan 40.0000
sepeda        : amatan = 22 dan 38, harapan = 30.0000 dan 30.0000
angkutan umum : amatan = 30 dan 30, harapan = 30.0000 dan 30.0000
chi-square = 7.4667, df = 2, p-value = 0.0239
p-value permutasi Monte Carlo : 0.0281

Hasilnya konsisten dari dua arah. p-value 0.0239 dari distribusi chi-square dan 0.0281 dari permutasi sama-sama berada di bawah 0.05, sehingga hipotesis kebebasan ditolak. Penyebab utamanya terbaca pada baris sepeda, yaitu 22 siswa pada angkatan 2024 berbanding 38 siswa pada angkatan 2025, sedangkan harapannya 30 untuk keduanya. Derajat kebebasannya mengikuti aturan (r−1)(c−1)(r-1)(c-1), dengan rr banyaknya baris dan cc banyaknya kolom, sehingga bernilai 2 untuk tabel 3×23 \times 2. Angka inilah yang menentukan bentuk distribusi chi-square acuannya.

Syarat frekuensi harapan dan hitungan mentah#

Aproksimasi distribusi chi-square hanya akurat apabila frekuensi harapan cukup besar. Aturan praktis yang umum menuntut frekuensi harapan bernilai sekurang-kurangnya 5 pada setiap sel, dengan toleransi bahwa paling banyak 20 persen sel boleh turun hingga 1 apabila sel lainnya memenuhi syarat. Apabila syarat ini gugur, p-value dari distribusi chi-square menjadi tidak dapat dipercaya, dan perbaikannya adalah menggabungkan kategori yang jarang atau menambah ukuran sampel. Ukuran sampel memengaruhi syarat ini dari dua arah. Sampel yang besar menaikkan seluruh frekuensi harapan sekaligus dan membuat syarat mudah terpenuhi, sedangkan tabel berukuran besar dengan sampel kecil sering melanggarnya, sehingga tabel dengan banyak kategori menuntut sampel yang lebih besar pula.

Kesalahan umum#

Kesalahan pertama adalah membiarkan frekuensi harapan kecil tanpa tindakan, misalnya melanjutkan pengujian pada tabel 4×44 \times 4 dengan sepuluh amatan, karena p-value yang dihasilkan tidak lagi mengikuti distribusi chi-square. Perbaikannya adalah menggabungkan kategori yang serupanya masih bermakna atau menambah data sampai syaratnya terpenuhi. Kesalahan kedua adalah menafsirkan penolakan kebebasan sebagai hubungan sebab-akibat, padahal uji ini hanya menunjukkan bahwa dua variabel bergerak bersama, dan arah sebabnya harus didukung oleh desain pengumpulan data.

Kesalahan ketiga adalah berhenti pada keputusan tolak atau terima tanpa menunjukkan sel yang menyimpang, padahal kekuatan uji chi-square justru pada kemudahan menunjuk selnya, misalnya baris sepeda pada contoh sebelumnya. Laporan yang baik menyertakan tabel amatan beserta harapannya sehingga pembaca dapat menilai sendiri besaran penyimpangannya. Dengan kebiasaan tersebut, hasil uji tidak berhenti sebagai angka p-value semata.

Ringkasan#

  • Uji chi-square meringkas selisih frekuensi amatan dan harapan menjadi χ2\chi^2, dengan uji kebaikan suai untuk satu variabel dan uji kebebasan untuk dua variabel pada tabel kontingensi.
  • Simulasi Monte Carlo dan distribusi chi-square memberi p-value yang berhimpit pada contoh dadu, yaitu 0.0184 berbanding 0.0184, serta berdekatan pada uji kebebasan, yaitu 0.0281 berbanding 0.0239.
  • Frekuensi harapan dihitung dari total baris dikalikan total kolom dibagi total keseluruhan, dan syarat praktisnya bernilai minimal 5 pada setiap sel.
  • Uji dijalankan pada hitungan mentah, bukan persentase, dan p-value hanya bermakna bila syarat frekuensi harapan terpenuhi.

Referensi#