Propensity score matching pada chapter sebelumnya berhasil menyeimbangkan kovariat terukur, tetapi dengan dua harga: 32 peserta dibuang karena tidak punya kembaran, dan seluruh informasi empat kovariat dipadatkan menjadi satu angka skor. Pertanyaan penutup Section ini: bisakah kita menghapus confounding nonlinear tanpa membuang satu baris data pun — memakai model machine learning untuk menyerap bagian hasil dan bagian treatment yang bisa dijelaskan kovariat, lalu membandingkan sisanya? Jawabannya adalah double machine learning (DML), dirumuskan Chernozhukov dan rekan-rekan pada 2018, dan kekuatannya justru terletak pada satu detail prosedur yang terlihat sepele: cross-fitting. Chapter ini membangun intuisinya dari teorema ekonometrika klasik, mendemonstrasikan bias yang muncul tanpa cross-fitting, lalu menutup Section dengan peta jujur tentang asumsi apa yang tetap dipertaruhkan.

Logika Partialling-Out: Teorema Frisch-Waugh-Lovell #

Kerangka kerjanya sudah tua: teorema Frisch–Waugh–Lovell (FWL) dari ekonometrika tahun 1960-an. Misalkan kita ingin koefisien W pada regresi Y ~ kovariat + W. FWL menyatakan bahwa koefisien tersebut identik dengan hasil prosedur tiga langkah:

text
Langkah 1: regresikan Y terhadap kovariat, simpan residualnya  Ỹ
Langkah 2: regresikan W terhadap kovariat, simpan residualnya  W̃
Langkah 3: regresikan Ỹ terhadap W̃ -> koefisien = koefisien W pada regresi penuh

Maknanya: residual adalah bagian dari variabel yang tidak bisa dijelaskan kovariat. Dengan menghapus bagian yang bisa dijelaskan dari kedua sisi, regresi langkah ketiga membandingkan dua “sisa” yang sudah bebas dari kovariat — confounding terhapus tanpa satu baris data dibuang. Ketika hubungan antara kovariat dan hasil bersifat linear, FWL bisa dijalankan dengan OLS biasa dan selesai. Persoalan muncul ketika struktur nonlinear: sin, kuadrat, interaksi antar fitur — dunia asli data pelanggan — tempat OLS linear salah bentuk dan meninggalkan sisa konfounding. Di situlah langkah 1 dan 2 diganti model machine learning, dan lahirlah gagasan DML.

Kenapa Machine Learning Saja Tidak Cukup #

Jalan pintas yang pertama terpikir: masukkan treatment sebagai satu fitur ke dalam GradientBoostingRegressor, lalu baca feature importance treatment. Jalan ini keliru dua lapis. Lapis pertama: feature importance mengukur asosiasi prediktif — masalah yang sudah kita bedah tuntas di awal Section. Lapis kedua lebih halus: model machine learning yang fleksibel selalu menukar sedikit ketepatan bentuk demi kestabilan — itulah makna regularisasi — dan bagian treatment yang terserap model tidak lagi muncul di residual. Ketika residual Ỹ tercemar sisa-sisa informasi treatment, koefisien langkah ketiga menjadi bias dengan arah yang sulit ditebak; ini disebut bias regularisasi dan bias overfitting. Semakin kuat model mengejar data latihnya, semakin kecil residual yang dihasilkannya pada data yang sama — residual yang “terlalu bersih” justru menuliskan jawaban yang keliru.

Solusi DML ada dua bagian yang saling melengkapi. Pertama, partialling-out ganda: kedua nuisance — E[Y|X] dan E[W|X] — diestimasi model ML terpisah, sehingga galat kedua model hanya bertemu di langkah ketiga sebagai hasil kali yang orde kecilnya cukup rendah untuk diabaikan secara asimptotik. Kedua, cross-fitting: setiap observasi dihitung residualnya oleh model yang tidak pernah melihat observasi itu — data dibagi K lipatan, model dilatih pada K−1 lipatan, residual dihitung pada lipatan sisanya, bergiliran. Dengan begitu tidak ada observasi yang dinilai oleh model yang hafal dirinya, dan bias overfitting praktis hilang tanpa perlu asumsi bentuk pada nuisance.

Contoh Kode: Confounding Nonlinear dengan Efek Sejati 3,0 #

Data sintetisnya sengaja dibuat sulit bagi metode parametrik: 1.200 pelanggan, enam kovariat berdistribusi normal, hasil mengikuti fungsi nonlinear g(X) (sinus, kuadrat, eksponensial, interaksi), dan peluang ikut program juga nonlinear dalam kovariat yang sama — confounding klasik yang regresi linear akan salah bentuk. Efek program ditanam tepat +3,0:

