Machine learning bekerja di dunia yang tidak pasti: model tidak pernah seratus persen yakin, melainkan mengeluarkan angka peluang — 0,73 peluang transaksi itu mencurigakan, 0,05 pelengkap email itu adalah spam. Probabilitas adalah bahasa formal untuk angka-angka semacam itu, dan sejumlah model membawanya di nama mereka sendiri: naive Bayes menghitung peluang bersyarat, logistic regression menghasilkan peluang kelas. Chapter ini membangun kosakata dasarnya — kejadian, kejadian bersyarat, kebebasan, nilai harapan — lalu menutup dengan tiga distribusi peluang yang paling sering muncul di machine learning.

Kejadian dan Ruang Sampel #

Eksperimen acak apa pun punya ruang sampel, yaitu daftar semua hasil yang mungkin. Satu lemparan dadu punya ruang sampel {1, 2, 3, 4, 5, 6}; satu kartu dari dek remi punya 52 anggota. Kejadian adalah himpunan bagian dari ruang sampel — “mata dadu genap” adalah kejadian {2, 4, 6}. Probabilitas kejadian A dihitung sebagai P(A) = n(A) / n(S) untuk ruang sampel yang berpeluang sama, dan hasilnya selalu berada di rentang 0 sampai 1. Probabilitas komplemen dihitung dengan 1 − P(A): peluang dadu tidak genap adalah 1 − 1/2 = 1/2.

Dua operasi himpunan memenuhi aturan yang perlu dihafal. Irisan “A dan B” menghitung hasil yang memenuhi keduanya; gabungan “A atau B” memenuhi aturan jumlah P(A atau B) = P(A) + P(B) − P(A dan B). Pengurangan di akhir wajib: tanpa pengurangan, bagian yang tumpang tindih akan terhitung dua kali.

Probabilitas Bersyarat dan Teorema Bayes #

Probabilitas bersyarat menjawab pertanyaan berbentuk “berapa peluang B kalau A sudah pasti terjadi?”. Rumusnya P(B | A) = P(A dan B) / P(A) — ruang sampel menyusut menjadi hanya anggota A, lalu kejadian B dihitung di dalam ruang yang lebih sempit itu. Pada dadu: dari hasil genap {2, 4, 6}, hanya angka 6 yang sekaligus lima atau lebih, sehingga P(B | A) = 1/3. Probabilitas bersama (joint probability) P(A dan B) hanyalah bentuk lain dari rumus yang sama setelah dikalikan silang.

Membalik arah pertanyaan itulah inti teorema Bayes: P(A | B) = P(B | A) · P(A) / P(B). Kita mengetahui peluang gejala jika penyakitnya ada, lalu ingin tahu peluang penyakit jika gejalanya muncul. Pola pembalikan ini menjadi fondasi spam filter dan klasifikasi teks, dan akan kita bedah tuntas pada Section Probabilistic Machine Learning — di sini cukup satu verifikasi kecil bahwa rumusnya konsisten.

Kebebasan dan Nilai Harapan #

Dua kejadian saling bebas (independent) jika pengetahuan tentang yang satu tidak mengubah peluang yang lain, secara formal P(A dan B) = P(A) · P(B). Kartu memberi ujian yang rapi: P(as) = 4/52 dan P(hati) = 13/52, sedangkan P(as hati) = 1/52 — dan hasil kali 4/52 × 13/52 memang tepat 1/52, jadi keduanya bebas. Model naive Bayes memakai asumsi kebebasan ini secara agresif: semua fitur dianggap saling bebas jika kelasnya diketahui, asumsi yang secara nyata sering keliru tetapi tetap menghasilkan classifier yang andal.

Nilai harapan E[X] adalah rata-rata bobot-peluang dari semua hasil: Σ x · P(X = x). Untuk dadu, E[X] = (1 + 2 + 3 + 4 + 5 + 6) / 6 = 3,5 — bukan hasil yang mungkin dari satu lemparan, melainkan rata-rata jangka panjang. Konsep ini menghubungkan probabilitas dengan statistika: mean dari sampel besar mendekati nilai harapan populasi.

File probabilitas-dasar.py merangkum seluruh aturan di atas dengan pecahan eksak dari modul fractions, sehingga tidak ada galat pembulatan dan setiap hasil bisa diperiksa dengan tangan.

python
# Probabilitas dasar dengan pecahan eksak: dadu, kartu, kejadian bersyarat.

import math
from fractions import Fraction

# ===== Dadu: kejadian, irisan, gabungan =====
# A = mata dadu genap = {2, 4, 6}; B = mata dadu >= 5 = {5, 6}
p_a = Fraction(3, 6)
p_b = Fraction(2, 6)
p_a_dan_b = Fraction(1, 6)      # irisan A dan B = {6}
p_a_atau_b = Fraction(4, 6)     # gabungan A atau B = {2, 4, 5, 6}

