Mengapa Bulan Ini Penting?

Apa itu Statistik Inferensial?

Statistik deskriptif (Bulan 5-6) hanya menggambarkan data yang sudah Abbas miliki. Statistik inferensial melangkah lebih jauh: Abbas menarik kesimpulan tentang populasi yang jauh lebih besar hanya dari secuil sampel. Ini adalah fondasi dari penelitian ilmiah, uji klinis, survei nasional, dan A/B testing produk.

  • Membuat klaim tentang dunia dari data terbatas. Abbas tidak perlu mensurvei 270 juta penduduk Indonesia untuk tahu rata-rata pengeluaran per bulan. Cukup sampel 1.000 orang yang representatif, lalu inferensial memberi Abbas angka beserta tingkat kepercayaannya.
  • Probabilitas adalah bahasanya. Setiap kesimpulan inferensial datang dengan peluang: "kami 95% yakin rata-rata populasi ada di antara X dan Y". Tanpa probabilitas, tidak ada klaim yang bisa dipercaya.
  • Distribusi normal adalah tulang punggung hampir semua uji statistik. Kenapa? Karena Central Limit Theorem membuktikan bahwa rata-rata sampel selalu mendekati distribusi normal, tidak peduli distribusi data aslinya seperti apa.
  • Hypothesis testing adalah cara ilmuwan membuat keputusan. Apakah obat baru benar-benar lebih efektif? Apakah iklan versi B lebih baik dari A? Semua dijawab dengan kerangka "null vs alternative hypothesis" dan nilai p.
  • p-value sering disalahpahami, bahkan oleh peneliti senior. Bulan ini Abbas akan paham betul apa arti p-value dan, sama pentingnya, apa yang bukan artinya. Ini keunggulan yang membedakan data analyst yang baik.
  • Error tidak bisa dihindari, tapi bisa dikelola. Type I error (false positive) dan Type II error (false negative) selalu ada. Abbas akan belajar bagaimana memilih threshold yang tepat sesuai konteks masalah.
  • Chi-square dan ANOVA memperluas kemampuan Abbas ke data kategorikal dan multi-grup. Tidak semua data numerik kontinu. Chi-square mengurus pertanyaan seperti "apakah gender mempengaruhi pilihan jurusan?" tanpa perlu asumsi distribusi normal pada data.
  • Korelasi dan regresi adalah pintu masuk ke machine learning. Simple linear regression di bulan ini adalah fondasi dari seluruh supervised learning. Abbas yang memahami regresi dari akar statistiknya akan jauh lebih kuat saat masuk ke ML di bulan-bulan berikutnya.
  • Semua konsep ini langsung bisa dipakai di dunia nyata. Apakah rata-rata nilai kelas Abbas berbeda secara signifikan dari rata-rata nasional? Apakah ada hubungan antara waktu belajar dan nilai? Semua pertanyaan ini dijawab persis dengan tools di bulan ini.
Tips Belajar Bulan 7

Statistik inferensial penuh dengan formula, tapi jangan hafal formula dulu. Setiap kali Abbas menemukan rumus baru, tanya dulu: "apa yang rumus ini sedang hitung, secara intuitif?" Intuisi dulu, formula kemudian. Bulan ini juga sangat berguna jika Abbas punya dataset nilai ujian kelas sendiri untuk dijadikan bahan latihan nyata.

Minggu 1: Probabilitas dan Distribusi

Sebelum bisa menguji hipotesis, Abbas perlu memahami bahasa yang dipakai statistik inferensial: probabilitas dan distribusi. Minggu ini membangun fondasi matematis yang akan dipakai sepanjang bulan.

Minggu 1 - Overview

Hari 1
Probability Basics: Event, Sample Space, dan Aturan Kombinasi
Mental Model: Probabilitas sebagai "Rasio Kemungkinan"

Bayangkan sebuah kantong berisi 100 kelereng: 30 merah, 70 biru. Probabilitas mengambil merah adalah 30/100 = 0,3. Semua konsep probabilitas lanjutan hanyalah perluasan logika sederhana ini ke situasi yang lebih kompleks.

Aktivitas 1: Definisi Formal (30 menit)

Pelajari tiga konsep dasar. Sample space (S) adalah himpunan semua kemungkinan hasil. Contoh: S untuk pelemparan dadu = {1,2,3,4,5,6}. Event (A) adalah subset dari S. Contoh: A = "muncul angka genap" = {2,4,6}. Probabilitas P(A) = jumlah elemen A dibagi jumlah elemen S = 3/6 = 0,5. Tulis definisi ini di buku catatan Abbas dengan contoh sendiri.

Aktivitas 2: Aturan Penjumlahan dan Perkalian (45 menit)

Pelajari dua aturan inti. P(A atau B) untuk event tidak saling eksklusif: P(A) + P(B) - P(A dan B). P(A dan B) untuk event independen: P(A) x P(B). Latihan: dari sebuah kelas 40 siswa, 20 suka matematika, 15 suka fisika, 8 suka keduanya. Berapa yang suka matematika atau fisika? Hitung manual dulu sebelum cek jawaban.

Aktivitas 3: Probabilitas Kondisional (30 menit)

P(A|B) dibaca "probabilitas A terjadi, dengan syarat B sudah terjadi". Formula: P(A|B) = P(A dan B) / P(B). Contoh nyata: dari 100 pelajar, 60 lulus ujian, 40 mengikuti les. Dari 40 yang les, 35 lulus. P(lulus | ikut les) = 35/40 = 0,875. Bandingkan dengan P(lulus tanpa les) = 25/60. Apa kesimpulan Abbas?

Aktivitas 4: Kode Python Probabilitas Dasar (30 menit)
import numpy as np # Simulasi: lempar dadu 10000 kali np.random.seed(42) lemparan = np.random.randint(1, 7, size=10000) # P(angka genap) p_genap = np.mean(lemparan % 2 == 0) print(f"P(genap) simulasi: {p_genap:.4f}") # harusnya ~0.5 # P(angka > 4) p_besar = np.mean(lemparan > 4) print(f"P(angka > 4): {p_besar:.4f}") # harusnya ~0.333 # P(genap DAN lebih dari 4) = P({6}) p_keduanya = np.mean((lemparan % 2 == 0) & (lemparan > 4)) print(f"P(genap AND >4): {p_keduanya:.4f}") # harusnya ~0.167
Aktivitas 5: Refleksi (15 menit)

Tulis di buku: kapan Abbas perlu memakai P(A atau B) vs P(A dan B)? Buat satu contoh dari kehidupan sehari-hari untuk masing-masing aturan.

Hari 2
Distribusi Normal: Z-Score dan Standardisasi
Mental Model: Kurva Lonceng sebagai "Peta Populasi"

Distribusi normal adalah peta yang menunjukkan di mana sebagian besar anggota populasi berada. Rata-rata (mean) adalah pusat peta. Standar deviasi adalah "skala" peta. Z-score adalah koordinat: "Abbas ada di posisi +1,5 standar deviasi dari rata-rata." Koordinat inilah yang membuat semua distribusi bisa dibandingkan dalam satuan yang sama.

Aktivitas 1: Sifat Distribusi Normal (30 menit)

Pelajari aturan empiris 68-95-99.7: 68% data ada dalam 1 standar deviasi dari mean, 95% dalam 2 SD, 99.7% dalam 3 SD. Gambarlah kurva normal di kertas, tandai batas-batas tersebut. Contoh: nilai ujian nasional rata-rata 70, SD = 10. Di mana 68% siswa berada? Di antara nilai 60 dan 80.

Aktivitas 2: Menghitung Z-Score Manual (30 menit)

Formula: z = (x - mu) / sigma. Dimana x adalah nilai individual, mu adalah rata-rata populasi, sigma adalah standar deviasi. Latihan: nilai ujian Abbas = 82, rata-rata kelas = 74, SD = 8. Z = (82-74)/8 = 1,0. Artinya Abbas berada 1 SD di atas rata-rata. Hitung juga: jika nilai Budi = 65, berapa z-score Budi? Interpretasikan hasilnya.

Aktivitas 3: Dari Z-Score ke Probabilitas (40 menit)

Setelah tahu z-score, Abbas bisa tahu probabilitas. P(X lebih kecil dari x) bisa dicari dari tabel z atau fungsi scipy. Contoh: z = 1,0, P(X kurang dari 82) = 0,8413. Artinya 84,13% siswa di bawah nilai Abbas. Ini disebut "percentile". Latihan: hitung probabilitas siswa mendapat nilai di atas 90, jika mean=74, SD=8.

Aktivitas 4: Kode Python Distribusi Normal (45 menit)
import numpy as np import matplotlib.pyplot as plt from scipy import stats mean_nilai = 74 sd_nilai = 8 # Z-score untuk nilai 82 nilai_abbas = 82 z_abbas = (nilai_abbas - mean_nilai) / sd_nilai print(f"Z-score Abbas: {z_abbas:.2f}") # Probabilitas: P(X < 82) p_bawah = stats.norm.cdf(nilai_abbas, loc=mean_nilai, scale=sd_nilai) print(f"Percentile Abbas: {p_bawah*100:.1f}%") # Probabilitas: P(X > 90) p_atas = 1 - stats.norm.cdf(90, loc=mean_nilai, scale=sd_nilai) print(f"P(nilai > 90): {p_atas:.4f}") # Plot kurva normal x = np.linspace(40, 110, 300) y = stats.norm.pdf(x, loc=mean_nilai, scale=sd_nilai) plt.figure(figsize=(8, 4)) plt.plot(x, y, color='steelblue', linewidth=2) plt.axvline(nilai_abbas, color='red', linestyle='--', label=f'Abbas={nilai_abbas}') plt.fill_between(x, y, where=(x < nilai_abbas), alpha=0.3, color='steelblue') plt.title('Distribusi Normal Nilai Ujian') plt.xlabel('Nilai') plt.legend() plt.tight_layout() plt.savefig('distribusi_normal.png', dpi=150) plt.show()
Aktivitas 5: Soal Tantangan (20 menit)

Sebuah tes IQ dirancang dengan mean 100 dan SD 15. Berapa persen populasi memiliki IQ di atas 130 (definisi "sangat gifted")? Berapa persen di bawah 85? Jawab dengan kode Python, bukan kalkulator.

Hari 3
Central Limit Theorem: Keajaiban Statistik
Mental Model: Mengapa CLT Disebut "Keajaiban"

Bayangkan distribusi nilai ujian kelas Abbas miring ke kanan (banyak yang dapat nilai rendah, sedikit yang tinggi). Jika Abbas ambil 30 sampel acak, hitung rata-ratanya, lalu ulangi proses itu 1.000 kali, distribusi dari 1.000 rata-rata itu akan berbentuk normal sempurna. Tidak peduli seberapa "aneh" distribusi aslinya. Ini CLT: distribusi sampling dari rata-rata selalu normal, jika n cukup besar (biasanya n lebih dari sama dengan 30).

Aktivitas 1: Memahami Distribusi Sampling (30 menit)

Beda antara distribusi data asli (satu angka per observasi) dan distribusi sampling (distribusi dari statistik, misalnya rata-rata, yang dihitung berulang kali dari banyak sampel). CLT berbicara tentang distribusi sampling. Tulis perbedaan ini dengan kalimat Abbas sendiri.

Aktivitas 2: Demonstrasi CLT dengan Distribusi Seragam (45 menit)
import numpy as np import matplotlib.pyplot as plt from scipy import stats np.random.seed(99) # Distribusi ASLI: seragam (sama sekali tidak normal) populasi = np.random.uniform(0, 100, size=100000) fig, axes = plt.subplots(1, 3, figsize=(15, 4)) # Plot 1: Distribusi asli axes[0].hist(populasi, bins=50, color='coral', edgecolor='white') axes[0].set_title('Distribusi Asli (Seragam)') # Plot 2: Distribusi sampling n=5 means_n5 = [np.mean(np.random.choice(populasi, 5)) for _ in range(1000)] axes[1].hist(means_n5, bins=50, color='steelblue', edgecolor='white') axes[1].set_title('Rata-rata Sampel (n=5)') # Plot 3: Distribusi sampling n=30 means_n30 = [np.mean(np.random.choice(populasi, 30)) for _ in range(1000)] axes[2].hist(means_n30, bins=50, color='seagreen', edgecolor='white') axes[2].set_title('Rata-rata Sampel (n=30) -- Normal!') plt.suptitle('Central Limit Theorem Demo', fontsize=14, fontweight='bold') plt.tight_layout() plt.savefig('clt_demo.png', dpi=150) plt.show() # Verifikasi: rata-rata distribusi sampling mendekati rata-rata populasi print(f"Rata-rata populasi: {np.mean(populasi):.2f}") print(f"Rata-rata dari means_n30: {np.mean(means_n30):.2f}") print(f"Standard Error (SE): {np.std(means_n30):.2f}") print(f"SE teoritis (SD/sqrt(n)): {np.std(populasi)/np.sqrt(30):.2f}")
Aktivitas 3: Standard Error vs Standard Deviation (20 menit)

Standard Deviation mengukur sebaran data individual. Standard Error mengukur sebaran rata-rata sampel. SE = SD / sqrt(n). Semakin besar sampel, SE semakin kecil, artinya rata-rata sampel semakin akurat. Buat tabel: hitung SE untuk n = 5, 10, 30, 100 dengan SD = 15.

Aktivitas 4: CLT dengan Distribusi Miring (25 menit)

Ulangi demonstrasi Aktivitas 2, tapi ganti distribusi seragam dengan distribusi eksponensial: populasi = np.random.exponential(scale=10, size=100000). Apakah distribusi sampling tetap normal untuk n=30? Bandingkan hasilnya.

Aktivitas 5: Implikasi Praktis (15 menit)

Tulis jawaban: kenapa CLT sangat penting untuk dunia nyata? Petunjuk: apakah data pendapatan, data harga saham, data jumlah pengunjung toko berdistribusi normal? Tidak. Tapi dengan CLT, Abbas tetap bisa memakai uji statistik yang mengasumsikan normalitas.

Hari 4
Confidence Interval: Bukan Sekadar Range, tapi Tentang Keyakinan
Mental Model: CI sebagai Jaring, Bukan Kotak

Banyak yang salah mengira: "CI 95% artinya ada 95% kemungkinan parameter populasi ada di interval ini." Salah besar. Nilai parameter populasi itu tetap, tidak punya probabilitas. Yang punya probabilitas adalah metodenya: jika Abbas ulangi pengambilan sampel 100 kali dan hitung CI setiap kali, rata-rata 95 dari 100 CI itu akan mencakup nilai parameter yang benar. Bayangkan 100 jaring dilempar ke kolam: 95 jaring menangkap ikan, 5 tidak. CI bukan kotak di mana ikan berenang, tapi jaring yang cukup sering menangkap ikan.

Aktivitas 1: Formula CI untuk Mean (30 menit)

CI = x-bar plus/minus z* x (SD / sqrt(n)). Dimana x-bar adalah rata-rata sampel, z* adalah nilai kritis (1,96 untuk 95%, 2,576 untuk 99%), SD adalah standar deviasi sampel, n adalah ukuran sampel. Latihan manual: sampel 36 siswa, rata-rata nilai = 78, SD = 12. Hitung CI 95%. Jawab: 78 plus/minus 1,96 x (12/sqrt(36)) = 78 plus/minus 3,92 = (74,08; 81,92).