python
# Double machine learning dengan cross-fitting: efek program upgrade pada
# data dengan confounding nonlinear. Model hasil (GradientBoosting) dan model
# treatment (RandomForest) dilatih pada lipatan yang berbeda dari data ujinya,
# lalu sisa-sisanya dibandingkan lewat OLS tanpa intersep.

import numpy as np
from scipy import stats
from sklearn.ensemble import GradientBoostingRegressor, RandomForestRegressor

rng = np.random.default_rng(42)

n = 1200
X = rng.normal(0.0, 1.0, size=(n, 6))

# Nuisance hasil: fungsi nonlinear dari kovariat.
g = (8.0 + 2.2 * np.sin(1.5 * X[:, 0]) + 0.9 * X[:, 1] ** 2
     + 1.5 * np.exp(-np.abs(X[:, 2])) + 0.8 * X[:, 3] * X[:, 4]
     - 0.7 * X[:, 5])

# Nuisance treatment: peluang ikut program juga nonlinear dalam kovariat.
logit_w = 1.2 * np.sin(1.5 * X[:, 0]) + 0.8 * X[:, 1] + 0.9 * np.tanh(X[:, 2]) - 0.5
p_w = 1.0 / (1.0 + np.exp(-logit_w))
w = (rng.random(n) < p_w).astype(float)

# Hasil teramati: bagian kovariat + efek treatment + derau.
EFEK_SEJATI = 3.0
y = g + EFEK_SEJATI * w + rng.normal(0.0, 1.5, n)

naif = y[w == 1].mean() - y[w == 0].mean()
print(f"Estimasi naif (selisih rata-rata) : {naif:+.3f}")
print(f"Efek sejati yang ditanam           : {EFEK_SEJATI:+.3f}")

# --- Partialling-out dengan cross-fitting K=3 ---
urutan = rng.permutation(n)
lipatan = np.array_split(urutan, 3)

y_sisa = np.zeros(n)
w_sisa = np.zeros(n)
for k in range(3):
    uji = lipatan[k]
    latih = np.concatenate([lipatan[j] for j in range(3) if j != k])

    # Model hasil: GradientBoosting mengejar struktur nonlinear g(X).
    model_y = GradientBoostingRegressor(
        n_estimators=300, max_depth=4, random_state=42)
    model_y.fit(X[latih], y[latih])
    y_sisa[uji] = y[uji] - model_y.predict(X[uji])

    # Model treatment: RandomForest dengan daun minimal agar skor peluangnya
    # mulus, tidak mendekati 0/1 yang membuat sisa treatment nyaris nol.
    model_w = RandomForestRegressor(
        n_estimators=300, min_samples_leaf=10, random_state=42, n_jobs=1)
    model_w.fit(X[latih], w[latih])
    w_sisa[uji] = w[uji] - model_w.predict(X[uji])

theta = float(np.dot(w_sisa, y_sisa) / np.dot(w_sisa, w_sisa))
sisa_akhir = y_sisa - theta * w_sisa
galat_baku = float(np.sqrt(np.sum(sisa_akhir ** 2) /
                           ((n - 1) * np.dot(w_sisa, w_sisa))))
t_kritis = stats.t.ppf(0.975, df=n - 1)
batas_bawah = theta - t_kritis * galat_baku
batas_atas = theta + t_kritis * galat_baku

print(f"\nDML cross-fitted (K=3)            : {theta:+.3f}")
print(f"Galat baku estimasi               : {galat_baku:.3f}")
print(f"Interval kepercayaan 95%          : "
      f"[{batas_bawah:+.3f}, {batas_atas:+.3f}]")
print(f"Interval memuat efek sejati 3,0   : "
      f"{batas_bawah <= EFEK_SEJATI <= batas_atas}")
print(f"Simpangan sisa hasil (setelah kovariat dijelaskan): {y_sisa.std():.3f}")
print(f"Simpangan sisa treatment                          : {w_sisa.std():.3f}")

Output yang Dihasilkan:

text
Estimasi naif (selisih rata-rata) : +3.884
Efek sejati yang ditanam           : +3.000

DML cross-fitted (K=3)            : +3.136
Galat baku estimasi               : 0.129
Interval kepercayaan 95%          : [+2.883, +3.389]
Interval memuat efek sejati 3,0   : True
Simpangan sisa hasil (setelah kovariat dijelaskan): 2.357
Simpangan sisa treatment                          : 0.432