print("== Satu lemparan dadu ==")
print(f"P(A)        = {p_a} = {float(p_a):.3f}")
print(f"P(B)        = {p_b} = {float(p_b):.3f}")
print(f"P(A dan B)  = {p_a_dan_b}")
print(f"P(A atau B) = {p_a_atau_b}")
aturan_jumlah = p_a + p_b - p_a_dan_b
print(f"Aturan jumlah P(A) + P(B) - P(A dan B) = {aturan_jumlah}")

# ===== Kejadian bersyarat dan cek Bayes =====
p_b_jika_a = p_a_dan_b / p_a
p_a_jika_b = p_a_dan_b / p_b
print("\n== Kejadian bersyarat ==")
print(f"P(B | A) = P(A dan B) / P(A) = {p_b_jika_a}")
print(f"P(A | B) = P(A dan B) / P(B) = {p_a_jika_b}")
cek_bayes = p_b_jika_a * p_a / p_b
print(f"Cek Bayes P(B | A) * P(A) / P(B)       = {cek_bayes}")

# ===== Kartu remi: uji kebebasan (independence) =====
p_as = Fraction(4, 52)
p_hati = Fraction(13, 52)
p_as_hati = Fraction(1, 52)
print("\n== Satu kartu dari 52 ==")
print(f"P(as)        = {p_as} = {float(p_as):.3f}")
print(f"P(hati)      = {p_hati} = {float(p_hati):.3f}")
print(f"P(as hati)   = {p_as_hati}")
print(f"P(as) * P(hati) = {p_as * p_hati}")
print("Kejadian as dan hati saling bebas: hasil kali = P(as hati)")

# ===== Nilai harapan satu lemparan dadu =====
e_dadu = sum(Fraction(1, 6) * mata for mata in range(1, 7))
print("\n== Nilai harapan dadu ==")
print(f"E[X] = {e_dadu} = {float(e_dadu):.2f}")

# ===== Binomial: tepat 3 kepala dari 5 lemparan koin adil =====
n, k = 5, 3
p_kepala = Fraction(1, 2)
# Rumus umum: C(n, k) * p^k * (1-p)^(n-k); dengan p = 1/2 jadi C(n,k)/2^n
p_binom = math.comb(n, k) * p_kepala ** n
print("\n== Binomial: koin adil ==")
print(f"P(tepat {k} kepala dari {n} lemparan) = {p_binom} = {float(p_binom):.4f}")

Output yang Dihasilkan:

text
== Satu lemparan dadu ==
P(A)        = 1/2 = 0.500
P(B)        = 1/3 = 0.333
P(A dan B)  = 1/6
P(A atau B) = 2/3
Aturan jumlah P(A) + P(B) - P(A dan B) = 2/3

== Kejadian bersyarat ==
P(B | A) = P(A dan B) / P(A) = 1/3
P(A | B) = P(A dan B) / P(B) = 1/2
Cek Bayes P(B | A) * P(A) / P(B)       = 1/2

== Satu kartu dari 52 ==
P(as)        = 1/13 = 0.077
P(hati)      = 1/4 = 0.250
P(as hati)   = 1/52
P(as) * P(hati) = 1/52
Kejadian as dan hati saling bebas: hasil kali = P(as hati)

== Nilai harapan dadu ==
E[X] = 7/2 = 3.50

== Binomial: koin adil ==
P(tepat 3 kepala dari 5 lemparan) = 5/16 = 0.3125

Mari kita telaah baris-baris kode yang berperan penting:

  1. Baris 8–11 (p_a sampai p_a_atau_b): empat kejadian dadu dinyatakan sebagai Fraction — 3/6, 2/6, 1/6, 4/6 — dan dicetak bersama bentuk desimalnya agar maknanya terlihat.
  2. Baris 18–19 (aturan jumlah): 1/2 + 1/3 − 1/6 dihitung Fraction menghasilkan 2/3, tepat sama dengan P(A atau B) yang dihitung langsung — aturan jumlah terbukti.
  3. Baris 22–28 (bersyarat dan Bayes): P(B | A) = 1/3 dan P(A | B) = 1/2 berbeda karena basis pertanyaannya berbeda; cek Bayes mengembalikan 1/2 yang identik dengan P(A | B), menandakan pembalikan arah konsisten.
  4. Baris 31–39 (kartu): hasil kali P(as) × P(hati) = 1/52 sama persis dengan P(as hati), sehingga kebebasan kedua kejadian terbukti secara eksak.
  5. Baris 42–44 (nilai harapan): sum(Fraction(1, 6) * mata ...) menghitung Σ x · P(X = x) menghasilkan 7/2 = 3,5.
  6. Baris 47–52 (binomial): math.comb(5, 3) menghitung kombinasi 10 cara, dikali (1/2)⁵ menghasilkan 5/16 = 0,3125 — peluang tepat tiga kepala dari lima lemparan.

Distribusi: Bernoulli, Binomial, dan Normal #

Distribusi peluang memetakan setiap hasil ke peluangnya. Bernoulli menggambarkan satu percobaan dua hasil dengan parameter p — dasar label biner dan keluaran sigmoid pada logistic regression. Binomial menghitung banyaknya kejadian sukses dari n percobaan bebas, seperti kode koin di atas. Normal menduduki posisi paling penting: kurva lonceng yang ditentukan dua parameter (mean μ dan simpangan baku σ), muncul sebagai model derau, residual regresi, hingga bobot awal jaringan saraf.

