Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Testni loyihalash
- 2.2. Sanity-check
- 2.3. Asosiy metrika tahlili
- 2.4. Ikkilamchi metrikalar va tuzatish
- 2.5. Segment tahlili
- 2.6. Qiyshiq metrikalar
- 2.7. Erta to'xtatish va tuzoqlar
- 2.8. A/B test — sababiy xulosaning amaliyoti
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Loyihalash va sanity-check
- Misol 2 — Asosiy metrika va qaror
- Misol 3 — Ikkilamchi metrikalar va bootstrap
- Misol 4 — Segmentlar, erta to'xtatish va hisobot
- 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
11.10-dars: Amaliyot — A/B test loyihasi
11-QISM — GIPOTEZA TESTLARI · 10-dars
1. Kirish va motivatsiya
11-qismda testlar tizimini 11.1-bob, quvvat va namuna hajmini 11.2-bob, t-testlarni 11.3-bob, proporsiyalarni 11.4-bob, xi-kvadratni 11.5-bob, ANOVA ni 11.6-bob, noparametrik testlarni 11.7-bob, bootstrap va permutatsiyani 11.8-bob hamda ko'p taqqoslashni 11.9-bob o'rgandik. Endi hammasini bitta A/B testda birlashtiramiz — boshidan oxirigacha: loyihalash → sanity-check → asosiy metrika → ikkilamchi metrikalar → segmentlar → hisobot.
A/B test — Data Science'dagi eng ko'p uchraydigan sababiy tahlil vositasi 4.10-bob: tasodifiy taqsimot tufayli farqni sababiy talqin qilish mumkin. Lekin uni buzish ham oson: quvvat yetmasligi, noto'g'ri birlik, erta to'xtatish, ko'p metrikani tuzatishsiz tekshirish, segmentlarni "qidirish". Bu dars — to'g'ri ish tartibining namunasi.
Real vaziyat. Mahsulot jamoasi yangi mahsulot sahifasini sinaydi. Data Scientist testni oldindan loyihalaydi: asosiy metrika — buyurtma konversiyasi (hozir 5.0%), amaliy chegara — nisbiy +12% (5.6% ga), quvvat 80%, alfa 0.05 → har guruhga ~21 900 foydalanuvchi, kunlik trafik 4 000 → 11 kun, to'liq haftalarga yaxlitlab 12 kun. Ikkilamchi metrikalar (o'rtacha chek, sahifada qolish vaqti, savatga qo'shish) va sath metrikalari (qaytish, xatolar) oldindan ro'yxatga olinadi. Test tugagach: A/A sanity-check, asosiy metrika (z-test + CI), ikkilamchilar (Holm), segmentlar (oldindan belgilangan 4 ta), yakuniy hisobot.
Bu darsda 11-qismning barcha bilimlarini bitta loyihada qo'llaymiz.
Bu darsda:
- Testni loyihalash (metrika, MDE, n, davomiylik)
- Sanity-check (taqsimot, A/A, SRM)
- Asosiy metrika tahlili
- Ikkilamchi metrikalar va tuzatish
- Segment tahlili (oldindan belgilangan)
- Qiyshiq metrikalar (bootstrap)
- Erta to'xtatish va tuzoqlar
- Yakuniy hisobot va qaror
ℹ Misollar real numpy/scipy/statsmodels bilan (Python 3.14). Barcha misollar bir xil
yarat()generatoridan foydalanadi.
2. Nazariya — chuqur tushuntirish
2.1. Testni loyihalash
1. GIPOTEZA 8.8-bob: "Yangi sahifa mahsulot afzalliklarini aniqroq ko'rsatadi →
buyurtma konversiyasi oshadi"
2. ASOSIY METRIKA: buyurtma konversiyasi (bitta!)
3. AMALIY CHEGARA: nisbiy +12% (5.0% → 5.6%)
4. QUVVAT: 80%, alfa = 0.05 (ikki tomonlama)
5. NAMUNA: har guruhga ~21 900 → 11 kun (12 kunga yaxlitlanadi)
6. IKKILAMCHI metrikalar va SATH (guardrail) metrikalari — oldindan ro'yxat
7. TO'XTASH QOIDASI: belgilangan muddat; oraliq tekshiruvlar faqat sath uchunTestning muvaffaqiyati oldindan hal qilinadi: bitta asosiy metrika 11.9-bob, amaliy chegara 11.1-bob, quvvat va namuna hajmi 11.2-bob, davomiylik (to'liq haftalar — 8.7 dagi hafta kuni effekti), to'xtash qoidasi (11.2 — ketma-ket tekshirish taqiqlanadi). Bularning hammasi hujjat sifatida yoziladi (8.8 — pre-registration).
2.2. Sanity-check
1. SRM (Sample Ratio Mismatch): guruhlar nisbati kutilganday (50/50) mi?
xi-kvadrat moslik testi 11.5-bob; p < 0.001 → texnik muammo, tahlilni to'xtating
2. A/A tekshiruvi: testdan oldingi davrda guruhlar farq qilmasligi kerak
3. Ma'lumot sifati: dublikatlar, yo'qolgan yozuvlar, bir foydalanuvchi ikki guruhda
4. Taqsimotlar: metrikaning shakli (qiyshiqmi?), outlierlar (8.6)Sanity-check — tahlilning birinchi qadami: agar guruhlarga taqsimot buzilgan bo'lsa (SRM), barcha keyingi natijalar ishonchsiz. SRM ning odatiy sabablari: bot trafigi, kesh, yuklanish xatolari, noto'g'ri yorliqlash. Bir foydalanuvchi ikki guruhda — birlik muammosi 11.3-bob. Bu bosqichda testni bekor qilish — yomon xabar, lekin noto'g'ri qarordan yaxshi.
2.3. Asosiy metrika tahlili
Konversiya — ulush 11.4-bob:
farq (foiz punkt) + nisbiy farq + 95% CI + p (z-test)
amaliy chegara bilan solishtirish
Qaror matritsasi:
CI butunlay chegaradan yuqori → ishga tushirish
CI nolni o'z ichiga oladi → dalil yetarli emas
CI butunlay manfiy → rad etish
CI keng (noaniq) → ma'lumot yetarli emas / davom ettirishQaror faqat p ga emas, CI va amaliy chegaraga tayanadi 11.1-bob: "p < 0.05" — statistik signal; "CI ning pastki chegarasi amaliy chegaradan yuqori" — biznes qarori. Bu yondashuv "muhim, lekin arzimas" va "muhim emas, lekin istiqbolli" holatlarini to'g'ri ajratadi.
2.4. Ikkilamchi metrikalar va tuzatish
Ikkilamchi metrikalar (chek, vaqt, savatga qo'shish) — tuzatish bilan (Holm, 11.9); sath metrikalari (xatolar, qaytish, shikoyatlar) — yomonlashuvni aniqlash uchun (bu yerda odatda tuzatilmaydi, chunki maqsad — xavfni o'tkazib yubormaslik; aksincha, sezgirroq alfa qo'yiladi). Barcha tekshirilgan metrikalar hisobotda ko'rsatiladi — nechtasi va qanday tuzatish bilan.
2.5. Segment tahlili
Segmentlar (qurilma, yangi/qaytgan, mintaqa) oldindan belgilanadi — 20 ta segmentni "qidirish" yolg'on kashfiyot mashinasi 11.9-bob. Segment tahlili ikki maqsadda: (1) zarar tekshiruvi — biror segmentda keskin yomonlashuv bormi; (2) gipoteza — effekt qayerda kuchliroq (keyingi test uchun). Segment natijalari hech qachon yakuniy qaror uchun yagona asos bo'lmaydi (8.8 — kashfiyot ≠ tasdiq).
2.6. Qiyshiq metrikalar
Pul va vaqt metrikalari kuchli qiyshiq (9.8, 11.7): o'rtacha chek uchun t-test noto'g'ri ishlashi mumkin. Yechimlar: bootstrap CI (11.8 — o'rtacha uchun ham, median uchun ham), log o'zgartirish, noparametrik test 11.7-bob, yoki winsorizatsiya (yuqori 0.5% ni kesish — oldindan e'lon qilingan qoida bilan). Muhim: o'rtacha biznes uchun muhim bo'lsa (umumiy daromad), medianga o'tib ketmang — bootstrap ishlating. Texnik nuans: scipy.stats.bootstrap ning standart BCa usuli katta namunada (o'n minglab qator) jackknife tufayli juda ko'p xotira talab qiladi — bunday holatda method="percentile" ishlating.
2.7. Erta to'xtatish va tuzoqlar
Asosiy tuzoqlar: erta to'xtatish ("p < 0.05 bo'ldi — to'xtatamiz" — I tur xato 2-4 barobar oshadi, 11.2); noto'g'ri birlik (sessiya emas, foydalanuvchi — 11.3); SRM ni tekshirmaslik; ko'p metrikani tuzatishsiz 11.9-bob; segment qidirish; novelty effekti (yangilik ta'siri — birinchi kunlar farqi keyin yo'qoladi); bayram/aksiya davri; test guruhlari orasidagi ta'sir (ijtimoiy tarmoqlarda, marketplace'da — SUTVA buzilishi); faqat g'alaba qidirish (neytral natija ham qimmatli).
2.8. A/B test — sababiy xulosaning amaliyoti
To'liq sikl: loyihalash (gipoteza, bitta asosiy metrika, amaliy chegara, quvvat va n, davomiylik, to'xtash qoidasi — 8.8, 11.1, 11.2) → sanity-check (SRM, A/A, ma'lumot sifati, taqsimotlar — 11.5, 8.6) → asosiy metrika (farq + CI + p, amaliy chegara bilan qaror — 11.4) → ikkilamchilar (tuzatish — 11.9) va sath metrikalari → segmentlar (oldindan, gipoteza sifatida) → qiyshiq metrikalar (bootstrap — 11.8) → hisobot (8.9: xulosa birinchi, cheklovlar, keyingi qadam). Bu — sanoat standarti ish tartibi.
3. Tez ma'lumotnoma
import numpy as np
from scipy import stats
from statsmodels.stats.proportion import proportions_ztest, confint_proportions_2indep
from statsmodels.stats.multitest import multipletests
from statsmodels.stats.power import NormalIndPower
from statsmodels.stats.proportion import proportion_effectsize
# 1) LOYIHALASH
h = proportion_effectsize(0.054, 0.05)
n = NormalIndPower().solve_power(effect_size=h, alpha=0.05, power=0.8)
# 2) SANITY: SRM
stats.chisquare([n_a, n_b]) # p < 0.001 → muammo
# 3) ASOSIY METRIKA
stat, p = proportions_ztest([x_b, x_a], [n_b, n_a])
lo, hi = confint_proportions_2indep(x_b, n_b, x_a, n_a, method="wald")
# 4) IKKILAMCHI (tuzatish)
rad, p_tuz, _, _ = multipletests(p_lar, alpha=0.05, method="holm")
# 5) QIYSHIQ METRIKA (bootstrap)
stats.bootstrap((chek_b, chek_a), lambda u, v, axis=-1: u.mean(axis) - v.mean(axis),
vectorized=True, n_resamples=10_000,
method="percentile", random_state=0) # katta n da BCa qimmat
QOIDA: oldindan reja · SRM · asosiy metrika bitta · tuzatish · CI bilan qarorA/B loyiha xulosasi
Loyihalash: gipoteza, asosiy metrika, amaliy chegara, quvvat, n, muddat
Sanity: SRM (chisquare), A/A, dublikat, taqsimot
Asosiy: farq (pp va nisbiy) + CI + p; chegara bilan qaror
Ikkilamchi: Holm; sath metrikalari alohida
Segment: oldindan, gipoteza sifatida
Qiyshiq metrika: bootstrap CI
Hisobot: xulosa birinchi, cheklovlar, keyingi qadam4. Batafsil misollar
Misollar real numpy/scipy/statsmodels bilan (Python 3.14). Har misol boshida bir xil
yarat()generatori.
Misol 1 — Loyihalash va sanity-check
"""A/B loyiha: namuna hajmi, davomiylik va sanity-check (real numpy/scipy/statsmodels)."""
import numpy as np
from scipy import stats
from statsmodels.stats.power import NormalIndPower
from statsmodels.stats.proportion import proportion_effectsize
def yarat(seed: int = 7):
"""Test ma'lumoti: 24 000 + 24 000 foydalanuvchi, 12 kun."""
rng = np.random.default_rng(seed)
n = 24_000
guruh = np.repeat(["A", "B"], n)
kun = rng.integers(0, 12, 2 * n)
qurilma = rng.choice(["mobil", "kompyuter"], 2 * n, p=[0.7, 0.3])
yangi = rng.random(2 * n) < 0.4
p_baza = np.where(kun % 7 >= 5, 0.062, 0.050) # dam olish kunlari yuqoriroq
p = np.where(guruh == "B", p_baza * 1.14, p_baza) # haqiqiy effekt: +14% nisbiy
konversiya = rng.random(2 * n) < p
chek = np.where(konversiya, rng.lognormal(np.log(180_000), 0.7, 2 * n), 0.0)
vaqt = rng.lognormal(np.log(95), 0.5, 2 * n) * np.where(guruh == "B", 1.02, 1.0)
qaytish = rng.random(2 * n) < 0.021
return {"guruh": guruh, "kun": kun, "qurilma": qurilma, "yangi": yangi,
"konversiya": konversiya, "chek": chek, "vaqt": vaqt, "qaytish": qaytish}
def main() -> None:
print("=== 1. Loyihalash ===")
baza, maqsad = 0.05, 0.056
h = proportion_effectsize(maqsad, baza)
n = NormalIndPower().solve_power(effect_size=h, alpha=0.05, power=0.8)
print(f" baza {baza:.1%}, amaliy chegara +12% nisbiy ({maqsad:.1%})")
print(f" har guruhga n = {np.ceil(n):,.0f}; kunlik trafik 4000 → "
f"{2 * np.ceil(n) / 4000:.1f} kun (12 kunga yaxlitlanadi)")
d = yarat()
print("\n=== 2. SRM (guruhlar nisbati) ===")
nA = (d["guruh"] == "A").sum(); nB = (d["guruh"] == "B").sum()
res = stats.chisquare([nA, nB])
print(f" A: {nA:,}, B: {nB:,}, p = {res.pvalue:.3f} → "
f"{'muammo!' if res.pvalue < 0.001 else 'normal'}")
print("\n=== 3. Ma'lumot sifati ===")
print(f" yozuvlar: {len(d['guruh']):,}, konversiyalar: {d['konversiya'].sum():,}")
print(f" chek > 0 bo'lganlar soni konversiyaga teng: "
f"{(d['chek'] > 0).sum() == d['konversiya'].sum()}")
print("\n=== 4. Metrika taqsimoti (chek, konversiya qilganlar) ===")
chek = d["chek"][d["konversiya"]]
print(f" o'rtacha {chek.mean():,.0f}, median {np.median(chek):,.0f}, "
f"skew {stats.skew(chek):.2f} → qiyshiq (bootstrap kerak)")
print(" ⭐ Sanity-check — tahlilning birinchi qadami")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Loyihalash ===
baza 5.0%, amaliy chegara +12% nisbiy (5.6%)
har guruhga n = 21,869; kunlik trafik 4000 → 10.9 kun (12 kunga yaxlitlanadi)
=== 2. SRM (guruhlar nisbati) ===
A: 24,000, B: 24,000, p = 1.000 → normal
=== 3. Ma'lumot sifati ===
yozuvlar: 48,000, konversiyalar: 2,717
chek > 0 bo'lganlar soni konversiyaga teng: True
=== 4. Metrika taqsimoti (chek, konversiya qilganlar) ===
o'rtacha 225,325, median 178,436, skew 2.80 → qiyshiq (bootstrap kerak)
⭐ Sanity-check — tahlilning birinchi qadamiNima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — Asosiy metrika va qaror
"""Asosiy metrika: farq, CI, p va amaliy chegara bilan qaror (real numpy/scipy/statsmodels)."""
import numpy as np
from scipy import stats
from statsmodels.stats.proportion import confint_proportions_2indep, proportions_ztest
def yarat(seed: int = 7):
"""Test ma'lumoti: 24 000 + 24 000 foydalanuvchi, 12 kun."""
rng = np.random.default_rng(seed)
n = 24_000
guruh = np.repeat(["A", "B"], n)
kun = rng.integers(0, 12, 2 * n)
qurilma = rng.choice(["mobil", "kompyuter"], 2 * n, p=[0.7, 0.3])
yangi = rng.random(2 * n) < 0.4
p_baza = np.where(kun % 7 >= 5, 0.062, 0.050) # dam olish kunlari yuqoriroq
p = np.where(guruh == "B", p_baza * 1.14, p_baza) # haqiqiy effekt: +14% nisbiy
konversiya = rng.random(2 * n) < p
chek = np.where(konversiya, rng.lognormal(np.log(180_000), 0.7, 2 * n), 0.0)
vaqt = rng.lognormal(np.log(95), 0.5, 2 * n) * np.where(guruh == "B", 1.02, 1.0)
qaytish = rng.random(2 * n) < 0.021
return {"guruh": guruh, "kun": kun, "qurilma": qurilma, "yangi": yangi,
"konversiya": konversiya, "chek": chek, "vaqt": vaqt, "qaytish": qaytish}
def main() -> None:
d = yarat()
A = d["guruh"] == "A"
nA, nB = A.sum(), (~A).sum()
xA, xB = d["konversiya"][A].sum(), d["konversiya"][~A].sum()
pA, pB = xA / nA, xB / nB
print("=== 1. Kuzatilgan ===")
print(f" A: {pA:.3%} ({xA:,}/{nA:,}), B: {pB:.3%} ({xB:,}/{nB:,})")
print(f" absolyut farq {100 * (pB - pA):+.2f} pp, nisbiy {(pB - pA) / pA:+.1%}")
print("\n=== 2. Test va CI ===")
stat, p = proportions_ztest([xB, xA], [nB, nA])
lo, hi = confint_proportions_2indep(xB, nB, xA, nA, method="wald")
print(f" z = {stat:.3f}, p = {p:.5f}")
print(f" 95% CI: [{100 * lo:+.2f}, {100 * hi:+.2f}] pp")
print(f" nisbiy CI (taxminan): [{lo / pA:+.1%}, {hi / pA:+.1%}]")
print("\n=== 3. Amaliy chegara bilan qaror ===")
chegara_pp = 0.05 * 0.12 # +12% nisbiy = +0.6 pp
print(f" amaliy chegara: +{100 * chegara_pp:.2f} pp")
if lo > chegara_pp:
qaror = "ISHGA TUSHIRISH (CI butunlay chegaradan yuqori)"
elif hi < 0:
qaror = "RAD ETISH (zarar)"
elif lo > 0:
qaror = "IJOBIY, lekin chegaraga yetmasligi mumkin — biznes qarori"
else:
qaror = "DALIL YETARLI EMAS"
print(f" qaror: {qaror}")
print("\n=== 4. Kunlar bo'yicha barqarorlik ===")
for k in [3, 6, 9, 12]:
m = d["kun"] < k
a = d["konversiya"][A & m]; b = d["konversiya"][(~A) & m]
_, pk = proportions_ztest([b.sum(), a.sum()], [len(b), len(a)])
print(f" {k:>2} kun: A {a.mean():.3%}, B {b.mean():.3%}, p = {pk:.4f}")
print(" ⭐ Qaror — CI va amaliy chegara bilan (faqat p emas)")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Kuzatilgan ===
A: 5.250% (1,260/24,000), B: 6.071% (1,457/24,000)
absolyut farq +0.82 pp, nisbiy +15.6%
=== 2. Test va CI ===
z = 3.891, p = 0.00010
95% CI: [+0.41, +1.23] pp
nisbiy CI (taxminan): [+7.8%, +23.5%]
=== 3. Amaliy chegara bilan qaror ===
amaliy chegara: +0.60 pp
qaror: IJOBIY, lekin chegaraga yetmasligi mumkin — biznes qarori
=== 4. Kunlar bo'yicha barqarorlik ===
3 kun: A 4.961%, B 6.101%, p = 0.0063
6 kun: A 5.101%, B 6.202%, p = 0.0002
9 kun: A 5.276%, B 6.354%, p = 0.0000
12 kun: A 5.250%, B 6.071%, p = 0.0001
⭐ Qaror — CI va amaliy chegara bilan (faqat p emas)Nima ko'rsatdi: 2.3, 2.7-bo'limlar.
Misol 3 — Ikkilamchi metrikalar va bootstrap
"""Ikkilamchi metrikalar (Holm) va qiyshiq chek uchun bootstrap CI (real numpy/scipy/statsmodels)."""
import numpy as np
from scipy import stats
from statsmodels.stats.multitest import multipletests
from statsmodels.stats.proportion import proportions_ztest
def yarat(seed: int = 7):
"""Test ma'lumoti: 24 000 + 24 000 foydalanuvchi, 12 kun."""
rng = np.random.default_rng(seed)
n = 24_000
guruh = np.repeat(["A", "B"], n)
kun = rng.integers(0, 12, 2 * n)
qurilma = rng.choice(["mobil", "kompyuter"], 2 * n, p=[0.7, 0.3])
yangi = rng.random(2 * n) < 0.4
p_baza = np.where(kun % 7 >= 5, 0.062, 0.050) # dam olish kunlari yuqoriroq
p = np.where(guruh == "B", p_baza * 1.14, p_baza) # haqiqiy effekt: +14% nisbiy
konversiya = rng.random(2 * n) < p
chek = np.where(konversiya, rng.lognormal(np.log(180_000), 0.7, 2 * n), 0.0)
vaqt = rng.lognormal(np.log(95), 0.5, 2 * n) * np.where(guruh == "B", 1.02, 1.0)
qaytish = rng.random(2 * n) < 0.021
return {"guruh": guruh, "kun": kun, "qurilma": qurilma, "yangi": yangi,
"konversiya": konversiya, "chek": chek, "vaqt": vaqt, "qaytish": qaytish}
def main() -> None:
d = yarat()
A = d["guruh"] == "A"
print("=== 1. Ikkilamchi metrikalar ===")
p_lar, nomlar = [], []
vaqt_res = stats.ttest_ind(d["vaqt"][~A], d["vaqt"][A], equal_var=False)
p_lar.append(vaqt_res.pvalue); nomlar.append("sahifada vaqt")
chek_a = d["chek"][A & d["konversiya"]]; chek_b = d["chek"][(~A) & d["konversiya"]]
chek_res = stats.ttest_ind(chek_b, chek_a, equal_var=False)
p_lar.append(chek_res.pvalue); nomlar.append("o'rtacha chek")
_, p_qayt = proportions_ztest([d["qaytish"][~A].sum(), d["qaytish"][A].sum()],
[(~A).sum(), A.sum()])
p_lar.append(p_qayt); nomlar.append("qaytish (sath)")
for nom, p in zip(nomlar, p_lar):
print(f" {nom:<16}: xom p = {p:.4f}")
print("\n=== 2. Holm tuzatishi (sath metrikasisiz) ===")
rad, p_tuz, _, _ = multipletests(p_lar[:2], alpha=0.05, method="holm")
for nom, p, pt, r in zip(nomlar[:2], p_lar[:2], p_tuz, rad):
print(f" {nom:<16}: tuzatilgan p = {pt:.4f}{' ← muhim' if r else ''}")
print("\n=== 3. O'rtacha chek: bootstrap CI (qiyshiq metrika) ===")
res = stats.bootstrap((chek_b, chek_a),
lambda u, v, axis=-1: u.mean(axis=axis) - v.mean(axis=axis),
vectorized=True, n_resamples=5_000,
method="percentile", random_state=0)
print(f" o'rtacha chek: A {chek_a.mean():,.0f}, B {chek_b.mean():,.0f}")
print(f" farq CI: [{res.confidence_interval.low:,.0f}, "
f"{res.confidence_interval.high:,.0f}] so'm")
print("\n=== 4. Mijoz boshiga daromad (konversiya × chek) ===")
rpu_a = d["chek"][A].mean(); rpu_b = d["chek"][~A].mean()
res2 = stats.bootstrap((d["chek"][~A], d["chek"][A]),
lambda u, v, axis=-1: u.mean(axis=axis) - v.mean(axis=axis),
vectorized=True, n_resamples=5_000,
method="percentile", random_state=0)
print(f" A {rpu_a:,.0f}, B {rpu_b:,.0f}, farq CI "
f"[{res2.confidence_interval.low:,.0f}, {res2.confidence_interval.high:,.0f}]")
print(" ⭐ Qiyshiq metrikalar — bootstrap; ikkilamchilar — tuzatish bilan")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ikkilamchi metrikalar ===
sahifada vaqt : xom p = 0.0000
o'rtacha chek : xom p = 0.2591
qaytish (sath) : xom p = 0.8243
=== 2. Holm tuzatishi (sath metrikasisiz) ===
sahifada vaqt : tuzatilgan p = 0.0000 ← muhim
o'rtacha chek : tuzatilgan p = 0.2591
=== 3. O'rtacha chek: bootstrap CI (qiyshiq metrika) ===
o'rtacha chek: A 221,166, B 228,921
farq CI: [-5,748, 21,185] so'm
=== 4. Mijoz boshiga daromad (konversiya × chek) ===
A 11,611, B 13,897, farq CI [1,077, 3,493]
⭐ Qiyshiq metrikalar — bootstrap; ikkilamchilar — tuzatish bilanNima ko'rsatdi: 2.4, 2.6-bo'limlar.
Misol 4 — Segmentlar, erta to'xtatish va hisobot
"""Segment tahlili, erta to'xtatish xavfi va yakuniy hisobot (real numpy/scipy/statsmodels)."""
import numpy as np
from scipy import stats
from statsmodels.stats.multitest import multipletests
from statsmodels.stats.proportion import proportions_ztest
def yarat(seed: int = 7):
"""Test ma'lumoti: 24 000 + 24 000 foydalanuvchi, 12 kun."""
rng = np.random.default_rng(seed)
n = 24_000
guruh = np.repeat(["A", "B"], n)
kun = rng.integers(0, 12, 2 * n)
qurilma = rng.choice(["mobil", "kompyuter"], 2 * n, p=[0.7, 0.3])
yangi = rng.random(2 * n) < 0.4
p_baza = np.where(kun % 7 >= 5, 0.062, 0.050) # dam olish kunlari yuqoriroq
p = np.where(guruh == "B", p_baza * 1.14, p_baza) # haqiqiy effekt: +14% nisbiy
konversiya = rng.random(2 * n) < p
chek = np.where(konversiya, rng.lognormal(np.log(180_000), 0.7, 2 * n), 0.0)
vaqt = rng.lognormal(np.log(95), 0.5, 2 * n) * np.where(guruh == "B", 1.02, 1.0)
qaytish = rng.random(2 * n) < 0.021
return {"guruh": guruh, "kun": kun, "qurilma": qurilma, "yangi": yangi,
"konversiya": konversiya, "chek": chek, "vaqt": vaqt, "qaytish": qaytish}
def main() -> None:
d = yarat()
A = d["guruh"] == "A"
print("=== 1. Oldindan belgilangan 4 segment ===")
segmentlar = {
"mobil": d["qurilma"] == "mobil",
"kompyuter": d["qurilma"] == "kompyuter",
"yangi mijoz": d["yangi"],
"qaytgan mijoz": ~d["yangi"],
}
p_lar = []
for nom, m in segmentlar.items():
a = d["konversiya"][A & m]; b = d["konversiya"][(~A) & m]
_, p = proportions_ztest([b.sum(), a.sum()], [len(b), len(a)])
p_lar.append(p)
print(f" {nom:<14}: A {a.mean():.2%}, B {b.mean():.2%}, "
f"nisbiy {(b.mean() - a.mean()) / a.mean():+.1%}, p = {p:.4f}")
rad, p_tuz, _, _ = multipletests(p_lar, alpha=0.05, method="holm")
print(f" Holm tuzatilgan p: {np.round(p_tuz, 4).tolist()}")
print("\n=== 2. Erta to'xtatish xavfi (simulyatsiya, H0 rost) ===")
rng = np.random.default_rng(1)
yolgon_erta = yolgon_oxir = 0
N = 2000
for _ in range(N):
a = rng.random((12, 2000)) < 0.05
b = rng.random((12, 2000)) < 0.05
erta = False
for k in range(1, 13):
_, p = proportions_ztest([b[:k].sum(), a[:k].sum()], [k * 2000, k * 2000])
if p < 0.05:
erta = True
break
yolgon_erta += erta
_, p_oxir = proportions_ztest([b.sum(), a.sum()], [24_000, 24_000])
yolgon_oxir += p_oxir < 0.05
print(f" har kuni tekshirish: {yolgon_erta / N:.3f}")
print(f" faqat oxirida: {yolgon_oxir / N:.3f} (kutilgan 0.05)")
print("\n=== 3. Yakuniy hisobot ===")
xA = d["konversiya"][A].sum(); xB = d["konversiya"][~A].sum()
nA = A.sum(); nB = (~A).sum()
pA, pB = xA / nA, xB / nB
_, p_asosiy = proportions_ztest([xB, xA], [nB, nA])
print(f" Asosiy metrika: konversiya {pA:.2%} → {pB:.2%} "
f"({(pB - pA) / pA:+.1%} nisbiy), p = {p_asosiy:.4f}")
print(" Ikkilamchilar: tuzatishdan keyingi natija — Misol 3 da")
yomon = [nom for nom, p, m in zip(segmentlar, p_tuz, segmentlar.values())
if p < 0.05 and d["konversiya"][(~A) & m].mean() < d["konversiya"][A & m].mean()]
print(f" Segmentlar: zarar ko'rsatgan segment {'yo\'q' if not yomon else yomon}")
print(" Cheklov: 12 kun, bitta mavsum; uzoq muddatli ta'sir o'lchanmagan")
print(" Tavsiya: ishga tushirish va 4 hafta monitoring")
print(" ⭐ Hisobot — qaror, cheklovlar va keyingi qadam bilan")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Oldindan belgilangan 4 segment ===
mobil : A 5.22%, B 6.23%, nisbiy +19.3%, p = 0.0001
kompyuter : A 5.33%, B 5.70%, nisbiy +7.0%, p = 0.3265
yangi mijoz : A 5.37%, B 6.05%, nisbiy +12.6%, p = 0.0436
qaytgan mijoz : A 5.17%, B 6.09%, nisbiy +17.7%, p = 0.0007
Holm tuzatilgan p: [0.0003, 0.3265, 0.0872, 0.0022]
=== 2. Erta to'xtatish xavfi (simulyatsiya, H0 rost) ===
har kuni tekshirish: 0.207
faqat oxirida: 0.056 (kutilgan 0.05)
=== 3. Yakuniy hisobot ===
Asosiy metrika: konversiya 5.25% → 6.07% (+15.6% nisbiy), p = 0.0001
Ikkilamchilar: tuzatishdan keyingi natija — Misol 3 da
Segmentlar: zarar ko'rsatgan segment yo'q
Cheklov: 12 kun, bitta mavsum; uzoq muddatli ta'sir o'lchanmagan
Tavsiya: ishga tushirish va 4 hafta monitoring
⭐ Hisobot — qaror, cheklovlar va keyingi qadam bilanNima ko'rsatdi: 2.5, 2.7, 2.8-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "p < 0.05 — ishga tushiramiz" | CI va amaliy chegara |
| "Natija tez chiqsa to'xtatamiz" | Erta to'xtatish — I tur xato oshadi |
| "Ko'p metrika — ko'p imkoniyat" | Tuzatish kerak (11.9) |
| "Segmentda topilgan effekt — natija" | Gipoteza (alohida test) |
| "SRM tekshirish shart emas" | Birinchi qadam |
| "O'rtacha chek — t-test" | Qiyshiq: bootstrap |
| "Neytral natija — muvaffaqiyatsizlik" | Qimmatli bilim |
| "Test tugadi — ish tugadi" | Monitoring va takroriy tekshiruv |
6. Keng tarqalgan xatolar va yechimlari
1. Rejasiz test
# "ishga tushiramiz, keyin ko'ramiz" # ⚠️
# oldindan: metrika, chegara, n, muddat, to'xtash qoidasi # ✅2. Erta to'xtatish
if p < 0.05: testni_toxtat() # har kuni # ⚠️
# belgilangan muddatgacha kutish # ✅3. SRM ni tekshirmaslik
# to'g'ridan-to'g'ri konversiyani solishtirish # ⚠️
stats.chisquare([n_a, n_b]) # avval # ✅4. Sessiya darajasi
proportions_ztest([klik_b, klik_a], [sessiya_b, sessiya_a]) # ⚠️
# foydalanuvchi darajasiga agregatsiya # ✅5. Tuzatishsiz ikkilamchilar
for m in metrikalar: test(m) # ⚠️
multipletests(p_lar, alpha=0.05, method="holm") # ✅6. Qiyshiq metrikaga t-test
stats.ttest_ind(chek_b, chek_a) # ⚠️
stats.bootstrap((chek_b, chek_a), farq_funksiyasi, ...) # ✅7. Segment qidirish
eng_yaxshi_segment = min(segmentlar, key=lambda s: p[s]) # ⚠️
# oldindan belgilangan segmentlar + tuzatish # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 11.1-11.9-darslar (o'tilgan): Butun qism
- 8.8-8.9-darslar (o'tilgan): Gipoteza, hisobot
- 4.10-dars (o'tilgan): Sababiylik va eksperiment
- 9.9-dars (o'tilgan): Qaror va xato narxi
- Keyingi qismlar: ML modellarini A/B test bilan baholash
8. Eng yaxshi amaliyotlar
Testni yozma reja bilan boshlang.
Bitta asosiy metrika.
SRM va sanity-checkdan boshlang.
CI va amaliy chegara bilan qaror.
Ikkilamchilarga tuzatish.
Segmentlarni oldindan belgilang.
Qiyshiq metrikalarga bootstrap.
Neytral natijani ham hisobot qiling.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # asosiy metrika nechta?
2. # amaliy chegara nima uchun?
3. # SRM nima?
4. # SRM p < 0.001 bo'lsa?
5. # erta to'xtatish ta'siri?
6. # ikkilamchilarga tuzatish?
7. # segmentlar qachon belgilanadi?
8. # qiyshiq metrikaga?
9. # sath (guardrail) metrikasi nima?
10. # CI nolni o'z ichiga olsa?
11. # test davomiyligi nega to'liq hafta?
12. # neytral natija — nima?Javoblar
- Bitta
- Biznes ahamiyati uchun
- Guruhlar nisbati buzilishi
- Tahlilni to'xtatib, sababni topish
- I tur xato oshadi
- Holm/BH
- Oldindan
- Bootstrap
- Zararni aniqlash metrikasi
- Dalil yetarli emas
- Hafta kuni effekti
- Qimmatli bilim
Vazifa 2: Xatolarni tuzating
1. # har kuni p ni tekshirib, p < 0.05 da to'xtatish
2. proportions_ztest([klik_b, klik_a], [sessiya_b, sessiya_a])
3. for m in 12_metrika: print(m, p[m] < 0.05)
4. stats.ttest_ind(chek_b, chek_a) # kuchli qiyshiq
5. # eng yaxshi natijali segmentni hisobotda ko'rsatishJavoblar
1. # oldindan belgilangan muddatgacha kutish (11.2)
2. # foydalanuvchi darajasida agregatsiya
3. rad, p_tuz, _, _ = multipletests(p_lar, alpha=0.05, method="holm")
4. stats.bootstrap((chek_b, chek_a), farq, vectorized=True, random_state=0)
5. # oldindan belgilangan segmentlar; natijani gipoteza deb belgilashVazifa 3: To'liq test
Modellang:
- O'z A/B testingiz (metrika, chegara, n)
- Sanity-check
- Asosiy va ikkilamchi tahlil
- Hisobot
Vazifa 4: Erta to'xtatish
Modellang:
- H0 rost, 21 kunlik test
- Har kuni tekshirish
- I tur xato o'sishi
- Ketma-ket usullar haqida qisqacha
Vazifa 5: Quvvat va MDE
Modellang:
- Turli baza konversiya
- Kerakli n va davomiylik
- MDE jadvali
- Qaysi testlarni o'tkazish mantiqiy
Vazifa 6: Integratsiya
Modellang:
- Quvvat (11.2)
- Proporsiya (11.4)
- Bootstrap (11.8)
- Tuzatish (11.9)
Vazifa 7: O'ylash
A/B test "oltin standart" deb ataladi, chunki tasodifiy taqsimot sababiy xulosaga imkon beradi. Lekin ko'p muhim savollarni A/B test bilan javoblab bo'lmaydi: brend obro'si, uzoq muddatli sodiqlik, tarmoq effektlari, kamdan-kam hodisalar. Bunday hollarda nima qilish kerak va A/B testning chegaralari qayerda?
Javob
Qisqa javob: A/B test qisqa muddatli, individual darajadagi va tez o'lchanadigan effektlar uchun ideal. Uzoq muddatli, tarmoqli yoki kamdan-kam hodisalar uchun boshqa usullar kerak: geo-testlar, difference-in-differences, kvazi-eksperimentlar, uzoq muddatli kuzatuv (holdout guruhlar).
1. A/B test chegaralari
| Muammo | Sabab |
|---|---|
| Uzoq muddatli effekt | Test 2 hafta, effekt oylar |
| Tarmoq effekti | Guruhlar bir-biriga ta'sir qiladi (SUTVA) |
| Kamdan-kam hodisa | Quvvat yetmaydi (11.2) |
| Brend/obro' | O'lchash qiyin, sekin |
| Yangilik effekti | Boshlang'ich reaksiya != barqaror |
2. Muqobil usullar
- Geo-test / switchback: shaharlar yoki vaqt bo'laklari darajasida tasodifiylashtirish
- Holdout guruh: foydalanuvchilarning kichik qismi uzoq vaqt eski tajribada
- Difference-in-differences: tabiiy eksperiment (4.10)
- Surrogat metrikalar: uzoq muddatli natija bilan bog'liq qisqa metrika (ehtiyotkorlik bilan)
- Sifat tadqiqoti: intervyu, kuzatuv
3. Amaliy tavsiyalar
- Test davomiyligini effekt tabiatiga moslash
- Tarmoq effektlari bo'lsa — klaster darajasida tasodifiylashtirish
- Uzoq muddatli monitoring (metrikalar drift qilyaptimi)
- Bir necha usulni birlashtirish (triangulyatsiya)
4. Data Scientist qanday
- "Bu savolga A/B test javob beradimi?" deb so'raydi
- Cheklovlarni hisobotda ochiq yozadi (8.9)
- Surrogat metrikalarning xavfini tushuntiradi
5. Xulosa
- A/B test — kuchli, lekin universal emas
- Uzoq muddat, tarmoq, kam hodisa — muammo
- Geo-test, holdout, kvazi-eksperiment — muqobil
- Usulni savolga moslash — asosiy mahorat
Nimani mustahkamlaydi: 2.1, 2.7-bo'limlar.
Xulosa
Bu darsda 11-qismning barcha bilimlarini A/B test loyihasida qo'lladik.
Eng muhim uch fikr:
Oldindan loyihalash. Gipoteza 8.8-bob, bitta asosiy metrika, amaliy chegara, quvvat va namuna hajmi 11.2-bob, davomiylik (to'liq haftalar) va to'xtash qoidasi — hammasi testdan oldin yoziladi. Erta to'xtatish I tur xatoni bir necha barobar oshiradi.
Sanity va qaror. Tahlil SRM va ma'lumot sifati tekshiruvidan boshlanadi 11.5-bob. Asosiy metrika: farq (foiz punkt va nisbiy) + ishonch oralig'i + p; qaror CI va amaliy chegara bilan qabul qilinadi, faqat p bilan emas (11.1, 11.4).
Ikkilamchilar, segmentlar, hisobot. Ikkilamchi metrikalarga tuzatish (Holm, 11.9), sath metrikalari alohida; segmentlar oldindan belgilanadi va natijalari gipoteza sifatida qaraladi 8.8-bob; qiyshiq metrikalarga bootstrap 11.8-bob. Hisobot — xulosa birinchi, cheklovlar va keyingi qadam bilan 8.9-bob.
11-qism yakunlandi! Gipoteza testlari — noaniqlik ostida qaror qabul qilishning rasmiy tili: test tizimi va p-qiymat, quvvat va namuna hajmi, t-testlar, proporsiyalar, xi-kvadrat, ANOVA, noparametrik testlar, bootstrap va permutatsiya, ko'p taqqoslash va A/B test amaliyoti. Keyingi qismda Machine Learning asoslari boshlanadi: o'rganish nima, train/test ajratish, overfitting va bias-variance, birinchi modellar va baholash.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!