Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. ML savollari: qisqa va to'g'ri javoblar
- 2.2. SQL savollari
- 2.3. Jonli kodlash (live coding)
- 2.4. Case study tuzilishi
- 2.5. O'z loyihangizni tushuntirish: STAR
- 2.6. Xulq-atvor savollari
- 2.7. Tuzoqlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — ML savollari kod bilan: L1/L2, bias-variance, nomutanosiblik, sizish, boosting
- Misol 2 — SQL savollari sqlite3 da: JOIN, HAVING, oyna funksiyalari, retention, dublikatlar
- Misol 3 — Jonli kodlash: pandas masalalari va algoritm murakkabligi
- Misol 4 — Case study: "sotuv 10% tushdi" — segment yoki ma'lumot xatosi?
- 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
29.10-dars: Intervyu: ML, SQL va case study
29-QISM — LOYIHALAR VA KARYERA · 10-dars
1. Kirish va motivatsiya
Oldingi darsda intervyuning statistika va ehtimollik bo'limini ko'rdik: har javobni formula, intuitsiya va simulyatsiya bilan tekshirish. Data Science intervyusi odatda bir necha bosqichdan iborat va statistika — ulardan faqat biri. Qolganlari: ML nazariyasi ("L1 va L2 farqi nima?", "nomutanosib sinflarda qaysi metrika?"), SQL (ko'pincha jonli, jadval sxemasi bilan), jonli kodlash (pandas yoki oddiy algoritm), case study ("metrika tushdi — nima qilasiz?") va xulq-atvor savollari ("eng qiyin loyihangiz haqida gapiring").
Bu bosqichlarning har biri boshqa narsani tekshiradi. ML savollari — tushunchalarni aniq va qisqa tushuntira olishni. SQL — ma'lumotni o'zingiz olish qobiliyatini (ko'p tashkilotda tahlilchi ishining katta qismi SQL). Jonli kodlash — bosim ostida to'g'ri, o'qiladigan kod yozishni va murakkablikni tushunishni. Case study — noaniq biznes savolini tuzilmali tahlilga aylantirishni. Xulq-atvor — jamoada ishlash va o'z ishingizni tushuntirishni.
Real vaziyat. Nomzod texnik savollarning hammasiga yaxshi javob berdi, lekin case study da "sotuv 10% tushdi — nima qilasiz?" savoliga darhol "marketing kampaniyasini boshlash kerak" deb javob berdi. Intervyuer so'radi: "Tushish haqiqiymi? Ma'lumot to'g'rimi? Qaysi segmentda?" Nomzod bunday savollarni o'ylamagan edi. Bu darsning 4-misolida aynan shu case study ni ikki stsenariyda ko'ramiz: birida tushish haqiqiy va bitta segmentdan keladi, ikkinchisida esa tushish umuman yo'q — yuklash quvuri buzilgan va bitta segmentning ma'lumoti yo'qolgan. Ikkala holatda ham umumiy raqam bir xil: "sotuv ~10% tushdi".
Bu darsda intervyuning ML, SQL, jonli kodlash va case study bo'limlarini ko'rib chiqamiz — har birida to'g'ri javob tuzilishi va uni kod bilan tekshirish.
Bu darsda:
- ML savollari: bias-variance, overfitting, L1 va L2, nomutanosib sinflar, metrika tanlash, sizish, daraxtlar va chiziqli modellar, gradient boosting
- SQL savollari: JOIN turlari, GROUP BY va HAVING, oyna funksiyalari, top-N, retention, dublikatlar — sqlite3 da haqiqiy jadvallar bilan
- Jonli kodlash: yondashuv, pandas masalalari, algoritm va murakkablik
- Case study tuzilishi: aniqlashtirish → metrika → ma'lumot → yondashuv → baholash → xatarlar
- O'z loyihangizni tushuntirish (STAR) va xulq-atvor savollari
- Tuzoqlar
ℹ Misollar real numpy/pandas/sklearn va sqlite3 bilan (Python 3.14). SQL so'rovlari jarayon ichidagi sqlite bazasida bajariladi; natijalar pandas bilan qayta tekshiriladi. Ma'lumotlar sintetik.
2. Nazariya — chuqur tushuntirish
2.1. ML savollari: qisqa va to'g'ri javoblar
ML savollarida intervyuer uzun ma'ruza emas, aniq ta'rif + nima uchun muhim + amaliy misol kutadi. Har savolga 30-60 soniyalik javob tayyorlang va uni kichik tajriba bilan tasdiqlay oling.
Bias-variance 12.5-bob.
SAVOL: "Bias-variance nima?"
JAVOB: kutilgan xato = bias^2 + variance + kamaytirib bo'lmaydigan shovqin
bias - model o'rtacha qanchalik noto'g'ri (juda sodda model)
variance - boshqa o'quv namunasida bashorat qanchalik o'zgaradi
(juda murakkab model)
murakkablik oshsa: bias kamayadi, variance oshadi -> U shaklidagi xato
XATO: "bias - bu ma'lumotdagi tarafkashlik" (boshqa tushuncha: 29.11)
TEKSHIRUV: 1-misol, 2-bo'lim - yoyilma test MSE bilan mos keladiOverfitting va unga qarshi choralar 12.4-bob.
BELGISI: o'quvda yaxshi, validatsiyada yomon; o'rganish egri chiziqlarida
katta bo'shliq 18.8-bob
CHORALAR:
ko'proq ma'lumot | regularizatsiya (L1, L2, dropout)
soddaroq model / kam belgi | erta to'xtatish (15.9, 20-qism)
cross-validation bilan tanlash | ansambllar (bagging - variance ni kamaytiradi)
augmentatsiya (22-qism) | sizishni yo'qotish (ba'zan "overfitting" -
| aslida sizish)
XATO: "overfitting bo'lsa, epochlarni ko'paytiraman" yoki faqat test
to'plamiga qarab sozlash (18.11 - validatsiyaga overfitting)L1 va L2 regularizatsiya (13.7, 13.8).
L2 (Ridge): loss + alfa * sum(w^2) koeffitsientlarni NOLGA YAQINLASHTIRADI,
lekin aynan nol qilmaydi; korrelyatsiyali
belgilar orasida og'irlikni bo'ladi
L1 (Lasso): loss + alfa * sum(|w|) ko'p koeffitsientni AYNAN NOL qiladi ->
belgi tanlash, siyrak model
NEGA: L1 cheklov sohasi romb - optimum ko'pincha burchakda (o'qda) bo'ladi;
L2 sohasi aylana - burchak yo'q
ElasticNet - ikkalasi birga (korrelyatsiyali belgilarda L1 beqaror)
XATO: belgilarni masshtablamasdan regularizatsiya 17.4-bob - jarima
birliklarga bog'liq bo'lib qoladi
TEKSHIRUV: 1-misol, 1-bo'lim - nol koeffitsientlar soniNomutanosib sinflar va metrika tanlash (14.9, 18.9).
SAVOL: "Firibgarlik 2%. Modelingiz accuracy 98% - yaxshimi?"
JAVOB: "hammasi manfiy" modeli ham ~98% oladi -> accuracy ma'nosiz
METRIKA: PR-AUC (tasodifiy darajasi = musbat ulushi), recall/precision
biznes chegarasida, ROC-AUC (tartiblash, lekin nomutanosiblikda
optimistik ko'rinadi)
CHEGARA: 0.5 emas - xatolar narxi bo'yicha tanlanadi 14.1-bob
USULLAR: class_weight, chegara tanlash, kalibrlash 14.10-bob;
oversampling/SMOTE - faqat o'quv qismida, CV ichida
XATO: resampling ni bo'lishdan OLDIN qilish (sizish); faqat ROC-AUC
TEKSHIRUV: 1-misol, 3-bo'limSizish — data leakage (12.9, 17.8).
TA'RIF: bashorat vaqtida mavjud bo'lmaydigan ma'lumot o'qitishga kirib qoladi
TURLARI:
maqsaddan sizish - belgi maqsadning natijasi ("qaytarilgan_summa" ->
"kredit qaytmadi")
bo'lishdan sizish - masshtablash, belgi tanlash, imputatsiya, target
encoding BUTUN ma'lumotda, keyin CV
vaqt sizishi - kelajak ma'lumoti bilan o'qitish (28.1-28.3)
guruh sizishi - bir mijozning qatorlari ham train, ham test da
YECHIM: Pipeline (19-qism) - hamma o'rganiladigan qadam CV ichida;
vaqt bo'yicha bo'lish; GroupKFold
BELGISI: "juda yaxshi" natija (AUC 0.99) - avval sizishni qidiring
TEKSHIRUV: 1-misol, 4-bo'lim - tasodifiy maqsadda accuracy 0.85Daraxtlar va chiziqli modellar (13, 15-qismlar).
CHIZIQLI: signal ~ chiziqli, kam ma'lumot, talqin kerak, ekstrapolyatsiya,
ko'p siyrak belgi (matn TF-IDF)
DARAXTLAR/BOOSTING: nochiziqlik, o'zaro ta'sirlar, zinapoyali bog'liqlik,
aralash turdagi belgilar, masshtablash shart emas; jadval
ma'lumotida ko'pincha eng kuchli
LEKIN: daraxt ekstrapolyatsiya qilmaydi (o'quv diapazonidan tashqarida
konstanta); chiziqli signalni "zinapoya" bilan yaqinlashtiradi
QOIDA: ikkalasini ham sinang, CV da juftlashgan taqqoslang 18.10-bob
TEKSHIRUV: 1-misol, 6-bo'limGradient boosting qanday ishlaydi 15.8-bob.
1. boshlang'ich bashorat F0 = o'rtacha (MSE uchun)
2. har qadamda: qoldiqlar r = y - F (MSE ning manfiy gradienti)
kichik daraxt h ni r ga o'qitish
F <- F + eta * h (eta - o'rganish tezligi, 0.05-0.1)
3. M ta qadam; erta to'xtatish validatsiya bo'yicha
BOSHQA LOSS: log-loss uchun "qoldiq" - y - p (gradient); daraxt
barglaridagi qiymatlar Nyuton qadami bilan hisoblanadi
RANDOM FOREST DAN FARQI: RF - mustaqil chuqur daraxtlar, o'rtacha
(variance ni kamaytiradi); boosting - ketma-ket sayoz daraxtlar,
har biri oldingilar xatosini tuzatadi (bias ni kamaytiradi)
TEKSHIRUV: 1-misol, 5-bo'lim - 10 qatorli noldan yozilgan versiya
sklearn bilan bir xil bashorat beradi2.2. SQL savollari
SQL intervyusida odatda jadval sxemasi beriladi va so'rov yozish so'raladi. Avval so'rovning mantiqiy bajarilish tartibini eslang — ko'p xato shundan kelib chiqadi:
MANTIQIY TARTIB: FROM / JOIN -> WHERE -> GROUP BY -> HAVING
-> SELECT (oyna funksiyalari shu yerda) -> DISTINCT
-> ORDER BY -> LIMIT
NATIJALAR:
WHERE da agregat (SUM, COUNT) ishlatib bo'lmaydi -> HAVING
WHERE da oyna funksiyasi natijasini ishlatib bo'lmaydi -> ichki so'rov/CTE
SELECT dagi taxallusni WHERE da ishlatib bo'lmaydi (ko'p SQL dialektida)JOIN turlari.
mijozlar (300) buyurtmalar (mijoz_id)
INNER JOIN - faqat ikkala tomonda ham mos bo'lganlar
LEFT JOIN - chapdagi HAMMA qator; mos kelmasa o'ng tomon NULL
-> qatorlar soni ORTADI (bir mijoz - ko'p buyurtma)
ANTI-JOIN - LEFT JOIN ... WHERE o'ng.id IS NULL
("hech narsa sotib olmaganlar")
FULL OUTER - ikkala tomondagi hammasi (sqlite 3.39+ da bor)
CROSS JOIN - har biri har biri bilan (dekart ko'paytma)
TUZOQ: LEFT JOIN dan keyin WHERE da o'ng jadval ustunini filtrlash
LEFT ni INNER ga aylantiradi -> shartni ON ga qo'yingGROUP BY, HAVING va agregatlar.
SELECT m.shahar, COUNT(DISTINCT b.mijoz_id) AS xaridorlar, SUM(b.summa) AS daromad
FROM buyurtmalar b JOIN mijozlar m ON m.id = b.mijoz_id
WHERE b.sana >= '2025-01-01' -- qatorlar filtri (guruhlashdan OLDIN)
GROUP BY m.shahar
HAVING COUNT(DISTINCT b.mijoz_id) >= 30 -- guruhlar filtri (guruhlashdan KEYIN)
ORDER BY daromad DESC;Oyna funksiyalari — qatorlarni yig'masdan guruh ichida hisoblash:
-- har shaharda top-2 mijoz (top-N per group)
SELECT * FROM (
SELECT shahar, mijoz_id, summa,
ROW_NUMBER() OVER (PARTITION BY shahar ORDER BY summa DESC, mijoz_id) AS rn
FROM jami) WHERE rn <= 2;
-- oyma-oy o'sish
SELECT oy, d, 1.0 * (d - LAG(d) OVER (ORDER BY oy)) / LAG(d) OVER (ORDER BY oy) AS osish
FROM oylik;
-- 7 kunlik sirg'aluvchi o'rtacha
SELECT sana, AVG(d) OVER (ORDER BY sana ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)
FROM kunlik;ROW_NUMBER - 1, 2, 3, 4 (tenglikda ham turli raqam; tartibni to'liq bering!)
RANK - 1, 2, 2, 4 (tenglikda bir xil, keyin sakrash)
DENSE_RANK - 1, 2, 2, 3 (sakrashsiz)
"top-2" savolida: tenglik bo'lsa nima qilish kerak? - ANIQLASHTIRING
ROWS va RANGE: ROWS - qatorlar soni; RANGE - qiymat oralig'i; kunlar
bo'shliqli bo'lsa "7 qator" != "7 kun" - avval kalendar jadval bilan to'ldiringRetention / kohort tahlili.
1. har mijozning kohorti = birinchi xarid oyi (MIN)
2. har xarid uchun oy_farq = xarid oyi - kohort oyi
3. kohort x oy_farq bo'yicha DISTINCT mijozlar soni / kohort hajmi
TUZOQ: oxirgi kohortlar uchun keyingi oylar hali KUZATILMAGAN - 0 emas,
NULL (aks holda retention "tushib ketgandek" ko'rinadi)Dublikatlar.
-- topish
SELECT mijoz_id, sana, summa, COUNT(*) FROM buyurtmalar
GROUP BY mijoz_id, sana, summa HAVING COUNT(*) > 1;
-- bittasini qoldirib o'chirish
DELETE FROM buyurtmalar WHERE id IN (
SELECT id FROM (SELECT id, ROW_NUMBER() OVER (
PARTITION BY mijoz_id, sana, summa ORDER BY id) AS rn FROM buyurtmalar)
WHERE rn > 1);NULL tuzoqlari: NULL = NULL — rost emas (IS NULL ishlating); COUNT(ustun) NULL larni sanamaydi, COUNT(*) sanaydi; AVG NULL larni tashlab yuboradi; NOT IN (... NULL ...) hech narsa qaytarmaydi — NOT EXISTS xavfsizroq.
2.3. Jonli kodlash (live coding)
1. ANIQLASHTIRISH: kirish formati, chegaraviy holatlar (bo'sh ro'yxat,
takrorlar, tenglik, NULL), natija formati
2. KICHIK MISOL: qo'lda 3-5 elementda natijani yozing
3. ODDIY VA TO'G'RI yechim - avval (hatto O(n^2) bo'lsa ham), ovoz chiqarib
4. MURAKKABLIK: vaqt va xotira; "yaxshilash mumkinmi?" - xesh, saralash,
ikki ko'rsatkich, uyum (heap)
5. TEST: misol, chegaraviy holat, oddiy yechim bilan solishtirish
pandas MASALALARI (tez-tez):
guruhlash + agregat, har guruhda top-N (sort + groupby.head),
sessiyalarga ajratish (diff + cumsum), birlashtirish (merge) va uning
qatorlar sonini tekshirish, pivot, sirg'aluvchi oyna (rolling)
ALGORITM MASALALARI (DS uchun odatda oddiy):
ikki son yig'indisi (xesh), top-k (Counter + heap), takrorlarni topish,
ikkilik qidiruv, satrlar bilan ishlash, oddiy dinamik dasturlash| Masala | Oddiy | Yaxshilangan | G'oya |
|---|---|---|---|
| Ikki son yig'indisi | O(n^2) | O(n) vaqt, O(n) xotira | ko'rilganlarni lug'atda saqlash |
| Top-k tez-tez element | O(m log m) saralash | O(n + m log k) | Counter + heap |
| Sessiyalarga ajratish | har juft | O(n log n) | saralash + diff + cumsum |
| Takrorlarni topish | O(n^2) | O(n) | to'plam (set) |
| Saralangan massivda qidiruv | O(n) | O(log n) | ikkilik qidiruv |
2.4. Case study tuzilishi
Case study — tuzilmasiz savol ("sotuv tushdi", "yangi funksiyani qanday baholaymiz?", "narxni oshirish kerakmi?"). Intervyuer to'g'ri javobni emas, tuzilmali fikrlashni baholaydi.
1. ANIQLASHTIRUVCHI SAVOLLAR
qaysi metrika? (daromad, buyurtmalar soni, konversiya?)
qaysi davr va nimaga nisbatan? (o'tgan oy, o'tgan yil shu oy?)
qachondan? keskinmi yoki asta-sekinmi?
hammada yoki qaysidir segmentda?
o'sha paytda nima o'zgardi? (reliz, narx, kampaniya, raqobatchi, bayram)
2. METRIKA DARAXTI
daromad = sessiyalar * konversiya * o'rtacha chek
sessiyalar = yangi + qaytgan; kanal bo'yicha ...
3. MA'LUMOT
avval SIFAT: to'liqlik (qatorlar soni), yangi manba, formatlar,
loglash o'zgarishi, vaqt zonasi; keyin kerakli jadvallar
4. YONDASHUV
ichki: dekompozitsiya (qaysi komponent?), segmentlar (qaysi segment?),
vaqt qatori (qachondan?)
tashqi: mavsumiylik (o'tgan yil), raqobatchilar, bozor
5. BAHOLASH
gipoteza -> tekshiruv: masalan "android reliz" -> android konversiyasi
reliz sanasidan boshlab tushganmi? versiya bo'yicha farq bormi?
6. XATARLAR VA KEYINGI QADAMLAR
noaniqliklar, qo'shimcha ma'lumot, tajriba (A/B), monitoringTo'liq namuna: "Onlayn do'konda oxirgi 4 haftada sotuv 10% tushdi. Nima qilasiz?"
1. ANIQLASHTIRISH:
"sotuv" - daromadmi yoki buyurtmalar soni? -> daromad
nimaga nisbatan? -> oldingi 4 hafta (hafta kunlari bir xil)
tushish keskinmi? -> hisobotda ko'rinmaydi, kunlik qatorni ko'raman
2. MA'LUMOT SIFATI (birinchi!):
kunlik qatorlar soni, har segment har kuni bormi, yangi manbalar,
loglash/ETL o'zgarishi -> agar segment YO'QOLGAN bo'lsa, tushish
haqiqiy emas, bu ma'lumot xatosi
3. DEKOMPOZITSIYA:
daromad = sessiyalar * konversiya * o'rtacha chek
qaysi komponent o'zgardi? (log-hissa)
4. SEGMENTLAR:
platforma, hudud, kanal, yangi/qaytgan mijozlar, kategoriya
qaysi segment tushishning qanchasini beradi? (hissa = segment o'zgarishi
/ umumiy oldingi daromad)
5. GIPOTEZA VA TEKSHIRUV:
"android konversiyasi -22%" -> android reliz sanasi? versiya bo'yicha?
ilova xatolari loglari? to'lov bosqichidagi voronka?
6. TAVSIYA VA XATARLAR:
relizni orqaga qaytarish / tuzatish, monitoring 27.11-bob - segment
darajasidagi ogohlantirish; keyingi relizlar uchun bosqichli chiqarish4-misolda xuddi shu tartib kod bilan bajariladi — va ikki stsenariyda ikki xil javob beradi.
2.5. O'z loyihangizni tushuntirish: STAR
"Loyihangiz haqida gapirib bering" — deyarli har intervyuda. Tuzilma — STAR:
S - SITUATION (vaziyat) 1-2 gap: kontekst, kim uchun, nega muhim
T - TASK (vazifa) sizning vazifangiz, metrika, cheklovlar
A - ACTION (harakat) SIZ nima qildingiz: ma'lumot, bazaviy model,
asosiy qarorlar va NEGA; nima ishlamadi
R - RESULT (natija) raqam bazaga nisbatan; biznes ta'siri;
nimani boshqacha qilardingiz
2-3 daqiqa; keyin intervyuer chuqurlashadi - har raqamni tushuntira olingNamuna (to'qima loyiha, 29.8 dagi namuna rezyumedan):
S: Bankda o'z vaqtida to'lanmagan kreditlar ulushi oshayotgan edi; eslatmalar
hammaga bir xil yuborilardi.
T: Keyingi oyda to'lovni kechiktirish ehtimolini bashorat qilish va eslatmalarni
xavfli mijozlarga yo'naltirish; metrika - ROC-AUC va eslatmadan keyingi to'lov
ulushi.
A: 18 oylik tranzaksiyalardan 40 belgi yig'dim, vaqt bo'yicha validatsiya
qildim (tasodifiy bo'lish sizish berardi - kelajak ma'lumoti). Bazaviy
logistik regressiya 0.71; gradient boosting 0.78 - 5 fold da juftlashgan
farq 2*SE dan katta. Ehtimollarni kalibrladim, chunki bo'lim chegarani
ehtimol bo'yicha tanlamoqchi edi. Ishlamagan narsa: "oxirgi to'lov
kechikishi" belgisi - u keyinroq to'ldirilar ekan (sizish), olib tashladim.
R: A/B testda yo'naltirilgan eslatma o'z vaqtida to'lov ulushini 2.1 foiz
punktga oshirdi (p = 0.01). Boshqacha qilganim: monitoringni birinchi
kundan qurardim - 3 oydan keyin drift tufayli qayta o'qitish kerak bo'ldi.2.6. Xulq-atvor savollari
TEZ-TEZ SO'RALADI: NIMA KUTILADI:
"eng qiyin loyihangiz" STAR, sizning hissangiz, saboq
"xato qilgan payt" halollik, nimani o'rgandingiz,
qanday tuzatdingiz
"texnik bo'lmagan odamga tushuntirish" 29.4 - oddiy til, qaror uchun raqam
"rahbar bilan kelishmovchilik" ma'lumotga tayanish, hurmat, murosaga
kelish yoki eskalatsiya
"muddat tig'iz, ma'lumot yomon" ustuvorlik, cheklovlarni ochiq aytish
"nega aynan bizda?" vakansiyani o'qiganingiz 29.8-bob
UMUMIY: 3-5 ta tayyor hikoya (STAR) - har biri bir necha savolga mos;
"biz" emas "men"; muvaffaqiyatsizlik ham - saboq bilan;
oxirida intervyuerga 2-3 savol (jamoa, ma'lumot infratuzilmasi,
muvaffaqiyat o'lchovi)2.7. Tuzoqlar
Asosiy tuzoqlar: ML ta'riflarini yodlab, misol va "nega"siz aytish; bias-variance ni ma'lumotdagi tarafkashlik bilan chalkashtirish; nomutanosib sinflarda accuracy; resampling yoki belgi tanlashni CV dan oldin qilish; "juda yaxshi" natijada sizishni qidirmaslik; SQL da WHERE va HAVING ni chalkashtirish; LEFT JOIN dan keyin WHERE bilan uni INNER ga aylantirish; JOIN dan keyin qatorlar sonini tekshirmaslik; ROW_NUMBER da tartibni to'liq bermaslik (tenglik); retention da kuzatilmagan oylarni 0 deb ko'rsatish; NOT IN va NULL; jonli kodlashda aniqlashtirmasdan yozish, sukut bilan yozish, murakkablikni aytmaslik, test qilmaslik; case study da ma'lumot sifatini tekshirmasdan biznes xulosasi; darhol yechim taklif qilish; faqat bitta gipoteza; STAR da "biz" va natijasiz hikoya; xulq-atvor savoliga tayyorlanmaslik.
3. Tez ma'lumotnoma
import sqlite3
from contextlib import closing
import pandas as pd
# SQL ni pandas ichida sinash
with closing(sqlite3.connect(":memory:")) as con:
df.to_sql("buyurtmalar", con, index=False)
natija = pd.read_sql_query("SELECT ... FROM buyurtmalar ...", con)
# pandas: har guruhda top-N
top = (df.sort_values(["shahar", "summa"], ascending=[True, False])
.groupby("shahar").head(2))
# pandas: sessiyalar (30 daqiqa)
df = df.sort_values(["user", "vaqt"])
farq = df.groupby("user")["vaqt"].diff()
df["sessiya"] = (farq.isna() | (farq > pd.Timedelta(minutes=30))).groupby(df["user"]).cumsum()
# case study: dekompozitsiya
r_ses = k_ses / o_ses
r_konv = (k_buy / k_ses) / (o_buy / o_ses)
r_chek = (k_dar / k_buy) / (o_dar / o_buy) # r_ses * r_konv * r_chek = k_dar / o_darSQL tez ma'lumotnoma
| Vazifa | Asosiy qism |
|---|---|
| Hech narsa sotib olmaganlar | LEFT JOIN ... WHERE b.id IS NULL |
| Guruh filtri | GROUP BY ... HAVING COUNT(*) > n |
| Har guruhda top-N | ROW_NUMBER() OVER (PARTITION BY g ORDER BY x DESC, id) + WHERE rn <= N |
| O'tgan davrga nisbatan | LAG(x) OVER (ORDER BY davr) |
| Sirg'aluvchi o'rtacha | AVG(x) OVER (ORDER BY sana ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) |
| Kumulyativ yig'indi | SUM(x) OVER (ORDER BY sana) |
| Kohort | MIN(oy) ... GROUP BY mijoz + oy farqi |
| Dublikatlar | GROUP BY kalit HAVING COUNT(*) > 1; ROW_NUMBER() ... rn > 1 ni o'chirish |
Intervyu bo'limlari xulosasi
ML: ta'rif + nega + misol + kichik tajriba; accuracy nomutanosiblikda ma'nosiz
SQL: mantiqiy tartib (FROM-WHERE-GROUP-HAVING-SELECT-ORDER); JOIN dan keyin qatorlar sonini tekshir
jonli kod: aniqlashtir -> misol -> oddiy yechim -> murakkablik -> test
case: aniqlashtir -> ma'lumot sifati -> dekompozitsiya -> segment -> gipoteza -> xatarlar
STAR: vaziyat, vazifa, SIZNING harakatingiz, natija bazaga nisbatan4. Batafsil misollar
Misollar real numpy/pandas/sklearn va sqlite3 bilan (Python 3.14). Har misol mustaqil ishlaydi; ma'lumotlar sintetik.
Misol 1 — ML savollari kod bilan: L1/L2, bias-variance, nomutanosiblik, sizish, boosting
"""ML intervyu savollari kod bilan: L1/L2, bias-variance, nomutanosib sinflar, sizish, boosting."""
import numpy as np
from sklearn.datasets import make_regression
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.linear_model import Lasso, LinearRegression, LogisticRegression, Ridge
from sklearn.metrics import average_precision_score, roc_auc_score
from sklearn.model_selection import cross_val_score, train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.tree import DecisionTreeRegressor
YIG = "yig'indi"
YOQ = "farq yo'q"
def main() -> None:
rng = np.random.default_rng(10)
print("=== 1. L1 va L2: qaysi biri siyrak koeffitsient beradi? ===")
X, y, haq_koef = make_regression(n_samples=200, n_features=50, n_informative=5,
noise=10, coef=True, random_state=0)
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.5, random_state=0)
for nom, m in [("OLS", LinearRegression()), ("Ridge (L2)", Ridge(alpha=10)),
("Lasso (L1)", Lasso(alpha=1.0, max_iter=10_000))]:
m.fit(Xtr, ytr)
nol = int(np.sum(np.abs(m.coef_) < 1e-8))
print(f" {nom:<11} nol koeffitsientlar {nol:>2}/50, test R^2 "
f"{m.score(Xte, yte):.3f}")
lasso = Lasso(alpha=1.0, max_iter=10_000).fit(Xtr, ytr)
tanlangan = np.flatnonzero(np.abs(lasso.coef_) > 1e-8)
inf = np.isin(np.flatnonzero(haq_koef != 0), tanlangan).sum()
print(f" Lasso tanlagan belgilar: {tanlangan.size} ta; informativlardan {inf}/5, "
f"shovqin belgilari {tanlangan.size - inf}")
print("\n=== 2. Bias-variance: polinom darajasi (n=30, 300 takror) ===")
xg = np.linspace(0.05, 0.95, 50)
haq = np.sin(2 * np.pi * xg)
print(f" {'daraja':>6} {'bias^2':>8} {'variance':>9} {'shovqin':>8} "
f"{YIG:>9} {'test MSE':>9}")
for d in [1, 3, 9]:
bash, mse = [], []
for _ in range(300):
x = rng.random(30)
yy = np.sin(2 * np.pi * x) + rng.normal(0, 0.3, 30)
m = make_pipeline(PolynomialFeatures(d), LinearRegression()).fit(x[:, None], yy)
b = m.predict(xg[:, None])
bash.append(b)
mse.append(np.mean((b - haq - rng.normal(0, 0.3, 50)) ** 2))
b = np.array(bash)
b2 = np.mean((b.mean(axis=0) - haq) ** 2)
var = np.mean(b.var(axis=0))
print(f" {d:>6} {b2:>8.4f} {var:>9.4f} {0.09:>8.4f} {b2 + var + 0.09:>9.4f} "
f"{np.mean(mse):>9.4f}")
print("\n=== 3. Nomutanosib sinflar (musbat ~2%) ===")
n = 20_000
Xc = rng.normal(0, 1, (n, 5))
logit = -4.6 + 1.2 * Xc[:, 0] + 0.8 * Xc[:, 1]
yc = (rng.random(n) < 1 / (1 + np.exp(-logit))).astype(int)
Xa, Xb, ya, yb = train_test_split(Xc, yc, test_size=0.5, random_state=0, stratify=yc)
print(f" musbat ulushi: {yb.mean():.4f}")
print(f" 'hammasi manfiy' modeli: accuracy {1 - yb.mean():.4f}, recall 0.0")
p = LogisticRegression().fit(Xa, ya).predict_proba(Xb)[:, 1]
print(f" logistik: ROC-AUC {roc_auc_score(yb, p):.3f}, PR-AUC "
f"{average_precision_score(yb, p):.3f} (tasodifiy PR-AUC = {yb.mean():.3f})")
for c in [0.5, 0.1]:
t = p >= c
tp = int((t & (yb == 1)).sum())
print(f" chegara {c}: precision {tp / max(t.sum(), 1):.3f}, "
f"recall {tp / yb.sum():.3f}")
print("\n=== 4. Sizish: belgi tanlash CV DAN OLDIN (y tasodifiy!) ===")
xato, togri = [], []
for _ in range(10):
Xs = rng.normal(0, 1, (100, 2000))
ys = rng.integers(0, 2, 100)
top = SelectKBest(f_classif, k=20).fit(Xs, ys).get_support()
xato.append(cross_val_score(LogisticRegression(max_iter=1000),
Xs[:, top], ys, cv=5).mean())
togri.append(cross_val_score(make_pipeline(SelectKBest(f_classif, k=20),
LogisticRegression(max_iter=1000)),
Xs, ys, cv=5).mean())
xato, togri = np.array(xato), np.array(togri)
print(" 10 ta tasodifiy ma'lumot (n=100, 2000 belgi, k=20), o'rtacha accuracy:")
for nom, v in [("tanlash hamma ma'lumotda, keyin CV", xato),
("tanlash Pipeline ichida (har fold)", togri)]:
print(f" {nom:<36} {v.mean():.3f} (SE {v.std(ddof=1) / np.sqrt(10):.3f})")
print(" haqiqiy accuracy: 0.5 (belgilar va y bog'liq emas)")
print("\n=== 5. Gradient boosting noldan (qoldiqlarga daraxt) va sklearn ===")
Xg = rng.uniform(-2, 2, (1000, 3))
yg = np.sin(Xg[:, 0]) * 2 + Xg[:, 1] ** 2 + rng.normal(0, 0.3, 1000)
Xg1, Xg2, yg1, yg2 = Xg[:700], Xg[700:], yg[:700], yg[700:]
f1, f2 = np.full(700, yg1.mean()), np.full(300, yg1.mean())
for _ in range(100):
qoldiq = yg1 - f1 # MSE ning manfiy gradienti
d = DecisionTreeRegressor(max_depth=2, random_state=0).fit(Xg1, qoldiq)
f1 += 0.1 * d.predict(Xg1)
f2 += 0.1 * d.predict(Xg2)
sk = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1, max_depth=2,
random_state=0).fit(Xg1, yg1)
mse_o = np.mean((f2 - yg2) ** 2)
mse_s = np.mean((sk.predict(Xg2) - yg2) ** 2)
print(f" o'zimizniki test MSE {mse_o:.4f}, sklearn {mse_s:.4f}, "
f"bashoratlar bir xil (maks farq < 1e-9): "
f"{np.max(np.abs(f2 - sk.predict(Xg2))) < 1e-9}")
print(f" o'rtacha bilan bazaviy MSE: {np.mean((yg2 - yg1.mean()) ** 2):.4f}")
print("\n=== 6. Daraxt yoki chiziqli model? (5-fold CV R^2) ===")
Xd = rng.uniform(-2, 2, (600, 4))
shakllar = {"chiziqli signal": Xd @ np.array([1.5, -2.0, 1.0, 0.5]),
"zinapoya + o'zaro ta'sir": (3 * (Xd[:, 0] > 0) * (Xd[:, 1] > 0)
+ 2 * (Xd[:, 2] > 1))}
for nom, signal in shakllar.items():
yd = signal + rng.normal(0, 0.5, 600)
r_lin = cross_val_score(LinearRegression(), Xd, yd, cv=5)
r_gb = cross_val_score(GradientBoostingRegressor(random_state=0), Xd, yd, cv=5)
d = r_gb - r_lin
se = d.std(ddof=1) / np.sqrt(len(d))
g = "boosting" if d.mean() > 2 * se else ("chiziqli" if d.mean() < -2 * se else YOQ)
print(f" {nom:<26} chiziqli {r_lin.mean():.3f}, boosting {r_gb.mean():.3f}, "
f"farq {d.mean():+.3f} (SE {se:.3f}) -> {g}")
print("\n=== 7. Xulosa ===")
print(f" L1: {50 - tanlangan.size} ta koeffitsient aynan nol, L2: 0 ta")
print(f" sizish: tasodifiy y da accuracy {xato.mean():.2f} "
f"(to'g'ri CV da {togri.mean():.2f})")
print(" ⭐ Har javobni kichik tajriba bilan tasdiqlash mumkin - intervyuda ayting")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. L1 va L2: qaysi biri siyrak koeffitsient beradi? ===
OLS nol koeffitsientlar 0/50, test R^2 0.976
Ridge (L2) nol koeffitsientlar 0/50, test R^2 0.949
Lasso (L1) nol koeffitsientlar 34/50, test R^2 0.987
Lasso tanlagan belgilar: 16 ta; informativlardan 5/5, shovqin belgilari 11
=== 2. Bias-variance: polinom darajasi (n=30, 300 takror) ===
daraja bias^2 variance shovqin yig'indi test MSE
1 0.1565 0.0200 0.0900 0.2665 0.2653
3 0.0029 0.0136 0.0900 0.1065 0.1082
9 0.0004 0.1046 0.0900 0.1950 0.1979
=== 3. Nomutanosib sinflar (musbat ~2%) ===
musbat ulushi: 0.0250
'hammasi manfiy' modeli: accuracy 0.9750, recall 0.0
logistik: ROC-AUC 0.840, PR-AUC 0.144 (tasodifiy PR-AUC = 0.025)
chegara 0.5: precision 0.400, recall 0.008
chegara 0.1: precision 0.164, recall 0.288
=== 4. Sizish: belgi tanlash CV DAN OLDIN (y tasodifiy!) ===
10 ta tasodifiy ma'lumot (n=100, 2000 belgi, k=20), o'rtacha accuracy:
tanlash hamma ma'lumotda, keyin CV 0.854 (SE 0.009)
tanlash Pipeline ichida (har fold) 0.521 (SE 0.021)
haqiqiy accuracy: 0.5 (belgilar va y bog'liq emas)
=== 5. Gradient boosting noldan (qoldiqlarga daraxt) va sklearn ===
o'zimizniki test MSE 0.1333, sklearn 0.1333, bashoratlar bir xil (maks farq < 1e-9): True
o'rtacha bilan bazaviy MSE: 4.1770
=== 6. Daraxt yoki chiziqli model? (5-fold CV R^2) ===
chiziqli signal chiziqli 0.974, boosting 0.952, farq -0.022 (SE 0.003) -> chiziqli
zinapoya + o'zaro ta'sir chiziqli 0.480, boosting 0.897, farq +0.417 (SE 0.026) -> boosting
=== 7. Xulosa ===
L1: 34 ta koeffitsient aynan nol, L2: 0 ta
sizish: tasodifiy y da accuracy 0.85 (to'g'ri CV da 0.52)
⭐ Har javobni kichik tajriba bilan tasdiqlash mumkin - intervyuda aytingNatija tahlili.
1-bo'lim — L1 va L2. 50 belgidan faqat 5 tasi informativ. OLS va Ridge birorta koeffitsientni nol qilmadi (0/50), Lasso esa 34/50 ni aynan nolga tushirdi va test R^2 bo'yicha eng yaxshi bo'ldi (0.987; OLS 0.976, Ridge 0.949). Intervyudagi javob shu bilan tasdiqlandi. Lekin halol qo'shimcha: Lasso 16 ta belgi qoldirdi — 5 ta informativning hammasi va 11 ta shovqin belgisi. L1 "belgi tanlaydi", lekin mukammal emas; alpha ni CV bilan tanlash va tanlov barqarorligini tekshirish kerak (Vazifa 3).
2-bo'lim — bias-variance yoyilmasi 300 ta turli o'quv namunasida o'lchandi. 1-darajali polinom (to'g'ri chiziq): bias^2 0.1565 katta, variance 0.0200 kichik — underfitting. 3-daraja: bias^2 0.0029, variance 0.0136 — eng kichik jami xato. 9-daraja: bias^2 deyarli nol (0.0004), lekin variance 0.1046 — overfitting. Eng muhimi — nazariya va tajriba mosligi: bias^2 + variance + shovqin yig'indisi (0.2665, 0.1065, 0.1950) mustaqil o'lchangan test MSE bilan (0.2653, 0.1082, 0.1979) deyarli bir xil. Intervyuda formulani aytish bilan birga "buni simulyatsiya bilan tekshirish mumkin" deyish — kuchli signal.
3-bo'lim — nomutanosib sinflar. Musbat ulushi 0.0250; "hammasi manfiy" modeli accuracy 0.9750 — lekin birorta firibgarni topmaydi. Logistik regressiya: ROC-AUC 0.840 (yaxshi ko'rinadi), PR-AUC 0.144 — tasodifiy darajadan (0.025) olti barobar yuqori, lekin mutlaq qiymati kamtarona. Chegara 0.5 da recall atigi 0.008 — model deyarli hech kimni musbat demaydi; chegara 0.1 da recall 0.288, precision 0.164. Chegara — biznes qarori (xatolar narxi), 0.5 — sukut qiymati, xolos.
4-bo'lim — sizish. Maqsad tasodifiy, belgilar ham tasodifiy — haqiqiy accuracy 0.5. Lekin 20 ta belgini butun ma'lumotda tanlab, keyin CV qilsak: o'rtacha 0.854 (SE 0.009, 10 ta ma'lumotda). Tanlash Pipeline ichida (har fold o'quv qismida): 0.521 (SE 0.021) — 0.5 dan sezilarli farq yo'q. Sizish CV ni ham "aldaydi": tanlash test qismlarini ham ko'rgan.
5-bo'lim — gradient boosting noldan: boshlang'ich o'rtacha, har qadamda qoldiqqa chuqurligi 2 bo'lgan daraxt, 0.1 qadam, 100 marta. Test MSE 0.1333 — sklearn GradientBoostingRegressor bilan aynan bir xil, bashoratlar ham bir xil (True). O'rtacha bilan bazaviy MSE 4.1770 — boosting uni 30 barobardan ko'proq kamaytirdi. "Gradient boosting qanday ishlaydi?" savoliga eng yaxshi javob — shu 10 qator.
6-bo'lim — daraxt yoki chiziqli model. Chiziqli signalda chiziqli model sezilarli yaxshi (0.974 va 0.952, farq -0.022, SE 0.003) — boosting chiziqni zinapoyalar bilan yaqinlashtiradi. Zinapoya va o'zaro ta'sirli signalda aksincha: boosting 0.897, chiziqli 0.480 (+0.417, SE 0.026). "Qaysi model yaxshi?" savoliga to'g'ri javob — "signal shakliga bog'liq, ikkalasini CV da juftlashgan taqqoslayman".
7-bo'lim — xulosa natijadan hisoblandi.
Misol 2 — SQL savollari sqlite3 da: JOIN, HAVING, oyna funksiyalari, retention, dublikatlar
"""SQL intervyu savollari sqlite3 da: JOIN, GROUP BY/HAVING, oyna funksiyalari, retention, dublikatlar."""
import sqlite3
from contextlib import closing
import numpy as np
import pandas as pd
SHAHARLAR = ["Toshkent", "Samarqand", "Buxoro", "Namangan"]
def yarat(rng):
"""Mijozlar va buyurtmalar (2025-yil, 1-6 oy); ba'zi buyurtmalar takrorlangan."""
n_m = 300
mijoz = pd.DataFrame({
"id": np.arange(1, n_m + 1),
"shahar": rng.choice(SHAHARLAR, n_m, p=[0.5, 0.2, 0.15, 0.15]),
"royxat": pd.to_datetime("2025-01-01")
+ pd.to_timedelta(rng.integers(0, 150, n_m), unit="D"),
})
qator = []
for _, m in mijoz.iterrows():
if rng.random() < 0.2: # 20% mijoz hech narsa sotib olmagan
continue
faollik = rng.uniform(0.01, 0.08)
kun = m["royxat"]
while kun < pd.Timestamp("2025-07-01"):
if rng.random() < faollik:
qator.append((int(m["id"]), kun, int(round(float(rng.lognormal(11.5, 0.6)), -3))))
kun += pd.Timedelta(days=1)
faollik *= 0.995 # vaqt o'tishi bilan faollik pasayadi
buy = pd.DataFrame(qator, columns=["mijoz_id", "sana", "summa"])
takror = buy.sample(15, random_state=1) # yuklashdagi xato: 15 ta takror qator
buy = pd.concat([buy, takror]).sort_values(["sana", "mijoz_id"]).reset_index(drop=True)
buy.insert(0, "id", np.arange(1, len(buy) + 1))
for df in (mijoz, buy):
for c in ("royxat", "sana"):
if c in df:
df[c] = df[c].dt.strftime("%Y-%m-%d")
return mijoz, buy
def korsat(con, sarlavha, sql, n=None):
df = pd.read_sql_query(sql, con)
print(f"\n--- {sarlavha} ---")
print(df.head(n).to_string(index=False) if n else df.to_string(index=False))
return df
def main() -> None:
rng = np.random.default_rng(2025)
mijoz, buy = yarat(rng)
with closing(sqlite3.connect(":memory:")) as con:
mijoz.to_sql("mijozlar", con, index=False)
buy.to_sql("buyurtmalar", con, index=False)
print("=== 0. Jadvallar ===")
print(f" mijozlar: {len(mijoz)} qator, buyurtmalar: {len(buy)} qator")
print("\n=== 1. JOIN turlari ===")
korsat(con, "INNER va LEFT JOIN: qatorlar va mijozlar soni", """
SELECT 'INNER' AS tur, COUNT(*) AS qatorlar, COUNT(DISTINCT m.id) AS mijozlar
FROM mijozlar m JOIN buyurtmalar b ON b.mijoz_id = m.id
UNION ALL
SELECT 'LEFT', COUNT(*), COUNT(DISTINCT m.id)
FROM mijozlar m LEFT JOIN buyurtmalar b ON b.mijoz_id = m.id""")
korsat(con, "Anti-join: hech narsa sotib olmaganlar (shahar bo'yicha)", """
SELECT m.shahar, COUNT(*) AS xaridsiz
FROM mijozlar m LEFT JOIN buyurtmalar b ON b.mijoz_id = m.id
WHERE b.id IS NULL
GROUP BY m.shahar ORDER BY xaridsiz DESC, m.shahar""")
print("\n=== 2. Dublikatlar: topish va o'chirish ===")
korsat(con, "Takror guruhlar (mijoz, sana, summa)", """
SELECT COUNT(*) AS takror_guruhlar, SUM(n - 1) AS ortiqcha_qatorlar
FROM (SELECT mijoz_id, sana, summa, COUNT(*) AS n FROM buyurtmalar
GROUP BY mijoz_id, sana, summa HAVING COUNT(*) > 1)""")
con.execute("""
DELETE FROM buyurtmalar WHERE id IN (
SELECT id FROM (
SELECT id, ROW_NUMBER() OVER (PARTITION BY mijoz_id, sana, summa
ORDER BY id) AS rn
FROM buyurtmalar) WHERE rn > 1)""")
qoldi = con.execute("SELECT COUNT(*) FROM buyurtmalar").fetchone()[0]
print(f" o'chirilgandan keyin: {qoldi} qator "
f"(pandas drop_duplicates: {len(buy.drop_duplicates(['mijoz_id', 'sana', 'summa']))})")
print("\n=== 3. GROUP BY va HAVING ===")
korsat(con, "Shaharlar: kamida 30 xaridor bo'lganlari, daromad (mln so'm)", """
SELECT m.shahar, COUNT(DISTINCT b.mijoz_id) AS xaridorlar,
COUNT(*) AS buyurtmalar, ROUND(SUM(b.summa) / 1e6, 1) AS daromad_mln
FROM buyurtmalar b JOIN mijozlar m ON m.id = b.mijoz_id
GROUP BY m.shahar HAVING COUNT(DISTINCT b.mijoz_id) >= 30
ORDER BY daromad_mln DESC""")
print("\n=== 4. Oyna funksiyalari ===")
top = korsat(con, "Har shaharda top-2 mijoz (ROW_NUMBER)", """
WITH jami AS (
SELECT m.shahar, b.mijoz_id, SUM(b.summa) AS summa
FROM buyurtmalar b JOIN mijozlar m ON m.id = b.mijoz_id
GROUP BY m.shahar, b.mijoz_id)
SELECT shahar, mijoz_id, summa FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY shahar
ORDER BY summa DESC, mijoz_id) AS rn
FROM jami) WHERE rn <= 2
ORDER BY shahar, rn""")
b2 = pd.read_sql_query("SELECT * FROM buyurtmalar", con).merge(
mijoz[["id", "shahar"]], left_on="mijoz_id", right_on="id")
pd_top = (b2.groupby(["shahar", "mijoz_id"], as_index=False)["summa"].sum()
.sort_values(["shahar", "summa", "mijoz_id"], ascending=[True, False, True])
.groupby("shahar").head(2))
print(f" pandas bilan mos: {pd_top['mijoz_id'].tolist() == top['mijoz_id'].tolist()}")
korsat(con, "Oylik daromad va o'sish (LAG)", """
WITH oy AS (SELECT substr(sana, 1, 7) AS oy, SUM(summa) AS d
FROM buyurtmalar GROUP BY 1)
SELECT oy, ROUND(d / 1e6, 1) AS daromad_mln,
ROUND(100.0 * (d - LAG(d) OVER (ORDER BY oy))
/ LAG(d) OVER (ORDER BY oy), 1) AS osish_foiz
FROM oy ORDER BY oy""")
korsat(con, "Kunlik daromadning 7 kunlik sirg'aluvchi o'rtachasi (oxirgi 5 kun)", """
WITH kun AS (SELECT sana, SUM(summa) AS d FROM buyurtmalar GROUP BY sana)
SELECT sana, ROUND(d / 1e3) AS kunlik_ming,
ROUND(AVG(d) OVER (ORDER BY sana ROWS BETWEEN 6 PRECEDING
AND CURRENT ROW) / 1e3) AS orta7_ming
FROM kun ORDER BY sana DESC LIMIT 5""")
print("\n=== 5. Retention: kohort (birinchi xarid oyi) va keyingi oylar ===")
ret = korsat(con, "Kohortlar: faol mijozlar ulushi (NULL - hali kuzatilmagan oy)", """
WITH oylar AS (
SELECT mijoz_id,
CAST(substr(sana, 1, 4) AS INTEGER) * 12
+ CAST(substr(sana, 6, 2) AS INTEGER) AS oy_n
FROM buyurtmalar),
birinchi AS (SELECT mijoz_id, MIN(oy_n) AS k_n FROM oylar GROUP BY mijoz_id),
faol AS (
SELECT DISTINCT o.mijoz_id, f.k_n, o.oy_n - f.k_n AS farq
FROM oylar o JOIN birinchi f USING (mijoz_id)),
jad AS (
SELECT k_n, farq, COUNT(*) AS n FROM faol GROUP BY k_n, farq),
mx AS (SELECT MAX(oy_n) AS mx FROM oylar)
SELECT printf('%d-%02d', (j0.k_n - 1) / 12, (j0.k_n - 1) % 12 + 1) AS kohort,
j0.n AS hajm,
CASE WHEN j0.k_n + 1 <= mx THEN ROUND(1.0 * COALESCE(j1.n, 0) / j0.n, 3) END AS oy_1,
CASE WHEN j0.k_n + 2 <= mx THEN ROUND(1.0 * COALESCE(j2.n, 0) / j0.n, 3) END AS oy_2,
CASE WHEN j0.k_n + 3 <= mx THEN ROUND(1.0 * COALESCE(j3.n, 0) / j0.n, 3) END AS oy_3
FROM jad j0 CROSS JOIN mx
LEFT JOIN jad j1 ON j1.k_n = j0.k_n AND j1.farq = 1
LEFT JOIN jad j2 ON j2.k_n = j0.k_n AND j2.farq = 2
LEFT JOIN jad j3 ON j3.k_n = j0.k_n AND j3.farq = 3
WHERE j0.farq = 0 ORDER BY j0.k_n""")
b2["oy"] = pd.PeriodIndex(b2["sana"], freq="M")
b2["kohort"] = b2.groupby("mijoz_id")["oy"].transform("min")
b2["farq"] = (b2["oy"] - b2["kohort"]).apply(lambda x: x.n)
jad = b2.groupby(["kohort", "farq"])["mijoz_id"].nunique().unstack(fill_value=0)
pd_oy1 = (jad[1] / jad[0]).to_numpy()[:-1]
sql_oy1 = ret["oy_1"].to_numpy()[:-1]
print(f" pandas bilan oy_1 mos (0.001 aniqlikda): "
f"{bool(np.all(np.abs(pd_oy1 - sql_oy1) < 0.001))}")
print("\n=== 6. Xulosa (natijadan hisoblangan) ===")
o1 = ret["oy_1"].dropna()
print(f" 1-oy retention: o'rtacha {o1.mean():.2f}, "
f"min {o1.min():.2f}, maks {o1.max():.2f} (to'liq kuzatilgan kohortlar)")
print(" ⭐ Har so'rovni kichik tekshiruv bilan tasdiqlang (pandas, qo'lda hisob)")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 0. Jadvallar ===
mijozlar: 300 qator, buyurtmalar: 895 qator
=== 1. JOIN turlari ===
--- INNER va LEFT JOIN: qatorlar va mijozlar soni ---
tur qatorlar mijozlar
INNER 895 209
LEFT 986 300
--- Anti-join: hech narsa sotib olmaganlar (shahar bo'yicha) ---
shahar xaridsiz
Toshkent 39
...
=== 2. Dublikatlar: topish va o'chirish ===
--- Takror guruhlar (mijoz, sana, summa) ---
takror_guruhlar ortiqcha_qatorlar
15 15
o'chirilgandan keyin: 880 qator (pandas drop_duplicates: 880)
=== 3. GROUP BY va HAVING ===
--- Shaharlar: kamida 30 xaridor bo'lganlari, daromad (mln so'm) ---
shahar xaridorlar buyurtmalar daromad_mln
Toshkent 114 485 55.4
Samarqand 42 161 17.9
=== 4. Oyna funksiyalari ===
--- Har shaharda top-2 mijoz (ROW_NUMBER) ---
shahar mijoz_id summa
Buxoro 172 1239000
Buxoro 80 1064000
Namangan 84 1773000
Namangan 75 1197000
Samarqand 221 1576000
Samarqand 279 1049000
...
=== 5. Retention: kohort (birinchi xarid oyi) va keyingi oylar ===
--- Kohortlar: faol mijozlar ulushi (NULL - hali kuzatilmagan oy) ---
kohort hajm oy_1 oy_2 oy_3
2025-01 16 0.625 0.625 0.438
2025-02 45 0.711 0.622 0.622
2025-03 50 0.660 0.620 0.600
2025-04 34 0.676 0.471 NaN
2025-05 48 0.583 NaN NaN
2025-06 16 NaN NaN NaN
...
=== 6. Xulosa (natijadan hisoblangan) ===
1-oy retention: o'rtacha 0.65, min 0.58, maks 0.71 (to'liq kuzatilgan kohortlar)
⭐ Har so'rovni kichik tekshiruv bilan tasdiqlang (pandas, qo'lda hisob)Natija tahlili.
0-bo'lim — 300 mijoz va 895 buyurtma (15 tasi ataylab takrorlangan — yuklash xatosi).
1-bo'lim — JOIN turlari. INNER JOIN: 895 qator, 209 mijoz. LEFT JOIN: 986 qator, 300 mijoz — qatorlar soni mijozlar sonidan ham, buyurtmalar sonidan ham farq qiladi: xarid qilganlar har buyurtmasi bilan, xarid qilmagan 91 mijoz esa bittadan NULL qator bilan kiradi (895 + 91 = 986). Intervyuda "JOIN dan keyin qatorlar sonini tekshiraman" deyish — yaxshi odat belgisi. Anti-join xarid qilmaganlarni shahar bo'yicha berdi: Toshkent 39, Samarqand 24, Namangan 15, Buxoro 13 (jami 91).
2-bo'lim — dublikatlar. 15 ta takror guruh, 15 ta ortiqcha qator; ROW_NUMBER bilan har guruhdan bittasini qoldirib o'chirgandan keyin 880 qator — pandas drop_duplicates bilan bir xil. Qolgan hamma so'rovlar tozalangan jadvalda bajarildi — tartib muhim: dublikatlar daromadni oshirib ko'rsatadi.
3-bo'lim — GROUP BY va HAVING. Faqat kamida 30 xaridori bor shaharlar qoldi: Toshkent (114 xaridor, 485 buyurtma, 55.4 mln so'm) va Samarqand (42, 161, 17.9). Buxoro va Namangan HAVING filtri bilan tushib qoldi — WHERE bu yerda ishlamaydi, chunki shart agregat (COUNT(DISTINCT ...)) ustida.
4-bo'lim — oyna funksiyalari. Har shaharda top-2 mijoz ROW_NUMBER bilan topildi va pandas bilan mos (True); tartibda mijoz_id ikkinchi kalit — tenglik bo'lsa ham natija deterministik. LAG bilan oylik o'sish: fevral +299.9% (yanvar to'liq emas — mijozlar yil davomida ro'yxatdan o'tadi), iyun -30.3% — sintetik ma'lumotda yangi ro'yxatlar may oxirida to'xtaydi va faollik pasayadi. Bu ham intervyu uchun saboq: "o'sish +300%" raqamini ko'rganda avval asosni (bazani) tekshiring. 7 kunlik sirg'aluvchi o'rtacha kunlik tebranishni silliqlaydi: masalan 29-iyunda kunlik 259 ming, o'rtacha 568 ming.
5-bo'lim — retention. Kohort — birinchi xarid oyi; jadvalda har kohortning keyingi oylarda faol qolgan ulushi. 1-oy retention 0.583 dan 0.711 gacha. Muhim detal: oxirgi kohortlar uchun keyingi oylar hali kuzatilmagan — jadvalda NaN (SQL da NULL), 0 emas. Oddiy versiya (COUNT(... ) / hajm) bu kataklarga 0 qo'yardi va "retention qulab tushdi" degan xato xulosa berardi. pandas bilan tekshiruv mos (True) — solishtirish 0.001 aniqlikda, chunki SQL va Python yaxlitlash qoidalari turlicha bo'lishi mumkin (masalan, 0.625 ni ikki xonagacha).
6-bo'lim — to'liq kuzatilgan kohortlarda 1-oy retention o'rtacha 0.65 (min 0.58, maks 0.71).
Misol 3 — Jonli kodlash: pandas masalalari va algoritm murakkabligi
"""Jonli kodlash masalalari: pandas bilan sessiyalar, ikki son yig'indisi, top-k - murakkablik bilan."""
import heapq
from collections import Counter
import numpy as np
import pandas as pd
def sessiyalar_pandas(df, bosh=30):
"""Har foydalanuvchida 30 daqiqadan katta tanaffus - yangi sessiya."""
df = df.sort_values(["user", "vaqt"]).copy()
farq = df.groupby("user")["vaqt"].diff()
df["yangi"] = farq.isna() | (farq > pd.Timedelta(minutes=bosh))
df["sessiya"] = df.groupby("user")["yangi"].cumsum()
return df
def sessiyalar_sikl(hodisalar, bosh=30):
"""Tekshiruv uchun oddiy Python: {user: sessiyalar soni}."""
natija, oxirgi = {}, {}
for u, t in sorted(hodisalar):
if u not in oxirgi or t - oxirgi[u] > pd.Timedelta(minutes=bosh):
natija[u] = natija.get(u, 0) + 1
oxirgi[u] = t
return natija
def ikki_son_sodda(a, maqsad):
"""O(n^2): barcha juftlar; qaytaradi (indekslar, taqqoslashlar soni)."""
q = 0
for i in range(len(a)):
for j in range(i + 1, len(a)):
q += 1
if a[i] + a[j] == maqsad:
return (i, j), q
return None, q
def ikki_son_xesh(a, maqsad):
"""O(n): lug'atda ko'rilgan qiymatlar; qaytaradi (indekslar, qadamlar soni)."""
korilgan = {}
for j, x in enumerate(a):
if maqsad - x in korilgan:
return (korilgan[maqsad - x], j), j + 1
korilgan[x] = j
return None, len(a)
def top_k(sozlar, k):
"""O(n + m log k): sanash + k o'lchamli uyum (heap)."""
return heapq.nsmallest(k, Counter(sozlar).items(), key=lambda x: (-x[1], x[0]))
def main() -> None:
rng = np.random.default_rng(3)
print("=== 1. pandas: sessiyalarga ajratish (30 daqiqa tanaffus) ===")
qator, haqiqiy = [], 0
for u in range(1, 41):
t = pd.Timestamp("2025-03-01 08:00") + pd.Timedelta(minutes=float(rng.uniform(0, 600)))
for _ in range(int(rng.integers(3, 12))): # sessiyalar
haqiqiy += 1
for _ in range(int(rng.integers(1, 25))): # sessiya ichidagi hodisalar
qator.append((u, t))
t += pd.Timedelta(minutes=float(rng.exponential(2)))
t += pd.Timedelta(minutes=float(30 + rng.exponential(240)))
df = pd.DataFrame(qator, columns=["user", "vaqt"]).sample(frac=1, random_state=0)
n = len(df)
s = sessiyalar_pandas(df)
soni = s.groupby("user")["sessiya"].max()
uzun = s.groupby(["user", "sessiya"])["vaqt"].agg(lambda v: (v.max() - v.min()).total_seconds() / 60)
print(f" hodisalar {n}, foydalanuvchilar {df['user'].nunique()}, "
f"sessiyalar {int(soni.sum())} (generatsiyada {haqiqiy})")
print(f" sessiya uzunligi (daqiqa): median {uzun.median():.1f}, "
f"90-persentil {uzun.quantile(0.9):.1f}")
tek = sessiyalar_sikl(list(zip(df["user"], df["vaqt"])))
print(f" oddiy sikl bilan mos: {all(tek[u] == soni[u] for u in soni.index)}")
print("\n=== 2. Ikki son yig'indisi: O(n^2) va O(n) ===")
print(f" {'n':>6} {'sodda qadam':>12} {'xesh qadam':>11} {'nisbat':>7} {'javob mos':>10}")
qs, qx = [], []
for n in [500, 1000, 2000, 4000]:
a = (2 * rng.permutation(10 * n)[:n]).tolist() # hammasi juft son
a[-1] += 1 # yagona toq son -> yagona javob juftligi
maqsad = a[-1] + a[-2] # eng yomon holat: juft oxirida
j1, q1 = ikki_son_sodda(a, maqsad)
j2, q2 = ikki_son_xesh(a, maqsad)
mos = a[j1[0]] + a[j1[1]] == maqsad and a[j2[0]] + a[j2[1]] == maqsad
qs.append(q1)
qx.append(q2)
print(f" {n:>6} {q1:>12} {q2:>11} {q1 / q2:>7.0f} {str(mos):>10}")
osish_s = np.exp2(np.mean(np.diff(np.log2(qs)))) # geometrik o'rtacha o'sish
osish_x = np.exp2(np.mean(np.diff(np.log2(qx))))
print(f" n x2 bo'lganda qadamlar: sodda x{osish_s:.1f}, xesh x{osish_x:.1f}")
print("\n=== 3. Top-k eng ko'p uchraydigan so'z ===")
lugat = [f"soz{i:03d}" for i in range(300)]
ehtimol = 1 / np.arange(1, 301)
sozlar = rng.choice(lugat, 50_000, p=ehtimol / ehtimol.sum()).tolist()
t = top_k(sozlar, 5)
ts = sorted(Counter(sozlar).items(), key=lambda x: (-x[1], x[0]))[:5]
tp = pd.Series(sozlar).value_counts()
tp = sorted(tp.items(), key=lambda x: (-x[1], x[0]))[:5]
print(" " + ", ".join(f"{s}:{c}" for s, c in t))
print(f" heap = to'liq saralash = pandas: {t == ts == tp}")
print("\n=== 4. pandas: har mijozning oxirgi buyurtmasi va buyurtmalar orasidagi kun ===")
b = pd.DataFrame({"mijoz": rng.integers(1, 201, 3000),
"sana": pd.Timestamp("2025-01-01")
+ pd.to_timedelta(rng.integers(0, 180, 3000), unit="D"),
"summa": rng.integers(20, 500, 3000) * 1000})
b = b.sort_values(["mijoz", "sana"])
oxirgi = b.groupby("mijoz").tail(1)
orasi = b.groupby("mijoz")["sana"].diff().dt.days
print(f" oxirgi buyurtmalar: {len(oxirgi)} qator (mijozlar {b['mijoz'].nunique()})")
print(f" buyurtmalar orasidagi kun: median {orasi.median():.0f}, "
f"o'rtacha {orasi.mean():.1f}")
idx = b.groupby("mijoz")["sana"].idxmax()
print(f" tail(1) va idxmax bir xil sanalar: "
f"{(oxirgi.set_index('mijoz')['sana'] == b.loc[idx].set_index('mijoz')['sana']).all()}")
print("\n=== 5. Xulosa ===")
print(" sessiyalar: O(n log n) (saralash) + O(n); ikki son: O(n) xotira evaziga;")
print(" top-k: O(n + m log k); har yechim oddiy versiya bilan solishtirildi")
print(" ⭐ Avval to'g'ri va oddiy, keyin tez; murakkablikni ovoz chiqarib ayting")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. pandas: sessiyalarga ajratish (30 daqiqa tanaffus) ===
hodisalar 3271, foydalanuvchilar 40, sessiyalar 270 (generatsiyada 270)
sessiya uzunligi (daqiqa): median 19.8, 90-persentil 44.6
oddiy sikl bilan mos: True
=== 2. Ikki son yig'indisi: O(n^2) va O(n) ===
n sodda qadam xesh qadam nisbat javob mos
500 124750 500 250 True
1000 499500 1000 500 True
2000 1999000 2000 1000 True
4000 7998000 4000 2000 True
n x2 bo'lganda qadamlar: sodda x4.0, xesh x2.0
=== 3. Top-k eng ko'p uchraydigan so'z ===
soz000:7970, soz001:3989, soz002:2587, soz003:1987, soz004:1551
heap = to'liq saralash = pandas: True
=== 4. pandas: har mijozning oxirgi buyurtmasi va buyurtmalar orasidagi kun ===
oxirgi buyurtmalar: 200 qator (mijozlar 200)
buyurtmalar orasidagi kun: median 8, o'rtacha 11.1
tail(1) va idxmax bir xil sanalar: True
=== 5. Xulosa ===
sessiyalar: O(n log n) (saralash) + O(n); ikki son: O(n) xotira evaziga;
top-k: O(n + m log k); har yechim oddiy versiya bilan solishtirildi
⭐ Avval to'g'ri va oddiy, keyin tez; murakkablikni ovoz chiqarib aytingNatija tahlili.
1-bo'lim — sessiyalarga ajratish. 40 foydalanuvchining 3271 hodisasi aralashtirilgan tartibda keladi. pandas yechimi: saralash, foydalanuvchi ichida diff, 30 daqiqadan katta tanaffus yoki birinchi hodisa — yangi sessiya, cumsum — sessiya raqami. Natija 270 sessiya — generatsiyadagi 270 bilan aynan mos, oddiy Python sikli bilan ham mos (True). Sessiya uzunligi: median 19.8 daqiqa, 90-persentil 44.6. Jonli kodlashda bu uch qadamli tekshiruv (ma'lum javobli kichik ma'lumot, oddiy yechim bilan solishtirish, chegaraviy holat) — ideal.
2-bo'lim — ikki son yig'indisi. Ma'lumot shunday qurilganki, yagona javob juftligi ro'yxat oxirida (eng yomon holat). Sodda yechim barcha juftlarni ko'radi: 124750 qadam n=500 da, 7998000 n=4000 da — aniq n(n-1)/2. Xesh yechimi — n qadam. n ikki barobar bo'lganda: sodda x4.0, xesh x2.0 — O(n^2) va O(n) ning ta'rifi. n=4000 da farq 2000 barobar. Intervyuda qadamlarni sanash — vaqtni o'lchashdan ishonchliroq (vaqt kompyuterga bog'liq).
3-bo'lim — top-k. Counter + heapq.nsmallest (salbiy chastota bo'yicha) — O(n + m log k). Natija to'liq saralash va pandas value_counts bilan bir xil (True). Tenglikda tartib: chastota bo'yicha kamayish, keyin so'z bo'yicha — aniq qoida bo'lmasa, turli usullar turlicha javob beradi.
4-bo'lim — pandas klassikasi: har mijozning oxirgi buyurtmasi (200 qator — har mijozga bitta) va buyurtmalar orasidagi kunlar (median 8, o'rtacha 11.1). tail(1) va idxmax bir xil sanalarni berdi. Intervyu uchun detal: bir kunda ikki buyurtma bo'lsa, "oxirgi" qaysi? — aniqlashtiring; idxmax birinchisini, saralangan tail(1) oxirgisini oladi.
5-bo'lim — har yechimning murakkabligi aytildi va oddiy versiya bilan solishtirildi.
Misol 4 — Case study: "sotuv 10% tushdi" — segment yoki ma'lumot xatosi?
"""Case study: "sotuv 10% tushdi" - ma'lumot sifati, metrika dekompozitsiyasi va segmentlar."""
import numpy as np
import pandas as pd
PLATFORMA = {"android": 0.45, "ios": 0.20, "veb": 0.35}
HUDUD = {"Toshkent": 0.45, "Samarqand": 0.20, "Farg'ona": 0.20, "Xorazm": 0.15}
YOQ = "2*SE ichida, haqiqiy tushish yo'q"
KUNLAR = pd.date_range("2025-09-01", periods=56, freq="D") # 4 hafta oldin + 4 hafta keyin
def yarat(rng, stsenariy):
"""Kunlik jadval: sana, platforma, hudud, sessiyalar, buyurtmalar, daromad."""
qator = []
for i, kun in enumerate(KUNLAR):
hafta = 1.15 if kun.dayofweek >= 5 else 1.0 # dam olish kunlari ko'proq
for p, pu in PLATFORMA.items():
for h, hu in HUDUD.items():
ses = rng.poisson(40_000 * pu * hu * hafta)
konv = {"android": 0.030, "ios": 0.036, "veb": 0.025}[p]
if stsenariy == "segment" and p == "android" and i >= 28:
konv *= 0.78 # yangi versiyadagi xato
buy = rng.binomial(ses, konv)
chek = rng.normal(185_000, 4_000)
qator.append((kun, p, h, ses, buy, buy * chek))
df = pd.DataFrame(qator, columns=["sana", "platforma", "hudud", "sessiyalar",
"buyurtmalar", "daromad"])
if stsenariy == "malumot": # yuklash quvuri buzildi
yoq = (df["platforma"] == "veb") & (df["hudud"] == "Toshkent") & \
(df["sana"] >= KUNLAR[38])
df = df[~yoq]
return df
def tahlil(df):
davr = np.where(df["sana"] >= KUNLAR[28], "keyin", "oldin")
df = df.assign(davr=davr)
x = {}
j = df.groupby("davr")[["sessiyalar", "buyurtmalar", "daromad"]].sum()
tushish = j.loc["keyin", "daromad"] / j.loc["oldin", "daromad"] - 1
print(f" daromad o'zgarishi: {tushish:+.1%}")
print(" [1] ma'lumot to'liqligi: kunlik qatorlar soni (kutilgan 12)")
qatorlar = df.groupby("sana").size()
kam = qatorlar[qatorlar < 12]
x["toliq_emas"] = len(kam)
if len(kam):
print(f" {len(kam)} kunda qatorlar kam: {kam.index.min():%m-%d} dan "
f"{kam.index.max():%m-%d} gacha, {int(kam.min())} ta")
yoq = (df[df["davr"] == "oldin"].groupby(["platforma", "hudud"]).size().index
.difference(df[df["sana"] == kam.index.max()]
.set_index(["platforma", "hudud"]).index))
print(f" yo'qolgan segmentlar: {', '.join('/'.join(s) for s in yoq)}")
ichida = ~df.set_index(["platforma", "hudud"]).index.isin(yoq)
kunlik = df[ichida].groupby(["davr", "sana"])["daromad"].sum()
a, b = kunlik["oldin"], kunlik["keyin"]
x["solishtirma"] = b.mean() / a.mean() - 1
x["se"] = np.sqrt(a.var() / len(a) + b.var() / len(b)) / a.mean()
print(f" yo'qolgan segmentlarsiz (like-for-like): {x['solishtirma']:+.1%} "
f"(SE {x['se']:.1%})")
else:
print(" hamma kunlar to'liq")
print(" [2] dekompozitsiya: daromad = sessiyalar * konversiya * o'rtacha chek")
o, k = j.loc["oldin"], j.loc["keyin"]
qism = {"sessiyalar": k["sessiyalar"] / o["sessiyalar"],
"konversiya": (k["buyurtmalar"] / k["sessiyalar"]) / (o["buyurtmalar"] / o["sessiyalar"]),
"o'rtacha chek": (k["daromad"] / k["buyurtmalar"]) / (o["daromad"] / o["buyurtmalar"])}
jami_log = np.log(k["daromad"] / o["daromad"])
for nom, r in qism.items():
print(f" {nom:<14} {r - 1:+.1%} (log-hissa {np.log(r) / jami_log:.0%})")
x["asosiy"] = max(qism, key=lambda q: abs(np.log(qism[q])))
print(" [3] segmentlar: daromad o'zgarishiga hissa")
for ust in ["platforma", "hudud"]:
s = df.pivot_table(index=ust, columns="davr", values="daromad", aggfunc="sum")
s["hissa"] = (s["keyin"] - s["oldin"]) / (o["daromad"])
s["ozgarish"] = s["keyin"] / s["oldin"] - 1
satr = ", ".join(f"{i} {r['ozgarish']:+.0%} (hissa {r['hissa']:+.1%})"
for i, r in s.sort_values("hissa").iterrows())
print(f" {ust:<9}: {satr}")
x[ust] = s["hissa"].idxmin(), s["hissa"].min() / tushish
return x
def main() -> None:
rng = np.random.default_rng(10)
for nom, st in [("A", "segment"), ("B", "malumot")]:
print(f"=== Stsenariy {nom}: 'oxirgi 4 haftada sotuv tushdi' ===")
x = tahlil(yarat(rng, st))
print(" [4] xulosa (natijadan):")
if x["toliq_emas"] > 0:
print(" avval MA'LUMOT XATOSI: segment qatorlari yo'qolgan - yuklash")
print(" quvurini tekshiring; biznes xulosasi keyin")
print(f" qolgan segmentlarda o'zgarish {x['solishtirma']:+.1%} - "
f"{YOQ if abs(x['solishtirma']) < 2 * x['se'] else 'tushish bor'}")
print(f" [1] bo'lmasa xato xulosa: '{x['asosiy']} tushdi, "
f"{x['hudud'][0]} {x['platforma'][0]}' - marketingga murojaat")
else:
seg, ulush = max([x["platforma"], x["hudud"]], key=lambda v: v[1])
print(f" ma'lumot to'liq; asosiy omil - {x['asosiy']}; tushishning "
f"{ulush:.0%} i '{seg}' segmentida")
print()
print("⭐ Tartib: ma'lumotni tekshir -> metrikani yoy -> segmentlarga bo'l -> gipoteza")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== Stsenariy A: 'oxirgi 4 haftada sotuv tushdi' ===
daromad o'zgarishi: -10.0%
[1] ma'lumot to'liqligi: kunlik qatorlar soni (kutilgan 12)
hamma kunlar to'liq
[2] dekompozitsiya: daromad = sessiyalar * konversiya * o'rtacha chek
sessiyalar -0.1% (log-hissa 1%)
konversiya -10.0% (log-hissa 100%)
o'rtacha chek +0.1% (log-hissa -1%)
[3] segmentlar: daromad o'zgarishiga hissa
platforma: android -22% (hissa -10.2%), veb -1% (hissa -0.2%), ios +2% (hissa +0.4%)
hudud : Toshkent -9% (hissa -4.0%), Samarqand -11% (hissa -2.2%), Farg'ona -10% (hissa -2.1%), Xorazm -11% (hissa -1.7%)
[4] xulosa (natijadan):
ma'lumot to'liq; asosiy omil - konversiya; tushishning 102% i 'android' segmentida
=== Stsenariy B: 'oxirgi 4 haftada sotuv tushdi' ===
daromad o'zgarishi: -9.5%
[1] ma'lumot to'liqligi: kunlik qatorlar soni (kutilgan 12)
18 kunda qatorlar kam: 10-09 dan 10-26 gacha, 11 ta
yo'qolgan segmentlar: veb/Toshkent
yo'qolgan segmentlarsiz (like-for-like): -0.6% (SE 1.9%)
[2] dekompozitsiya: daromad = sessiyalar * konversiya * o'rtacha chek
sessiyalar -10.3% (log-hissa 110%)
konversiya +0.8% (log-hissa -8%)
o'rtacha chek +0.2% (log-hissa -2%)
[3] segmentlar: daromad o'zgarishiga hissa
platforma: veb -31% (hissa -9.3%), ios -1% (hissa -0.3%), android +0% (hissa +0.2%)
hudud : Toshkent -21% (hissa -9.4%), Farg'ona -3% (hissa -0.6%), Samarqand +0% (hissa +0.1%), Xorazm +3% (hissa +0.5%)
[4] xulosa (natijadan):
avval MA'LUMOT XATOSI: segment qatorlari yo'qolgan - yuklash
quvurini tekshiring; biznes xulosasi keyin
qolgan segmentlarda o'zgarish -0.6% - 2*SE ichida, haqiqiy tushish yo'q
[1] bo'lmasa xato xulosa: 'sessiyalar tushdi, Toshkent veb' - marketingga murojaat
⭐ Tartib: ma'lumotni tekshir -> metrikani yoy -> segmentlarga bo'l -> gipotezaNatija tahlili.
Ikkala stsenariy ham bir xil boshlanadi: "oxirgi 4 haftada daromad ~10% tushdi" (-10.0% va -9.5%). Lekin sabablar butunlay boshqa, va tahlil tartibi ularni ajratadi.
Stsenariy A — haqiqiy tushish. [1] Ma'lumot to'liq: har kuni 12 ta segment qatori bor. [2] Dekompozitsiya: sessiyalar -0.1%, o'rtacha chek +0.1%, konversiya -10.0% — tushishning 100% i konversiyadan (log-hissa). Trafik joyida — marketing muammosi emas. [3] Segmentlar: android daromadi -22% va tushishning -10.2 foiz punktini beradi; veb (-1%) va ios (+2%) deyarli o'zgarmagan. Hududlar bo'yicha tushish bir tekis (-9% dan -11% gacha) — muammo geografik emas. [4] Xulosa natijadan: asosiy omil — konversiya, tushishning 102% i android segmentida (100% dan oshishi — boshqa segmentlar biroz o'sgan). Keyingi gipoteza: android ilovasining yangi versiyasi — reliz sanasi, versiya bo'yicha konversiya, to'lov bosqichi xatolari.
Stsenariy B — ma'lumot xatosi. [1] 18 kunda (10-09 dan 10-26 gacha) qatorlar 12 emas, 11 ta — veb/Toshkent segmenti yo'qolgan. Yo'qolgan segmentsiz (like-for-like) solishtirsak — -0.6% (SE 1.9%), ya'ni 2*SE ichida: haqiqiy tushish yo'q. Agar [1] qadam bo'lmaganida: [2] "sessiyalar -10.3%" va [3] "veb -31%, Toshkent -21%" — tahlilchi "Toshkent veb trafigi tushdi" deb marketingga murojaat qilardi. Kod bu xato xulosani ham chop etdi — u aynan kirish qismidagi nomzodning javobi. To'g'ri javob: yuklash quvurini (ETL) tekshirish; biznes qarori — keyin.
Umumiy saboq: ma'lumot sifati tekshiruvi — case study ning birinchi qadami, oxirgisi emas. Intervyuda "avval ma'lumotning to'g'riligini tekshiraman: qatorlar soni, segmentlar, yangi manbalar" deyish ko'pincha eng qimmatli javob — ishda esa bu 27.11 dagi monitoring vazifasi: segment darajasidagi "qatorlar soni" ogohlantirishi bu muammoni tahlilchidan oldin ushlagan bo'lardi.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "L2 ham keraksiz belgilarni nolga tushiradi" | L2 kichraytiradi, lekin nol qilmaydi (1-misol: 0/50); L1 — 34/50 |
| "Lasso faqat informativ belgilarni qoldiradi" | 16 ta tanladi: 5 informativ + 11 shovqin — tanlov mukammal emas |
| "Murakkab model — kichik xato" | 9-darajali polinomda variance 0.1046, 3-darajalidan yomon |
| "Accuracy 97.5% — yaxshi model" | "Hammasi manfiy" ham 0.975; PR-AUC va recall ga qarang |
| "CV ishlatdim — sizish bo'lmaydi" | Belgi tanlash CV dan oldin: tasodifiy maqsadda 0.854 |
| "Boosting — qora quti" | 10 qator: qoldiqqa sayoz daraxt, kichik qadam — sklearn bilan bir xil |
| "Boosting har doim chiziqli modeldan yaxshi" | Chiziqli signalda chiziqli model sezilarli yaxshi |
| "LEFT JOIN qatorlar sonini saqlaydi" | Bir mijoz ko'p buyurtma — qatorlar ko'payadi (300 dan 986) |
| "Kohort jadvalidagi 0 — mijozlar ketgan" | Oxirgi kohortlar uchun oylar hali kuzatilmagan — NULL |
| "Sotuv 10% tushdi — marketing kerak" | Avval ma'lumot sifati: 4-misolda tushish umuman ma'lumot xatosi edi |
6. Keng tarqalgan xatolar va yechimlari
1. Belgi tanlash CV dan tashqarida
X_top = SelectKBest(k=20).fit_transform(X, y); cross_val_score(model, X_top, y) # ⚠️
cross_val_score(make_pipeline(SelectKBest(k=20), model), X, y) # ✅2. Nomutanosiblikda accuracy
print(accuracy_score(y, model.predict(X))) # ⚠️
print(average_precision_score(y, model.predict_proba(X)[:, 1]), y.mean()) # ✅3. LEFT JOIN ni WHERE bilan buzish
SELECT m.id, b.summa FROM mijozlar m LEFT JOIN buyurtmalar b ON b.mijoz_id = m.id
WHERE b.sana >= '2025-06-01'; -- ⚠️ INNER ga aylandi
SELECT m.id, b.summa FROM mijozlar m LEFT JOIN buyurtmalar b
ON b.mijoz_id = m.id AND b.sana >= '2025-06-01'; -- ✅ shart ON da4. Top-N da tenglik
ROW_NUMBER() OVER (PARTITION BY shahar ORDER BY summa DESC) -- ⚠️ tasodifiy tartib
ROW_NUMBER() OVER (PARTITION BY shahar ORDER BY summa DESC, mijoz_id) -- ✅ deterministik5. Retention da kuzatilmagan oylar
ROUND(1.0 * COUNT(DISTINCT CASE WHEN farq = 3 THEN id END) / hajm, 2) -- ⚠️ 0 ko'rsatadi
CASE WHEN kohort_n + 3 <= oxirgi_oy THEN ... END -- ✅ NULL6. Jonli kodlashda darhol "optimal" yechim
# ⚠️ jim o'ylab, murakkab yechimni birdaniga yozish va test qilmaslik
# ✅ "Avval O(n^2) oddiy yechim, keyin lug'at bilan O(n); ikkalasini solishtiraman"7. Case study da ma'lumotni tekshirmaslik
xulosa = "trafik tushdi, marketing kerak" # ⚠️
qatorlar = df.groupby("sana").size(); assert (qatorlar == kutilgan).all() # ✅ avval7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 12.4, 12.5, 12.9-darslar (o'tilgan): Overfitting, bias-variance, Pipeline va sizish
- 13.7, 13.8-darslar (o'tilgan): Ridge, Lasso va ElasticNet
- 14.9, 18.9-darslar (o'tilgan): Nomutanosib sinflar va metrika tanlash
- 15.8-dars (o'tilgan): Gradient boosting
- 17.8-dars (o'tilgan): Leakage turlari
- 03-qism (o'tilgan): pandas — guruhlash, merge, oyna funksiyalari
- 27.11-dars (o'tilgan): Monitoring — case study dagi "ma'lumot to'liqligi" tekshiruvi aslida monitoring vazifasi
- 29.4-dars (o'tilgan): Natijani taqdim etish — STAR va case study javobi ham taqdimot
- 29.9-dars (o'tilgan): Statistika intervyusi — case study da SE va sezilarlilik
- 29.11-dars: Ma'lumot etikasi — intervyuda "modelingiz adolatlimi?" savoli
8. Eng yaxshi amaliyotlar
Har ML tushunchasi uchun: ta'rif, nega muhim, misol va uni tasdiqlaydigan kichik tajriba.
SQL: mantiqiy bajarilish tartibini eslang; har JOIN dan keyin qatorlar sonini tekshiring.
Oyna funksiyalarida tartibni to'liq bering; tenglik bo'yicha savolni aniqlashtiring.
Jonli kodlash: aniqlashtirish → kichik misol → oddiy yechim → murakkablik → test.
Case study: avval ma'lumot sifati, keyin dekompozitsiya va segmentlar, keyin gipoteza.
3-5 ta STAR hikoya tayyorlang; har birida sizning harakatingiz va bazaga nisbatan natija.
Bilmaganingizni tan oling va qanday tekshirishingizni ayting.
Intervyu oxirida savollar bering: ma'lumot infratuzilmasi, jamoa, muvaffaqiyat qanday o'lchanadi.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # Ridge (alpha=10) nechta koeffitsientni aynan nol qiladi?
2. # 9-darajali polinom (n=30): bias^2 yoki variance kattami?
3. # musbat 2.5%: tasodifiy modelning PR-AUC si qancha?
4. # tasodifiy y, belgi tanlash CV dan oldin: accuracy 0.5 ga yaqinmi?
5. # chiziqli signalda boosting chiziqli modelni yengadimi?
6. # 300 mijoz, 209 tasi xarid qilgan: LEFT JOIN qatorlari 300 mi?
7. # ROW_NUMBER va RANK: tenglikda farqi?
8. # oxirgi kohortning 3-oy retention i - 0 mi?
9. # ikki son yig'indisi: n ikki barobar - sodda yechim qadamlari necha barobar?
10. # "sotuv 10% tushdi": birinchi qadam?Javoblar
- Nol —
0/50(L2 kichraytiradi, lekin nol qilmaydi) - Variance (
0.1046va bias^20.0004) - Musbat ulushiga teng —
0.025 - Yo'q —
0.854; to'g'ri CV da0.521 - Yo'q — chiziqli model sezilarli yaxshi (
0.974va0.952) - Yo'q —
986(xaridorlar har buyurtmasi bilan + 91 ta NULL qator) ROW_NUMBERhar doim 1, 2, 3;RANKtenglikda bir xil raqam va keyin sakraydi- Yo'q — hali kuzatilmagan,
NULL - To'rt barobar (
x4.0); xesh — ikki barobar - Aniqlashtirish va ma'lumot sifati — qatorlar soni, segmentlar to'liqligi
Vazifa 2: SQL yozing
2-misoldagi jadvallar bilan:
- Har oy uchun yangi xaridorlar soni (birinchi xaridi shu oyda bo'lganlar)
- Har mijozning birinchi va ikkinchi xaridi orasidagi kunlar; o'rtacha qiymat shahar bo'yicha
- Har shaharda daromadning kumulyativ yig'indisi kun bo'yicha
- Oxirgi 30 kunda xarid qilmagan, lekin undan oldin kamida 3 marta xarid qilgan mijozlar ("ketish xavfi")
- Har mijoz uchun
RANKvaDENSE_RANKbo'yicha shahardagi o'rni — tengliklar bormi?
Javoblar
-- 1
WITH b AS (SELECT mijoz_id, MIN(substr(sana, 1, 7)) AS oy FROM buyurtmalar GROUP BY mijoz_id)
SELECT oy, COUNT(*) AS yangi FROM b GROUP BY oy ORDER BY oy;
-- 2
WITH t AS (SELECT mijoz_id, sana,
ROW_NUMBER() OVER (PARTITION BY mijoz_id ORDER BY sana, id) AS rn
FROM buyurtmalar)
SELECT m.shahar, AVG(julianday(t2.sana) - julianday(t1.sana)) AS orta_kun
FROM t t1 JOIN t t2 ON t2.mijoz_id = t1.mijoz_id AND t1.rn = 1 AND t2.rn = 2
JOIN mijozlar m ON m.id = t1.mijoz_id
GROUP BY m.shahar ORDER BY m.shahar;
-- 3
WITH k AS (SELECT m.shahar, b.sana, SUM(b.summa) AS d
FROM buyurtmalar b JOIN mijozlar m ON m.id = b.mijoz_id
GROUP BY m.shahar, b.sana)
SELECT shahar, sana, SUM(d) OVER (PARTITION BY shahar ORDER BY sana) AS kumulyativ
FROM k ORDER BY shahar, sana;
-- 4
SELECT mijoz_id FROM buyurtmalar
GROUP BY mijoz_id
HAVING MAX(sana) < date((SELECT MAX(sana) FROM buyurtmalar), '-30 days')
AND COUNT(*) >= 3
ORDER BY mijoz_id;
-- 5
WITH j AS (SELECT m.shahar, b.mijoz_id, SUM(b.summa) AS s
FROM buyurtmalar b JOIN mijozlar m ON m.id = b.mijoz_id
GROUP BY m.shahar, b.mijoz_id)
SELECT shahar, mijoz_id, s,
RANK() OVER (PARTITION BY shahar ORDER BY s DESC) AS r,
DENSE_RANK() OVER (PARTITION BY shahar ORDER BY s DESC) AS dr
FROM j ORDER BY shahar, r;Vazifa 3: ML savollari
1-misol asosida:
- Lasso
alphani 0.1, 1, 5, 20 qiling — nol koeffitsientlar soni va test R^2 qanday o'zgaradi? Informativ belgilar qachon yo'qola boshlaydi? - Bias-variance da n ni 30 dan 300 ga oshiring — 9-darajali polinom variance si qanday o'zgaradi?
- Nomutanosib misolda
class_weight="balanced"— ROC-AUC, PR-AUC va 0.5 chegaradagi recall qanday o'zgaradi? - Gradient boosting ni log-loss uchun noldan yozing (qoldiq
y - p) vaGradientBoostingClassifierbilan solishtiring (barglardagi Nyuton qadami tufayli bashoratlar aynan bir xil bo'lmaydi — nega?)
Vazifa 4: Jonli kodlash
3-misol asosida (avval oddiy yechim, keyin yaxshilangan, ikkalasini solishtiring):
- Ro'yxatdagi birinchi takrorlanmaydigan elementni toping — O(n)
- Har foydalanuvchining eng uzun sessiyasi (daqiqa) — pandas
- Saralangan ikki ro'yxatni birlashtirish — O(n + m)
- Sirg'aluvchi oynadagi maksimum (k=7) — oddiy O(nk) va deque bilan O(n)
Vazifa 5: Case study
4-misol asosida:
- Uchinchi stsenariy qo'shing: o'rtacha chek tushgan (masalan, chegirma aksiyasi) — tahlil uni topadimi?
- Mavsumiylik: oldingi davr o'rniga o'tgan yilning shu davri bilan solishtirish qanday o'zgaradi?
- Segment hissasini "aralash (mix)" va "stavka (rate)" effektlariga ajrating (konversiya uchun)
- Ma'lumot to'liqligi tekshiruvini kengaytiring: segment qatori bor, lekin buyurtmalar 0 bo'lsa-chi?
Vazifa 6: STAR
O'zingizning bitta loyihangiz (kursdagi amaliyot darsidan bo'lsa ham) uchun STAR javob yozing (150-200 so'z). Keyin o'zingizga intervyuer bo'lib 5 ta chuqurlashtiruvchi savol bering ("nega bu metrika?", "bazaviy model nima edi?", "qanday tekshirdingiz?", "nima ishlamadi?", "yana nima qilardingiz?").
Vazifa 7: O'ylash
Intervyuer: "Mobil ilovamizda o'tgan haftaga nisbatan faol foydalanuvchilar 15% ga kamaydi. Direktor darhol reklama byudjetini oshirishni so'rayapti. Sizda 30 daqiqa bor — nima qilasiz va direktorga nima deysiz?"
Javob
Qisqa javob: 30 daqiqada reklama haqida qaror qilinmaydi — avval tushish haqiqiymi va qayerda ekanini aniqlayman. Reklama faqat "yangi foydalanuvchilar oqimi kamaydi" degan tashxisga javob bo'lishi mumkin.
1. Aniqlashtirish (5 daqiqa). "Faol foydalanuvchi" ta'rifi o'zgarganmi? O'tgan hafta odatiy edimi (bayram, aksiya)? Tushish keskin (bir kunda) yoki asta-sekinmi? Shu haftada reliz, narx o'zgarishi, texnik muammo bo'lganmi?
2. Ma'lumot sifati (10 daqiqa). 4-misoldagi [1] qadam:
kunlik = df.groupby(["sana", "platforma", "versiya"]).size() # qatorlar soni
# yangi ilova versiyasi hodisalarni yubormayaptimi? (loglash xatosi)
# bir platforma yoki mamlakat to'liq yo'qolganmi?4-misolning B stsenariysida xuddi shunday "tushish" butunlay ma'lumot xatosi edi.
3. Dekompozitsiya va segmentlar (10 daqiqa). Faol = yangi + qaytgan (retention). Qaysi biri kamaydi? Platforma, ilova versiyasi, mamlakat/hudud, kanal bo'yicha. Agar yangi foydalanuvchilar kamaygan — trafik/marketing masalasi; qaytganlar kamaygan — mahsulot masalasi (reliz, xato, sifat).
4. Gipoteza va keyingi qadamlar (5 daqiqa). Masalan: "tushishning 90% i android 5.2 versiyasida, reliz kunidan boshlab" — reklama emas, versiyani tuzatish.
Direktorga javob: "Byudjet qarorini bir soatga kechiktirishni so'rayman. Hozir uchta narsani tekshiryapman: raqam to'g'rimi (loglash buzilmaganmi), tushish yangi foydalanuvchilardami yoki qaytganlardami, va qaysi platformada. Agar muammo yangi reliz yoki ma'lumot xatosida bo'lsa, reklama pulni behuda sarflaydi. Natijani va aniq tavsiyani bugun beraman."
Nimani mustahkamlaydi: 2.1, 2.2, 2.4, 2.5-bo'limlar.
Xulosa
Bu darsda intervyuning ML, SQL, jonli kodlash va case study bo'limlarini ko'rib chiqdik — har bir javobni kod bilan tekshirdik.
Eng muhim uch fikr:
ML javobi — ta'rif, sabab va tajriba. 1-misolda L1
34/50koeffitsientni aynan nol qildi, L2 — birortasini ham (lekin Lasso 11 ta shovqin belgisini ham qoldirdi); bias-variance yoyilmasi test MSE bilan mos keldi (0.1065va0.1082); nomutanosiblikda accuracy0.975ma'nosiz edi; belgi tanlashdagi sizish tasodifiy maqsadda0.854accuracy berdi (to'g'ri CV da0.521); 10 qatorli gradient boosting sklearn bilan bir xil bashorat berdi.SQL va jonli kodlash — to'g'rilikni tekshirish odati. 2-misolda LEFT JOIN qatorlarni
895dan986ga oshirdi, dublikatlar o'chirildi (880), top-N, LAG, sirg'aluvchi o'rtacha va retention so'rovlari pandas bilan tasdiqlandi; kuzatilmagan kohort oylari0emas,NULL. 3-misolda sessiyalar generatsiyadagi soni bilan (270) mos keldi, ikki son masalasida n ikki barobar bo'lganda qadamlar x4.0va x2.0o'sdi.Case study — avval ma'lumot, keyin biznes. 4-misolda ikkita "10% tushish": birida konversiya (
-10.0%) va android segmenti (tushishning102%i), ikkinchisida yo'qolgan veb/Toshkent segmenti — like-for-like o'zgarish-0.6%(SE 1.9%), ya'ni tushish yo'q. Tuzilma — aniqlashtirish, ma'lumot sifati, dekompozitsiya, segmentlar, gipoteza, xatarlar; o'z loyihangiz esa STAR bilan: vaziyat, vazifa, sizning harakatingiz, bazaga nisbatan natija.
Keyingi darsda Ma'lumot etikasi va adolatlilik: model qarorlari odamlarga qanday ta'sir qiladi, tarafkashlik manbalari, adolatlilik metrikalarini hisoblash, maxfiylik va javobgarlik.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!