Fungsi kepadatan peluang (pdf) normal bernilai tertinggi di μ dan menurun ke dua sisi; fungsi distribusi kumulatif (cdf) menjumlahkan luas hingga satu titik. File distribusi-normal.py menghitung keduanya dengan scipy.stats.norm, lalu menguji aturan 68–95–99,7 secara empiris: sekitar 68 persen data normal berada dalam satu simpangan baku dari mean dan 95 persen dalam dua simpangan baku.

python
# Distribusi normal: pdf pada titik kunci dan proporsi empiris sekitar mean.

import numpy as np
from scipy.stats import norm

# Distribusi normal standar: mean 0, simpangan baku 1
print("== Nilai pdf dan cdf normal standar ==")
for z in [-2.0, -1.0, 0.0, 1.0, 2.0]:
    print(f"pdf(z = {z:+.1f}) = {norm.pdf(z):.4f}")
print(f"P(Z <= 1.00)      = {norm.cdf(1.0):.4f}")
print(f"P(-1 <= Z <= 1)   = {norm.cdf(1.0) - norm.cdf(-1.0):.4f}")
print(f"P(-2 <= Z <= 2)   = {norm.cdf(2.0) - norm.cdf(-2.0):.4f}")

# Normal dengan parameter lain: tinggi badan dewasa N(170, 7) dalam cm
print("\n== Normal N(170, 7): tinggi badan (cm) ==")
print(f"pdf(170)   = {norm.pdf(170, loc=170, scale=7):.4f}")
print(f"P(X <= 163) = {norm.cdf(163, loc=170, scale=7):.4f}")

# Uji empiris: 50.000 sampel dari N(0, 1) dengan seed tetap
rng = np.random.default_rng(42)
sampel = rng.normal(loc=0.0, scale=1.0, size=50_000)
print("\n== Proporsi empiris dari 50.000 sampel ==")
print(f"Proporsi |z| <= 1 : {np.mean(np.abs(sampel) <= 1.0):.4f}")
print(f"Proporsi |z| <= 2 : {np.mean(np.abs(sampel) <= 2.0):.4f}")
print(f"Rata-rata sampel  : {sampel.mean():.4f}")
print(f"Std sampel        : {sampel.std():.4f}")

Output yang Dihasilkan:

text
== Nilai pdf dan cdf normal standar ==
pdf(z = -2.0) = 0.0540
pdf(z = -1.0) = 0.2420
pdf(z = +0.0) = 0.3989
pdf(z = +1.0) = 0.2420
pdf(z = +2.0) = 0.0540
P(Z <= 1.00)      = 0.8413
P(-1 <= Z <= 1)   = 0.6827
P(-2 <= Z <= 2)   = 0.9545

== Normal N(170, 7): tinggi badan (cm) ==
pdf(170)   = 0.0570
P(X <= 163) = 0.1587

== Proporsi empiris dari 50.000 sampel ==
Proporsi |z| <= 1 : 0.6806
Proporsi |z| <= 2 : 0.9538
Rata-rata sampel  : -0.0005
Std sampel        : 1.0026

Bedah kode di atas baris demi baris:

  1. Baris 8–9 (norm.pdf): pdf di z = 0 bernilai 0,3989 — puncak kurva lonceng standar — lalu turun ke 0,2420 di z = ±1 dan 0,0540 di z = ±2. Nilai pdf adalah kepadatan, bukan peluang titik; peluang selalu dihitung dari luas area.
  2. Baris 10–12 (norm.cdf): P(Z ≤ 1) = 0,8413, sehingga luas antara −1 dan 1 adalah 0,6827 dan antara −2 dan 2 adalah 0,9545 — angka 68 dan 95 persen yang terkenal itu.
  3. Baris 14–17 (parameter bebas): norm.pdf(170, loc=170, scale=7) menunjukkan parameterisasi μ dan σ; P(X ≤ 163) = 0,1587 karena 163 tepat satu σ di bawah mean — selaras dengan cdf di z = −1.
  4. Baris 20–26 (uji empiris): 50.000 sampel dari generator berseed menghasilkan proporsi 0,6806 di dalam satu σ dan 0,9538 di dalam dua σ — mendekati nilai teoretis; rata-rata −0,0005 dan simpangan baku 1,0026 memperlihatkan sampel besar yang mengikuti populasinya.
DistribusiParameterContoh peran di machine learning
BernoullipLabel biner, keluaran sigmoid
Binomialn, pJumlah sukses dalam n uji, uji A/B
Normalμ, σDerau, residual regresi, inisialisasi bobot

Kita kini punya tiga fondasi — aljabar linear untuk bentuk model, kalkulus untuk cara belajarnya, statistika dan probabilitas untuk cara membaca data dan ketidakpastiannya. Langkah berikutnya bersifat teknis: penguasaan NumPy, pustaka tempat seluruh matematika tersebut dieksekusi dengan cepat. Mari kita mulai dengan Chapter NumPy untuk Machine Learning.

Referensi Resmi #