Aktivitas 2: Pengaruh n terhadap Lebar CI (30 menit)

Hitung CI 95% untuk data yang sama (mean=78, SD=12) tapi dengan n = 9, 36, 100, 400. Buat tabel. Apa polanya? Semakin besar n, semakin sempit CI. Artinya sampel yang lebih besar memberikan estimasi yang lebih presisi. Ini alasan survey yang bagus selalu menjelaskan "margin of error" bersama dengan ukuran sampel.

Aktivitas 3: Kode Python CI dengan scipy (40 menit)
import numpy as np from scipy import stats # Data: nilai ujian sampel 36 siswa np.random.seed(7) nilai_sampel = np.random.normal(78, 12, size=36) n = len(nilai_sampel) mean = np.mean(nilai_sampel) se = stats.sem(nilai_sampel) # Standard Error # CI 95% menggunakan t-distribution (lebih tepat untuk sampel kecil) ci_95 = stats.t.interval( confidence=0.95, df=n - 1, loc=mean, scale=se ) print(f"Ukuran sampel: {n}") print(f"Rata-rata sampel: {mean:.2f}") print(f"Standard Error: {se:.2f}") print(f"CI 95%: ({ci_95[0]:.2f}, {ci_95[1]:.2f})") # Bandingkan CI 90%, 95%, 99% for level in [0.90, 0.95, 0.99]: ci = stats.t.interval(confidence=level, df=n-1, loc=mean, scale=se) lebar = ci[1] - ci[0] print(f"CI {int(level*100)}%: ({ci[0]:.2f}, {ci[1]:.2f}) -- lebar: {lebar:.2f}")
Aktivitas 4: Kapan Pakai Z vs T? (20 menit)