Mari kita bedah bagian-bagian pentingnya:

  1. Baris 16–23 (dua nuisance): g menghasilkan bagian hasil yang berasal dari kovariat; logit_w nonlinear menghasilkan peluang ikut program — keduanya memakai kovariat yang sama dengan bentuk yang berbeda, inilah confounding yang harus dihapus.
  2. Baris 26–27 (hasil teramati): y = g + 3.0*w + derau — efek treatment murni ditambahkan di atas nuisance; kebenaran yang harus ditemukan kembali.
  3. Baris 34–35 (pembagian lipatan): rng.permutation(n) mengacak urutan lalu np.array_split membaginya menjadi tiga lipatan yang sama besar — pembagian manual yang transparan dibanding KFold.
  4. Baris 39–54 (cross-fitting): untuk tiap lipatan, latih berisi dua lipatan lainnya; model hasil GradientBoostingRegressor(max_depth=4) mengejar struktur nonlinear g, model treatment RandomForestRegressor(min_samples_leaf=10) sengaja dibuat mulus agar skor peluangnya tidak mendekati 0/1 — propensity yang nyakin deterministik membuat residual treatment nyaris nol dan estimasi menjadi rapuh.
  5. Baris 56–62 (OLS tanpa intersep): theta = W̃·Ỹ / W̃·W̃ adalah kemiringan regresi residual-treatment terhadap residual-hasil; galat baku mengikuti rumus OLS melalui titik nol dengan galat baku residu akhir dan stats.t.ppf memberi batas interval kepercayaan.

Angkanya menutup kisah Section ini dengan rapi. Estimasi naif +3,884 — sepertiga terlalu tinggi, karena peserta program memang berada di wilayah kovariat yang baseline-nya besar. DML cross-fitted menghasilkan +3,136 dengan galat baku 0,129 dan interval kepercayaan 95% [+2,883; +3,389] yang memuat kebenaran +3,0; galat estimasi tinggal 0,136 dari 0,884 milik pembacaan naif. Dua baris terakhir memperlihatkan anatomi partialling-out: simpangan sisa hasil 2,357 (derau asli 1,5 ditambah bagian g yang belum sempurna dipelajari) dan simpangan sisa treatment 0,432 — informasi treatment yang benar-benar bebas dari kovariat, bahan bakar estimasi.

Asumsi yang Tetap Dipertaruhkan #

DML menyelesaikan masalah bentuk fungsi, bukan masalah konfounder tersembunyi. Asumsi unconfoundedness dari Chapter Framework Potential Outcomes tetap berlaku penuh: kovariat yang benar-benar memengaruhi treatment dan hasil harus ada di dalam X. Konfounder tak terukur — niat belanja yang tidak pernah menjadi kolom — tidak ikut terseimbangkan, dan estimasi DML yang meyakinkan pun tetap bias diam-diam. Positivity juga tetap disyaratkan: wilayah kovariat tempat peluang ikut program mendekati nol atau satu menyumbang hampir tidak ada informasi residual. Kerangka kerja yang jujur karenanya selalu berpasangan: DML untuk estimasi, lalu analisis sensitivitas — “seberapa kuat konfounder tak terukur harus agar kesimpulan berubah?” — untuk keraguan yang tersisa.

Sebagai penutup Section, empat pendekatan yang kita bangun bisa diletakkan pada satu peta:

PendekatanData yang terpakaiConfounding yang ditanganiEstimand alami
Selisih rata-rata naifSemuaTidak adaBias murni
Regresi linear dengan kovariatSemuaLinear, terukurKoefisien parametrik
Propensity score matchingHanya pasangan yang cocokTerukur, lewat satu skorATT
DML cross-fittedSemuaNonlinear, terukurATE

Benang merah seluruh Section — dari paradoks Simpson sampai cross-fitting — adalah satu pertanyaan: apa yang terjadi jika kita melakukan satu perubahan. Inferensi kausal menjawab intervensi tunggal: ubah treatment sekali, ukur perbedaannya. Reinforcement learning membalik arah pertanyaannya: bagaimana seorang agen harus bertindak berulang kali, belajar dari konsekuensi tindakannya sendiri, untuk memaksimalkan imbalan yang terkumpul lintas waktu — wilayah di mana eksplorasi dan eksploitasi saling tarik-menarik. Perjalanan itu dimulai dari Chapter Konsep Reinforcement Learning.

Referensi Resmi #