Mundarija (26)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Korrelyatsiya va sabab
- 2.2. Potentsial natijalar (Rubin modeli)
- 2.3. DAG lar: nimani nazorat qilish kerak?
- 2.4. Simpson paradoksi
- 2.5. RCT — oltin standart
- 2.6. Kuzatuv ma'lumotida: to'rt yondashuv
- 2.7. Overlap, balans va og'irliklarni kesish
- 2.8. Ikki karra mustahkam baholash (AIPW)
- 2.9. O'lchanmagan chalkashtiruvchi — halol chegara
- 2.10. Uplift modellashtirish
- 2.11. Farqlar farqi (difference-in-differences)
- 2.12. Tuzoqlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — DAG lar simulyatsiyada: chalkashtiruvchi, mediator, kollayder, Simpson
- Misol 2 — Kupon ta'siri: naiv farq, regressiya, moslashtirish, IPW va AIPW
- Misol 3 — Mustahkamlik: noto'g'ri modellar, o'lchanmagan chalkashtiruvchi, kuchsiz overlap
- Misol 4 — Uplift modellashtirish (T/S-learner, Qini) va farqlar farqi
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
28.11-dars: Sababiy xulosa (causal inference)
28-QISM — MAXSUS MAVZULAR · 11-dars
1. Kirish va motivatsiya
Oldingi darsda katta ma'lumot bilan ishlashni o'rgandik: million qatorlarni bo'laklab o'qish, oqimda hisoblash, taxminiy tuzilmalar. Lekin ma'lumot qancha katta bo'lmasin, u o'z-o'zidan bitta savolga javob bermaydi: "agar biz X ni qilsak, Y qanday o'zgaradi?" Bu — sabab haqidagi savol, va unga javob berish uchun hajm emas, dizayn kerak.
Kursning boshida (4.10, 8.4) "korrelyatsiya — sabab emas" degan qoidani o'rgangan edik: yashirin o'zgaruvchi, teskari bog'liqlik, Simpson paradoksi. 11-qismda va 27.13 da esa sababni aniqlashning eng ishonchli yo'lini — tasodifiy tajribani (A/B test) ko'rdik. Lekin amalda ko'p savollarga A/B test qilib bo'lmaydi yoki kech bo'ladi: kupon allaqachon bir yil davomida tarqatilgan, aksiya o'tib ketgan, siyosat butun shaharga birdan joriy qilingan. Qo'limizda faqat kuzatuv ma'lumoti bor. Bu darsda shunday ma'lumotdan sababiy ta'sirni qanday baholash, qachon bunga ishonish mumkin va — eng muhimi — qachon mumkin emasligini o'rganamiz.
Real vaziyat. Onlayn do'kon bir yil davomida mijozlarga 20% lik chegirma kuponi yubordi. Tahlil shuni ko'rsatdi: kupon olganlar keyingi oyda o'rtacha 60 ming so'm ko'proq xarid qilgan. Marketing "kupon xaridni 60 ming so'mga oshiradi" deb hisobot yozdi va byudjetni ikki barobar oshirishni so'radi. Lekin kuponlarni tizim sodiq mijozlarga ko'proq yuborgan edi — ular kuponsiz ham ko'p xarid qilardi. Keyinroq o'tkazilgan A/B test haqiqiy ta'sir 3 barobar kichik ekanini ko'rsatdi, sodiq mijozlarda esa deyarli nol. Bu darsning 2-misolida aynan shu vaziyatni sintetik ma'lumotda qayta quramiz — haqiqiy ta'sir ma'lum bo'lgani uchun har bir usulning xatosini o'lchay olamiz.
Bu darsda sababiy savolni to'g'ri qo'yishni, kuzatuv ma'lumotidan ta'sirni baholash usullarini va ularning farazlarini halol tekshirishni o'rganamiz.
Bu darsda:
- Korrelyatsiya va sabab — nima uchun farq qiladi
- Potentsial natijalar (Rubin):
Y(1),Y(0), ATE, ATT, CATE va farazlar - DAG lar: chalkashtiruvchi, mediator, kollayder; orqa eshik mezoni; Simpson paradoksi
- RCT — oltin standart
- Kuzatuv ma'lumotida: regressiya bilan tuzatish, propensity score, moslashtirish, IPW
- Overlap (positivity), balans tekshiruvi, og'irliklarni kesish
- Ikki karra mustahkam baholash (AIPW) va bootstrap CI
- O'lchanmagan chalkashtiruvchi — hamma usulning chegarasi; sezgirlik tahlili
- Uplift modellashtirish: T-learner, S-learner, Qini egri chizig'i
- Farqlar farqi (DiD) va parallel trendlar farazi
- Tuzoqlar
ℹ Misollar real numpy/statsmodels/sklearn bilan (Python 3.14). DoWhy, EconML, CausalML bu muhitda yo'q — hamma usul noldan yoziladi. Ma'lumot sintetik va haqiqiy ta'sir ma'lum — shuning uchun har usulning xatosini o'lchaymiz.
2. Nazariya — chuqur tushuntirish
2.1. Korrelyatsiya va sabab
KUZATILGAN: kupon olganlar 60 ming so'm ko'p xarid qildi
SAVOL: kupon BERILSA, xarid qanchaga oshadi?
Farq manbalari:
1. SABAB kupon -> xarid (biz izlayotgan)
2. CHALKASHTIRISH sodiqlik -> kupon, sodiqlik -> xarid (yashirin umumiy sabab)
3. TESKARI xarid -> kupon (ko'p xarid qilganga kupon yuboriladi)
4. TANLASH faqat "sharh qoldirganlar" tahlil qilindi (kollayder)
5. TASODIF kichik namuna, ko'p taqqoslash 11.9-bob
Korrelyatsiya = 1 + 2 + 3 + 4 + 5 aralashmasi.
Sababiy xulosa = 2-5 ni ajratib, faqat 1 ni baholash.Bashorat va sabab — turli savollar. Bashorat modeli uchun "kupon olgan" belgisi foydali bo'lishi mumkin (u sodiqlikni ko'rsatadi), lekin bu kupon berish xaridni oshirishini anglatmaydi. 12-qismdan beri qurgan modellarimiz P(Y | X) ni o'rganadi; sababiy savol esa P(Y | do(X)) — "X ni biz o'zgartirganda".
2.2. Potentsial natijalar (Rubin modeli)
Har mijoz i uchun IKKI potentsial natija:
Y_i(1) - kupon berilsa, keyingi oydagi xarid
Y_i(0) - kupon berilmasa
Individual ta'sir: tau_i = Y_i(1) - Y_i(0)
ASOSIY MUAMMO: har mijozda faqat BITTASI kuzatiladi
Y_i = T_i * Y_i(1) + (1 - T_i) * Y_i(0)
ikkinchisi - "kontrfaktual" (bo'lmagan olam)
O'RTACHA TA'SIRLAR (estimand - nimani baholaymiz):
ATE = E[Y(1) - Y(0)] butun populyatsiya
ATT = E[Y(1) - Y(0) | T = 1] kupon OLGANLAR orasida
ATC = E[Y(1) - Y(0) | T = 0] olmaganlar orasida
CATE = E[Y(1) - Y(0) | X = x] belgilar bo'yicha (uplift)
NAIV FARQ nima beradi:
E[Y | T=1] - E[Y | T=0]
= ATT + ( E[Y(0) | T=1] - E[Y(0) | T=0] )
\_____ tanlash siljishi (selection bias) _____/
sodiqlar kupon olsa: E[Y(0)|T=1] > E[Y(0)|T=0] -> naiv farq OSHIRIB ko'rsatadiTa'sir turli mijozlarda turlicha bo'lsa, ATE va ATT farq qiladi. Kupon sodiq mijozlarga ko'proq berilgan va ularga kam ta'sir qilsa — ATT < ATE. "Kupon qancha foyda berdi?" (o'tgan dastur baholash) — ATT; "hammaga bersak-chi?" — ATE; "kimga berish kerak?" — CATE. Savolni tanlamasdan usul tanlab bo'lmaydi.
Kuzatuv ma'lumotidan sababiy ta'sirni baholash uchun farazlar:
1. IGNORABILITY (chalkashtiruvchi qolmagan): (Y(1), Y(0)) mustaqil T | X
X ni hisobga olgach, kupon olish "tasodifiy" - hamma umumiy sabablar X da
TEKSHIRIB BO'LMAYDI - faqat domen bilimi bilan asoslanadi
2. POSITIVITY (overlap): 0 < P(T=1 | X) < 1 har X uchun
har turdagi mijozda kupon olgan ham, olmagan ham bor
TEKSHIRSA BO'LADI - propensity taqsimoti bilan
3. SUTVA / izchillik: bir mijozning kuponi boshqasiga ta'sir qilmaydi,
"kupon" bitta aniq muolaja (20% lik, bir xil muddat)2.3. DAG lar: nimani nazorat qilish kerak?
DAG (directed acyclic graph) — o'zgaruvchilar orasidagi sababiy strelkalar. Uchta asosiy tuzilma:
CHALKASHTIRUVCHI (fork) MEDIATOR (chain) KOLLAYDER
sodiqlik kupon -> tashrif -> xarid kupon xarid
/ \ \_________________/^ \ /
v v (bevosita) v v
kupon ---> xarid sharh
NAZORAT QILISH KERAK UMUMIY ta'sir uchun NAZORAT NAZORAT QILMASLIK
(orqa eshikni yopadi) QILMASLIK kerak; nazorat kerak! Kollayder bo'yicha
qilsangiz - faqat BEVOSITA filtr/nazorat mustaqil
ta'sir qoladi kupon va xarid orasida
SOXTA bog'lanish yaratadiORQA ESHIK MEZONI (backdoor criterion):
T dan Y ga ta'sirni baholash uchun Z to'plami yetarli, agar:
1. Z hech bir elementi T ning avlodi (natijasi) emas
2. Z T <- ... -> Y ko'rinishidagi barcha "orqa eshik" yo'llarni to'sadi
shunda ATE = sum_z ( E[Y | T=1, Z=z] - E[Y | T=0, Z=z] ) * P(Z=z)
"YOMON NAZORAT" (bad controls):
mediator - ta'sirning bir qismini yeb qo'yadi
kollayder - soxta bog'lanish ochadi
T dan KEYIN o'lchangan har narsa (T ning natijasi bo'lishi mumkin)
QOIDA: "hamma belgini modelga qo'shaman" - sababiy tahlilda XATONazorat qilish har doim ham yaxshi emas. Qaysi o'zgaruvchini nazorat qilish kerakligini ma'lumot emas, sababiy tuzilma hal qiladi — DAG ni ma'lumotga qaramasdan, domen bilimi bilan chizing.
2.4. Simpson paradoksi
8.4 da ko'rgan edik: guruhlarga ajratganda bog'liqlik yo'nalishi o'zgarishi mumkin. Sababiy nuqtai nazardan bu — chalkashtiruvchi (segment) ta'siri:
kuponsiz kupon farq
yangi mijozlar 5.0% 8.0% +3.0 <- har segmentda kupon YORDAM beradi
doimiy mijozlar 30.0% 33.0% +3.0
UMUMIY ~20% ~13% MANFIY <- kuponlar asosan yangi mijozlarga
(past bazaviy konversiya) berilgan
Qaysi javob to'g'ri? Segment kuponga SABAB bo'lgani uchun (segment -> kupon)
-> segment ichidagi farq va segment ulushlari bilan standartlash.
Agar segment kuponning NATIJASI bo'lsa (mediator) - umumiy farq to'g'ri bo'lardi.2.5. RCT — oltin standart
Tasodifiy taqsimlashda (27.13 dagi A/B test, 11-qismdagi testlar) T hech narsaga bog'liq emas — na kuzatilgan, na kuzatilmagan belgilarga. Shuning uchun E[Y(0) | T=1] = E[Y(0) | T=0], tanlash siljishi nolga teng va oddiy farq ATE ni beradi. Kuzatuv ma'lumotidagi barcha usullar — RCT ni taqlid qilish urinishi: "X bir xil bo'lgan mijozlar orasida kupon tasodifiy berilgan deb faraz qilamiz". Imkon bo'lsa — tajriba qiling; kuzatuv tahlili tajribaning o'rnini bosmaydi, faqat tajriba mumkin bo'lmaganda eng yaxshi mavjud javobni beradi.
2.6. Kuzatuv ma'lumotida: to'rt yondashuv
1. REGRESSIYA BILAN TUZATISH
Y ~ T + X -> T koeffitsienti
ta'sir X ga bog'liq bo'lsa - bu ATE EMAS, balki variansga qarab
vaznlangan o'rtacha; model shakli noto'g'ri bo'lsa - siljish
G-HISOBLASH (standartlash): mu_1(x) = E[Y | T=1, X=x] va mu_0(x) alohida
ATE = mean_i ( mu_1(x_i) - mu_0(x_i) )
2. PROPENSITY SCORE: e(x) = P(T = 1 | X = x) (logistik regressiya, 13.10)
Rosenbaum-Rubin: X bo'yicha ignorability bo'lsa, e(X) bo'yicha ham bor
-> ko'p o'lchovli X o'rniga BITTA son bo'yicha tenglashtirish
3. MOSLASHTIRISH (matching): har kupon olgan mijozga e(x) si eng yaqin
kupon OLMAGAN mijoz; farqlar o'rtachasi -> ATT
logit(e) bo'yicha, "caliper" (masalan 0.2 * std) - uzoq juftlar tashlanadi
qaytarib (with replacement) - bitta nazorat bir necha marta ishlatiladi
4. IPW (inverse probability weighting):
w = T / e + (1 - T) / (1 - e)
g'oya: kupon olish ehtimoli past bo'lgan kupon oluvchi - "kamyob",
u o'ziga o'xshash ko'p odam uchun "gapiradi"
Hajek (normallangan): sum(w*T*Y)/sum(w*T) - sum(w*(1-T)*Y)/sum(w*(1-T))
ATT uchun: kupon olganlar w = 1, olmaganlar w = e / (1 - e)2.7. Overlap, balans va og'irliklarni kesish
OVERLAP TEKSHIRUVI:
e(x) taqsimotini guruhlar bo'yicha ko'ring (min, kvantillar, max)
e ~ 0 yoki e ~ 1 bo'lgan hudud - u yerda taqqoslash uchun "egizak" yo'q
maks og'irlik, samarali namuna hajmi: ESS = (sum w)^2 / sum w^2
BALANS (SMD - standartlashgan o'rtachalar farqi):
SMD = (orta_1 - orta_0) / sqrt((var_1 + var_0) / 2)
vaznlashdan (yoki moslashtirishdan) KEYIN |SMD| < 0.1 - odatiy mezon
balans yo'q -> propensity modeli yetarli emas (belgilar, nochiziqlik)
KESISH (trimming/clipping):
e ni [0.05, 0.95] ga kesish yoki o'sha hududdagi qatorlarni tashlash
dispersiya keskin kamayadi, lekin BAHOLANADIGAN kattalik o'zgaradi:
endi "overlap hududidagi mijozlar uchun ta'sir" - buni hisobotda ayting2.8. Ikki karra mustahkam baholash (AIPW)
AIPW (augmented IPW):
psi_i = mu_1(x_i) - mu_0(x_i)
+ T_i * (Y_i - mu_1(x_i)) / e(x_i)
- (1 - T_i) * (Y_i - mu_0(x_i)) / (1 - e(x_i))
ATE = mean(psi_i)
NEGA "IKKI KARRA":
natija modeli (mu) TO'G'RI bo'lsa - tuzatish hadlari o'rtachada 0 -> to'g'ri
propensity (e) TO'G'RI bo'lsa - tuzatish mu xatosini aynan yo'qotadi
IKKALASI noto'g'ri bo'lsa - kafolat yo'q
BONUS: ikkalasi yaxshi bo'lsa - dispersiya IPW dan ancha kichik
AMALDA: mu va e ni ML modellari (HistGB) bilan, cross-fitting bilan
(bir qismda o'qitib, boshqasida baholash) - "double ML" g'oyasiNoaniqlik. Sababiy baho — bitta son emas. Bootstrap 11.8-bob bilan ishonch oralig'i quriladi, lekin butun jarayon qayta bajarilishi kerak: propensity modelini ham har bootstrap namunasida qayta o'qitish.
2.9. O'lchanmagan chalkashtiruvchi — halol chegara
Barcha yuqoridagi usullar BITTA farazga tayanadi: hamma chalkashtiruvchilar X da.
Agar U (masalan, mijoz daromadi) kupon olishga ham, xaridga ham ta'sir qilsa
va ma'lumotda YO'Q bo'lsa:
regressiya, moslashtirish, IPW, AIPW - HAMMASI siljigan
va hech biri buni o'zi "sezmaydi" (balans X bo'yicha mukammal bo'lishi mumkin)
NIMA QILISH MUMKIN:
sezgirlik tahlili - "U qanchalik kuchli bo'lsa, xulosa o'zgaradi?"
(E-qiymat: kuzatilgan ta'sirni yo'qotish uchun U ning ham T, ham Y bilan
bog'lanishi qanchalik kuchli bo'lishi kerak)
boshqa dizayn: instrumental o'zgaruvchi (IV), regressiya uzilishi (RDD),
farqlar farqi (DiD, 2.11), tabiiy tajriba
eng yaxshisi - RCT2.10. Uplift modellashtirish
Marketing uchun asosiy savol ko'pincha ATE emas, balki kimga berish: CATE(x) = E[Y(1) - Y(0) | X = x].
TO'RT SEGMENT (xarid ehtimoli bo'yicha):
kuponsiz OLMAYDI kuponsiz OLADI
kupon bilan OLADI ISHONTIRILADIGAN "BARIBIR OLADI"
(persuadables) + (sure things) 0 - kupon isrof
kupon bilan OLMAYDI "YO'QOTILGAN" "BEZOVTA QILMA"
(lost causes) 0 (sleeping dogs) - zarar!
JAVOB MODELI (xato!): P(xarid | X) yuqorilarga kupon -> asosan "baribir oladi"
META-LEARNER LAR:
S-learner: bitta model f(X, T); uplift = f(x, 1) - f(x, 0)
kamchilik: model T ni "kuchsiz" belgi sifatida e'tiborsiz
qoldirishi mumkin -> uplift nolga siqiladi
T-learner: ikki model f1 (T=1 da), f0 (T=0 da); uplift = f1(x) - f0(x)
kamchilik: ikki modelning xatolari qo'shiladi
X-learner, DR-learner - ikkalasining yaxshi tomonlarini birlashtiradi
BAHOLASH - faqat RCT (yoki ishonchli tuzatilgan) ma'lumotda:
QINI EGRI CHIZIG'I: mijozlarni bashorat qilingan uplift bo'yicha saralab,
birinchi k ta ichida:
Qini(k) = Y_1(k) - Y_0(k) * N_1(k) / N_0(k)
(kupon olganlar xaridlari - kuponsizlar xaridlari, hajmga moslab)
= "shu k ta mijozga kupon berilsa, qo'shimcha xaridlar soni"
tasodifiy tartib - to'g'ri chiziq; maydon farqi - Qini koeffitsientiIndividual uplift ni to'g'ridan-to'g'ri tekshirib bo'lmaydi (har mijozda bitta natija). Shuning uchun baholash guruh darajasida: yuqori uplift deb baholangan guruhda kupon va kuponsizlar farqi haqiqatan kattami?
2.11. Farqlar farqi (difference-in-differences)
Aksiya faqat Samarqand do'konlarida 27-haftadan boshlandi. Toshkent do'konlari — nazorat.
oldin (1-26 hafta) keyin (27-52 hafta) farq
Samarqand A_oldin A_keyin A_keyin - A_oldin
Toshkent B_oldin B_keyin B_keyin - B_oldin
DiD = (A_keyin - A_oldin) - (B_keyin - B_oldin)
NAIV 1: A_keyin - A_oldin - trend va mavsumni ta'sir deb oladi
NAIV 2: A_keyin - B_keyin - shaharlar orasidagi doimiy farqni ta'sir deb oladi
DiD: ikkalasini ham yo'qotadi, AGAR:
PARALLEL TRENDLAR FARAZI: aksiya bo'lmaganda Samarqand va Toshkent
bir xil DINAMIKADA o'zgarardi (darajalari har xil bo'lishi mumkin)
TEKSHIRUV: aksiyadan oldingi davrda "soxta aksiya" (placebo) DiD ~ 0 bo'lishi
kerak; oldingi haftalar bo'yicha farqlar grafigi (event study)
BUZILSA: Samarqand tezroq o'sayotgan bo'lsa - DiD o'sishni ta'sirga qo'shadi
SE: do'kon bo'yicha (klaster) - bir do'konning haftalari mustaqil emas2.12. Tuzoqlar
Asosiy tuzoqlar: naiv farqni ta'sir deb e'lon qilish; estimandni (ATE/ATT/CATE) aniqlamasdan usul tanlash; "hamma belgini nazorat qilish" — mediator va kollayderni ham; muolajadan keyin o'lchangan belgilarni modelga qo'shish; overlap ni tekshirmasdan IPW; ekstremal og'irliklar va samarali namuna hajmini ko'rmaslik; balansni tekshirmaslik; bootstrap da propensity modelini qayta o'qitmaslik; kesish (trimming) baholanadigan kattalikni o'zgartirishini aytmaslik; o'lchanmagan chalkashtiruvchini e'tiborsiz qoldirish — "biz hamma narsani nazorat qildik"; uplift ni javob modeli bilan almashtirish; uplift modelni kuzatuv ma'lumotida (tuzatishsiz) baholash; DiD da parallel trendlarni tekshirmaslik; DiD da SE ni do'kon bo'yicha klasterlamaslik.
3. Tez ma'lumotnoma
import numpy as np
from sklearn.linear_model import LinearRegression, LogisticRegression
# propensity score
e = LogisticRegression(C=1e6, max_iter=1000).fit(X, T).predict_proba(X)[:, 1]
# overlap va balans
w = T / e + (1 - T) / (1 - e)
ess = w[T == 1].sum() ** 2 / (w[T == 1] ** 2).sum()
def smd(x, T, w):
m1 = np.average(x[T == 1], weights=w[T == 1])
m0 = np.average(x[T == 0], weights=w[T == 0])
return (m1 - m0) / np.sqrt((x[T == 1].var() + x[T == 0].var()) / 2)
# g-hisoblash (T-learner) va AIPW
mu1 = LinearRegression().fit(X[T == 1], Y[T == 1]).predict(X)
mu0 = LinearRegression().fit(X[T == 0], Y[T == 0]).predict(X)
ate_g = np.mean(mu1 - mu0)
ate_ipw = (np.sum(T * Y / e) / np.sum(T / e)
- np.sum((1 - T) * Y / (1 - e)) / np.sum((1 - T) / (1 - e)))
psi = mu1 - mu0 + T * (Y - mu1) / e - (1 - T) * (Y - mu0) / (1 - e)
ate_aipw = psi.mean()
# DiD (do'kon darajasida)
farq = y[:, keyin].mean(1) - y[:, oldin].mean(1)
did = farq[muolaja].mean() - farq[~muolaja].mean()
se = np.sqrt(farq[muolaja].var(ddof=1) / muolaja.sum()
+ farq[~muolaja].var(ddof=1) / (~muolaja).sum())Haqiqiy loyihada (ma'lumotnoma; bu muhitda o'rnatilmagan)
# DoWhy - DAG bilan savolni qo'yish, baholash va "rad etish" testlari
from dowhy import CausalModel
model = CausalModel(data=df, treatment="kupon", outcome="xarid",
common_causes=["sodiqlik", "oldingi", "faollik"])
estimand = model.identify_effect()
baho = model.estimate_effect(estimand,
method_name="backdoor.propensity_score_weighting")
rad = model.refute_estimate(estimand, baho, method_name="placebo_treatment_refuter")
# EconML - CATE va double ML
from econml.dml import LinearDML
from econml.metalearners import TLearner
from sklearn.ensemble import HistGradientBoostingRegressor
dml = LinearDML(model_y=HistGradientBoostingRegressor(),
model_t=HistGradientBoostingRegressor(), discrete_treatment=True)
dml.fit(Y, T, X=X_het, W=X_boshqa)
cate = dml.effect(X_het)Qaysi vaziyatda nima
| Vaziyat | Usul | Asosiy faraz |
|---|---|---|
| Tajriba qilish mumkin | RCT / A/B test | tasodifiy taqsimlash |
| Kuzatuv, chalkashtiruvchilar o'lchangan | g-hisoblash, IPW, moslashtirish, AIPW | ignorability + overlap |
| Modellarga to'liq ishonch yo'q | AIPW (+ cross-fitting) | bittasi to'g'ri |
| Guruh va vaqt, oldin/keyin | DiD | parallel trendlar |
| Chegara bo'yicha qaror (ball >= 70) | RDD | chegara atrofida taqqoslanuvchanlik |
| Tasodifiy "turtki" bor | instrumental o'zgaruvchi | turtki faqat T orqali ta'sir qiladi |
| Kimga berish kerak? | uplift (T/S/X-learner) + Qini | RCT ma'lumotida baholash |
Sababiy xulosa xulosasi
savol -> estimand (ATE/ATT/CATE) -> DAG -> nazorat to'plami (orqa eshik)
mediator va kollayderni NAZORAT QILMA
kuzatuv: overlap -> balans (SMD) -> bir necha usul (reg, IPW, AIPW) + bootstrap CI
AIPW: bittasi to'g'ri bo'lsa yetadi; o'lchanmagan U -> hammasi yiqiladi
uplift: javob modeli emas; Qini - RCT da
DiD: parallel trendlar -> placebo tekshiruv, do'kon bo'yicha SE4. Batafsil misollar
Misollar real numpy/statsmodels/sklearn bilan (Python 3.14). Har misol mustaqil ishlaydi; ma'lumot sintetik va haqiqiy ta'sir ma'lum.
Misol 1 — DAG lar simulyatsiyada: chalkashtiruvchi, mediator, kollayder, Simpson
"""DAG lar simulyatsiyada: nimani nazorat qilish kerak va nimani - yo'q."""
import numpy as np
import statsmodels.api as sm
def koef(y, *ustunlar):
"""OLS: birinchi regressor koeffitsienti va SE si."""
r = sm.OLS(y, sm.add_constant(np.column_stack(ustunlar))).fit()
return float(r.params[1]), float(r.bse[1])
def sigmoid(z):
return 1 / (1 + np.exp(-z))
def main() -> None:
rng = np.random.default_rng(0)
n = 20_000
xulosa = []
print("=== 1. Chalkashtiruvchi: sodiqlik -> kupon, sodiqlik -> xarid ===")
sod = rng.normal(0, 1, n)
kupon = (rng.random(n) < sigmoid(1.5 * sod - 0.5)).astype(float)
xarid = 200 + 60 * sod + 30 * kupon + rng.normal(0, 40, n)
naiv = xarid[kupon == 1].mean() - xarid[kupon == 0].mean()
b1, _ = koef(xarid, kupon)
b2, s2 = koef(xarid, kupon, sod)
print(" haqiqiy ta'sir: 30.0 ming so'm")
print(f" sodiqlik o'rtachasi: kupon {sod[kupon == 1].mean():+.2f}, "
f"kuponsiz {sod[kupon == 0].mean():+.2f}")
print(f" naiv farq {naiv:6.1f}")
print(f" xarid ~ kupon + sodiq {b2:6.1f} (SE {s2:.2f})")
xulosa.append(("chalkashtiruvchi", naiv, b2, s2, 30.0))
print("\n=== 2. Mediator: kupon -> tashriflar -> xarid (kupon tasodifiy) ===")
kupon = rng.integers(0, 2, n).astype(float)
tashrif = 2 + 1.5 * kupon + rng.normal(0, 1, n)
xarid = 100 + 20 * tashrif + 10 * kupon + rng.normal(0, 40, n)
b1, s1 = koef(xarid, kupon)
b2, s2 = koef(xarid, kupon, tashrif)
print(" haqiqiy: umumiy ta'sir 10 + 20 * 1.5 = 40.0, bevosita 10.0")
print(f" xarid ~ kupon {b1:6.1f} (SE {s1:.2f}) <- umumiy")
print(f" xarid ~ kupon + tashrif {b2:6.1f} (SE {s2:.2f}) <- faqat bevosita")
xulosa.append(("mediator (umumiy)", b2, b1, s1, 40.0))
print("\n=== 3. Kollayder: kupon -> sharh <- xarid (kupon ta'sir QILMAYDI) ===")
kupon = rng.integers(0, 2, n).astype(float)
xarid = 200 + rng.normal(0, 50, n)
sharh = rng.random(n) < sigmoid(-2 + 1.5 * kupon + 0.04 * (xarid - 200))
b1, s1 = koef(xarid, kupon)
b2, s2 = koef(xarid, kupon, sharh.astype(float))
ichida = (xarid[sharh & (kupon == 1)].mean()
- xarid[sharh & (kupon == 0)].mean())
print(" haqiqiy ta'sir: 0.0")
print(f" hamma mijozlar: xarid ~ kupon {b1:6.1f} (SE {s1:.2f})")
print(f" xarid ~ kupon + sharh {b2:6.1f} (SE {s2:.2f})")
print(f" faqat sharh qoldirganlar ({sharh.mean():.1%}): farq {ichida:6.1f}")
xulosa.append(("kollayder", b2, b1, s1, 0.0))
print("\n=== 4. Simpson paradoksi: segment -> kupon, segment -> konversiya ===")
n2 = 40_000
doimiy = rng.random(n2) < 0.4
kupon = rng.random(n2) < np.where(doimiy, 0.2, 0.7)
p = np.where(doimiy, 0.30, 0.05) + 0.03 * kupon
oldi = rng.random(n2) < p
print(f" {'segment':<10} {'kuponsiz':>9} {'kupon':>7} {'farq':>7} "
f"{'kupon ulushi':>13}")
farqlar, ulushlar = [], []
for nom, s in [("yangi", ~doimiy), ("doimiy", doimiy)]:
k0, k1 = oldi[s & ~kupon].mean(), oldi[s & kupon].mean()
farqlar.append(k1 - k0)
ulushlar.append(s.mean())
print(f" {nom:<10} {k0:>9.3f} {k1:>7.3f} {k1 - k0:>+7.3f} "
f"{kupon[s].mean():>13.2f}")
u0, u1 = oldi[~kupon].mean(), oldi[kupon].mean()
print(f" {'UMUMIY':<10} {u0:>9.3f} {u1:>7.3f} {u1 - u0:>+7.3f} "
f"{kupon.mean():>13.2f}")
standart = float(np.dot(farqlar, ulushlar))
print(f" standartlangan (segment ulushlari bilan): {standart:+.3f} "
f"(haqiqiy +0.030)")
print("\n=== 5. Xulosa (natijadan hisoblangan) ===")
for nom, yomon, yaxshi, se, haq in xulosa:
print(f" {nom:<18} noto'g'ri tanlov {yomon:6.1f}, to'g'ri {yaxshi:6.1f}"
f" (haqiqiy {haq:.1f}); to'g'ri 2*SE ichida: "
f"{abs(yaxshi - haq) <= 2 * se}")
print(" ⭐ Nazorat to'plamini DAG hal qiladi, ma'lumot emas")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Chalkashtiruvchi: sodiqlik -> kupon, sodiqlik -> xarid ===
haqiqiy ta'sir: 30.0 ming so'm
sodiqlik o'rtachasi: kupon +0.63, kuponsiz -0.43
naiv farq 94.4
xarid ~ kupon + sodiq 31.1 (SE 0.67)
=== 2. Mediator: kupon -> tashriflar -> xarid (kupon tasodifiy) ===
haqiqiy: umumiy ta'sir 10 + 20 * 1.5 = 40.0, bevosita 10.0
xarid ~ kupon 39.2 (SE 0.63) <- umumiy
xarid ~ kupon + tashrif 9.1 (SE 0.70) <- faqat bevosita
=== 3. Kollayder: kupon -> sharh <- xarid (kupon ta'sir QILMAYDI) ===
haqiqiy ta'sir: 0.0
hamma mijozlar: xarid ~ kupon 0.7 (SE 0.71)
xarid ~ kupon + sharh -11.9 (SE 0.59)
faqat sharh qoldirganlar (32.6%): farq -14.4
=== 4. Simpson paradoksi: segment -> kupon, segment -> konversiya ===
segment kuponsiz kupon farq kupon ulushi
yangi 0.052 0.081 +0.029 0.70
doimiy 0.301 0.335 +0.034 0.20
UMUMIY 0.211 0.121 -0.090 0.50
standartlangan (segment ulushlari bilan): +0.031 (haqiqiy +0.030)
=== 5. Xulosa (natijadan hisoblangan) ===
chalkashtiruvchi noto'g'ri tanlov 94.4, to'g'ri 31.1 (haqiqiy 30.0); to'g'ri 2*SE ichida: True
mediator (umumiy) noto'g'ri tanlov 9.1, to'g'ri 39.2 (haqiqiy 40.0); to'g'ri 2*SE ichida: True
kollayder noto'g'ri tanlov -11.9, to'g'ri 0.7 (haqiqiy 0.0); to'g'ri 2*SE ichida: True
⭐ Nazorat to'plamini DAG hal qiladi, ma'lumot emasNatija tahlili.
1-bo'lim — chalkashtiruvchi. Kupon olganlarning o'rtacha sodiqligi +0.63, olmaganlarniki -0.43 — tizim kuponni sodiq mijozlarga ko'proq bergan. Naiv farq 94.4 ming so'm — haqiqiy ta'sirdan (30) uch barobar katta: farqning katta qismi kupondan emas, sodiqlikdan. Sodiqlikni nazorat qilgach (xarid ~ kupon + sodiqlik) 31.1 (SE 0.67) — orqa eshik yopildi.
2-bo'lim — mediator. Kupon tasodifiy berilgan (RCT), shuning uchun oddiy regressiya 39.2 — umumiy ta'sirni (40) to'g'ri beradi. "Ko'proq nazorat — yaxshiroq" degan fikr bilan tashriflar sonini qo'shsak, koeffitsient 9.1 ga tushadi — bu faqat bevosita ta'sir (tashrif orqali o'tmaydigan qism). Marketing uchun "kupon xaridni qanchaga oshiradi" savoliga bu javob uch barobar kam baholaydi. Mediatorni nazorat qilish faqat "ta'sir qaysi yo'l bilan o'tadi" degan boshqa savolga javob beradi.
3-bo'lim — kollayder. Kupon xaridga umuman ta'sir qilmaydi, butun ma'lumotda farq 0.7 (SE 0.71) — to'g'ri. Lekin sharh qoldirish kupondan ham, katta xariddan ham kelib chiqadi. Faqat sharh qoldirganlarni (32.6%) tahlil qilsak — kupon "xaridni 14.4 ming so'mga kamaytiradi". Mantiq: sharh qoldirgan kuponsiz mijoz buni katta xarid tufayli qilgan bo'lishi ehtimoli yuqori; kupon oluvchida esa sharh uchun boshqa sabab bor. Regressiyaga sharhni qo'shish ham xuddi shu soxta ta'sirni beradi (-11.9). Amalda bu juda ko'p uchraydi: "faqat ilovani o'rnatganlar", "faqat so'rovnomaga javob berganlar" — tanlov o'zi kollayder bo'lishi mumkin.
4-bo'lim — Simpson paradoksi. Har ikkala segmentda kupon konversiyani oshiradi (+0.029 va +0.034), lekin umumiy jadvalda kupon olganlar konversiyasi past (0.121 va 0.211, farq -0.090). Sabab: kuponlarning 70% i past konversiyali yangi mijozlarga berilgan. Segment kuponga sabab bo'lgani uchun to'g'ri javob — segment ichidagi farqlar, segment ulushlari bilan standartlangan: +0.031 (haqiqiy +0.030).
5-bo'lim jadvali uchta holatni bitta qatorda ko'rsatadi: bir xil ma'lumot, bir xil regressiya — faqat qaysi o'zgaruvchi nazorat qilingani o'zgardi, va javob butunlay o'zgardi. To'g'ri tanlov har safar haqiqiy qiymatning 2*SE oralig'ida.
Misol 2 — Kupon ta'siri: naiv farq, regressiya, moslashtirish, IPW va AIPW
"""Kupon ta'siri kuzatuv ma'lumotida: usullarni haqiqiy ATE/ATT bilan solishtirish."""
import numpy as np
from sklearn.linear_model import LinearRegression, LogisticRegression
from sklearn.neighbors import NearestNeighbors
USTUNLAR = ["sodiqlik", "log_oldingi", "faollik", "toshkent"]
MAQSAD = {"naiv farq": "ATE", "regressiya T+X": "ATE", "g-hisoblash": "ATE",
"moslashtirish": "ATT", "IPW": "ATE", "IPW ATT": "ATT",
"IPW kesilgan": "ATE", "AIPW": "ATE"}
def yarat(seed, n=4000):
"""Sodiq mijozlar kuponni ko'proq oladi va kuponsiz ham ko'p xarid qiladi."""
rng = np.random.default_rng(seed)
sod = rng.normal(0, 1, n)
oldingi = rng.poisson(np.exp(1.0 + 0.5 * sod))
faol = rng.normal(0, 1, n)
toshkent = (rng.random(n) < 0.45).astype(float)
X = np.column_stack([sod, np.log1p(oldingi), faol, toshkent])
logit = -0.6 + 1.3 * sod + 0.4 * np.log1p(oldingi) + 0.5 * faol - 0.3 * toshkent
T = (rng.random(n) < 1 / (1 + np.exp(-logit))).astype(int)
tau = 40 - 15 * sod + 8 * faol # sodiqlarga kam ta'sir
y0 = 180 + 55 * sod + 20 * np.log1p(oldingi) + 15 * faol + 20 * toshkent
Y = y0 + tau * T + rng.normal(0, 60, n) # ming so'm
return X, T, Y, tau
def propensity(X, T):
return LogisticRegression(C=1e6, max_iter=1000).fit(X, T).predict_proba(X)[:, 1]
def usullar(X, T, Y):
e = propensity(X, T)
b = {"naiv farq": Y[T == 1].mean() - Y[T == 0].mean()}
b["regressiya T+X"] = LinearRegression().fit(
np.column_stack([T, X]), Y).coef_[0]
mu1 = LinearRegression().fit(X[T == 1], Y[T == 1]).predict(X)
mu0 = LinearRegression().fit(X[T == 0], Y[T == 0]).predict(X)
b["g-hisoblash"] = np.mean(mu1 - mu0)
lg = np.log(e / (1 - e))
nn = NearestNeighbors(n_neighbors=1).fit(lg[T == 0, None])
d, j = nn.kneighbors(lg[T == 1, None])
ok = d[:, 0] <= 0.2 * lg.std()
b["moslashtirish"] = np.mean(Y[T == 1][ok] - Y[T == 0][j[ok, 0]])
def hajek(e_):
w1, w0 = T / e_, (1 - T) / (1 - e_)
return np.sum(w1 * Y) / np.sum(w1) - np.sum(w0 * Y) / np.sum(w0)
b["IPW"] = hajek(e)
w0 = (1 - T) * e / (1 - e)
b["IPW ATT"] = Y[T == 1].mean() - np.sum(w0 * Y) / np.sum(w0)
b["IPW kesilgan"] = hajek(np.clip(e, 0.05, 0.95))
psi = mu1 - mu0 + T * (Y - mu1) / e - (1 - T) * (Y - mu0) / (1 - e)
b["AIPW"] = psi.mean()
return {k: float(v) for k, v in b.items()}, e, float(ok.mean())
def smd(x, T, w):
m1 = np.average(x[T == 1], weights=w[T == 1])
m0 = np.average(x[T == 0], weights=w[T == 0])
return (m1 - m0) / np.sqrt((x[T == 1].var() + x[T == 0].var()) / 2)
def main() -> None:
X, T, Y, tau = yarat(0)
ate, att = tau.mean(), tau[T == 1].mean()
haq = {"ATE": ate, "ATT": att}
print("=== 1. Ma'lumot (urug' 0): kim kupon oldi? ===")
print(f" n={len(T)}, kupon olganlar ulushi {T.mean():.3f}")
print(f" haqiqiy ATE {ate:.2f}, ATT {att:.2f} ming so'm "
f"(sodiqlarga ta'sir kam -> ATT < ATE)")
print("\n=== 2. Overlap va balans ===")
b, e, moslandi = usullar(X, T, Y)
for g, nom in [(1, "kupon"), (0, "kuponsiz")]:
q = np.quantile(e[T == g], [0, 0.05, 0.5, 0.95, 1])
print(f" {nom:<8} e: min {q[0]:.3f} 5% {q[1]:.3f} med {q[2]:.3f} "
f"95% {q[3]:.3f} max {q[4]:.3f}")
print(f" e < 0.05 yoki e > 0.95: {np.mean((e < 0.05) | (e > 0.95)):.3f} ulush")
w = T / e + (1 - T) / (1 - e)
for g, nom in [(1, "kupon"), (0, "kuponsiz")]:
wg = w[T == g]
print(f" {nom:<8} maks og'irlik {wg.max():6.1f}, ESS "
f"{wg.sum() ** 2 / (wg ** 2).sum():6.0f} / {len(wg)}")
print(f" moslashtirish: caliper ichida {moslandi:.3f} kupon oluvchi")
print(f" {'belgi':<12} {'SMD xom':>8} {'SMD IPW':>8}")
bir = np.ones(len(T))
for j, u in enumerate(USTUNLAR):
print(f" {u:<12} {smd(X[:, j], T, bir):>+8.3f} "
f"{smd(X[:, j], T, w):>+8.3f}")
print("\n=== 3. Usullar (urug' 0) va bootstrap 95% CI (200 takror) ===")
rng = np.random.default_rng(123)
bs = {k: [] for k in b}
for _ in range(200):
i = rng.integers(0, len(T), len(T))
bi, _, _ = usullar(X[i], T[i], Y[i])
for k in bi:
bs[k].append(bi[k])
print(f" {'usul':<15} {'maqsad':>6} {'baho':>7} {'95% CI':>17} "
f"{'haqiqiy':>8} {'qamradi':>8}")
for k, v in b.items():
lo, hi = np.percentile(bs[k], [2.5, 97.5])
h = haq[MAQSAD[k]]
print(f" {k:<15} {MAQSAD[k]:>6} {v:>7.2f} [{lo:>6.2f}, {hi:>6.2f}] "
f"{h:>8.2f} {str(lo <= h <= hi):>8}")
print("\n=== 4. 30 urug': xato = baho - haqiqiy (o'z maqsadiga nisbatan) ===")
xato = {k: [] for k in MAQSAD}
for s in range(1, 31):
X, T, Y, tau = yarat(s)
bi, _, _ = usullar(X, T, Y)
h = {"ATE": tau.mean(), "ATT": tau[T == 1].mean()}
for k in bi:
xato[k].append(bi[k] - h[MAQSAD[k]])
print(f" {'usul':<15} {'o_rt xato':>9} {'SE':>6} {'RMSE':>7} {'siljigan':>9}")
siljimagan = []
for k in MAQSAD:
x = np.array(xato[k])
se = x.std(ddof=1) / np.sqrt(len(x))
rmse = float(np.sqrt(np.mean(x ** 2)))
silj = abs(x.mean()) > 2 * se
if not silj:
siljimagan.append((rmse, k))
print(f" {k:<15} {x.mean():>+9.2f} {se:>6.2f} {rmse:>7.2f} "
f"{str(silj):>9}")
siljimagan.sort()
print(f" siljimaganlar ichida eng kichik RMSE: {siljimagan[0][1]} "
f"({siljimagan[0][0]:.2f})")
print(" ⭐ Naiv farq - chalkashtirish; tuzatish - faqat o'lchangan X bo'yicha")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ma'lumot (urug' 0): kim kupon oldi? ===
n=4000, kupon olganlar ulushi 0.452
haqiqiy ATE 40.22, ATT 33.17 ming so'm (sodiqlarga ta'sir kam -> ATT < ATE)
=== 2. Overlap va balans ===
kupon e: min 0.014 5% 0.187 med 0.647 95% 0.943 max 0.992
kuponsiz e: min 0.003 5% 0.043 med 0.267 95% 0.759 max 0.970
e < 0.05 yoki e > 0.95: 0.056 ulush
kupon maks og'irlik 69.1, ESS 753 / 1808
kuponsiz maks og'irlik 32.8, ESS 1251 / 2192
moslashtirish: caliper ichida 0.992 kupon oluvchi
belgi SMD xom SMD IPW
sodiqlik +1.187 -0.024
log_oldingi +0.762 -0.009
faollik +0.311 +0.031
toshkent -0.071 +0.017
=== 3. Usullar (urug' 0) va bootstrap 95% CI (200 takror) ===
usul maqsad baho 95% CI haqiqiy qamradi
naiv farq ATE 102.44 [ 98.01, 107.43] 40.22 False
regressiya T+X ATE 40.01 [ 35.84, 44.25] 40.22 True
g-hisoblash ATE 40.89 [ 36.78, 45.32] 40.22 True
moslashtirish ATT 32.95 [ 28.23, 42.67] 33.17 True
IPW ATE 38.05 [ 29.59, 47.06] 40.22 True
IPW ATT ATT 35.01 [ 28.03, 43.73] 33.17 True
IPW kesilgan ATE 41.52 [ 35.23, 48.12] 40.22 True
AIPW ATE 38.32 [ 32.30, 44.09] 40.22 True
=== 4. 30 urug': xato = baho - haqiqiy (o'z maqsadiga nisbatan) ===
usul o_rt xato SE RMSE siljigan
naiv farq +62.57 0.39 62.61 True
regressiya T+X -0.57 0.37 2.07 False
g-hisoblash +0.41 0.38 2.07 False
moslashtirish +0.51 0.72 3.91 False
IPW +0.49 0.55 3.00 False
IPW ATT +1.11 0.81 4.50 False
IPW kesilgan +3.69 0.51 4.59 True
AIPW +0.38 0.45 2.44 False
siljimaganlar ichida eng kichik RMSE: g-hisoblash 2.07-bob
⭐ Naiv farq - chalkashtirish; tuzatish - faqat o'lchangan X bo'yichaNatija tahlili.
1-bo'lim — mijozlarning 45.2% i kupon olgan. Haqiqiy ATE 40.22, ATT 33.17 ming so'm: kupon asosan sodiq mijozlarga borgan, ularga esa ta'sir kichikroq — shuning uchun "kupon olganlar uchun ta'sir" (ATT) "hamma uchun ta'sir" dan (ATE) past.
2-bo'lim — overlap va balans. Propensity taqsimotlari keng ustma-ust tushadi, lekin chetlar bor: kupon olganlarda eng kichik e = 0.014, kuponsizlarda eng katta 0.970; 5.6% qator [0.05, 0.95] dan tashqarida. IPW og'irliklarining maksimumi 69.1 — bitta mijoz 69 kishi uchun "gapiradi"; samarali namuna hajmi kupon olganlarda 1808 dan 753 ga tushdi. Balans: xom ma'lumotda sodiqlik bo'yicha SMD +1.187 (juda katta nomutanosiblik), IPW dan keyin -0.024; hamma belgi |SMD| < 0.1 — propensity modeli o'z vazifasini bajargan. Moslashtirishda kupon oluvchilarning 99.2% i caliper ichida juft topdi.
3-bo'lim — bitta ma'lumotda baholar va bootstrap CI (propensity modeli har bootstrap namunasida qayta o'qitildi). Naiv farq 102.44, CI [98.01, 107.43] — haqiqiy ATE (40.22) dan juda uzoq va CI uni qamramaydi: katta namuna "aniq noto'g'ri" javob beradi. Qolgan hamma usul o'z maqsadini qamradi. CI kengligiga e'tibor bering: g-hisoblash ~8.5, AIPW ~11.8, IPW ~17.5 — og'irliklar ekstremal bo'lsa, IPW eng shovqinli. Moslashtirish va IPW ATT ATT ni (33.17) baholaydi — ularni ATE bilan solishtirish xato bo'lardi.
4-bo'lim — 30 ta mustaqil ma'lumotda. Naiv farq o'rtacha +62.57 ga siljigan — tasodif emas, tizimli xato. Regressiya (-0.57), g-hisoblash (+0.41), moslashtirish, IPW va AIPW — sezilarli siljish yo'q. Kesilgan IPW esa +3.69 ga siljigan: e ni [0.05, 0.95] ga kesish og'irliklarni o'zgartiradi, va baholanadigan kattalik endi aniq ATE emas — dispersiya bilan siljish almashtirildi. RMSE bo'yicha g-hisoblash va oddiy regressiya eng yaxshi (2.07), AIPW 2.44, IPW 3.00. Bu ma'lumotda natija modeli (chiziqli) haqiqatga yaqin, shuning uchun unga tayanadigan usullar eng aniq. Ta'sir sodiqlikka bog'liq bo'lsa ham, T + X regressiyasining siljishi bu yerda sezilarli chiqmadi; lekin umuman olganda u ATE emas, balki vaznlangan o'rtachani baholaydi. Keyingi misolda natija modeli noto'g'ri bo'lganda bu tartib qanday o'zgarishini ko'ramiz.
Misol 3 — Mustahkamlik: noto'g'ri modellar, o'lchanmagan chalkashtiruvchi, kuchsiz overlap
"""Ikki karra mustahkamlik, o'lchanmagan chalkashtiruvchi va overlap - 30 urug'da."""
import numpy as np
from sklearn.linear_model import LinearRegression, LogisticRegression
HAQIQIY = 20.0
USULLAR = ["regressiya", "IPW", "IPW kesilgan", "AIPW"]
def yarat(rng, n, kuch=1.0, u_kuch=0.0):
"""x1 ning kvadrati ham tanlashga, ham natijaga ta'sir qiladi; u - yashirin."""
x1, x2, u = rng.normal(0, 1, (3, n))
logit = kuch * (-0.8 + 0.8 * x1 + 0.7 * (x1 ** 2 - 1) + 0.5 * x2) + u_kuch * u
T = (rng.random(n) < 1 / (1 + np.exp(-logit))).astype(int)
Y = (100 + 20 * x1 + 25 * (x1 ** 2 - 1) + 10 * x2 + 25 * u_kuch * u
+ HAQIQIY * T + rng.normal(0, 30, n))
return x1, x2, T, Y
def baholar(Xn, Xp, T, Y):
"""Xn - natija modeli belgilari, Xp - propensity modeli belgilari."""
e = LogisticRegression(C=1e6, max_iter=1000).fit(Xp, T).predict_proba(Xp)[:, 1]
e = np.clip(e, 1e-6, 1 - 1e-6) # faqat 0 ga bo'lishdan saqlanish
mu1 = LinearRegression().fit(Xn[T == 1], Y[T == 1]).predict(Xn)
mu0 = LinearRegression().fit(Xn[T == 0], Y[T == 0]).predict(Xn)
def hajek(e_):
w1, w0 = T / e_, (1 - T) / (1 - e_)
return np.sum(w1 * Y) / np.sum(w1) - np.sum(w0 * Y) / np.sum(w0)
psi = mu1 - mu0 + T * (Y - mu1) / e - (1 - T) * (Y - mu0) / (1 - e)
w = T / e + (1 - T) / (1 - e)
return ({"regressiya": np.mean(mu1 - mu0), "IPW": hajek(e),
"IPW kesilgan": hajek(np.clip(e, 0.05, 0.95)), "AIPW": psi.mean()},
float(w.max()), float(w.sum() ** 2 / (w ** 2).sum() / len(w)))
def tajriba(kuch, u_kuch, natija_togri, ps_togri, urug=30, n=3000):
xatolar = {k: [] for k in USULLAR}
maks_w, ess = [], []
for s in range(urug):
rng = np.random.default_rng(s)
x1, x2, T, Y = yarat(rng, n, kuch, u_kuch)
togri = np.column_stack([x1, x1 ** 2, x2])
notogri = np.column_stack([x1, x2])
b, mw, es = baholar(togri if natija_togri else notogri,
togri if ps_togri else notogri, T, Y)
for k in USULLAR:
xatolar[k].append(b[k] - HAQIQIY)
maks_w.append(mw)
ess.append(es)
return ({k: np.array(v) for k, v in xatolar.items()},
float(np.median(maks_w)), float(np.mean(ess)))
def katak(x):
se = x.std(ddof=1) / np.sqrt(len(x))
belgi = "*" if abs(x.mean()) > 2 * se else " "
return f"{x.mean():+6.1f}{belgi}({x.std(ddof=1):4.1f})"
def main() -> None:
print("=== 1. Ikki karra mustahkamlik: 30 urug', haqiqiy ATE = 20 ===")
print(" katak: o'rtacha xato, * - sezilarli siljish (> 2 SE), (std)")
ssenariylar = [
("ikkala model to'g'ri", 1.0, 0.0, True, True),
("natija modeli xato", 1.0, 0.0, False, True),
("propensity xato", 1.0, 0.0, True, False),
("ikkalasi xato", 1.0, 0.0, False, False),
]
print(f" {'ssenariy':<22}" + "".join(f"{k:>15}" for k in USULLAR))
for nom, *arg in ssenariylar:
x, _, _ = tajriba(*arg)
print(f" {nom:<22}" + "".join(f"{katak(x[k]):>15}" for k in USULLAR))
print("\n=== 2. Kuchsiz overlap: tanlash 3 barobar kuchli (modellar to'g'ri) ===")
for nom, kuch in [("oddiy tanlash", 1.0), ("kuchli tanlash", 3.0)]:
x, mw, ess = tajriba(kuch, 0.0, True, True)
print(f" {nom:<16} maks og'irlik (mediana) {mw:8.1f}, ESS ulushi "
f"{ess:.3f}")
print(" " + " ".join(f"{k}: {katak(x[k])}" for k in USULLAR[1:]))
print("\n=== 3. O'lchanmagan chalkashtiruvchi u (modellar x bo'yicha to'g'ri) ===")
print(f" {'u kuchi':>8}" + "".join(f"{k:>15}" for k in USULLAR))
for u_kuch in [0.0, 0.25, 0.5, 1.0]:
x, _, _ = tajriba(1.0, u_kuch, True, True)
print(f" {u_kuch:>8}" + "".join(f"{katak(x[k]):>15}" for k in USULLAR))
x, _, _ = tajriba(1.0, 1.0, True, True)
hammasi = all(abs(x[k].mean()) > 2 * x[k].std(ddof=1) / np.sqrt(30)
for k in USULLAR)
print(f" u kuchi 1.0 da hamma usul sezilarli siljigan: {hammasi}")
print(" ⭐ AIPW: bittasi to'g'ri bo'lsa yetadi; yashirin u ga qarshi - ojiz")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ikki karra mustahkamlik: 30 urug', haqiqiy ATE = 20 ===
katak: o'rtacha xato, * - sezilarli siljish (> 2 SE), (std)
ssenariy regressiya IPW IPW kesilgan AIPW
ikkala model to'g'ri +0.2 ( 1.7) +1.2 ( 4.2) +3.1*( 2.1) +0.2 ( 2.0)
natija modeli xato +27.4*( 2.1) +1.2 ( 4.2) +3.1*( 2.1) +1.2 ( 4.2)
propensity xato +0.2 ( 1.7) +34.4*( 3.9) +32.1*( 2.4) +0.3 ( 1.8)
ikkalasi xato +27.4*( 2.1) +34.4*( 3.9) +32.1*( 2.4) +47.8*( 6.4)
=== 2. Kuchsiz overlap: tanlash 3 barobar kuchli (modellar to'g'ri) ===
oddiy tanlash maks og'irlik (mediana) 30.0, ESS ulushi 0.533
IPW: +1.2 ( 4.2) IPW kesilgan: +3.1*( 2.1) AIPW: +0.2 ( 2.0)
kuchli tanlash maks og'irlik (mediana) 385.9, ESS ulushi 0.047
IPW: +7.2*11.7-bob IPW kesilgan: +29.5*( 3.1) AIPW: +2.2 10.4-bob
=== 3. O'lchanmagan chalkashtiruvchi u (modellar x bo'yicha to'g'ri) ===
u kuchi regressiya IPW IPW kesilgan AIPW
0.0 +0.2 ( 1.7) +1.2 ( 4.2) +3.1*( 2.1) +0.2 ( 2.0)
0.25 +1.6*( 1.8) +2.8*( 3.8) +4.5*( 2.0) +1.6*( 2.0)
0.5 +5.9*( 1.8) +7.0*( 3.8) +8.7*( 2.1) +5.9*( 2.0)
1.0 +20.8*( 1.8) +22.5*( 2.4) +23.2*( 1.8) +21.0*( 1.8)
u kuchi 1.0 da hamma usul sezilarli siljigan: True
⭐ AIPW: bittasi to'g'ri bo'lsa yetadi; yashirin u ga qarshi - ojizNatija tahlili.
Bu misolda x1^2 ham kupon olishga, ham natijaga ta'sir qiladi. "To'g'ri" model x1^2 ni o'z ichiga oladi, "xato" model — yo'q (amalda: nochiziqlikni unutish). Har katak — 30 urug' bo'yicha o'rtacha xato va std.
1-bo'lim — ikki karra mustahkamlik jadvalda:
- Ikkala model to'g'ri — regressiya va AIPW siljimagan (
+0.2), IPW siljimagan, lekin std ikki barobar katta (4.2va2.0). Kesilgan IPW+3.1— 2-misoldagi kabi, kesish baholanadigan kattalikni o'zgartiradi. - Natija modeli xato — regressiya
+27.4ga siljidi (haqiqiy ta'sirdan ham katta!). AIPW+1.2— siljish yo'q: to'g'ri propensity natija modeli xatosini tuzatdi. - Propensity xato — IPW
+34.4, kesilgan IPW+32.1; AIPW+0.3— to'g'ri natija modeli uni qutqardi. - Ikkalasi xato — AIPW
+47.8— hammasidan yomon. Ikki karra mustahkamlik "ikkitadan bittasi" kafolati, "ikkalasi xato bo'lsa ham" emas; bu holda tuzatish hadi xatoni hatto kuchaytirishi mumkin (adabiyotda Kang va Schafer misoli bilan mashhur).
2-bo'lim — overlap. Tanlash 3 barobar kuchaytirilganda propensity 0 va 1 ga yaqinlashdi: maksimal og'irlik mediana 30.0 dan 385.9 ga, samarali namuna ulushi 0.533 dan 0.047 ga tushdi — 3000 qatordan faqat ~140 tasi "ishlayapti". IPW std 4.2 dan 11.7 ga, AIPW std 2.0 dan 10.4 ga oshdi va IPW +7.2 ga siljidi. Kesilgan IPW barqarorroq (std 3.1), lekin +29.5 ga siljigan — overlap bo'lmagan hududda ma'lumot yo'q, va hech qanday formula uni yaratib bera olmaydi. Halol yo'l: overlap hududini aniqlash va ta'sirni faqat shu hudud uchun e'lon qilish.
3-bo'lim — o'lchanmagan chalkashtiruvchi u. Hamma model x bo'yicha to'g'ri. u kuchi oshgan sari hamma usul bir xilda siljiydi: 0.25 da +1.6, 0.5 da +5.9, 1.0 da +20.8 — +23.2 (ta'sirning o'zi 20!). AIPW ning ikki karra mustahkamligi bu yerda yordam bermaydi: ikkala model ham x bo'yicha to'g'ri, lekin u ni ko'rmaydi. Va eng yomoni — hech bir diagnostika buni ko'rsatmaydi: x bo'yicha balans mukammal bo'ladi. Yagona himoya — domen bilimi (qaysi chalkashtiruvchi yetishmayapti?), sezgirlik tahlili (shu jadval — "u qanchalik kuchli bo'lsa, xulosa o'zgaradi?") va imkon bo'lsa, tajriba.
Misol 4 — Uplift modellashtirish (T/S-learner, Qini) va farqlar farqi
"""Kimga kupon berish (uplift, Qini) va aksiya ta'siri farqlar farqi bilan."""
import numpy as np
from sklearn.ensemble import HistGradientBoostingClassifier
def sigmoid(z):
return 1 / (1 + np.exp(-z))
def uplift_malumot(rng, n):
"""RCT: kupon 50% tasodifiy. Ta'sir narxga sezgir va yangi mijozlarda katta."""
sod = rng.normal(0, 1, n)
sezgir = rng.normal(0, 1, n)
faol = rng.normal(0, 1, n)
yangi = (rng.random(n) < 0.3).astype(float)
X = np.column_stack([sod, sezgir, faol, yangi])
z0 = -1.2 + 1.0 * sod + 0.5 * faol - 0.3 * yangi
delta = -0.1 + 0.8 * sezgir + 0.7 * yangi - 0.5 * sod
T = rng.integers(0, 2, n)
p0, p1 = sigmoid(z0), sigmoid(z0 + delta)
Y = (rng.random(n) < np.where(T == 1, p1, p0)).astype(int)
return X, T, Y, p1 - p0
def model():
return HistGradientBoostingClassifier(max_iter=150, learning_rate=0.05,
max_leaf_nodes=15, min_samples_leaf=50,
random_state=0)
def qini(uplift, T, Y):
"""Qini egri chizig'i: top-k ga kupon berilsa qo'shimcha xaridlar."""
t = np.argsort(-uplift, kind="stable")
T, Y = T[t], Y[t]
n1, n0 = np.cumsum(T), np.cumsum(1 - T)
q = np.cumsum(Y * T) - np.cumsum(Y * (1 - T)) * n1 / np.maximum(n0, 1)
k = np.arange(1, len(T) + 1)
return float(np.mean(q - q[-1] * k / len(T))), q
def did(y, muolaja, oldin, keyin):
"""Do'kon darajasida DiD va SE (do'kon bo'yicha klaster)."""
farq = y[:, keyin].mean(1) - y[:, oldin].mean(1)
a, b = farq[muolaja], farq[~muolaja]
return (a.mean() - b.mean(),
np.sqrt(a.var(ddof=1) / len(a) + b.var(ddof=1) / len(b)))
def did_malumot(rng, parallel):
hafta = np.arange(1, 53)
muolaja = np.arange(24) < 12 # 12 Samarqand do'koni
daraja = np.where(muolaja, 80.0, 120.0) + rng.normal(0, 8, 24)
y = (daraja[:, None] + 0.3 * hafta + 8 * np.sin(2 * np.pi * hafta / 52)
+ 12.0 * (muolaja[:, None] & (hafta >= 27))
+ rng.normal(0, 4, (24, 52)))
if not parallel:
y += 0.35 * hafta * muolaja[:, None] # Samarqand tezroq o'sadi
return y, muolaja, hafta
def main() -> None:
rng = np.random.default_rng(0)
Xtr, Ttr, Ytr, _ = uplift_malumot(rng, 20_000)
Xte, Tte, Yte, tau = uplift_malumot(rng, 20_000)
print("=== 1. Uplift: RCT ma'lumoti (o'quv 20 000, test 20 000) ===")
ate = Yte[Tte == 1].mean() - Yte[Tte == 0].mean()
print(f" o'rtacha uplift: haqiqiy {tau.mean():+.4f}, test RCT bahosi "
f"{ate:+.4f}")
print(f" ishontiriladigan (tau > 0.05) {np.mean(tau > 0.05):.3f}, "
f"'bezovta qilma' (tau < -0.02) {np.mean(tau < -0.02):.3f}")
javob = model().fit(Xtr, Ytr).predict_proba(Xte)[:, 1]
f1 = model().fit(Xtr[Ttr == 1], Ytr[Ttr == 1]).predict_proba(Xte)[:, 1]
f0 = model().fit(Xtr[Ttr == 0], Ytr[Ttr == 0]).predict_proba(Xte)[:, 1]
s = model().fit(np.column_stack([Xtr, Ttr]), Ytr)
s_up = (s.predict_proba(np.column_stack([Xte, np.ones(len(Xte))]))[:, 1]
- s.predict_proba(np.column_stack([Xte, np.zeros(len(Xte))]))[:, 1])
bashorat = {"tasodifiy": rng.random(len(Tte)), "javob modeli": javob,
"S-learner": s_up, "T-learner": f1 - f0, "oracle (haqiqiy)": tau}
print("\n=== 2. Qini: test to'plamida ===")
k30 = int(0.3 * len(Tte))
print(f" {'model':<17} {'Qini maydoni':>12} {'top-30% qo_sh.':>15} "
f"{'corr(tau)':>10}")
for nom, u in bashorat.items():
maydon, q = qini(u, Tte, Yte)
print(f" {nom:<17} {maydon:>12.1f} {q[k30 - 1]:>15.1f} "
f"{np.corrcoef(u, tau)[0, 1]:>10.3f}")
print(f" hammaga kupon ({len(Tte):,} ta): qo'shimcha xaridlar "
f"{qini(tau, Tte, Yte)[1][-1]:.1f}")
print("\n=== 3. Juftlashgan bootstrap (200): Qini maydoni farqi ===")
b_rng = np.random.default_rng(1)
juftlar = [("T-learner", "S-learner"), ("T-learner", "javob modeli")]
farqlar = {j: [] for j in juftlar}
for _ in range(200):
i = b_rng.integers(0, len(Tte), len(Tte))
m = {nom: qini(bashorat[nom][i], Tte[i], Yte[i])[0]
for nom in ["T-learner", "S-learner", "javob modeli"]}
for a, b in juftlar:
farqlar[(a, b)].append(m[a] - m[b])
for (a, b), v in farqlar.items():
v = np.array(v)
print(f" {a} - {b}: {v.mean():+.1f} (SE {v.std(ddof=1):.1f}), "
f"sezilarli: {abs(v.mean()) > 2 * v.std(ddof=1)}")
ts = np.array(farqlar[("T-learner", "S-learner")])
if ts.mean() > 2 * ts.std(ddof=1):
print(" tanlov: T-learner (S-learner sezilarli yomon)")
elif ts.mean() < -2 * ts.std(ddof=1):
print(" tanlov: S-learner (sezilarli yaxshi va soddaroq - bitta model)")
else:
print(" tanlov: S-learner (sodda, T dan sezilarli yomon emas)")
print("\n=== 4. Farqlar farqi: aksiya Samarqandda 27-haftadan, haqiqiy +12 ===")
for nom, parallel in [("parallel trendlar", True), ("trendlar farqli", False)]:
y, muolaja, hafta = did_malumot(np.random.default_rng(5), parallel)
oldin, keyin = hafta < 27, hafta >= 27
oldin_keyin = (y[muolaja][:, keyin].mean()
- y[muolaja][:, oldin].mean())
keyin_farq = y[muolaja][:, keyin].mean() - y[~muolaja][:, keyin].mean()
d, se = did(y, muolaja, oldin, keyin)
p, pse = did(y[:, :26], muolaja, hafta[:26] < 14, hafta[:26] >= 14)
print(f" [{nom}]")
print(f" naiv oldin-keyin {oldin_keyin:+6.1f}, naiv shaharlar farqi "
f"{keyin_farq:+6.1f}")
print(f" DiD {d:+6.2f} (SE {se:.2f}); placebo (1-26 hafta, soxta "
f"14-hafta) {p:+5.2f} (SE {pse:.2f})")
print(f" parallel trend tekshiruvi o'tdi: {abs(p) <= 2 * pse}; "
f"DiD 2*SE ichida +12 ga: {abs(d - 12) <= 2 * se}")
print(" ⭐ Uplift - RCT da baholanadi; DiD - placebo bilan tekshiriladi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Uplift: RCT ma'lumoti (o'quv 20 000, test 20 000) ===
o'rtacha uplift: haqiqiy +0.0150, test RCT bahosi +0.0134
ishontiriladigan (tau > 0.05) 0.391, 'bezovta qilma' (tau < -0.02) 0.395
=== 2. Qini: test to'plamida ===
model Qini maydoni top-30% qo_sh. corr(tau)
tasodifiy -20.2 8.3 -0.016
javob modeli -19.6 15.4 -0.023
S-learner 464.0 593.7 0.952
T-learner 447.0 562.6 0.917
oracle (haqiqiy) 476.6 647.9 1.000
hammaga kupon (20,000 ta): qo'shimcha xaridlar 135.1
=== 3. Juftlashgan bootstrap (200): Qini maydoni farqi ===
T-learner - S-learner: -16.8 (SE 8.0), sezilarli: True
T-learner - javob modeli: +466.2 (SE 27.4), sezilarli: True
tanlov: S-learner (sezilarli yaxshi va soddaroq - bitta model)
=== 4. Farqlar farqi: aksiya Samarqandda 27-haftadan, haqiqiy +12 ===
[parallel trendlar]
naiv oldin-keyin +10.0, naiv shaharlar farqi -25.5
DiD +12.77 (SE 0.52); placebo (1-26 hafta, soxta 14-hafta) -0.65 (SE 0.61)
parallel trend tekshiruvi o'tdi: True; DiD 2*SE ichida +12 ga: True
[trendlar farqli]
naiv oldin-keyin +19.1, naiv shaharlar farqi -11.7
DiD +21.87 (SE 0.52); placebo (1-26 hafta, soxta 14-hafta) +3.90 (SE 0.61)
parallel trend tekshiruvi o'tdi: False; DiD 2*SE ichida +12 ga: False
⭐ Uplift - RCT da baholanadi; DiD - placebo bilan tekshiriladiNatija tahlili.
1-bo'lim — RCT ma'lumoti: kupon tasodifiy berilgan. O'rtacha uplift juda kichik (+0.0150, test bahosi +0.0134) — "hammaga kupon" deyarli foyda bermaydi. Lekin o'rtacha ostida ikki qarama-qarshi guruh yashiringan: 39.1% mijozda kupon xarid ehtimolini 5 foiz punktdan ko'proq oshiradi, 39.5% ida esa kamaytiradi ("bezovta qilma" — masalan, sodiq mijoz kuponni "narx sun'iy oshirilgan" deb qabul qiladi).
2-bo'lim — Qini. Javob modeli (xarid ehtimoli yuqorilarga kupon) tasodifiydan yaxshi emas: Qini maydoni -19.6 (tasodifiy -20.2), haqiqiy uplift bilan korrelyatsiyasi -0.023. U "baribir oladiganlar" ni topadi — ular kuponsiz ham xarid qiladi. Uplift modellari esa oracle ga yaqin: S-learner 464.0, T-learner 447.0, oracle 476.6. Eng kuchli raqam — top-30% mijozga kupon bersak, qo'shimcha xaridlar S-learner bilan 593.7, hammaga kupon bersak esa atigi 135.1 — kam kupon bilan to'rt barobar ko'p natija, chunki "bezovta qilma" guruhiga kupon yuborilmaydi.
3-bo'lim — juftlashgan bootstrap. T-learner S-learner dan 16.8 ga yomon (SE 8.0) — sezilarli. Bu kutilganidan farqli bo'lishi mumkin (nazariyada S-learner uplift ni nolga "siqishi" bilan tanilgan), lekin bu ma'lumotda ta'sir silliq va kuchli, bitta model uni barcha 40 000 qatorda o'rganadi, T-learner esa har modelni yarim ma'lumotda o'qitadi va ikki xatoni qo'shadi. Qoida bo'yicha — S-learner: u ham soddaroq (bitta model), ham sezilarli yaxshiroq. Boshqa ma'lumotda natija teskari bo'lishi mumkin — shuning uchun baholash har safar RCT test to'plamida qayta o'tkaziladi.
4-bo'lim — farqlar farqi. Parallel trendlar bajarilganda: naiv "oldin-keyin" +10.0 (trend va mavsum aralashgan), naiv "Samarqand va Toshkent" -25.5 (shaharlar darajasi farqi — aksiya "zarar" qilganga o'xshaydi!). DiD +12.77 (SE 0.52) — haqiqiy +12 ga yaqin, placebo (aksiyadan oldingi davrda soxta aksiya) -0.65 (SE 0.61) — nolga yaqin, tekshiruv o'tdi. Trendlar farqli bo'lganda (Samarqand har hafta 0.35 ga tezroq o'sadi): DiD +21.87 — o'sish ta'sirga qo'shilgan, xato deyarli ikki barobar. Lekin placebo +3.90 (SE 0.61) buni oldindan ko'rsatdi: tekshiruv o'tmadi. Placebo testi parallel trendlarni isbotlamaydi (oldingi davrda parallel bo'lib, keyin ajralishi mumkin), lekin buzilganini ko'pincha ushlaydi.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Kupon olganlar ko'p xarid qildi — demak kupon ishlaydi" | Naiv farq = ta'sir + tanlash siljishi (1 va 2-misolda 3 barobar katta) |
| "Hamma belgini nazorat qilsak xavfsiz" | Mediator ta'sirni yeydi, kollayder soxta bog'lanish yaratadi |
| "Katta namuna — ishonchli sababiy xulosa" | Katta namuna noto'g'ri javobni tor CI bilan beradi |
| "ATE va ATT — bir xil narsa" | Ta'sir heterogen bo'lsa farq qiladi; savolga qarab tanlanadi |
| "Propensity modeli yaxshi bashorat qilsa — yaxshi" | Maqsad — balans va overlap, AUC emas; juda yuqori AUC — overlap yo'qligi belgisi |
| "IPW — eng to'g'ri usul" | Ekstremal og'irliklarda juda shovqinli; balans va ESS ni tekshiring |
| "AIPW hamma muammoni hal qiladi" | Bittasi to'g'ri bo'lsa ishlaydi; ikkalasi xato yoki yashirin U bo'lsa — yo'q |
| "Balans mukammal — chalkashtirish yo'q" | Faqat o'lchangan X bo'yicha; U ko'rinmaydi |
| "Xarid ehtimoli yuqorilarga kupon beramiz" | Bu javob modeli; uplift modeli kerak |
| "DiD har doim trendni yo'qotadi" | Faqat parallel trendlar bajarilsa; placebo bilan tekshiring |
6. Keng tarqalgan xatolar va yechimlari
1. Naiv farq
tasir = df[df.kupon == 1].xarid.mean() - df[df.kupon == 0].xarid.mean() # ⚠️
# DAG -> nazorat to'plami -> g-hisoblash / IPW / AIPW + bootstrap CI # ✅2. Muolajadan keyingi belgini nazorat qilish
LinearRegression().fit(df[["kupon", "tashriflar", "sodiqlik"]], y) # ⚠️ mediator
LinearRegression().fit(df[["kupon", "sodiqlik"]], y) # ✅ faqat oldingi belgilar3. Overlap siz IPW
w = T / e + (1 - T) / (1 - e); ate = ... # ⚠️
# avval: e taqsimoti guruhlar bo'yicha, maks og'irlik, ESS, SMD # ✅4. Bootstrap da propensity qayta o'qitilmaydi
e = propensity(X, T)
for _ in range(200): i = ...; ate_i = ipw(T[i], Y[i], e[i]) # ⚠️
for _ in range(200): i = ...; ate_i = ipw(T[i], Y[i], propensity(X[i], T[i])) # ✅5. Kesishni yashirish
e = np.clip(e, 0.05, 0.95) # va hisobotda "ATE" # ⚠️
# "overlap hududi (0.05 < e < 0.95) uchun ta'sir" deb yozing # ✅6. Uplift o'rniga javob modeli
maqsad = model.fit(X, y).predict_proba(X)[:, 1].argsort()[::-1][:k] # ⚠️
uplift = f1.predict_proba(X)[:, 1] - f0.predict_proba(X)[:, 1] # ✅ + Qini (RCT da)7. DiD da faraz tekshirilmaydi
did = (a_keyin - a_oldin) - (b_keyin - b_oldin) # ⚠️
# + placebo (oldingi davrda soxta sana), SE do'kon bo'yicha klaster # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 4.10, 8.4-darslar (o'tilgan): Korrelyatsiya va sababiyat, Simpson paradoksi
- 11-qism (o'tilgan): Gipoteza testlari, bootstrap 11.8-bob — CI va sezilarlilik
- 13.3, 13.10-darslar (o'tilgan): Koeffitsientlarni talqin qilish va logistik regressiya — propensity
- 17.8-dars (o'tilgan): Leakage — muolajadan keyingi belgilar sababiy tahlilda ham tuzoq
- 27.13-dars (o'tilgan): A/B test — sababiy ta'sirni aniqlashning oltin standarti
- 28.10-dars (o'tilgan): Katta ma'lumot — hajm sababni isbotlamaydi
- 28.12-dars: Amaliyot — aksiya ta'sirini sababiy baholash (aksiya tasodifiy emas)
- Loyihalar va karyera qismi: Mahsulot tahlili intervyularining markaziy savoli: "bu o'zgarish metrikani oshirdimi?"
8. Eng yaxshi amaliyotlar
Avval savol va estimand: ATE, ATT yoki CATE?
DAG ni ma'lumotga qaramasdan chizing; nazorat to'plamini orqa eshik mezoni bilan tanlang.
Imkon bo'lsa — tajriba; kuzatuv tahlili tajribaning o'rnini bosmaydi.
Overlap va balansni tekshiring:
etaqsimoti, maks og'irlik, ESS, SMD.Bir necha usul (g-hisoblash, IPW, AIPW) — mos kelishi ishonchni oshiradi, farqi esa savol tug'diradi.
Butun jarayonni bootstrap qiling; kesish bo'lsa, estimand o'zgarganini yozing.
Yashirin chalkashtiruvchilar ro'yxatini va sezgirlik tahlilini hisobotga qo'shing.
Uplift — RCT da baholanadi; DiD — placebo bilan tekshiriladi.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # sodiqlar kupon ko'proq olsa, naiv farq ta'sirni oshiradimi yoki kamaytiradimi?
2. # mediatorni nazorat qilsak nima baholanadi?
3. # faqat sharh qoldirganlarni tahlil qilish - qanday xato?
4. # Simpson: har segmentda +3 punkt, umumiy -9 - qaysi javob to'g'ri?
5. # kupon sodiqlarga ko'proq berilsa va ularga kam ta'sir qilsa: ATT va ATE?
6. # IPW dan keyin |SMD| < 0.1 bo'lsa, chalkashtirish yo'qmi?
7. # e ni [0.05, 0.95] ga kesish nimani o'zgartiradi?
8. # AIPW: natija modeli xato, propensity to'g'ri - siljish?
9. # AIPW: ikkalasi xato - siljish?
10. # yashirin u kuchaysa AIPW nima qiladi?
11. # javob modeli bilan tanlangan top-30% - uplift?
12. # placebo DiD 0 dan sezilarli farq qilsa?Javoblar
- Oshiradi (1-misolda 94.4 va 30)
- Faqat bevosita ta'sir (9.1 va umumiy 40)
- Kollayder bo'yicha tanlash — soxta ta'sir (-14.4, haqiqiy 0)
- Segment kuponga sabab bo'lsa — segment ichidagi va standartlangan (+0.031)
- ATT < ATE (33.17 va 40.22)
- Yo'q — faqat o'lchangan X bo'yicha
- Og'irliklarni va baholanadigan kattalikni; dispersiya kamayadi, siljish paydo bo'ladi
- Deyarli yo'q (+1.2)
- Katta (+47.8) — kafolat yo'q
- Boshqa usullar bilan birga siljiydi (+21.0)
- Tasodifiydan deyarli farq qilmaydi
- Parallel trendlar shubhali — DiD ga ishonmang
Vazifa 2: Xatolarni tuzating
1. tasir = y[kupon == 1].mean() - y[kupon == 0].mean() # kuzatuv ma'lumoti
2. X = df[["kupon", "tashriflar", "sharh_qoldirdi", "sodiqlik"]]
3. e = propensity(X, T)
ates = [ipw(T[i], Y[i], e[i]) for i in bootstrap_indekslar]
4. maqsad = df.sort_values("xarid_ehtimoli", ascending=False).head(k)
5. did = (sam_keyin - sam_oldin) - (tosh_keyin - tosh_oldin) # tekshiruvsizJavoblar
1. # DAG -> X = [sodiqlik, oldingi, faollik, shahar]; AIPW + bootstrap CI
2. X = df[["kupon", "sodiqlik"]] # mediator va kollayder yo'q
3. ates = [ipw(T[i], Y[i], propensity(X[i], T[i])) for i in bootstrap_indekslar]
4. uplift = f1.predict_proba(X)[:, 1] - f0.predict_proba(X)[:, 1]
maqsad = df.assign(u=uplift).sort_values("u", ascending=False).head(k)
5. # + placebo DiD oldingi davrda; SE do'kon bo'yicha klasterVazifa 3: DAG lar
Modellang (1-misol asosida):
- Teskari bog'liqlik: xarid → kupon (ko'p xarid qilganga kupon yuboriladi) — naiv farq qanday o'zgaradi?
- Mediator va chalkashtiruvchi birga — qaysi to'plam umumiy ta'sirni beradi?
- M-tuzilma:
A → Z ← B,A → T,B → Y— Z ni nazorat qilish kerakmi? Simulyatsiya bilan tekshiring - Simpson misolida segment kuponning natijasi bo'lsin — endi qaysi javob to'g'ri?
Vazifa 4: Usullar
Modellang (2-misol asosida):
- Propensity ni HistGB bilan baholang — balans va AIPW xatosi qanday o'zgaradi?
- Moslashtirishda caliper ni 0.05, 0.2, 1.0 qiling — siljish va dispersiya
- Cross-fitting bilan AIPW: ma'lumotni 2 ga bo'lib, modellarni bir yarmida o'qitib, ikkinchisida baholang
- ATC ni baholang va haqiqiy qiymat bilan solishtiring
Vazifa 5: Mustahkamlik
Modellang (3-misol asosida):
- Overlap hududini
0.05 < e < 0.95deb, ta'sirni faqat shu hudud uchun baholang — haqiqiy qiymat ham shu hudud bo'yicha hisoblansin - E-qiymat g'oyasi:
uning qaysi kuchida AIPW xulosasi "ta'sir yo'q" ga o'tadi? uning proksisi bor (ubilan korrelyatsiyasi 0.7) — uni qo'shish siljishni qanchaga kamaytiradi?- Natija modelini HistGB qiling — "natija modeli xato" ssenariysida regressiya siljishi yo'qoladimi?
Vazifa 6: Uplift va DiD
Modellang (4-misol asosida):
- X-learner yozing va Qini da T/S bilan juftlashgan taqqoslang
- Kupon narxi 15 ming so'm, xarid marjasi 60 ming so'm — foydani maksimallashtiradigan top-k ulushini toping
- Uplift modelini kuzatuv ma'lumotida (kupon sodiqlarga ko'proq) o'qiting — Qini RCT test da qanday?
- DiD da event study: har hafta uchun muolaja va nazorat farqini chizing (aksiyadan oldingi haftalar ~0 bo'lishi kerak)
Vazifa 7: O'ylash
Marketing direktori: "Bir yillik ma'lumotda kupon olganlar 60 ming so'm ko'proq xarid qilgan. Tahlilchilar buni 'chalkashtirish' deb, propensity score bilan 38 ming so'm chiqardi. Ammo men ular noto'g'ri deb o'ylayman — biz sodiqlikni ham, oldingi xaridlarni ham nazorat qildik, demak 38 ming — haqiqiy ta'sir. Keyingi yil kupon byudjetini ikki barobar oshiramiz."
Javob
Qisqa javob: 38 ming — 60 mingdan ancha ishonchliroq, lekin "haqiqiy ta'sir" deb e'lon qilish uchun ikkita savol ochiq: yashirin chalkashtiruvchi va byudjetni oshirganda kimga kupon borishi.
1. Nega 60 ming noto'g'ri. Kupon sodiq mijozlarga ko'proq berilgan — ular kuponsiz ham ko'p xarid qiladi. 2-misolda xuddi shu tuzilmada naiv farq 102.44, haqiqiy ATE esa 40.22 edi.
2. Nega 38 ming ham kafolat emas.
# 1) yashirin chalkashtiruvchilar: daromad, raqobatchi do'kon yaqinligi,
# kupon yuborish qoidasi (masalan, "savat tashlab ketganlarga")
# -> 3-misol: u kuchi 1.0 da HAMMA usul +21 ga siljidi, balans esa mukammal
# 2) overlap: kupon olmagan sodiq mijozlar bormi? ESS, maks og'irlik
# 3) estimand: 38 ming - ATE mi, ATT mi? byudjet oshsa yangi mijozlarga
# beriladi - ularga ta'sir boshqacha (CATE)3. Byudjetni ikki barobar oshirish haqida. Qo'shimcha kuponlar kimga boradi? Hozir olmayotgan mijozlarga — ular uchun ta'sir boshqa (ATC yoki ularning CATE si). 4-misolda o'rtacha uplift deyarli nol edi, lekin top-30% ga yo'naltirish hammaga berishdan to'rt barobar ko'p qo'shimcha xarid berdi, "bezovta qilma" guruhida esa kupon zarar qildi.
4. Taklif.
- Keyingi 4 hafta: mijozlarning 10% ida A/B test (kupon tasodifiy) — haqiqiy ATE va CATE uchun ma'lumot.
- Shu ma'lumotda uplift modeli (S/T-learner) va Qini bilan tanlov.
- Byudjet "kimga" savoli hal bo'lgach oshiriladi.
Direktorga javob: "38 ming — biz o'lchagan chalkashtiruvchilarni hisobga olgan eng yaxshi baho, lekin u 'biz hamma sababni o'lchaganmiz' degan farazga tayanadi — buni ma'lumot bilan tekshirib bo'lmaydi. Byudjetni ikki barobar qilish esa boshqa savol: qo'shimcha kuponlar hozir olmayotgan mijozlarga boradi, ularga ta'sir noma'lum. Mijozlarning kichik qismida bir oylik tajriba bu savolga aniq javob beradi va kuponni kimga berish kerakligini ham ko'rsatadi — shundan keyin byudjet raqam bilan asoslanadi."
Nimani mustahkamlaydi: 2.2, 2.3, 2.6, 2.9-bo'limlar.
Xulosa
Bu darsda kuzatuv ma'lumotidan sababiy ta'sirni baholashni va uning chegaralarini o'rgandik.
Eng muhim uch fikr:
Sababiy savol — dizayn masalasi, hajm emas. 1-misolda naiv farq haqiqiy ta'sirdan uch barobar katta chiqdi (
94.4va30); mediatorni nazorat qilish umumiy ta'sirni40dan9.1ga tushirdi; kollayder bo'yicha tanlash nol ta'sirni-14.4qilib ko'rsatdi; Simpson paradoksida umumiy jadval kuponni zararli (-0.090) ko'rsatdi, segmentlar esa foydali (+0.031). Qaysi o'zgaruvchini nazorat qilishni DAG hal qiladi, ma'lumot emas.Kuzatuv ma'lumotida — bir necha usul, overlap, balans va halol CI. 2-misolda naiv farq 30 urug'da o'rtacha
+62.6ga siljidi; regressiya, g-hisoblash, moslashtirish, IPW (ATE va ATT) va AIPW siljimadi (RMSE2.07-4.50), kesilgan IPW esa estimandni o'zgartirib+3.69ga siljidi. IPW dan keyin SMD1.187dan-0.024ga tushdi. 3-misolda AIPW bitta model xato bo'lganda ham to'g'ri qoldi (+1.2,+0.3), ikkalasi xato bo'lganda esa+47.8ga siljidi; kuchsiz overlap da samarali namuna4.7%ga tushib, hamma usul shovqinli bo'ldi.O'lchanmagan chalkashtiruvchiga qarshi hech bir formula yordam bermaydi. 3-misolda yashirin
ukuchaygan sari barcha usullar birga siljidi (+21gacha — ta'sirning o'zidek), diagnostikalar esa jim edi. Shuning uchun tajriba — oltin standart, uplift modeli (4-misol: S-learner Qini464.0, javob modeli tasodifiy darajada) RCT ma'lumotida baholanadi, DiD esa parallel trendlar bajarilganda to'g'ri (+12.77), buzilganda+21.87beradi — va placebo testi buni oldindan ko'rsatdi.
Keyingi darsda Amaliyot: 28-qismning yakuniy loyihasi — do'konlar tarmog'i uchun talab bashorati va anomaliya monitoringi. Ko'p do'konli kunlik savdo ma'lumotini tayyorlash va sifat tekshiruvi, bazaviy, ETS va global gradient boosting modellarini rolling-origin backtest da juftlashgan taqqoslash, bashorat intervallari va zaxira qarori, aksiya ta'sirini sababiy baholash, yakuniy model paketi va monitoring rejasi.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!