Jika SD populasi diketahui dan n besar (lebih dari 30): pakai distribusi Z. Jika SD populasi tidak diketahui (situasi nyata hampir selalu ini) dan/atau n kecil: pakai distribusi T (Student's t). Distribusi T lebih "lebar" untuk mengkompensasi ketidakpastian tambahan. Dengan n besar (lebih dari 100), Z dan T memberikan hasil hampir identik.

Aktivitas 5: Salah Kaprah CI (15 menit)

Cari artikel berita Indonesia yang menyebutkan "margin of error". Baca bagaimana mereka menjelaskan CI. Apakah penjelasannya benar secara statistik? Tulis analisis singkat di buku catatan.

Hari 5
Latihan: Hitung CI untuk Rata-rata Nilai Ujian 50 Siswa Sampel
Project Hari Ini

Abbas akan mensimulasikan menjadi peneliti pendidikan. Tugas: dari sampel 50 siswa, estimasi rata-rata nilai ujian populasi nasional beserta confidence interval-nya. Lalu bandingkan: seberapa sering CI sampel berhasil "menangkap" nilai populasi sesungguhnya?

Aktivitas 1: Setup Data (20 menit)
import numpy as np from scipy import stats import matplotlib.pyplot as plt # Populasi "sesungguhnya" (kita tahu karena ini simulasi) np.random.seed(2024) populasi = np.random.normal(loc=72, scale=14, size=10000) mean_populasi = np.mean(populasi) print(f"Rata-rata populasi sesungguhnya: {mean_populasi:.2f}") # Ambil 1 sampel ukuran 50 sampel_50 = np.random.choice(populasi, size=50, replace=False) print(f"Rata-rata sampel: {np.mean(sampel_50):.2f}") print(f"SD sampel: {np.std(sampel_50, ddof=1):.2f}")
Aktivitas 2: Hitung dan Interpretasikan CI (30 menit)
# Hitung CI 95% untuk sampel n = len(sampel_50) mean_s = np.mean(sampel_50) se = stats.sem(sampel_50) ci = stats.t.interval(0.95, df=n-1, loc=mean_s, scale=se) print(f"CI 95%: ({ci[0]:.2f}, {ci[1]:.2f})") print(f"Lebar CI: {ci[1]-ci[0]:.2f} poin nilai") # Apakah CI ini menangkap nilai populasi sesungguhnya? tertangkap = ci[0] <= mean_populasi <= ci[1] print(f"CI menangkap nilai populasi? {tertangkap}")
Aktivitas 3: Simulasi 100 Sampel (45 menit)
# Ulangi 100 kali: ambil sampel, hitung CI n_simulasi = 100 ci_list = [] tertangkap_list = [] for i in range(n_simulasi): s = np.random.choice(populasi, size=50, replace=False) ci_i = stats.t.interval(0.95, df=49, loc=np.mean(s), scale=stats.sem(s)) ci_list.append(ci_i) tertangkap_list.append(ci_i[0] <= mean_populasi <= ci_i[1]) persen_tertangkap = np.mean(tertangkap_list) * 100 print(f"Dari {n_simulasi} CI yang dihitung:") print(f" {persen_tertangkap:.0f}% menangkap nilai populasi") print(f" {100-persen_tertangkap:.0f}% meleset") print(f" (teoritis: 95% menangkap, 5% meleset)") # Visualisasi: plot semua CI fig, ax = plt.subplots(figsize=(5, 12)) for i, (ci_i, hit) in enumerate(zip(ci_list, tertangkap_list)): color = 'steelblue' if hit else 'crimson' ax.plot([ci_i[0], ci_i[1]], [i, i], color=color, alpha=0.7, linewidth=1.2) ax.axvline(mean_populasi, color='black', linestyle='--', label='Rata-rata Populasi') ax.set_title('100 Confidence Interval 95%\n(merah = meleset)') ax.legend() plt.tight_layout() plt.savefig('ci_simulasi.png', dpi=150) plt.show()
Aktivitas 4: Eksplorasi Mandiri (20 menit)

Ubah ukuran sampel dari 50 menjadi 10, lalu 200. Bagaimana lebar CI berubah? Apakah persen yang "menangkap" tetap sekitar 95%? Catat temuan Abbas.

Aktivitas 5: Tulis Laporan Mini (15 menit)

Tulis paragraf singkat (5-7 kalimat): "Sebagai peneliti, saya mengambil sampel 50 siswa dari populasi besar dan mendapatkan rata-rata X dengan CI 95% (Y, Z). Ini berarti..." Sertakan interpretasi yang benar tentang apa CI 95% artinya.

Checkpoint Minggu 1

Sebelum lanjut ke Minggu 2, pastikan Abbas bisa menjawab: (1) Apa perbedaan distribusi populasi dan distribusi sampling? (2) Kenapa CLT penting meski data tidak normal? (3) Apa artinya CI 95% secara tepat? Jika ada yang belum yakin, ulangi hari yang relevan.

Minggu 2: Hypothesis Testing

Hypothesis testing adalah mesin pengambilan keputusan berbasis data. Minggu ini Abbas belajar cara ilmuwan, dokter, dan product manager membuktikan atau menggugurkan klaim dengan data.

Minggu 2 - Overview

Hari 1
Null vs Alternative Hypothesis dan P-Value: Penjelasan Intuitif
Mental Model: Hypothesis Testing sebagai "Sidang Pengadilan"

Dalam sidang, terdakwa "dianggap tidak bersalah" sampai terbukti sebaliknya. Null hypothesis (H0) adalah "tidak bersalah": tidak ada efek, tidak ada perbedaan. Alternative hypothesis (H1) adalah tuduhan jaksa: ada efek, ada perbedaan. Tugas Abbas adalah mengumpulkan bukti (data) yang cukup kuat untuk "menolak H0". P-value adalah seberapa mungkin bukti sekuat ini muncul jika H0 benar. Jika sangat tidak mungkin (p lebih kecil dari 0,05), Abbas "menolak H0".

Aktivitas 1: Struktur Formal Hypothesis Testing (30 menit)

Pelajari 5 langkah baku: (1) Rumuskan H0 dan H1. (2) Tentukan alpha (tingkat signifikansi, biasanya 0,05). (3) Hitung statistik uji dari data. (4) Hitung p-value. (5) Bandingkan p-value dengan alpha: jika p kurang dari alpha, tolak H0. Contoh: "Apakah rata-rata nilai kelas Abbas berbeda dari 75?" H0: mu = 75. H1: mu tidak sama dengan 75. Ini two-tailed test.

Aktivitas 2: Apa Itu P-Value Sebenarnya? (30 menit)

Definisi tepat: p-value adalah probabilitas mendapatkan hasil se-ekstrem atau lebih ekstrem dari data yang diamati, JIKA null hypothesis benar. Bukan probabilitas H0 benar. Bukan probabilitas Abbas membuat kesalahan. Tulis analogi Abbas sendiri untuk menjelaskan ini ke teman yang belum belajar statistik. Ini latihan pemahaman yang kuat.

Aktivitas 3: One-Tailed vs Two-Tailed Test (20 menit)

Two-tailed: H1 adalah "berbeda" (tidak peduli lebih besar atau lebih kecil). One-tailed: H1 adalah "lebih besar" atau "lebih kecil" secara spesifik. Kapan pakai which? One-tailed lebih powerful, tapi hanya valid jika Abbas sudah punya alasan teoritis sebelum melihat data untuk menduga arah perbedaannya. Jangan pilih one-tailed hanya karena p-value menjadi lebih kecil.

Aktivitas 4: Kritik p-Value (30 menit)

Baca (atau tonton) dua sumber: (1) Artikel American Statistical Association 2016 tentang p-value. (2) Pencarian "p-hacking explained" di YouTube. Tulis: apa itu p-hacking, dan bagaimana cara menghindarinya? Petunjuk: pre-registration, multiple comparison correction (Bonferroni), melaporkan effect size bukan hanya p-value.

Aktivitas 5: Latihan Merumuskan Hipotesis (20 menit)

Untuk setiap pertanyaan berikut, tulis H0 dan H1 yang tepat: (a) Apakah obat baru menurunkan tekanan darah lebih dari 10 mmHg? (b) Apakah rata-rata waktu pengiriman toko A sama dengan toko B? (c) Apakah siswa yang sarapan mendapat nilai lebih tinggi dari yang tidak? Tentukan juga: one-tailed atau two-tailed, dan mengapa.

Hari 2
One-Sample T-Test: Apakah Rata-rata Berbeda dari Nilai Tertentu?
Mental Model: T-Test sebagai "Seberapa Jauh dari Ekspektasi?"

Bayangkan Abbas melempar dadu 30 kali dan mendapat rata-rata 3,7. Rata-rata dadu yang adil adalah 3,5. Apakah perbedaan 0,2 ini karena dadunya dicurang, atau hanya kebetulan variasi normal? T-test menjawab pertanyaan ini secara formal: ia mengukur seberapa jauh rata-rata sampel dari nilai hipotesis, dalam satuan standard error. Semakin besar t-statistic, semakin tidak mungkin perbedaan itu terjadi secara kebetulan.

Aktivitas 1: Formula T-Statistic (25 menit)

t = (x-bar - mu0) / (s / sqrt(n)). Dimana x-bar adalah rata-rata sampel, mu0 adalah nilai hipotesis (dari H0), s adalah standar deviasi sampel, n adalah ukuran sampel. Nilai t besar (positif atau negatif) menunjukkan data jauh dari H0. Derajat kebebasan (df) = n - 1. Hitung manual: sampel 25 siswa, x-bar = 78, s = 10, H0: mu = 75. t = (78-75)/(10/sqrt(25)) = 3/2 = 1,5.

Aktivitas 2: Implementasi scipy (40 menit)
import numpy as np from scipy import stats # Data: nilai 25 siswa kelas Abbas np.random.seed(42) nilai_kelas = np.random.normal(78, 10, size=25) # One-sample t-test: apakah rata-rata != 75? mu_hipotesis = 75 t_stat, p_value = stats.ttest_1samp(nilai_kelas, popmean=mu_hipotesis) print(f"Rata-rata sampel: {np.mean(nilai_kelas):.2f}") print(f"T-statistic: {t_stat:.4f}") print(f"P-value (two-tailed): {p_value:.4f}") alpha = 0.05 if p_value < alpha: print(f"Tolak H0: rata-rata kelas berbeda signifikan dari {mu_hipotesis}") else: print(f"Gagal tolak H0: tidak cukup bukti rata-rata berbeda dari {mu_hipotesis}") # Untuk one-tailed (H1: rata-rata > 75) p_one_tailed = p_value / 2 if t_stat > 0 else 1 - p_value / 2 print(f"P-value (one-tailed, H1: mu > {mu_hipotesis}): {p_one_tailed:.4f}")
Aktivitas 3: Asumsi T-Test (20 menit)

T-test memiliki asumsi yang harus dicek: (1) Data independen (satu observasi tidak mempengaruhi yang lain). (2) Data berdistribusi normal, atau n cukup besar (CLT membantu). (3) Tidak ada outlier ekstrem yang mendistorsi mean. Cara cek normalitas: histogram, Q-Q plot, atau Shapiro-Wilk test. Tulis kode: stat, p = stats.shapiro(nilai_kelas); print(p). Jika p lebih besar dari 0,05, asumsi normalitas terpenuhi.

Aktivitas 4: Effect Size dengan Cohen's d (25 menit)

P-value signifikan tidak berarti perbedaannya besar secara praktis. Effect size mengukur besarnya perbedaan. Cohen's d = (x-bar - mu0) / s. Panduan: d = 0,2 kecil, d = 0,5 sedang, d = 0,8 besar. Hitung d untuk contoh di atas. Apakah perbedaan yang signifikan secara statistik juga signifikan secara praktis? Tulis interpretasi Abbas.

Aktivitas 5: Eksplorasi Pingouin (20 menit)
import pingouin as pg import pandas as pd import numpy as np np.random.seed(42) nilai_kelas = np.random.normal(78, 10, size=25) # pingouin memberi output lebih lengkap (termasuk effect size) hasil = pg.ttest(nilai_kelas, 75) print(hasil.to_string()) # Output: T, dof, alternative, p-val, CI95%, cohen-d, power
Hari 3
Two-Sample T-Test dan Paired T-Test
Mental Model: Dua Jenis Perbandingan

Two-sample t-test: dua kelompok berbeda orang. Contoh: kelas A vs kelas B. Pertanyaan: apakah rata-rata dua kelompok independen ini berbeda? Paired t-test: kelompok yang sama, dua kondisi berbeda. Contoh: nilai sebelum dan sesudah les tambahan siswa yang sama. Karena setiap orang dibandingkan dengan dirinya sendiri, variasi antar-individu "dikurangi" dan tes ini lebih powerful. Pilih yang salah, kesimpulan bisa menyesatkan.

Aktivitas 1: Two-Sample T-Test Independen (35 menit)
import numpy as np from scipy import stats np.random.seed(5) # Kelas A: metode belajar konvensional kelas_a = np.random.normal(74, 11, size=30) # Kelas B: metode belajar baru kelas_b = np.random.normal(79, 10, size=28) # Levene test: apakah varians sama? (asumsi equal variance) lev_stat, lev_p = stats.levene(kelas_a, kelas_b) print(f"Levene test p-value: {lev_p:.4f}") equal_var = lev_p > 0.05 # True jika varians sama # Two-sample t-test (Welch's jika varians tidak sama) t_stat, p_value = stats.ttest_ind(kelas_a, kelas_b, equal_var=equal_var) print(f"Rata-rata Kelas A: {np.mean(kelas_a):.2f}") print(f"Rata-rata Kelas B: {np.mean(kelas_b):.2f}") print(f"T-statistic: {t_stat:.4f}") print(f"P-value: {p_value:.4f}")
Aktivitas 2: Paired T-Test (35 menit)
# Nilai 20 siswa SEBELUM dan SESUDAH les tambahan np.random.seed(13) sebelum = np.random.normal(70, 12, size=20) # Efek les: tambah rata-rata 5 poin, dengan sedikit variasi sesudah = sebelum + np.random.normal(5, 4, size=20) # Paired t-test t_stat_p, p_value_p = stats.ttest_rel(sebelum, sesudah) print(f"Rata-rata sebelum: {np.mean(sebelum):.2f}") print(f"Rata-rata sesudah: {np.mean(sesudah):.2f}") print(f"Rata-rata selisih: {np.mean(sesudah - sebelum):.2f}") print(f"T-statistic: {t_stat_p:.4f}") print(f"P-value: {p_value_p:.4f}") # Bandingkan: bagaimana jika salah pakai independent t-test? t_salah, p_salah = stats.ttest_ind(sebelum, sesudah) print(f"\nJika salah pakai independent t-test:") print(f"P-value: {p_salah:.4f} (lebih besar, kurang powerful)")
Aktivitas 3: Kapan Paired vs Independent? (15 menit)

Buat tabel keputusan: baris = skenario, kolom = jenis t-test. Skenario: (a) Bandingkan gaji pria dan wanita di perusahaan berbeda. (b) Bandingkan berat badan pasien sebelum dan sesudah diet 3 bulan. (c) Bandingkan nilai ujian dua sekolah berbeda. (d) Bandingkan kecepatan membaca siswa sebelum dan sesudah program literasi. Isi kolom dengan "Independent" atau "Paired" beserta alasannya.

Aktivitas 4: Visualisasi Hasil T-Test (30 menit)
import matplotlib.pyplot as plt fig, axes = plt.subplots(1, 2, figsize=(12, 5)) # Boxplot two-sample axes[0].boxplot([kelas_a, kelas_b], labels=['Kelas A', 'Kelas B'], patch_artist=True, boxprops=dict(facecolor='lightblue')) axes[0].set_title(f'Two-Sample T-Test\np = {p_value:.3f}') axes[0].set_ylabel('Nilai') # Plot sebelum-sesudah (paired) for i in range(len(sebelum)): axes[1].plot([0, 1], [sebelum[i], sesudah[i]], color='steelblue', alpha=0.4, linewidth=1) axes[1].set_xticks([0, 1]) axes[1].set_xticklabels(['Sebelum', 'Sesudah']) axes[1].set_title(f'Paired T-Test\np = {p_value_p:.3f}') axes[1].set_ylabel('Nilai') plt.tight_layout() plt.savefig('ttest_comparison.png', dpi=150) plt.show()
Aktivitas 5: Eksplorasi dengan Pingouin (15 menit)

Coba pg.ttest(kelas_a, kelas_b, paired=False) dan pg.ttest(sebelum, sesudah, paired=True). Perhatikan kolom "power" di output. Power adalah probabilitas mendeteksi perbedaan nyata jika memang ada. Power yang ideal adalah 0,80 atau lebih. Jika power rendah, apa yang bisa Abbas lakukan? (Jawab: perbesar sampel.)

Hari 4
Type I dan Type II Error: Tradeoff yang Selalu Ada
Mental Model: Detektor Asap vs Dokter Kanker

Detektor asap sengaja dirancang sensitif: lebih baik bunyi alarm karena asap rokok (false positive / Type I error) daripada tidak bunyi saat ada kebakaran nyata (false negative / Type II error). Sebaliknya, dokter yang mendiagnosis kanker lebih takut melewatkan pasien yang benar-benar sakit (Type II error) karena konsekuensinya fatal. Setiap domain punya toleransi berbeda terhadap dua jenis error ini.

Aktivitas 1: Tabel Keputusan 2x2 (25 menit)

Buat tabel: baris = keputusan Abbas (Tolak H0 / Gagal Tolak H0), kolom = realita (H0 Benar / H0 Salah). Isi empat sel: (1) Tolak H0 padahal H0 Benar = Type I Error (alpha). (2) Tolak H0 padahal H0 Salah = Keputusan Benar (Power = 1 - beta). (3) Gagal Tolak H0 padahal H0 Benar = Keputusan Benar (1 - alpha). (4) Gagal Tolak H0 padahal H0 Salah = Type II Error (beta). Hafal tabel ini.

Aktivitas 2: Hubungan Alpha, Beta, dan Power (30 menit)

Alpha = P(Type I Error). Beta = P(Type II Error). Power = 1 - Beta. Tradeoff utama: menurunkan alpha (lebih ketat) meningkatkan beta (lebih sering melewatkan efek nyata). Analogi: jika hakim menjadi lebih ketat standar pembuktiannya, lebih sedikit orang tidak bersalah dihukum (alpha turun), tapi lebih banyak orang bersalah yang lolos (beta naik). Ada empat cara meningkatkan power tanpa mengorbankan alpha: perbesar n, perbesar effect size (tidak selalu bisa dikontrol), kurangi variasi data, pakai one-tailed test jika tepat.

Aktivitas 3: Power Analysis dengan Pingouin (35 menit)
import pingouin as pg import numpy as np import matplotlib.pyplot as plt # Berapa n yang dibutuhkan untuk power 80%? # Effect size d=0.5 (sedang), alpha=0.05 n_needed = pg.power_ttest(d=0.5, power=0.80, alpha=0.05, contrast='two-samples') print(f"N per grup yang dibutuhkan: {n_needed:.0f}") # Plot: bagaimana power berubah dengan ukuran sampel? n_values = np.arange(5, 200, 5) powers = [pg.power_ttest(d=0.5, n=n, alpha=0.05, contrast='two-samples') for n in n_values] plt.figure(figsize=(8, 4)) plt.plot(n_values, powers, color='steelblue', linewidth=2) plt.axhline(0.80, color='red', linestyle='--', label='Power = 0.80') plt.xlabel('Ukuran Sampel per Grup (n)') plt.ylabel('Power') plt.title('Power Analysis: Effect Size = 0.5 (Medium)') plt.legend() plt.grid(alpha=0.3) plt.tight_layout() plt.savefig('power_analysis.png', dpi=150) plt.show()
Aktivitas 4: Studi Kasus Pemilihan Alpha (20 menit)

Untuk setiap skenario berikut, tentukan alpha yang tepat dan jelaskan mengapa: (a) Uji apakah iklan baru meningkatkan klik 5%. (b) Uji apakah vaksin baru lebih aman dari vaksin lama. (c) Uji apakah warna tombol checkout mempengaruhi konversi. (d) Uji apakah ada hubungan antara makanan tertentu dan kanker. Petunjuk: konsekuensi Type I dan Type II error berbeda drastis di setiap kasus.

Aktivitas 5: Menulis Laporan Keputusan (15 menit)

Tulis paragraf tentang cara melaporkan hasil t-test yang baik: harus menyertakan (1) nilai t dan p-value, (2) effect size, (3) CI, (4) power jika relevan, (5) interpretasi dalam konteks masalah. Ini standar pelaporan yang dipakai jurnal ilmiah.

Hari 5
Latihan: Apakah Kelas A Lebih Baik dari Kelas B? T-Test dari Data Nilai
Project Hari Ini: Evaluasi Metode Pengajaran

Abbas berperan sebagai data analyst di sebuah sekolah. Kepala sekolah ingin tahu: apakah metode pengajaran baru di Kelas B menghasilkan nilai lebih tinggi dari Kelas A yang pakai metode konvensional? Abbas harus menjawab dengan data, bukan opini.

Aktivitas 1: Persiapan Data dan EDA (25 menit)
import numpy as np import pandas as pd from scipy import stats import matplotlib.pyplot as plt import pingouin as pg np.random.seed(2025) # Kelas A: 32 siswa, metode lama kelas_a = np.round(np.random.normal(73, 12, 32)).clip(0, 100) # Kelas B: 30 siswa, metode baru kelas_b = np.round(np.random.normal(79, 11, 30)).clip(0, 100) df = pd.DataFrame({ 'nilai': np.concatenate([kelas_a, kelas_b]), 'kelas': ['A'] * 32 + ['B'] * 30 }) print(df.groupby('kelas')['nilai'].describe().round(2))
Aktivitas 2: Cek Asumsi (20 menit)
# 1. Cek normalitas: Shapiro-Wilk for nama, grup in [('A', kelas_a), ('B', kelas_b)]: stat, p = stats.shapiro(grup) print(f"Shapiro-Wilk Kelas {nama}: stat={stat:.3f}, p={p:.3f}") print(f" Asumsi normal: {'Ya' if p > 0.05 else 'Tidak'}") # 2. Cek homogenitas varians: Levene lev_stat, lev_p = stats.levene(kelas_a, kelas_b) print(f"\nLevene test p={lev_p:.3f}") print(f"Varians homogen: {'Ya' if lev_p > 0.05 else 'Tidak -- pakai Welch t-test'}")
Aktivitas 3: Jalankan T-Test dan Interpretasi (30 menit)
# H0: rata-rata Kelas A = rata-rata Kelas B # H1: rata-rata Kelas B > Kelas A (one-tailed) hasil = pg.ttest(kelas_b, kelas_a, paired=False, alternative='greater') print(hasil[['T', 'dof', 'alternative', 'p-val', 'CI95%', 'cohen-d', 'power']].to_string()) # Kesimpulan otomatis p = hasil['p-val'].values[0] d = hasil['cohen-d'].values[0] power = hasil['power'].values[0] print(f"\nKesimpulan:") print(f" p-value = {p:.4f} {'< 0.05 --> Tolak H0' if p < 0.05 else '>= 0.05 --> Gagal tolak H0'}") print(f" Cohen's d = {d:.2f} ({'kecil' if d < 0.3 else 'sedang' if d < 0.7 else 'besar'})") print(f" Power = {power:.2f}")
Aktivitas 4: Visualisasi Perbandingan (25 menit)
fig, axes = plt.subplots(1, 2, figsize=(12, 5)) # Boxplot dengan jitter axes[0].boxplot([kelas_a, kelas_b], labels=['Kelas A\n(Konvensional)', 'Kelas B\n(Metode Baru)'], patch_artist=True, boxprops=dict(facecolor='#e8f4f8')) axes[0].set_title('Distribusi Nilai per Kelas') axes[0].set_ylabel('Nilai Ujian') # Histogram overlay axes[1].hist(kelas_a, bins=12, alpha=0.6, color='steelblue', label='Kelas A') axes[1].hist(kelas_b, bins=12, alpha=0.6, color='coral', label='Kelas B') axes[1].axvline(np.mean(kelas_a), color='steelblue', linestyle='--') axes[1].axvline(np.mean(kelas_b), color='coral', linestyle='--') axes[1].legend() axes[1].set_title('Overlay Histogram') axes[1].set_xlabel('Nilai') plt.tight_layout() plt.savefig('kelas_comparison.png', dpi=150) plt.show()
Aktivitas 5: Laporan untuk Kepala Sekolah (20 menit)

Tulis laporan singkat (setengah halaman) yang ditujukan kepada kepala sekolah non-statistisi. Laporan harus mencakup: pertanyaan penelitian, metodologi (tanpa jargon berlebihan), hasil (p-value, effect size dalam bahasa awam), kesimpulan, dan rekomendasi. Gunakan kalimat seperti "Dengan tingkat kepercayaan 95%, metode baru terbukti meningkatkan nilai rata-rata sebesar X poin."

Checkpoint Minggu 2

Pastikan Abbas bisa membedakan: (1) Kapan pakai one-sample vs two-sample vs paired t-test. (2) Apa arti p-value 0,03 secara tepat. (3) Mengapa effect size sama pentingnya dengan p-value. (4) Apa bedanya Type I dan Type II error dalam konteks keputusan nyata.

Minggu 3: Chi-Square dan ANOVA

T-test hanya bisa membandingkan dua kelompok dan hanya untuk data numerik. Minggu ini Abbas mendapat dua senjata baru: chi-square untuk data kategorikal, dan ANOVA untuk membandingkan tiga kelompok atau lebih sekaligus.

Minggu 3 - Overview

Hari 1
Chi-Square Test of Independence: Hubungan Antar Kategori
Mental Model: Chi-Square sebagai "Detektor Pola Tersembunyi"

Bayangkan Abbas punya tabel: baris = jenis kelamin (pria/wanita), kolom = pilihan jurusan (IPA/IPS/Bahasa). Jika gender dan pilihan jurusan tidak berhubungan, distribusi pilihan jurusan harusnya sama untuk pria dan wanita. Chi-square mengukur seberapa jauh frekuensi yang diamati (observed) dari yang diharapkan jika tidak ada hubungan (expected). Semakin jauh, semakin kuat bukti bahwa ada hubungan antara dua variabel kategorik tersebut.

Aktivitas 1: Membangun Tabel Kontingensi (30 menit)

Tabel kontingensi (contingency table) adalah tabel silang frekuensi dua variabel kategorikal. Buat manual: 200 siswa, 100 pria dan 100 wanita. Pria memilih IPA 60, IPS 30, Bahasa 10. Wanita memilih IPA 40, IPS 35, Bahasa 25. Masukkan ke tabel 2x3. Hitung juga "row total" dan "column total" dan "grand total". Ini fondasi chi-square.

Aktivitas 2: Hitung Expected Frequency (25 menit)

Expected frequency untuk sel (i, j) = (row total i x column total j) / grand total. Untuk sel "Pria, IPA": expected = (100 x 100) / 200 = 50. Hitung expected untuk semua 6 sel. Bandingkan dengan observed. Sel mana yang paling jauh menyimpang? Ini yang paling berkontribusi pada nilai chi-square.

Aktivitas 3: Implementasi dengan scipy (40 menit)
import numpy as np from scipy import stats import pandas as pd # Tabel kontingensi: baris=gender, kolom=jurusan observed = np.array([ [60, 30, 10], # Pria: IPA, IPS, Bahasa [40, 35, 25], # Wanita: IPA, IPS, Bahasa ]) chi2, p_value, dof, expected = stats.chi2_contingency(observed) print("=== Chi-Square Test of Independence ===") print(f"Chi2 statistic: {chi2:.4f}") print(f"P-value: {p_value:.4f}") print(f"Degrees of freedom: {dof}") print(f"\nExpected frequencies:") print(pd.DataFrame(expected, index=['Pria', 'Wanita'], columns=['IPA', 'IPS', 'Bahasa']).round(2)) if p_value < 0.05: print("\nKesimpulan: Ada hubungan signifikan antara gender dan pilihan jurusan.") else: print("\nKesimpulan: Tidak ada bukti cukup untuk hubungan gender dan jurusan.") # Effect size: Cramer's V n = observed.sum() cramers_v = np.sqrt(chi2 / (n * (min(observed.shape) - 1))) print(f"Cramer's V (effect size): {cramers_v:.3f}") # 0.1 kecil, 0.3 sedang, 0.5 besar
Aktivitas 4: Asumsi Chi-Square (20 menit)

Chi-square punya asumsi yang sering diabaikan: (1) Observasi independen. (2) Expected frequency di setiap sel minimal 5. Jika ada sel dengan expected kurang dari 5, pakai Fisher's Exact Test (untuk tabel 2x2) atau gabungkan kategori. Cek apakah data di Aktivitas 3 memenuhi syarat ini. Apa yang Abbas lakukan jika tidak terpenuhi?

Aktivitas 5: Visualisasi Tabel Kontingensi (15 menit)
import matplotlib.pyplot as plt jurusan = ['IPA', 'IPS', 'Bahasa'] pria = [60, 30, 10] wanita = [40, 35, 25] x = np.arange(len(jurusan)) fig, ax = plt.subplots(figsize=(8, 4)) ax.bar(x - 0.2, pria, width=0.4, label='Pria', color='steelblue') ax.bar(x + 0.2, wanita, width=0.4, label='Wanita', color='coral') ax.set_xticks(x) ax.set_xticklabels(jurusan) ax.set_title(f'Pilihan Jurusan per Gender\nChi2={chi2:.2f}, p={p_value:.3f}') ax.set_ylabel('Frekuensi') ax.legend() plt.tight_layout() plt.savefig('chi2_independence.png', dpi=150) plt.show()
Hari 2
Chi-Square Goodness of Fit: Apakah Data Sesuai Teori?
Mental Model: Goodness of Fit sebagai "Perbandingan Resep vs Masakan"

Jika resep kue mengatakan tepung:gula:mentega = 3:2:1, setelah menganalisis 100 kue produksi, Abbas ingin tahu: apakah komposisi nyata sesuai dengan resep? Chi-square goodness of fit membandingkan frekuensi observasi dengan frekuensi yang diharapkan dari teori atau distribusi yang telah ditentukan sebelumnya. Ini berbeda dari test of independence karena hanya melibatkan satu variabel, bukan dua.

Aktivitas 1: Konsep Goodness of Fit (25 menit)

H0: distribusi data sesuai dengan distribusi yang dihipotesiskan. H1: distribusi tidak sesuai. Contoh klasik: Mendel mengamati 787 biji kacang hijau dan 277 kuning (rasio 3:1 teoritis). Apakah data Mendel cocok dengan teori? Expected: 787+277 = 1064 total. Ekspektasi 3:1 berarti 798 hijau, 266 kuning. Hitung chi2 manual: sum((O-E)^2 / E) = (787-798)^2/798 + (277-266)^2/266 = 0,151 + 0,455 = 0,606.

Aktivitas 2: Implementasi Python (35 menit)
from scipy import stats import numpy as np # Contoh 1: Mendel's pea experiment observed_mendel = [787, 277] expected_ratio = [3, 1] total = sum(observed_mendel) expected_mendel = [total * r / sum(expected_ratio) for r in expected_ratio] chi2_mendel, p_mendel = stats.chisquare(observed_mendel, f_exp=expected_mendel) print("=== Mendel's Pea Experiment ===") print(f"Chi2: {chi2_mendel:.4f}, p-value: {p_mendel:.4f}") print(f"Data Mendel {'sesuai' if p_mendel > 0.05 else 'TIDAK sesuai'} teori 3:1") # Contoh 2: Distribusi nilai ujian vs seragam # H0: semua grade (A,B,C,D,E) sama sering muncul observed_grade = [45, 38, 62, 30, 25] # A,B,C,D,E chi2_grade, p_grade = stats.chisquare(observed_grade) print(f"\n=== Distribusi Grade ===") print(f"Chi2: {chi2_grade:.4f}, p-value: {p_grade:.4f}") print(f"Distribusi grade {'seragam' if p_grade > 0.05 else 'TIDAK seragam'}")
Aktivitas 3: Uji Keserasian Distribusi Normal (30 menit)

Goodness of fit juga bisa menguji apakah data berdistribusi normal menggunakan uji Kolmogorov-Smirnov. Buat kode: stat, p = stats.kstest(data, 'norm', args=(np.mean(data), np.std(data))). Coba dengan data yang jelas normal (dari np.random.normal) dan data yang jelas tidak normal (dari np.random.exponential). Bandingkan hasilnya. Catatan: untuk n kecil, Shapiro-Wilk lebih direkomendasikan.

Aktivitas 4: Kapan Goodness of Fit Berguna? (20 menit)

Tulis 3 skenario nyata di dunia data analyst di mana goodness of fit dipakai: (a) Memeriksa apakah distribusi error model machine learning mendekati normal. (b) Memeriksa apakah distribusi permintaan produk per hari sesuai distribusi Poisson (untuk perencanaan stok). (c) Memeriksa apakah proporsi konversi traffic dari berbagai channel sesuai dengan target yang ditetapkan marketing. Tulis H0 dan H1 untuk setiap skenario.

Aktivitas 5: Visualisasi Goodness of Fit (15 menit)

Buat bar chart yang membandingkan observed vs expected untuk kasus grade di Aktivitas 2. Tambahkan label perbedaan (O-E) di atas setiap pasang bar. Ini cara yang jelas untuk menunjukkan sel mana yang paling "tidak sesuai" harapan.

Hari 3
One-Way ANOVA: Bandingkan Lebih dari Dua Kelompok
Mental Model: Mengapa Tidak Pakai Banyak T-Test Saja?

Jika Abbas ingin membandingkan 4 kelompok, ada 6 pasang perbandingan yang harus dilakukan dengan t-test. Dengan alpha = 0,05, setiap uji punya 5% peluang false positive. Untuk 6 uji sekaligus, peluang setidaknya satu false positive melonjak ke 1 - (0,95)^6 = 26,5%. ANOVA menguji semua kelompok sekaligus dalam satu uji, sehingga peluang Type I Error tetap terkontrol di 5%.

Aktivitas 1: Logika ANOVA: Variasi Antar vs Dalam Kelompok (30 menit)

ANOVA membandingkan dua sumber variasi. "Between-group variance": seberapa jauh rata-rata setiap kelompok dari grand mean. "Within-group variance": seberapa bervariasinya data di dalam setiap kelompok. Jika between-group variance jauh lebih besar dari within-group variance, kemungkinan kelompok memang berbeda. Rasio ini disebut F-statistic: F = MS_between / MS_within. F yang besar menunjukkan ada kelompok yang berbeda.

Aktivitas 2: Implementasi One-Way ANOVA (40 menit)
import numpy as np from scipy import stats import pingouin as pg import pandas as pd np.random.seed(77) # Nilai matematika dari 4 jurusan berbeda ipa = np.random.normal(82, 9, size=25) ips = np.random.normal(72, 11, size=25) bahasa = np.random.normal(68, 10, size=25) smk = np.random.normal(75, 12, size=25) # scipy: one-way ANOVA f_stat, p_value = stats.f_oneway(ipa, ips, bahasa, smk) print(f"F-statistic: {f_stat:.4f}") print(f"P-value: {p_value:.6f}") print(f"{'Tolak H0: minimal satu kelompok berbeda' if p_value < 0.05 else 'Gagal tolak H0'}") # pingouin: output lebih lengkap + effect size (eta-squared) df_long = pd.DataFrame({ 'nilai': np.concatenate([ipa, ips, bahasa, smk]), 'jurusan': ['IPA']*25 + ['IPS']*25 + ['Bahasa']*25 + ['SMK']*25 }) aov = pg.anova(data=df_long, dv='nilai', between='jurusan', detailed=True) print("\n", aov.to_string()) # eta-squared: 0.01 kecil, 0.06 sedang, 0.14 besar
Aktivitas 3: Asumsi ANOVA (20 menit)

ANOVA punya 3 asumsi: (1) Normalitas residual. Cek dengan Q-Q plot atau Shapiro-Wilk per kelompok. (2) Homogenitas varians (homoscedasticity). Cek dengan Levene test. (3) Independensi observasi. Jika asumsi normalitas atau homogenitas varians dilanggar, gunakan alternatif non-parametrik: Kruskal-Wallis test (stats.kruskal(ipa, ips, bahasa, smk)). Tulis kode Kruskal-Wallis dan bandingkan p-value-nya dengan ANOVA.

Aktivitas 4: Interpretasi F-Table (25 menit)

ANOVA menghasilkan tabel ANOVA (Sum of Squares, df, Mean Squares, F, p). Latihan membaca tabel: SS_between menunjukkan total variasi yang "dijelaskan" oleh perbedaan kelompok. SS_within menunjukkan variasi "residual" dalam kelompok. Eta-squared = SS_between / SS_total adalah proporsi variasi yang dijelaskan oleh kelompok. Hitung eta-squared dari output pingouin dan interpretasikan.

Aktivitas 5: Visualisasi ANOVA (15 menit)
import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(8, 5)) data_plot = [ipa, ips, bahasa, smk] labels = ['IPA', 'IPS', 'Bahasa', 'SMK'] bp = ax.boxplot(data_plot, labels=labels, patch_artist=True) colors = ['#a8d8ea', '#ffb347', '#b5ead7', '#ffc0cb'] for patch, color in zip(bp['boxes'], colors): patch.set_facecolor(color) ax.axhline(np.concatenate([ipa, ips, bahasa, smk]).mean(), color='gray', linestyle='--', label='Grand Mean') ax.set_title(f'Nilai Matematika per Jurusan\nF={f_stat:.2f}, p={p_value:.4f}') ax.set_ylabel('Nilai') ax.legend() plt.tight_layout() plt.savefig('anova_boxplot.png', dpi=150) plt.show()
Hari 4
Post-Hoc Tests: Tukey HSD
Mental Model: ANOVA Hanya Bilang "Ada yang Berbeda", Tukey Bilang "Siapa"

