Sedikit angka di dunia riset dikutip selaras p-value — dan sedikit juga yang disalahartikan seluas itu. Bab berita menuliskannya sebagai “terbukti signifikan”, laporan internal menumpukinya sebagai stempel kepastian, padahal makna aslinya jauh lebih sempit. Pada chapter ini kita definisikan p-value dengan presisi, menghitungnya langsung dari statistik uji, lalu membongkar dua kesalahpahaman terbesarnya: bahwa p-value mengukur peluang hipotesis nol benar, dan bahwa p-value kecil berarti efeknya besar. Setelah chapter ini, membaca kalimat “p < 0,05” tidak akan sama lagi.
Definisi yang Tepat #
p-value adalah peluang — dengan syarat H0 benar — memperoleh data yang sama ekstremnya atau lebih ekstrem lagi daripada yang kita lihat. Perhatikan arah syaratnya:
p-value = P(data se-ekstrem ini atau lebih | H0 benar)Yang diberi peluang adalah data, bukan hipotesis. p-value tidak pernah menyatakan “peluang H0 benar”, karena pengondisinya justru menganggap H0 benar sejak awal. Ia juga bukan ukuran besar efek: dua penelitian dengan efek yang sama besar bisa menghasilkan p-value yang jauh berbeda, seperti akan kita buktikan sebentar lagi. Karena itu tabel berikut layak dihafal:
| Pernyataan | Status |
|---|---|
| “Peluang mendapat data seekstrem ini bila H0 benar adalah p” | Benar |
| “Peluang H0 benar adalah p” | Keliru — membalik arah syarat |
| “p kecil berarti efeknya besar” | Keliru — p sensitif terhadap n |
| “p ≥ 0,05 berarti tidak ada efek” | Keliru — hanya berarti bukti kurang |
Menghitung p-value dari Statistik Uji #
Bab sebelumnya menghasilkan t hitung −4,0452 untuk uji porsi kopi. p-value-nya adalah luas kedua ekor kurva-t (df = 15) di luar ±4,0452. Fungsi t.sf (survival function) menghitung satu ekor kanan; untuk uji dua sisi kita menggandakannya:
import numpy as np
from scipy.stats import t, ttest_1samp
porsi = np.array([
296, 302, 288, 291, 299, 285, 293, 306,
297, 290, 288, 301, 294, 287, 295, 292,
])
hasil = ttest_1samp(porsi, popmean=300.0)
p_manual = 2 * t.sf(abs(hasil.statistic), df=porsi.size - 1)
print(f"t hitung (scipy) : {hasil.statistic:.4f}")
print(f"p-value (scipy) : {hasil.pvalue:.6f}")
print(f"p-value (manual) : {p_manual:.6f}")Output yang Dihasilkan:
t hitung (scipy) : -4.0452
p-value (scipy) : 0.001058
p-value (manual) : 0.001058Bacaannya begini: bila rata-rata porsi memang benar 300 ml, peluang mengukur 16 gelas dan mendapat rata-rata sampel sejauh 294 ml atau lebih jauh lagi hanya 0,1%. Data kita termasuk sangat jarang di dunia tempat H0 benar — kelangkaan itulah yang mendorong kita menolak H0. Perhitungan manual dengan 2 * t.sf(...) menghasilkan angka yang sama persis dengan scipy, karena memang itulah yang scipy hitung di balik layar.
p-value Tidak Mengukur Besarnya Efek #
Sekarang eksperimen yang membongkar anggapan keliru kedua. Dua peneliti mengukur porsi kopi dari proses yang sama-sama “menyimpang 2,5 ml dari klaim” — satu dengan 12 gelas, satu dengan 160 gelas:
import numpy as np
from scipy.stats import ttest_1samp
rng = np.random.default_rng(42)
mu0 = 300.0
kecil = rng.normal(297.5, 8.0, size=12)
besar = rng.normal(297.5, 8.0, size=160)
for nama, data in [("n = 12 ", kecil), ("n = 160", besar)]:
hasil = ttest_1samp(data, popmean=mu0)
print(f"{nama}: xbar = {data.mean():.2f}, "
f"selisih = {data.mean() - mu0:+.2f} ml, p-value = {hasil.pvalue:.4f}")Output yang Dihasilkan:
n = 12 : xbar = 296.37, selisih = -3.63 ml, p-value = 0.1291
n = 160: xbar = 297.12, selisih = -2.88 ml, p-value = 0.0000Mari kita telaah hasil ini:
- n = 12 → p = 0,1291: selisih 3,63 ml terlalu kecil dibanding derau pengukuran; sampel sekecil ini tidak cukup bukti untuk melawan klaim.
- n = 160 → p = 0,0000: selisihnya bahkan lebih kecil (2,88 ml — sekitar 1% isi gelas), tetapi dengan 160 gelas, selisih sekecil itu pun konsisten terlihat dan p-value jatuh di bawah 0,0001.
- Pelajarannya: p-value mencampur dua bahan — jarak rata-rata dari klaim dan ketelitian pengukuran (yang naik dengan n). p-value kecil hanya berkata “kita cukup yakin ada selisih”; besar selisih itu harus dibaca dari data, dan kepentingannya dinilai dengan ukuran efek pada chapter Ukuran Efek.
Ambang 0,05: Konvensi, Bukan Hukum Alam #
Dari mana angka 0,05? Bukan dari alam — ia warisan konvensi yang dipopulerkan R.A. Fisher pada era tabel statistik tercetak, lalu mengeras menjadi kebiasaan publikasi. Simulasi berikut memperlihatkan sisi hikmahnya: ketika H0 selalu benar dan kita menguji berulang kali, berapa banyak “penemuan” palsu yang muncul?
import numpy as np
from scipy.stats import ttest_1samp
rng = np.random.default_rng(42)
alpha = 0.05
signifikan = 0
percobaan = 2000
for _ in range(percobaan):
sampel = rng.normal(300.0, 8.0, size=16)
if ttest_1samp(sampel, popmean=300.0).pvalue < alpha:
signifikan += 1
print(f"H0 selalu benar: {signifikan}/{percobaan} uji signifikan "
f"({signifikan / percobaan:.1%})")Output yang Dihasilkan:
H0 selalu benar: 111/2000 uji signifikan (5.5%)Dari 2.000 uji pada populasi yang benar-benar sesuai H0, 111 uji (5,5%) tetap menghasilkan p < 0,05. Ini bukan galat simulasi — p-value memang berdistribusi seragam di bawah H0, sehingga sekitar 5% uji pasti “signifikan” tanpa ada efek apa pun. Angka 5% inilah laju positif palsu yang kita sepakati menanggungnya sebagai harga pengambilan keputusan dari sampel.
Rangkuman #
- p-value = P(data se-ekstrem ini atau lebih | H0 benar): peluang menempel pada data, bukan pada hipotesis.
- Untuk uji dua sisi, p = 2 × t.sf(|t|, df); hasilnya identik dengan keluaran
ttest_1samp. - p-value mencampur besar selisih dan ketelitian pengukuran: selisih 2,88 ml bisa “sangat signifikan” hanya karena n besar — p kecil tidak berarti efek besar.
- Ambang 0,05 adalah konvensi dengan arti pasti: bila H0 selalu benar, sekitar 5% uji akan tampak signifikan (simulasi kita: 5,5%).
Menolak H0 yang sebenarnya benar adalah satu jenis kesalahan; gagal menolak H0 yang sebenarnya salah adalah jenis lainnya. Dua-duanya punya nama, laju, dan harga keputusannya sendiri — pokok bahasan chapter Kesalahan Tipe I dan Tipe II.