ANOVA yang signifikan (p lebih kecil dari 0,05) hanya memberitahu bahwa setidaknya satu kelompok berbeda dari yang lain. Tapi ANOVA tidak bilang kelompok mana. Seperti seorang detektif yang tahu bahwa ada pelaku di antara 4 tersangka, tapi belum tahu siapa. Post-hoc test (khususnya Tukey HSD) kemudian membandingkan semua pasang kelompok, sambil menyesuaikan untuk multiple comparison sehingga Type I Error tetap terkontrol.

Aktivitas 1: Kapan Post-Hoc Dilakukan? (15 menit)

Aturan baku: post-hoc test hanya dilakukan JIKA ANOVA signifikan. Jika ANOVA tidak signifikan, tidak ada kelompok yang berbeda, jadi tidak ada yang perlu dibandingkan lebih lanjut. Jangan lakukan post-hoc test sebelum melihat hasil ANOVA, ini data dredging. Selain Tukey HSD, ada Bonferroni, Scheffe, dan Dunn (untuk non-parametrik). Tukey HSD adalah pilihan default yang seimbang untuk banyak kasus.

Aktivitas 2: Tukey HSD dengan Pingouin (40 menit)
import pingouin as pg import pandas as pd import numpy as np from scipy import stats np.random.seed(77) df_long = pd.DataFrame({ 'nilai': np.concatenate([ np.random.normal(82, 9, 25), # IPA np.random.normal(72, 11, 25), # IPS np.random.normal(68, 10, 25), # Bahasa np.random.normal(75, 12, 25), # SMK ]), 'jurusan': ['IPA']*25 + ['IPS']*25 + ['Bahasa']*25 + ['SMK']*25 }) # Tukey HSD post-hoc tukey = pg.pairwise_tukey(data=df_long, dv='nilai', between='jurusan') print(tukey[['A', 'B', 'mean(A)', 'mean(B)', 'diff', 'p-tukey', 'hedges']].to_string()) # Filter hanya yang signifikan signif = tukey[tukey['p-tukey'] < 0.05] print(f"\nPasangan yang berbeda signifikan ({len(signif)} dari {len(tukey)}):") print(signif[['A', 'B', 'diff', 'p-tukey']].to_string())
Aktivitas 3: Visualisasi Hasil Tukey (30 menit)
import matplotlib.pyplot as plt import numpy as np # Plot mean + CI per kelompok (compact summary plot) jurusan_list = ['IPA', 'IPS', 'Bahasa', 'SMK'] means = df_long.groupby('jurusan')['nilai'].mean()[jurusan_list] sems = df_long.groupby('jurusan')['nilai'].sem()[jurusan_list] fig, ax = plt.subplots(figsize=(7, 5)) ax.bar(jurusan_list, means, yerr=sems * 1.96, capsize=5, color=['#a8d8ea', '#ffb347', '#b5ead7', '#ffc0cb'], edgecolor='gray', linewidth=0.8) ax.set_title('Rata-rata Nilai per Jurusan\n(error bar = 95% CI)') ax.set_ylabel('Nilai Rata-rata') ax.set_ylim(55, 95) # Tambah notasi signifikansi antara IPA dan Bahasa ax.annotate('', xy=(2, 90), xytext=(0, 90), arrowprops=dict(arrowstyle='-', color='black')) ax.text(1, 91, '***', ha='center', fontsize=14) plt.tight_layout() plt.savefig('tukey_summary.png', dpi=150) plt.show()
Aktivitas 4: Bonferroni vs Tukey (20 menit)

Bonferroni correction lebih konservatif (lebih sulit menolak H0) tapi lebih universal. Tukey lebih powerful tapi khusus untuk perbandingan semua pasang kelompok. Coba: pg.pairwise_tests(data=df_long, dv='nilai', between='jurusan', padjust='bonf'). Bandingkan p-value Bonferroni vs Tukey. Mana yang lebih sering signifikan? Mengapa?

Aktivitas 5: Rangkuman Keputusan (10 menit)

Buat flowchart keputusan singkat di buku: (1) Ingin bandingkan 2 kelompok numerik independen? Pakai t-test. (2) Ingin bandingkan lebih dari 2 kelompok? Pakai ANOVA. (3) ANOVA signifikan? Lanjut ke Tukey HSD. (4) Data kategorikal, ingin tahu hubungan antar variabel? Pakai chi-square independence. (5) Data tidak normal atau sampel sangat kecil? Pakai non-parametrik (Mann-Whitney atau Kruskal-Wallis).

Hari 5
Latihan: Apakah Jurusan Berpengaruh pada Nilai Matematika? ANOVA Lengkap
Project Hari Ini: Analisis Nilai Matematika Lintas Jurusan

Abbas mendapat tugas dari kepala sekolah: "Buktikan dengan data apakah pilihan jurusan siswa berhubungan dengan performa matematika mereka." Ini adalah analisis ANOVA lengkap dari nol: EDA, asumsi, uji, post-hoc, visualisasi, dan pelaporan.

Aktivitas 1: Generate dan Eksplorasi Data (20 menit)
import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy import stats import pingouin as pg np.random.seed(2025) jurusan_data = { 'IPA': np.round(np.random.normal(83, 9, 35)).clip(40, 100), 'IPS': np.round(np.random.normal(71, 12, 30)).clip(40, 100), 'Bahasa': np.round(np.random.normal(67, 11, 28)).clip(40, 100), 'SMK': np.round(np.random.normal(76, 10, 32)).clip(40, 100), } dfs = [] for j, vals in jurusan_data.items(): dfs.append(pd.DataFrame({'nilai': vals, 'jurusan': j})) df = pd.concat(dfs, ignore_index=True) print(df.groupby('jurusan')['nilai'].agg(['count', 'mean', 'std', 'min', 'max']).round(2))
Aktivitas 2: Cek Asumsi Lengkap (25 menit)
# 1. Normalitas per kelompok print("=== Shapiro-Wilk Normalitas ===") for j in df['jurusan'].unique(): data_j = df[df['jurusan'] == j]['nilai'] stat, p = stats.shapiro(data_j) status = 'OK' if p > 0.05 else 'PERIKSA' print(f" {j}: p={p:.3f} [{status}]") # 2. Homogenitas varians print("\n=== Levene Test (Homogenitas Varians) ===") groups = [df[df['jurusan'] == j]['nilai'].values for j in df['jurusan'].unique()] lev_stat, lev_p = stats.levene(*groups) print(f" Levene stat={lev_stat:.3f}, p={lev_p:.3f}") print(f" Varians homogen: {'Ya' if lev_p > 0.05 else 'Tidak -- pertimbangkan Welch ANOVA'}")
Aktivitas 3: ANOVA dan Post-Hoc (30 menit)
# ANOVA aov = pg.anova(data=df, dv='nilai', between='jurusan', detailed=True) print("=== One-Way ANOVA ===") print(aov[['Source', 'SS', 'df', 'F', 'p-unc', 'np2']].to_string()) f_val = aov[aov['Source'] == 'jurusan']['F'].values[0] p_val = aov[aov['Source'] == 'jurusan']['p-unc'].values[0] eta2 = aov[aov['Source'] == 'jurusan']['np2'].values[0] if p_val < 0.05: print(f"\nANOVA signifikan (p={p_val:.4f}). Lanjut ke Tukey HSD.") tukey = pg.pairwise_tukey(data=df, dv='nilai', between='jurusan') print("\n=== Tukey HSD ===") print(tukey[['A', 'B', 'diff', 'p-tukey', 'hedges']].to_string())
Aktivitas 4: Visualisasi Final (25 menit)

Buat figure dengan 2 subplots: (1) Boxplot per jurusan dengan warna berbeda dan grand mean ditandai. (2) Heatmap p-value dari semua pasang perbandingan Tukey (buat matrix simetris 4x4, warna merah jika signifikan, abu jika tidak). Simpan sebagai anova_final.png. Ini jenis visualisasi yang biasa muncul di paper ilmiah.

Aktivitas 5: Laporan Tertulis (20 menit)

Tulis laporan satu halaman dalam format yang bisa dipresentasikan ke guru/kepala sekolah. Struktur: (1) Pertanyaan penelitian. (2) Data yang digunakan (n per kelompok, distribusi). (3) Hasil ANOVA (F, df, p, eta-squared dalam bahasa awam). (4) Hasil post-hoc: pasang jurusan mana yang berbeda signifikan dan berapa besar perbedaannya. (5) Kesimpulan dan implikasi. Gunakan kalimat: "Jurusan berpengaruh signifikan terhadap nilai matematika, F(3,121) = X, p = Y, eta-squared = Z."

Checkpoint Minggu 3

Pastikan Abbas paham: (1) Perbedaan chi-square independence vs goodness of fit. (2) Mengapa ANOVA lebih baik dari banyak t-test berulang. (3) Kapan post-hoc test dilakukan dan mengapa. (4) Cara membaca tabel ANOVA dan menginterpretasikan eta-squared. Jika ragu, revisit hari yang relevan sebelum lanjut ke Minggu 4.

Minggu 4: Korelasi dan Regresi Linear Sederhana

Minggu terakhir Bulan 7 ini menghubungkan statistik inferensial ke prediksi. Korelasi mengukur kekuatan hubungan dua variabel, regresi membangun model prediksi. Ini pintu masuk langsung ke machine learning.

Minggu 4 - Overview

Hari 1
Pearson Correlation: r, rยฒ, dan Interpretasinya
Mental Model: Korelasi sebagai "Kekuatan Gerakan Bersama"

Bayangkan dua penari. Jika setiap kali penari A melangkah kanan, penari B juga melangkah kanan: korelasi sempurna positif (r = +1). Jika setiap kali A naik, B turun secara konsisten: korelasi sempurna negatif (r = -1). Jika gerakan mereka sama sekali tidak berhubungan: r = 0. Pearson r hanya mengukur hubungan LINEAR, bukan semua bentuk hubungan. Dua variabel bisa sangat berhubungan (kurva U) tapi r mendekati nol.

Aktivitas 1: Formula Pearson r (25 menit)

r = sum((xi - x-bar)(yi - y-bar)) / sqrt(sum((xi - x-bar)^2) x sum((yi - y-bar)^2)). Ini adalah kovarians dibagi perkalian standar deviasi keduanya. Interpretasi: r antara 0,1 dan 0,3 adalah korelasi lemah. r antara 0,3 dan 0,7 adalah sedang. r di atas 0,7 adalah kuat. r negatif menunjukkan arah berlawanan. Hitung manual untuk 5 pasang data: jam_belajar = [2,4,5,7,9] dan nilai = [55,65,70,80,90].

Aktivitas 2: Pearson r dengan Uji Signifikansi (40 menit)
import numpy as np from scipy import stats import matplotlib.pyplot as plt import pingouin as pg import pandas as pd np.random.seed(42) jam_belajar = np.random.uniform(1, 10, 50) nilai = 50 + 5 * jam_belajar + np.random.normal(0, 8, 50) # scipy: hitung r dan p-value r, p = stats.pearsonr(jam_belajar, nilai) print(f"Pearson r: {r:.4f}") print(f"P-value: {p:.6f}") print(f"r-squared (Rยฒ): {r**2:.4f}") print(f"Interpretasi: {r**2*100:.1f}% variasi nilai dijelaskan oleh jam belajar") # pingouin: lebih lengkap (CI untuk r juga) df_cor = pd.DataFrame({'jam': jam_belajar, 'nilai': nilai}) hasil_cor = pg.corr(df_cor['jam'], df_cor['nilai'], method='pearson') print("\n", hasil_cor.to_string()) # Scatter plot dengan garis tren fig, ax = plt.subplots(figsize=(7, 5)) ax.scatter(jam_belajar, nilai, alpha=0.7, color='steelblue', s=50) m, b = np.polyfit(jam_belajar, nilai, 1) x_line = np.linspace(1, 10, 100) ax.plot(x_line, m * x_line + b, color='red', linewidth=2, label=f'r = {r:.3f}, Rยฒ = {r**2:.3f}') ax.set_xlabel('Jam Belajar per Hari') ax.set_ylabel('Nilai Ujian') ax.set_title('Korelasi: Jam Belajar vs Nilai') ax.legend() plt.tight_layout() plt.savefig('korelasi_scatter.png', dpi=150) plt.show()
Aktivitas 3: Berbagai Pola Korelasi (30 menit)

Buat 4 scatter plot: (1) r mendekati +1. (2) r mendekati -0,8. (3) r mendekati 0 (tidak berhubungan). (4) Hubungan kuat tapi non-linear (parabola) dengan r mendekati 0. Ini menunjukkan keterbatasan Pearson r: ia tidak menangkap hubungan non-linear. Untuk kasus 4, gunakan Spearman correlation (stats.spearmanr) dan lihat apakah hasilnya lebih tinggi.

Aktivitas 4: Correlation Matrix (25 menit)
import seaborn as sns # Dataset multi-variabel np.random.seed(5) n = 100 df_multi = pd.DataFrame({ 'jam_belajar': np.random.uniform(1, 10, n), 'jam_tidur': np.random.uniform(5, 9, n), 'nilai_mid': np.random.normal(75, 10, n), 'nilai_uas': np.random.normal(78, 11, n), }) # Buat hubungan buatan: nilai_uas terkorelasi dengan jam belajar df_multi['nilai_uas'] += 4 * df_multi['jam_belajar'] corr_matrix = df_multi.corr() fig, ax = plt.subplots(figsize=(6, 5)) sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='RdYlBu_r', center=0, ax=ax, square=True, linewidths=0.5) ax.set_title('Correlation Matrix') plt.tight_layout() plt.savefig('corr_matrix.png', dpi=150) plt.show()
Aktivitas 5: Latihan Interpretasi (15 menit)

Dari correlation matrix yang dihasilkan, tulis interpretasi untuk setiap pasang variabel yang r-nya lebih besar dari 0,3 atau lebih kecil dari -0,3. Format: "Terdapat korelasi [kuat/sedang/lemah] [positif/negatif] antara X dan Y (r = Z), artinya..."

Hari 2
Correlation is Not Causation: 5 Contoh Nyata yang Mengecoh
Mental Model: Tiga Penjelasan untuk Korelasi

Jika A dan B berkorelasi kuat, ada tiga kemungkinan: (1) A menyebabkan B. (2) B menyebabkan A. (3) Ada variabel ketiga C yang menyebabkan keduanya (confounding variable). Korelasi tidak bisa membedakan ketiganya. Hanya desain penelitian yang tepat (eksperimen terkontrol, randomized controlled trial) yang bisa membuktikan kausalitas.

Aktivitas 1: 5 Korelasi Palsu (Spurious Correlations) (40 menit)

Pelajari dan diskusikan 5 contoh korelasi yang mengecoh: (1) Konsumsi es krim berkorelasi dengan angka tenggelam. Penyebab sebenarnya: musim panas (confounding). (2) Jumlah Nicolas Cage muncul di film per tahun berkorelasi dengan kematian akibat tenggelam di kolam renang. Ini korelasi kebetulan murni (spurious). (3) Negara dengan cokelat terbanyak punya pemenang Nobel terbanyak. Kemungkinan: kekayaan negara adalah confounding variable. (4) Sepatu yang lebih besar berkorelasi dengan membaca lebih baik pada anak SD. Penyebab: usia yang lebih tua menyebabkan keduanya. (5) Pemakai topi berkorelasi dengan lebih pintar. Kemungkinan confounding: latar belakang sosial ekonomi. Tulis analisis Abbas untuk setiap kasus.

Aktivitas 2: Simulasi Spurious Correlation (35 menit)
import numpy as np from scipy import stats import matplotlib.pyplot as plt np.random.seed(101) n_tahun = 20 # Variabel confounding: pertumbuhan ekonomi per tahun pertumbuhan_ekonomi = np.linspace(1, 5, n_tahun) + np.random.normal(0, 0.3, n_tahun) # Keduanya dipengaruhi pertumbuhan ekonomi, BUKAN satu sama lain penjualan_es_krim = 100 + 30 * pertumbuhan_ekonomi + np.random.normal(0, 10, n_tahun) angka_kriminalitas = 500 + 50 * pertumbuhan_ekonomi + np.random.normal(0, 20, n_tahun) r_naive, p_naive = stats.pearsonr(penjualan_es_krim, angka_kriminalitas) print(f"Korelasi es krim vs kriminalitas: r={r_naive:.3f}, p={p_naive:.4f}") print(f"Signifikan? {'Ya -- tapi PALSU!' if p_naive < 0.05 else 'Tidak'}") # Partial correlation: kontrol untuk pertumbuhan ekonomi import pingouin as pg import pandas as pd df_sim = pd.DataFrame({ 'es_krim': penjualan_es_krim, 'kriminalitas': angka_kriminalitas, 'ekonomi': pertumbuhan_ekonomi }) partial = pg.partial_corr(data=df_sim, x='es_krim', y='kriminalitas', covar='ekonomi') print(f"\nPartial correlation (kontrol ekonomi): r={partial['r'].values[0]:.3f}, p={partial['p-val'].values[0]:.3f}") print("Korelasi menghilang setelah dikontrol! Ini konfirmasi spurious.")
Aktivitas 3: Cara Membuktikan Kausalitas (25 menit)

Pelajari tiga pendekatan: (1) Randomized Controlled Trial (RCT): assign random ke grup treatment vs kontrol. Ini gold standard. Contoh: uji vaksin. (2) Natural experiment: manfaatkan kejadian alami yang bertindak seperti randomisasi. Contoh: siswa yang lahir sedikit sebelum batas usia masuk sekolah vs sedikit sesudahnya. (3) Difference-in-differences, instrumental variables, regression discontinuity: teknik ekonometrika untuk estimasi kausal dari data observasional. Tulis mana yang paling mungkin dipakai untuk menguji: "apakah les menambah nilai?", "apakah makan sarapan meningkatkan konsentrasi?".

Aktivitas 4: Spurious Correlations Website (20 menit)

Kunjungi spuriouscorrelations.com (jika tersedia) atau cari "funny spurious correlations" di Google. Temukan 2 korelasi absurd yang ternyata r-nya di atas 0,9. Tulis: apa yang membuat korelasi ini spurious? Apakah ada confounding variable, atau ini murni kebetulan dari data?

Aktivitas 5: Buat Framework Evaluasi Klaim Kausal (15 menit)

Buat checklist 5 pertanyaan yang harus Abbas tanyakan setiap kali melihat klaim "X menyebabkan Y" dalam berita atau artikel: (1) Apakah ini hanya berdasarkan korelasi? (2) Apakah ada desain eksperimen? (3) Apakah ada confounding variable yang mungkin? (4) Apakah arah kausalitas bisa terbalik? (5) Apakah sample size cukup besar? Framework ini berlaku seumur hidup, jauh melampaui statistik.

Hari 3
Simple Linear Regression: y = mx + b dalam Konteks Data
Mental Model: Regresi sebagai "Garis Terbaik di Antara Titik-titik"

Korelasi menjawab: "seberapa kuat hubungan X dan Y?" Regresi menjawab: "jika X berubah satu unit, berapa Y berubah, dan bisa kita prediksi Y untuk nilai X baru?" Garis regresi y = b0 + b1*x adalah garis yang meminimalkan total kuadrat jarak vertikal dari setiap titik data ke garis (Ordinary Least Squares). b1 adalah kemiringan: "setiap tambahan satu jam belajar, nilai naik b1 poin." b0 adalah intersep: "nilai prediksi jika jam belajar nol."

Aktivitas 1: OLS dan Intuisi Residual (30 menit)

Residual = nilai aktual - nilai prediksi = yi - y-hat. OLS mencari b0 dan b1 yang meminimalkan sum(residual^2). Kenapa kuadrat? Supaya error positif dan negatif tidak saling menghilangkan, dan error besar dihukum lebih berat dari error kecil. Hitung manual b1 = r x (SD_y / SD_x) dan b0 = mean_y - b1 x mean_x untuk data jam belajar vs nilai dari Hari 1.

Aktivitas 2: Implementasi dengan scipy dan numpy (40 menit)
import numpy as np from scipy import stats import matplotlib.pyplot as plt np.random.seed(42) jam = np.random.uniform(1, 10, 60) nilai = 45 + 5.2 * jam + np.random.normal(0, 9, 60) # Method 1: scipy linregress slope, intercept, r_val, p_val, std_err = stats.linregress(jam, nilai) print(f"=== scipy linregress ===") print(f"Slope (b1): {slope:.4f}") print(f"Intercept (b0): {intercept:.4f}") print(f"R-squared: {r_val**2:.4f}") print(f"P-value slope: {p_val:.6f}") print(f"Std Error slope: {std_err:.4f}") # Prediksi: nilai jika belajar 6 jam jam_pred = 6 nilai_pred = intercept + slope * jam_pred print(f"\nPrediksi nilai untuk {jam_pred} jam belajar: {nilai_pred:.1f}") # Plot dengan confidence band x_line = np.linspace(0, 11, 200) y_pred = intercept + slope * x_line fig, ax = plt.subplots(figsize=(8, 5)) ax.scatter(jam, nilai, alpha=0.6, color='steelblue', s=40, label='Data aktual') ax.plot(x_line, y_pred, color='crimson', linewidth=2, label=f'y = {intercept:.1f} + {slope:.2f}x') ax.scatter([jam_pred], [nilai_pred], color='gold', s=150, zorder=5, label=f'Prediksi: {nilai_pred:.1f}') ax.set_xlabel('Jam Belajar') ax.set_ylabel('Nilai Ujian') ax.set_title('Simple Linear Regression') ax.legend() plt.tight_layout() plt.savefig('regresi_linear.png', dpi=150) plt.show()
Aktivitas 3: Regresi dengan statsmodels (30 menit)
import statsmodels.api as sm # statsmodels memberi output lebih detail (mirip output R/SPSS) X = sm.add_constant(jam) # tambah kolom konstanta (intercept) model = sm.OLS(nilai, X).fit() print(model.summary()) # Output mencakup: coefficients, t-stats, p-values, CI, R-squared, F-test # Ini format laporan ilmiah standar untuk regresi # Prediksi dengan interval prediksi X_new = sm.add_constant([4, 6, 8]) pred = model.get_prediction(X_new) pred_summary = pred.summary_frame(alpha=0.05) print("\nPrediksi untuk jam=4, 6, 8:") print(pred_summary[['mean', 'obs_ci_lower', 'obs_ci_upper']].round(2))
Aktivitas 4: Asumsi Regresi Linear (20 menit)

Regresi OLS punya 4 asumsi utama (LINE): (L) Linearity: hubungan X dan Y benar-benar linear. (I) Independence: residual tidak saling berkorelasi. (N) Normality: residual berdistribusi normal. (E) Equal variance (homoscedasticity): varians residual konstan di semua nilai X. Pelanggaran asumsi ini tidak membuat model salah total, tapi membuat inferensi (p-value, CI) tidak dapat dipercaya. Tulis cara cek setiap asumsi ini.

Aktivitas 5: Batasan Ekstrapolasi (15 menit)

Model regresi hanya valid untuk range X yang ada di data training. Jika Abbas membangun model dari data jam belajar 1-10 jam, jangan gunakan model untuk memprediksi nilai siswa yang belajar 20 jam. Ini disebut ekstrapolasi yang berbahaya. Buat contoh: prediksi nilai untuk jam=0, 5, 10, 15, 20. Mana yang masuk akal, mana yang tidak? Bagaimana cara Abbas mengidentifikasi batas aman prediksi?

Hari 4
Evaluasi Model Regresi: Rยฒ, Residual Plot, RMSE
Mental Model: Tiga Dimensi Evaluasi Model

Rยฒ menjawab: "berapa persen variasi Y bisa dijelaskan model?" Residual plot menjawab: "apakah ada pola yang tidak ditangkap model?" (Pola di residual = model masih punya ruang perbaikan.) RMSE menjawab: "rata-rata seberapa jauh prediksi model dari nilai aktual, dalam satuan yang sama dengan Y?" Ketiganya saling melengkapi dan tidak bisa digantikan satu sama lain.

Aktivitas 1: R-Squared dan Adjusted R-Squared (25 menit)

Rยฒ = 1 - (SS_residual / SS_total). Nilai 0 berarti model tidak lebih baik dari prediksi rata-rata. Nilai 1 berarti model sempurna. Rยฒ selalu naik jika kita tambah variabel baru, bahkan jika variabel itu tidak berguna. Adjusted Rยฒ menghukum penambahan variabel tidak berguna: Adj-Rยฒ = 1 - (1-Rยฒ) x (n-1)/(n-k-1), di mana k adalah jumlah prediktor. Untuk simple linear regression, keduanya hampir sama. Adj-Rยฒ penting saat kita mulai membandingkan model dengan jumlah variabel berbeda.

Aktivitas 2: Residual Analysis Lengkap (45 menit)
import numpy as np import matplotlib.pyplot as plt import statsmodels.api as sm from scipy import stats np.random.seed(42) jam = np.random.uniform(1, 10, 60) nilai = 45 + 5.2 * jam + np.random.normal(0, 9, 60) X = sm.add_constant(jam) model = sm.OLS(nilai, X).fit() y_pred = model.fittedvalues residuals = model.resid fig, axes = plt.subplots(2, 2, figsize=(12, 9)) # 1. Residuals vs Fitted axes[0, 0].scatter(y_pred, residuals, alpha=0.6, color='steelblue') axes[0, 0].axhline(0, color='red', linestyle='--') axes[0, 0].set_xlabel('Fitted Values') axes[0, 0].set_ylabel('Residuals') axes[0, 0].set_title('Residuals vs Fitted') # 2. Q-Q Plot residual stats.probplot(residuals, dist='norm', plot=axes[0, 1]) axes[0, 1].set_title('Q-Q Plot Residual') # 3. Histogram residual axes[1, 0].hist(residuals, bins=15, color='steelblue', edgecolor='white') axes[1, 0].set_title('Histogram Residual') # 4. Scale-Location (sqrt abs residual vs fitted) axes[1, 1].scatter(y_pred, np.sqrt(np.abs(residuals)), alpha=0.6, color='coral') axes[1, 1].set_xlabel('Fitted Values') axes[1, 1].set_title('Scale-Location') plt.suptitle('Diagnostik Residual Model Regresi', fontsize=13, fontweight='bold') plt.tight_layout() plt.savefig('residual_diagnostic.png', dpi=150) plt.show()
Aktivitas 3: Hitung RMSE dan MAE (25 menit)
import numpy as np # RMSE: Root Mean Squared Error rmse = np.sqrt(np.mean((nilai - y_pred) ** 2)) # MAE: Mean Absolute Error mae = np.mean(np.abs(nilai - y_pred)) # MAPE: Mean Absolute Percentage Error mape = np.mean(np.abs((nilai - y_pred) / nilai)) * 100 print(f"R-squared: {model.rsquared:.4f}") print(f"Adjusted Rยฒ: {model.rsquared_adj:.4f}") print(f"RMSE: {rmse:.2f} poin nilai") print(f"MAE: {mae:.2f} poin nilai") print(f"MAPE: {mape:.2f}%") print(f"\nInterpretasi RMSE:") print(f" Rata-rata prediksi meleset {rmse:.1f} poin dari nilai aktual") print(f" ({rmse/np.std(nilai)*100:.1f}% dari standar deviasi data)")
Aktivitas 4: Cara Membaca Output statsmodels (20 menit)

Output model.summary() punya tiga bagian. Bagian atas: info umum model (Rยฒ, Adj-Rยฒ, F-statistic, AIC, BIC). Bagian tengah: koefisien (nilai, standard error, t-statistic, p-value, 95% CI). Bagian bawah: diagnostik (Durbin-Watson untuk autokorelasi, Jarque-Bera untuk normalitas residual, Condition Number untuk multikolinearitas). Pelajari setiap baris dan tulis interpretasinya.

Aktivitas 5: Model Buruk vs Model Baik (20 menit)

Buat dua model: (1) Model baik: variabel prediktor yang memang berhubungan. (2) Model buruk: variabel prediktor yang tidak ada hubungannya (random noise). Bandingkan Rยฒ, RMSE, dan residual plot keduanya. Apa yang membedakan diagnostik model baik vs buruk? Ini melatih intuisi untuk mendeteksi model yang overfit atau underfit.

Hari 5
Mini Project: Prediksi Nilai UAS dari Jumlah Jam Belajar
Mini Project Penutup Bulan 7

Abbas membangun model prediksi end-to-end: dari raw data ke laporan prediksi yang siap dipresentasikan. Ini latihan workflow data analyst yang sesungguhnya: collect, explore, model, evaluate, communicate.

Aktivitas 1: Generate Dataset Realistis (20 menit)
import numpy as np import pandas as pd import matplotlib.pyplot as plt import statsmodels.api as sm from scipy import stats import pingouin as pg np.random.seed(2025) n = 80 # Dataset: 80 siswa, beberapa fitur realistis jam_belajar = np.random.uniform(0.5, 12, n).round(1) nilai_mid = 40 + 3 * jam_belajar + np.random.normal(0, 10, n) # UAS dipengaruhi jam belajar + nilai mid + noise nilai_uas = 20 + 4.5 * jam_belajar + 0.3 * nilai_mid + np.random.normal(0, 8, n) nilai_uas = nilai_uas.clip(30, 100).round(1) df = pd.DataFrame({ 'siswa_id': [f'S{i+1:03d}' for i in range(n)], 'jam_belajar': jam_belajar, 'nilai_mid': nilai_mid.round(1), 'nilai_uas': nilai_uas }) print(df.describe().round(2)) df.to_csv('data_siswa_uas.csv', index=False) print("\nData disimpan ke data_siswa_uas.csv")
Aktivitas 2: EDA dan Korelasi (25 menit)
# Eksplorasi visual fig, axes = plt.subplots(1, 2, figsize=(12, 5)) axes[0].scatter(df['jam_belajar'], df['nilai_uas'], alpha=0.6, color='steelblue') axes[0].set_xlabel('Jam Belajar') axes[0].set_ylabel('Nilai UAS') axes[0].set_title('Jam Belajar vs Nilai UAS') axes[1].scatter(df['nilai_mid'], df['nilai_uas'], alpha=0.6, color='coral') axes[1].set_xlabel('Nilai Mid') axes[1].set_ylabel('Nilai UAS') axes[1].set_title('Nilai Mid vs Nilai UAS') plt.tight_layout() plt.savefig('eda_scatter.png', dpi=150) plt.show() # Korelasi Pearson kedua prediktor r_jam, p_jam = stats.pearsonr(df['jam_belajar'], df['nilai_uas']) r_mid, p_mid = stats.pearsonr(df['nilai_mid'], df['nilai_uas']) print(f"r(jam_belajar, nilai_uas) = {r_jam:.3f} (p={p_jam:.4f})") print(f"r(nilai_mid, nilai_uas) = {r_mid:.3f} (p={p_mid:.4f})")
Aktivitas 3: Bangun dan Evaluasi Model (30 menit)
# Model 1: hanya jam_belajar X1 = sm.add_constant(df['jam_belajar']) model1 = sm.OLS(df['nilai_uas'], X1).fit() rmse1 = np.sqrt(np.mean(model1.resid ** 2)) print("=== Model 1: y ~ jam_belajar ===") print(f"Rยฒ: {model1.rsquared:.4f}") print(f"RMSE: {rmse1:.2f}") print(f"Koefisien: intercept={model1.params[0]:.2f}, slope={model1.params[1]:.2f}") print(f"Interpretasi: setiap tambah 1 jam belajar, nilai UAS naik {model1.params[1]:.2f} poin") # Prediksi untuk siswa baru contoh_siswa = pd.DataFrame({'jam_belajar': [3, 6, 9]}) X_new = sm.add_constant(contoh_siswa['jam_belajar']) pred1 = model1.get_prediction(X_new).summary_frame(alpha=0.05) print("\nPrediksi nilai UAS:") print(pred1[['mean', 'obs_ci_lower', 'obs_ci_upper']].round(1))
Aktivitas 4: Visualisasi Final Model (20 menit)
fig, ax = plt.subplots(figsize=(9, 6)) x_line = np.linspace(df['jam_belajar'].min(), df['jam_belajar'].max(), 200) X_line = sm.add_constant(x_line) pred_line = model1.get_prediction(X_line).summary_frame(alpha=0.05) ax.scatter(df['jam_belajar'], df['nilai_uas'], alpha=0.6, color='steelblue', s=45, label='Data aktual') ax.plot(x_line, pred_line['mean'], color='crimson', linewidth=2, label=f'Regresi: y = {model1.params[0]:.1f} + {model1.params[1]:.2f}x') ax.fill_between(x_line, pred_line['obs_ci_lower'], pred_line['obs_ci_upper'], alpha=0.15, color='crimson', label='95% Prediction Interval') ax.set_xlabel('Jam Belajar per Hari', fontsize=12) ax.set_ylabel('Nilai UAS', fontsize=12) ax.set_title(f'Model Prediksi Nilai UAS\nRยฒ = {model1.rsquared:.3f}, RMSE = {rmse1:.2f}', fontsize=13) ax.legend(fontsize=10) plt.tight_layout() plt.savefig('model_final.png', dpi=150) plt.show()
Aktivitas 5: Laporan Mini Project (25 menit)

Tulis laporan mini project satu halaman penuh dengan struktur: (1) Judul dan latar belakang. (2) Data: n siswa, variabel yang diukur, statistik deskriptif. (3) Analisis korelasi: r antara jam belajar dan nilai UAS, interpretasi. (4) Model regresi: persamaan, Rยฒ, RMSE, interpretasi koefisien. (5) Contoh prediksi: "Siswa yang belajar 5 jam per hari diprediksi mendapat nilai UAS X, dengan interval prediksi 95% dari Y sampai Z." (6) Keterbatasan model: apa yang tidak diukur, bahaya ekstrapolasi, korelasi bukan kausalitas. Ini template yang bisa Abbas pakai untuk setiap proyek analisis ke depannya.

Selamat: Bulan 7 Selesai

Abbas telah menguasai: probabilitas dan distribusi normal, Central Limit Theorem, confidence interval, t-test (one-sample, two-sample, paired), chi-square (independence dan goodness of fit), one-way ANOVA dengan post-hoc Tukey, korelasi Pearson, dan regresi linear sederhana. Ini adalah fondasi statistik inferensial yang dipakai di hampir semua penelitian kuantitatif. Bulan 8 akan membangun di atas fondasi ini untuk masuk ke machine learning.

Buku Referensi Bulan 7

Empat buku ini dipilih karena saling melengkapi: dari intuisi visual, ke rigur matematis, ke aplikasi Python, hingga ke pemikiran kritis tentang kausalitas.

Statistics

Robert S. Freedman, Pisani, Purves

Freeman, edisi ke-4

Statistik Dasar Tanpa Formula Berat Intuisi Dulu

Buku terbaik untuk membangun intuisi statistik tanpa tenggelam dalam matematika. Pendekatan Freedman sangat naratif: setiap konsep diceritakan dari konteks dunia nyata sebelum formula ditampilkan. Khususnya berguna untuk Bab probabilitas, distribusi, dan hypothesis testing di Minggu 1 dan 2. Abbas akan sering kembali ke buku ini untuk "rereset" pemahaman ketika merasa bingung dengan derivasi matematis.

Bab yang Paling Relevan untuk Bulan 7

Bab 13-19 (sampling, chance error, confidence intervals), Bab 26-29 (tests of significance, chi-square). Baca naratifnya dulu, abaikan latihan soal yang terlalu teoritis, kerjakan yang punya konteks nyata.

Naked Statistics: Stripping the Dread from the Data

Charles Wheelan

W. W. Norton, 2013

Populer Non-teknis Sangat Menghibur

Wheelan menulis statistik seperti seorang jurnalis bercerita: penuh anekdot, humor, dan contoh dari kehidupan nyata mulai dari Liga Baseball hingga uji klinis vaksin. Tidak ada satu formula pun yang ditampilkan tanpa konteks yang membuat pembaca peduli. Buku ini adalah antidote terbaik jika Abbas mulai merasa statistik kering dan abstrak. Baca satu bab per malam sebagai bacaan ringan sebelum tidur, bukan sebagai buku teks.

Fokus untuk Bulan 7

Bab 7 (Central Limit Theorem), Bab 8 (inference), Bab 9 (hypothesis testing), Bab 11 (regression). Buku ini tidak akan mengajarkan cara coding, tapi akan membuat Abbas paham KENAPA kita melakukan semua ini.

Think Stats: Exploratory Data Analysis in Python

Allen B. Downey

O'Reilly, edisi ke-2 (tersedia gratis online)

Python Simulasi Gratis Online

Downey mengajarkan statistik melalui simulasi komputer, bukan derivasi matematika. Ketika konsep distribusi sampling muncul, Abbas tidak menghafal rumus, melainkan mensimulasikannya sendiri dan mengamati hasilnya. Pendekatan ini sangat cocok dengan cara Abbas sudah belajar di bulan-bulan sebelumnya. Buku ini bisa didownload gratis dari greenteapress.com dan semua kode tersedia di GitHub.

Cara Terbaik Pakai Buku Ini

Buka Jupyter Notebook, baca satu seksi, lalu langsung run kodenya, modifikasi parameter, dan amati apa yang berubah. Jangan sekadar membaca. Bab 6 (probability), Bab 7 (estimation), Bab 9 (hypothesis testing) adalah yang paling relevan untuk Bulan 7.

The Book of Why: The New Science of Cause and Effect

Judea Pearl dan Dana Mackenzie

Basic Books, 2018

Kausalitas Filosofi Data Menantang Paradigma

Pearl adalah pemenang Turing Award yang revolusioner. Buku ini mempertanyakan fondasi statistik klasik: bahwa korelasi tidak pernah bisa berbicara tentang kausalitas tanpa intervensi. Ia memperkenalkan "causal ladder": association (korelasi), intervention (do-calculus), dan counterfactual. Buku ini bukan untuk dipahami semuanya di Bulan 7, tapi untuk mulai Abbas sadari: statistik yang sudah dipelajari baru berada di anak tangga pertama. Ini bacaan untuk pembentukan mindset, bukan untuk hafalan teknis.

Kapan Membaca Ini

Baca Bab 1 dan 2 setelah selesai Hari 2 Minggu 4 (correlation is not causation). Pearl akan memperdalam intuisi Abbas tentang mengapa "correlation is not causation" bukan sekadar peringatan, melainkan perbedaan fundamental tentang cara kerja dunia.

Tools dan Library Bulan 7

Enam library ini membentuk toolkit statistik inferensial Python yang lengkap. Masing-masing punya kekuatan berbeda dan saling melengkapi, bukan saling menggantikan.

scipy Wajib

SciPy (scipy.stats)

Library statistik inferensial utama Python. Mencakup semua distribusi probabilitas, uji hipotesis, goodness of fit, korelasi, dan banyak lagi. Ini adalah pilihan default pertama Abbas untuk hampir semua uji statistik di Bulan 7.

stats.ttest_1samp() - one-sample t-test
stats.ttest_ind() - two-sample t-test independen
stats.ttest_rel() - paired t-test
stats.f_oneway() - one-way ANOVA
stats.chi2_contingency() - chi-square independence
stats.chisquare() - chi-square goodness of fit
stats.pearsonr() - korelasi Pearson + p-value
stats.spearmanr() - korelasi Spearman (non-parametrik)
stats.linregress() - regresi linear sederhana
stats.norm.cdf() / .pdf() - distribusi normal
stats.shapiro() - uji normalitas
stats.levene() - uji homogenitas varians
Install
# Sudah termasuk dalam paket Anaconda/conda # Jika belum: pip install scipy
statsmodels Wajib

Statsmodels

Library untuk model statistik yang lebih lengkap, dengan output yang mendekati format R dan SPSS. Khususnya kuat untuk regresi: output-nya mencakup koefisien, standard error, t-stat, p-value, CI, Rยฒ, F-test, dan diagnostik dalam satu blok. Ini yang dipakai di Minggu 4 untuk regresi linear.

sm.OLS(y, X).fit() - Ordinary Least Squares regression
model.summary() - output lengkap mirip format jurnal
model.get_prediction() - prediksi dengan confidence/prediction interval
sm.add_constant(X) - tambah intercept ke matrix prediktor
model.resid - residual untuk diagnostik
model.rsquared, .rsquared_adj - Rยฒ dan Adjusted Rยฒ
model.fittedvalues - nilai prediksi (y-hat)
Kenapa Bukan Scikit-learn untuk Regresi?

sklearn cocok untuk prediksi (machine learning). statsmodels cocok untuk inferensi (p-value, CI, hipotesis). Di Bulan 7 Abbas butuh inferensi, bukan hanya prediksi. Bulan 9 (ML) akan banyak memakai sklearn.

pg Sangat Direkomendasikan

Pingouin

Library statistik yang dirancang khusus untuk psikologi dan ilmu sosial, tapi sangat berguna untuk semua domain. Kekuatannya: output sangat informatif (selalu menyertakan effect size dan power), sintaks bersih, dan mendukung banyak uji yang scipy tidak cover langsung (Tukey HSD, partial correlation, power analysis).

pg.ttest(x, y) - t-test dengan output lengkap + cohen-d + power
pg.anova(data, dv, between) - ANOVA dengan eta-squared
pg.pairwise_tukey(data, dv, between) - Tukey HSD post-hoc
pg.corr(x, y) - korelasi + CI + power
pg.partial_corr(data, x, y, covar) - partial correlation
pg.power_ttest(d, n, alpha) - power analysis untuk t-test
pg.chi2_independence(data, x, y) - chi-square dengan Cramer V
Install
pip install pingouin
np Wajib

NumPy

Fondasi dari semua komputasi numerik Python. Sudah dipakai sejak Bulan 3, tapi di Bulan 7 Abbas menggunakannya untuk hal yang lebih spesifik: simulasi distribusi, hitung statistik deskriptif yang dibutuhkan sebelum uji inferensial, dan manipulasi array data untuk dimasukkan ke scipy atau statsmodels.

np.random.normal(mu, sigma, n) - generate data normal
np.random.seed(n) - reproducibility
np.mean(), np.std(ddof=1) - mean dan sample SD
np.sqrt(), np.abs() - operasi matematika dasar
np.concatenate(), np.arange() - manipulasi array
np.polyfit(x, y, 1) - quick linear fit untuk visualisasi
plt Wajib

Matplotlib

Library visualisasi utama yang sudah dikenal sejak Bulan 4. Di Bulan 7, Abbas memakai matplotlib untuk jenis plot baru yang relevan untuk statistik inferensial: residual plots, Q-Q plots, histogram distribusi, visualisasi CI, dan boxplot multi-grup untuk ANOVA. Setiap analisis statistik harus selalu disertai visualisasi.

plt.subplots(rows, cols) - multi-panel figure untuk diagnostik
ax.boxplot(data, labels, patch_artist) - boxplot untuk ANOVA
ax.scatter(x, y, alpha) - scatter plot korelasi dan regresi
ax.fill_between(x, lower, upper) - prediction interval band
ax.axhline(0), ax.axvline(mu) - garis referensi
stats.probplot(residuals, plot=ax) - Q-Q plot (via scipy)
Tambahan: Seaborn untuk Heatmap
import seaborn as sns # sns.heatmap() untuk correlation matrix # sns.regplot() untuk scatter + regression line sekaligus # sns.boxplot() untuk ANOVA (lebih cantik dari matplotlib)
GUI Bonus: Tanpa Kode

Jamovi

Software statistik GUI gratis yang tampilannya mirip SPSS, tapi lebih modern dan lebih ringan. Sangat berguna ketika Abbas ingin cepat verifikasi hasil analisis Python tanpa menulis kode, atau saat perlu menjelaskan analisis ke orang lain yang tidak bisa Python. Jamovi menjalankan semua uji yang ada di Bulan 7 dengan beberapa klik. Tersedia untuk macOS (termasuk Apple Silicon M5 milik Abbas).

T-Tests (one-sample, independent, paired) dengan output visual
ANOVA + Tukey post-hoc dengan tabel otomatis
Chi-Square: independence dan goodness of fit
Correlation matrix visual, dengan p-value dan CI
Linear regression dengan diagnostik lengkap
Descriptives dengan histogram, boxplot, Q-Q plot
Cara Pakai Jamovi di Bulan 7

Setelah Abbas menyelesaikan analisis di Python, impor dataset yang sama ke Jamovi dan replikasi hasil. Jika hasil Jamovi dan Python berbeda, cari tahu kenapa: apakah ada perbedaan setting (equal variance, alternative hypothesis)? Proses debugging ini sangat memperdalam pemahaman Abbas tentang pilihan-pilihan di balik setiap fungsi Python.

Install

Download di jamovi.org, gratis, tidak perlu registrasi. File .csv dari pandas bisa langsung dibuka di Jamovi.

Urutan Belajar Library yang Disarankan

Minggu 1 dan 2: fokus di scipy.stats dan numpy untuk membangun intuisi dari bawah. Minggu 2 dan 3: tambahkan pingouin untuk output yang lebih kaya (effect size, power). Minggu 3: mulai eksplorasi Jamovi untuk verifikasi silang. Minggu 4: perkenalkan statsmodels untuk regresi dengan inferensi lengkap. Jangan coba kuasai semuanya sekaligus: kuasai scipy dulu, yang lain menyusul.

Tips Praktis dan Jebakan Pemula

Statistik inferensial punya banyak jebakan yang bahkan peneliti senior pun kadang jatuh ke sana. Bagian ini mengumpulkan kesalahan paling umum yang akan Abbas temui, lengkap dengan cara menghindarinya.

Jebakan #1: Salah Memahami p-value

Ini jebakan terbesar dan paling sering terjadi. p-value bukan probabilitas bahwa H0 benar. p-value bukan probabilitas bahwa Abbas salah. p-value bukan ukuran seberapa besar efek yang Abbas temukan.

Definisi yang benar: p-value adalah probabilitas mendapatkan hasil setidaknya sepola ini (atau lebih ekstrem), dengan asumsi H0 benar.

Analogi: Bayangkan Abbas curiga sebuah koin curang. Abbas lempar 10 kali, keluar kepala 9 kali. p-value menjawab: "Jika koin ini jujur, seberapa sering Abbas bisa dapat 9 atau 10 kepala hanya karena kebetulan?" Jawabannya kira-kira 1%. Itu bukan berarti koin 99% curang. Itu berarti hasil seperti ini sangat langka jika koin jujur.

Yang benar untuk dikatakan: "Hasil ini tidak konsisten dengan H0 (p = 0.01)." Bukan: "H0 terbukti salah dengan probabilitas 99%."

Jebakan #2: Significant secara Statistik, Tapi Tidak Bermakna di Dunia Nyata

Dengan sampel yang sangat besar, perbedaan yang sangat kecil pun bisa menghasilkan p < 0.05. Contoh: platform e-commerce menguji dua warna tombol beli. Dengan 1 juta pengguna, mereka menemukan warna biru menghasilkan konversi 2.01% dan warna hijau 2.00%. p-value: 0.001. Sangat signifikan!

Tapi apakah perbedaan 0.01% itu worth biaya redesign seluruh platform? Tentu tidak.

Solusi: Selalu hitung effect size bersamaan dengan p-value. Untuk t-test pakai Cohen's d. Untuk korelasi, nilai r-nya sendiri sudah jadi effect size. Untuk ANOVA pakai eta-squared.

from scipy import stats import numpy as np # Cohen's d: effect size untuk t-test def cohens_d(group1, group2): n1, n2 = len(group1), len(group2) pooled_sd = np.sqrt( ((n1 - 1) * np.std(group1, ddof=1)**2 + (n2 - 1) * np.std(group2, ddof=1)**2) / (n1 + n2 - 2) ) return (np.mean(group1) - np.mean(group2)) / pooled_sd # Interpretasi Cohen's d: # d ~ 0.2 = efek kecil (bisa diabaikan untuk keputusan bisnis) # d ~ 0.5 = efek sedang # d >= 0.8 = efek besar (layak dipertimbangkan) group_biru = np.random.normal(0.0201, 0.001, 1000000) group_hijau = np.random.normal(0.0200, 0.001, 1000000) d = cohens_d(group_biru, group_hijau) print(f"Cohen's d: {d:.4f}") # sangat kecil meski p signifikan
Jebakan #3: Melupakan Asumsi Sebelum Uji

Setiap uji statistik punya asumsi. Melanggar asumsi bisa membuat p-value Abbas tidak valid sama sekali.

T-test mengasumsikan: data mendekati normal (atau n besar), dan varians kedua grup hampir sama (untuk independent t-test). Chi-square mengasumsikan: frekuensi ekspektasi tiap sel minimal 5. ANOVA mengasumsikan: normalitas residual dan homogenitas varians.

Kebiasaan yang harus dibangun: sebelum menjalankan uji apa pun, selalu cek asumsi terlebih dahulu.

from scipy import stats # Cek normalitas sebelum t-test data = [23, 25, 28, 22, 30, 27, 24, 26, 29, 25] stat, p_shapiro = stats.shapiro(data) print(f"Shapiro-Wilk: stat={stat:.4f}, p={p_shapiro:.4f}") # Jika p_shapiro > 0.05: data tidak signifikan berbeda dari normal # Jika p_shapiro < 0.05: data mungkin tidak normal, pertimbangkan Mann-Whitney # Cek equal variance sebelum independent t-test group_a = [23, 25, 28, 22, 30] group_b = [31, 35, 29, 33, 28] stat_lev, p_lev = stats.levene(group_a, group_b) print(f"Levene's test: p={p_lev:.4f}") # Jika p_lev < 0.05: gunakan Welch's t-test (equal_var=False) t_stat, p_val = stats.ttest_ind(group_a, group_b, equal_var=(p_lev > 0.05)) print(f"t={t_stat:.3f}, p={p_val:.4f}")
Jebakan #4: Multiple Testing Problem

Jika Abbas menguji 20 hipotesis sekaligus dengan alpha 0.05, secara matematika Abbas hampir pasti akan mendapat minimal satu hasil yang "signifikan" hanya karena kebetulan, bahkan jika semua H0 benar. Ini disebut inflasi Type I error.

Analogi: Jika Abbas melempar koin jujur 20 kali berturut-turut, probabilitas mendapat setidaknya sekali "6 kepala berturut-turut" (kebetulan langka) jauh lebih besar dari yang Abbas kira. Semakin banyak percobaan, semakin tinggi peluang kebetulan.

Solusi: Koreksi Bonferroni: bagi alpha dengan jumlah uji. Untuk 20 uji dengan alpha 0.05, gunakan threshold p < 0.0025 per uji.

from statsmodels.stats.multitest import multipletests # Contoh: 10 uji sekaligus p_values = [0.001, 0.04, 0.03, 0.6, 0.002, 0.09, 0.04, 0.5, 0.03, 0.08] reject, p_corrected, _, _ = multipletests(p_values, method='bonferroni') for i, (raw, corrected, rej) in enumerate(zip(p_values, p_corrected, reject)): status = "SIGNIFIKAN" if rej else "tidak" print(f"Uji {i+1}: p_raw={raw:.3f} | p_corrected={corrected:.4f} | {status}")
Tips #5: Visualisasi Sebelum Menguji

Jangan pernah langsung lari ke uji statistik tanpa melihat datanya terlebih dahulu. Histogram, boxplot, dan scatter plot sering mengungkap sesuatu yang angka p-value sembunyikan: outlier ekstrem, distribusi bimodal, hubungan non-linear, atau subgrup tersembunyi di dalam data.

Urutan yang benar: Plot dulu, cek distribusi, baru uji. Jika plot terlihat aneh, selidiki sebelum melanjutkan.

import matplotlib.pyplot as plt import numpy as np # Sebelum t-test: bandingkan distribusi kedua grup secara visual group_a = np.random.normal(70, 10, 100) group_b = np.random.normal(75, 15, 100) fig, axes = plt.subplots(1, 2, figsize=(10, 4)) axes[0].hist(group_a, alpha=0.6, label='Grup A', bins=15) axes[0].hist(group_b, alpha=0.6, label='Grup B', bins=15) axes[0].legend() axes[0].set_title('Distribusi Kedua Grup') axes[1].boxplot([group_a, group_b], labels=['A', 'B']) axes[1].set_title('Boxplot Perbandingan') plt.tight_layout() plt.show()
Jebakan #6: p-value = 0.051 Bukan Berarti "Tidak Ada Efek"

Batas 0.05 adalah konvensi, bukan hukum alam. p = 0.051 dan p = 0.049 secara praktis hampir identik, tapi sering diperlakukan sangat berbeda. Peneliti kadang mengatakan p = 0.051 "tidak ada temuan" padahal efeknya sama besarnya.

Yang lebih baik: Laporkan nilai p tepatnya (bukan hanya "p < 0.05"), sertakan confidence interval, dan bahas effect size. Pembaca bisa menilai sendiri apakah efek itu bermakna.

Contoh pelaporan yang baik: "Grup perlakuan mendapat skor rata-rata 2.3 poin lebih tinggi dari kontrol (95% CI: 0.8 hingga 3.8, p = 0.003, Cohen's d = 0.41)." Jauh lebih informatif dari sekadar "hasilnya signifikan."

Tips #7: Pakai Alternatif Non-Parametrik Saat Asumsi Dilanggar

Jika data Abbas tidak memenuhi asumsi normalitas dan sampel terlalu kecil untuk mengandalkan CLT, jangan dipaksakan menggunakan t-test atau ANOVA. Scipy menyediakan alternatif non-parametrik yang tidak mengasumsikan distribusi tertentu.

from scipy import stats # Alternatif untuk setiap uji parametrik: # One-sample t-test --> Wilcoxon signed-rank test stat, p = stats.wilcoxon(data, alternative='two-sided') # Independent t-test --> Mann-Whitney U test stat, p = stats.mannwhitneyu(group_a, group_b, alternative='two-sided') # Paired t-test --> Wilcoxon signed-rank (dengan perbedaan) differences = [a - b for a, b in zip(before, after)] stat, p = stats.wilcoxon(differences) # One-way ANOVA --> Kruskal-Wallis test stat, p = stats.kruskal(group1, group2, group3) print(f"p = {p:.4f}")

Kelemahan non-parametrik: sedikit lebih lemah (butuh efek lebih besar untuk terdeteksi) dan tidak memberikan confidence interval semudah parametrik. Tapi lebih valid jika asumsi dilanggar.

Tips #8: Intuisi p-value Lewat Simulasi

Cara terbaik memahami p-value secara intuitif adalah dengan mensimulasikannya sendiri. Kode di bawah mendemonstrasikan apa yang p-value benar-benar hitung: berapa kali data bisa "seekstrem ini" jika H0 benar.

import numpy as np np.random.seed(42) # Skenario: klaim rata-rata nilai = 70, Abbas punya sampel 30 siswa nilai_klaim = 70 sampel = np.random.normal(74, 10, 30) # rata-rata asli 74 t_obs = (np.mean(sampel) - nilai_klaim) / (np.std(sampel, ddof=1) / np.sqrt(30)) # Simulasi: berapa kali t-stat bisa sekuat ini jika H0 benar? simulasi_t = [] for _ in range(10000): sampel_h0 = np.random.normal(nilai_klaim, np.std(sampel, ddof=1), 30) t_sim = (np.mean(sampel_h0) - nilai_klaim) / (np.std(sampel_h0, ddof=1) / np.sqrt(30)) simulasi_t.append(t_sim) # p-value = proporsi simulasi yang menghasilkan t >= t_obs p_simulasi = np.mean(np.abs(simulasi_t) >= np.abs(t_obs)) print(f"t observasi: {t_obs:.3f}") print(f"p-value dari simulasi: {p_simulasi:.4f}") # Bandingkan dengan scipy: from scipy import stats _, p_scipy = stats.ttest_1samp(sampel, nilai_klaim) print(f"p-value dari scipy: {p_scipy:.4f}") # Keduanya harusnya sangat dekat!

Latihan Tambahan

Latihan di bawah dirancang lebih menantang dari latihan di minggu belajar. Abbas perlu menggabungkan beberapa konsep sekaligus dan membuat keputusan analitis sendiri, persis seperti skenario dunia nyata.

Latihan A: Simulasi A/B Testing Lengkap

Konteks: Abbas adalah analis di sebuah startup edukasi. Tim produk ingin tahu apakah notifikasi belajar malam hari meningkatkan skor latihan soal. Mereka mengacak 200 pengguna: 100 dapat notifikasi (Grup B), 100 tidak (Grup A). Tugasmu: lakukan analisis lengkap dari nol.

Yang harus dilakukan: (1) Generate data simulasi, (2) visualisasi distribusi kedua grup, (3) cek asumsi, (4) pilih uji yang tepat, (5) hitung effect size, (6) buat kesimpulan dalam bahasa bisnis.

import numpy as np from scipy import stats import matplotlib.pyplot as plt np.random.seed(7) # Grup A: tanpa notifikasi, rata-rata skor 68, SD 12 grup_a = np.random.normal(68, 12, 100).clip(0, 100) # Grup B: dengan notifikasi, rata-rata skor 73, SD 13 grup_b = np.random.normal(73, 13, 100).clip(0, 100) # --- LANGKAH 1: Visualisasi --- fig, axes = plt.subplots(1, 2, figsize=(12, 4)) axes[0].hist(grup_a, alpha=0.6, bins=15, label='Tanpa notif', color='steelblue') axes[0].hist(grup_b, alpha=0.6, bins=15, label='Dengan notif', color='coral') axes[0].legend(); axes[0].set_title('Distribusi Skor') axes[1].boxplot([grup_a, grup_b], labels=['Tanpa Notif', 'Dengan Notif'], patch_artist=True, boxprops=dict(facecolor='lightyellow')) axes[1].set_title('Boxplot Perbandingan') plt.tight_layout(); plt.show() # --- LANGKAH 2: Cek Asumsi --- _, p_norm_a = stats.shapiro(grup_a) _, p_norm_b = stats.shapiro(grup_b) _, p_levene = stats.levene(grup_a, grup_b) print(f"Normalitas A: p={p_norm_a:.4f}, B: p={p_norm_b:.4f}") print(f"Homogenitas varians: p={p_levene:.4f}") # --- LANGKAH 3: Uji (Welch jika varians tidak equal) --- equal_var = p_levene > 0.05 t_stat, p_val = stats.ttest_ind(grup_b, grup_a, equal_var=equal_var) print(f"t = {t_stat:.3f}, p = {p_val:.4f}") # --- LANGKAH 4: Effect Size (Cohen's d) --- n_a, n_b = len(grup_a), len(grup_b) pooled_sd = np.sqrt(((n_a-1)*np.std(grup_a,ddof=1)**2 + (n_b-1)*np.std(grup_b,ddof=1)**2) / (n_a+n_b-2)) d = (np.mean(grup_b) - np.mean(grup_a)) / pooled_sd print(f"Cohen's d = {d:.3f}") # --- LANGKAH 5: Kesimpulan Bisnis --- # Tulis interpretasi Abbas di sini: # "Notifikasi malam meningkatkan skor rata-rata sebesar X poin # (dari 68 ke 73), efek ini signifikan (p=...) dengan ukuran # efek sedang (d=...). Rekomendasi: ..."
Latihan B: Bootstrap Confidence Interval dari Nol

Konteks: Abbas ingin memperkirakan rata-rata waktu belajar harian siswa SMA di Indonesia. Abbas punya sampel 50 siswa. Tapi distribusinya miring (skewed) karena beberapa siswa belajar sangat lama. Uji parametrik biasa kurang tepat. Gunakan bootstrap untuk membangun CI tanpa asumsi distribusi.

Konsep kunci: Bootstrap mengambil resample dengan penggantian dari data yang ada ribuan kali, menghitung statistik di setiap resample, lalu distribusi statistik itu dipakai untuk memperkirakan ketidakpastian.

import numpy as np import matplotlib.pyplot as plt np.random.seed(42) # Data miring: sebagian besar belajar 1-3 jam, beberapa belajar 8+ jam waktu_belajar = np.random.exponential(scale=2.5, size=50) # dalam jam waktu_belajar = np.clip(waktu_belajar, 0.5, 10) print(f"Rata-rata sampel: {np.mean(waktu_belajar):.2f} jam") print(f"Median sampel: {np.median(waktu_belajar):.2f} jam") # Bootstrap: 10.000 resample n_bootstrap = 10000 bootstrap_means = np.zeros(n_bootstrap) for i in range(n_bootstrap): resample = np.random.choice(waktu_belajar, size=len(waktu_belajar), replace=True) bootstrap_means[i] = np.mean(resample) # 95% CI dari percentile distribusi bootstrap ci_lower = np.percentile(bootstrap_means, 2.5) ci_upper = np.percentile(bootstrap_means, 97.5) print(f"95% Bootstrap CI: [{ci_lower:.2f}, {ci_upper:.2f}] jam") # Visualisasi distribusi bootstrap plt.figure(figsize=(8, 4)) plt.hist(bootstrap_means, bins=50, color='steelblue', alpha=0.7, edgecolor='white') plt.axvline(ci_lower, color='red', linestyle='--', label=f'CI Lower: {ci_lower:.2f}') plt.axvline(ci_upper, color='red', linestyle='--', label=f'CI Upper: {ci_upper:.2f}') plt.axvline(np.mean(waktu_belajar), color='green', label='Mean sampel') plt.legend(); plt.title('Distribusi Bootstrap Mean'); plt.show()

Pertanyaan refleksi: Bandingkan hasil bootstrap CI dengan CI parametrik dari stats.t.interval(). Seberapa berbeda hasilnya? Mengapa bisa berbeda pada data yang miring?

Latihan C: ANOVA + Post-Hoc Tukey Lengkap

Konteks: Sekolah menguji tiga metode belajar: buku teks tradisional, video YouTube, dan aplikasi interaktif. 30 siswa dibagi merata ke tiga kelompok. Setelah 2 minggu, mereka diuji. Apakah ada perbedaan nyata antar metode, dan metode mana yang terbaik?

import numpy as np from scipy import stats import matplotlib.pyplot as plt np.random.seed(99) buku = np.random.normal(68, 10, 10) video = np.random.normal(75, 9, 10) app = np.random.normal(80, 8, 10) # LANGKAH 1: Visualisasi awal plt.figure(figsize=(7, 4)) plt.boxplot([buku, video, app], labels=['Buku', 'Video', 'App'], patch_artist=True) plt.title('Skor per Metode Belajar'); plt.ylabel('Skor'); plt.show() # LANGKAH 2: One-Way ANOVA f_stat, p_anova = stats.f_oneway(buku, video, app) print(f"ANOVA: F={f_stat:.3f}, p={p_anova:.4f}") # LANGKAH 3: Post-hoc Tukey jika ANOVA signifikan if p_anova < 0.05: from statsmodels.stats.multicomp import pairwise_tukeyhsd import pandas as pd data_all = np.concatenate([buku, video, app]) labels_all = ['Buku']*10 + ['Video']*10 + ['App']*10 tukey = pairwise_tukeyhsd(data_all, labels_all, alpha=0.05) print(tukey) # Output: tabel perbandingan tiap pasang, dengan reject=True jika signifikan else: print("ANOVA tidak signifikan: tidak perlu post-hoc.") # LANGKAH 4: Eta-squared (effect size untuk ANOVA) # Eta^2 = SS_between / SS_total grand_mean = np.mean(np.concatenate([buku, video, app])) ss_between = sum(len(g) * (np.mean(g) - grand_mean)**2 for g in [buku, video, app]) ss_total = sum((x - grand_mean)**2 for g in [buku, video, app] for x in g) eta_sq = ss_between / ss_total print(f"Eta-squared: {eta_sq:.3f}") # 0.01 = kecil, 0.06 = sedang, 0.14 = besar
Latihan D: Diagnostik Regresi Linear

Konteks: Banyak orang menggunakan regresi linear tanpa mengecek apakah asumsinya terpenuhi. Latihan ini mengajarkan Abbas cara membaca dan menginterpretasikan 4 plot diagnostik regresi yang krusial: residual vs fitted, Q-Q plot, scale-location, dan leverage.

import numpy as np import matplotlib.pyplot as plt from scipy import stats import statsmodels.api as sm np.random.seed(21) jam_belajar = np.random.uniform(1, 8, 50) skor_ujian = 50 + 4.5 * jam_belajar + np.random.normal(0, 5, 50) # Regresi dengan statsmodels (lebih kaya diagnostik dari scipy) X = sm.add_constant(jam_belajar) model = sm.OLS(skor_ujian, X).fit() print(model.summary()) residuals = model.resid fitted = model.fittedvalues # 4 Plot Diagnostik fig, axes = plt.subplots(2, 2, figsize=(12, 10)) # Plot 1: Residual vs Fitted (cek linearitas dan homoskedastisitas) axes[0,0].scatter(fitted, residuals, alpha=0.6) axes[0,0].axhline(0, color='red', linestyle='--') axes[0,0].set_xlabel('Fitted values'); axes[0,0].set_ylabel('Residuals') axes[0,0].set_title('Residuals vs Fitted') # Plot 2: Q-Q Plot (cek normalitas residual) stats.probplot(residuals, dist='norm', plot=axes[0,1]) axes[0,1].set_title('Normal Q-Q') # Plot 3: Scale-Location (cek homoskedastisitas lebih jelas) axes[1,0].scatter(fitted, np.sqrt(np.abs(residuals)), alpha=0.6) axes[1,0].set_xlabel('Fitted values'); axes[1,0].set_ylabel('sqrt(|Residuals|)') axes[1,0].set_title('Scale-Location') # Plot 4: Leverage / Cook's Distance (cek outlier berpengaruh) influence = model.get_influence() (c, p) = influence.cooks_distance axes[1,1].stem(np.arange(len(c)), c, markerfmt=',') axes[1,1].axhline(4/len(skor_ujian), color='red', linestyle='--', label='Threshold') axes[1,1].set_title("Cook's Distance"); axes[1,1].legend() plt.tight_layout(); plt.show() # Pertanyaan: di plot mana Abbas harus melihat "pola" sebagai tanda bahaya? # Residual vs Fitted: pola melengkung = asumsi linearitas dilanggar # Q-Q: titik jauh dari garis diagonal = residual tidak normal # Scale-Location: pola cone/kipas = heteroskedastisitas # Cook's Distance: titik di atas threshold merah = outlier berpengaruh, selidiki!