Ma'lumot sifati: yomon ma'lumot modelga yetib bormasin
Kalkulyatorga "besh qop" deb yozib bo'lmaydi
Kalkulyatorni oling va 5 / 0 bosing. Ekranda Error chiqadi.
Endi unga "besh qop kartoshka" yozmoqchi bo'ling — yozolmaysiz ham. Tugmalar yo'q.
Kalkulyator sizni himoya qiladi: u faqat tushunadigan narsasini qabul qiladi, qolganiga darhol "yo'q" deydi.
Endi modelni oling. Unga kvartira maydonini manfiy bering: -45 kvadrat metr.
Model nima qiladi?
Javob beradi. Xotirjam. Masalan "broker ehtimoli 0.31".
U "manfiy maydon bo'lmaydi" demaydi. Chunki u maydon nimaligini bilmaydi — u faqat
sonlarni ko'radi va o'zi o'rgangan formulaga qo'yadi. -45 ham son, 45 ham son.
Model — himoyasiz kalkulyator
Mana shu bobning butun mavzusi.
Oddiy dasturda noto'g'ri kirish istisno (exception) otadi. Siz bilasiz, log da ko'rasiz, tuzatasiz.
Modelda bunday himoya yo'q. U:
- har qanday sonni qabul qiladi (manfiy, nol, million)
- har doim javob qaytaradi
- javobning ishonchli ko'rinishini saqlaydi
Ya'ni yomon ma'lumot modelga yetib borsa, natija shunchaki noto'g'ri bo'ladi — va yana o'sha 1-bobdagi jimlik: hech kim aytmaydi.
Demak himoyani biz qo'yishimiz kerak, modelgacha.
Avval muammoning haqiqiyligini ko'rsatamiz: ma'lumotga hayotda uchraydigan uchta nuqson kiritamiz va ikki xil model bilan sinaymiz.
import numpy as np import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.metrics import f1_score XUS = ["xonalar", "maydon", "qavat", "jami_qavat", "narx_mln", "tavsif_uzunligi", "rasmlar_soni", "telefon_takrorlanishi", "kunlik_elonlar", "egasi_tasdiqlangan"] d = pd.read_csv(DATA / "ijara.csv") Xtr, Xte, ytr, yte = train_test_split(d[XUS], d["broker"], test_size=0.25, stratify=d["broker"], random_state=42) def buz(X, tur, ulush=0.25, seed=7): """Ma'lumotga haqiqiy hayotdagi nuqsonlarni kiritadi.""" r = np.random.default_rng(seed) x = X.copy() idx = r.choice(x.index, int(len(x) * ulush), replace=False) if tur == "birlik": # mln so'm o'rniga so'm yozilgan x.loc[idx, "narx_mln"] = x.loc[idx, "narx_mln"] * 1_000_000 elif tur == "nol": # yetishmagan qiymat 0 bilan to'ldirilgan x.loc[idx, "maydon"] = 0 elif tur == "manfiy": # kiritish xatosi x.loc[idx, "rasmlar_soni"] = -1 return x MODELLAR = { "RandomForest (daraxt)": RandomForestClassifier( n_estimators=150, min_samples_leaf=3, random_state=42, n_jobs=1), "LogisticRegression (chiziqli)": make_pipeline( StandardScaler(), LogisticRegression(max_iter=2000, random_state=42)), } NUQSONLAR = [("birlik", "narx birligi almashgan (mln -> so'm)"), ("nol", "maydon = 0 (yetishmagan qiymat)"), ("manfiy", "rasmlar_soni = -1 (mumkin emas)")] qatorlar = [] tayyor = {} for nom, model in MODELLAR.items(): m = model.fit(Xtr, ytr) tayyor[nom] = m qator = {"model": nom, "toza": round(f1_score(yte, m.predict(Xte)), 3)} for tur, _ in NUQSONLAR: qator[tur] = round(f1_score(yte, m.predict(buz(Xte, tur))), 3) qatorlar.append(qator) show(pd.DataFrame(qatorlar)) for tur, izoh in NUQSONLAR: print(f" {tur:8} = {izoh}")
birlik = narx birligi almashgan (mln -> so'm) nol = maydon = 0 (yetishmagan qiymat) manfiy = rasmlar_soni = -1 (mumkin emas)
| model | toza | birlik | nol | manfiy |
|---|---|---|---|---|
| RandomForest (daraxt) | 0.86 | 0.861 | 0.861 | 0.846 |
| LogisticRegression (chiziqli) | 0.861 | 0.732 | 0.861 | 0.822 |
Bu jadval kutilmagan narsani ko'rsatadi va u bobning eng muhim fikri.
Daraxt modeli deyarli ta'sirlanmadi. Narx million barobar oshdi — F1 o'zgarmadi. Sababi: daraxt
qiymatni emas, chegaradan katta yoki kichikligini ko'radi. narx > 8.4 sharti uchun 5 million
ham, 500 million ham bir xil: "katta".
Chiziqli model esa qulaydi: F1 0.861 dan 0.732 ga tushdi. Unda har xususiyat qiymati bilan vaznga ko'paytiriladi, shuning uchun million barobar kattalashgan son butun hisobni buzadi.
Mana amaliy xulosa: tekshiruvga bo'lgan ehtiyoj model turiga bog'liq. Daraxt bilan ishlayotgan bo'lsangiz, ba'zi nuqsonlar sizni "qutqarib" qoladi — lekin bu omad, himoya emas.
Va uchala holatda ham, qaysi model bo'lishidan qat'i nazar:
- dastur yiqilmadi
- xato xabari yo'q
- jurnalda hech narsa yo'q
- model javob qaytardi
maydon = 0 fizik jihatdan mumkin emas, rasmlar_soni = -1 ham. Model buni bilmaydi — u uchun
bular shunchaki sonlar.
Tekshiruv chegarada bo'lsin
Yechim aeroportdan olingan.
Aeroportda xavfsizlik tekshiruvi bitta joyda — kirishda. Undan o'tgandan keyin sizni har eshikda qaytadan tekshirmaydilar. Nega? Chunki chegaradan o'tgan hamma narsa tekshirilgan deb hisoblanadi.
Agar tekshiruv tarqoq bo'lsa — bir eshikda bor, boshqasida yo'q — butun tizim eng zaif eshik darajasida bo'ladi.
Ma'lumot bilan ham xuddi shunday. Qoida: ma'lumot tizimga kirgan joyda tekshiriladi, ichkarida esa unga ishoniladi.
Bu ikki tomonlama foyda beradi:
- Ichki kod soddalashadi — har funksiyada "maydon manfiymasmi?" deb tekshirish shart emas.
- Xato erta topiladi — manbaga yaqin joyda, sabab hali ma'lum bo'lganda.
Ikkinchisi muhimroq. Buzuq qator o'nta bosqichdan o'tib, oxirida model javobini buzsa, siz sababni orqaga qarab qidirasiz. Chegarada ushlansa — qaysi fayl, qaysi qator, qaysi qoida buzilgani darhol ma'lum.
diagramma( { "Tashqi manba\n(CSV, API, oqim)": (0, 1.2, 2.6, 1.1, "manba"), "TEKSHIRUV\n(sxema + qoidalar)": (3.4, 1.2, 2.6, 1.1, "qayta"), "Toza ma'lumot\n(ishonchli)": (6.8, 0, 2.6, 1.1, "saqlash"), "Karantin\n(rad etilganlar)": (6.8, 2.4, 2.6, 1.1, "xizmat"), }, [ ("Tashqi manba\n(CSV, API, oqim)", "TEKSHIRUV\n(sxema + qoidalar)"), ("TEKSHIRUV\n(sxema + qoidalar)", "Toza ma'lumot\n(ishonchli)", "o'tdi"), ("TEKSHIRUV\n(sxema + qoidalar)", "Karantin\n(rad etilganlar)", "rad etildi"), ], nom="tekshiruv_chegarasi.png", kenglik=12, izoh="Tekshiruv bitta joyda. Rad etilgan qatorlar yo'qolmaydi — karantinga tushadi va sababi yoziladi.", )

Tekshiruv bitta joyda. Rad etilgan qatorlar yo'qolmaydi — karantinga tushadi va sababi yoziladi.
Karantin muhim: rad etilgan qatorni shunchaki tashlab yuborish xato. U tekshirilishi kerak — balki qoida noto'g'ri, balki manba buzilgan.
Sxemani yozamiz
shu faylni yaratingsrc/quvur/sxema.py
"""Ma'lumot sxemasi va tekshiruv qoidalari. Har ustun uchun: turi, ruxsat etilgan oraliq, bo'sh bo'lishi mumkinmi. Bu "ma'lumot shartnomasi" (data contract) — manba va iste'molchi o'rtasidagi kelishuv. """ from dataclasses import dataclass, field from typing import Any import pandas as pd @dataclass(frozen=True, slots=True) class Ustun: nom: str tur: str # "son" | "butun" | "matn" | "mantiqiy" eng_kam: float | None = None eng_ko_p: float | None = None bosh_bolishi_mumkin: bool = False ruxsat_etilgan: tuple[str, ...] = () # matn uchun: faqat shu qiymatlar @dataclass(frozen=True, slots=True) class Sxema: ustunlar: tuple[Ustun, ...] def nomlari(self) -> list[str]: return [u.nom for u in self.ustunlar] def tekshir(df: pd.DataFrame, sxema: Sxema) -> tuple[pd.DataFrame, pd.DataFrame, list[str]]: """(toza, karantin, xabarlar) qaytaradi. Istisno OTMAYDI — qarorni chaqiruvchi qabul qiladi.""" xabarlar: list[str] = [] yetishmayotgan = set(sxema.nomlari()) - set(df.columns) if yetishmayotgan: raise ValueError(f"ustunlar yetishmaydi: {sorted(yetishmayotgan)}") yomon = pd.Series(False, index=df.index) sabablar = pd.Series("", index=df.index) def belgila(maska: pd.Series, sabab: str) -> None: nonlocal yomon, sabablar soni = int(maska.sum()) if soni: xabarlar.append(f"{sabab}: {soni} qator") sabablar[maska & (sabablar == "")] = sabab yomon = yomon | maska for u in sxema.ustunlar: s = df[u.nom] if not u.bosh_bolishi_mumkin: belgila(s.isna(), f"{u.nom} bo'sh") if u.tur in {"son", "butun"}: son = pd.to_numeric(s, errors="coerce") belgila(son.isna() & s.notna(), f"{u.nom} son emas") if u.tur == "butun": belgila(son.notna() & (son % 1 != 0), f"{u.nom} butun emas") if u.eng_kam is not None: belgila(son.notna() & (son < u.eng_kam), f"{u.nom} < {u.eng_kam}") if u.eng_ko_p is not None: belgila(son.notna() & (son > u.eng_ko_p), f"{u.nom} > {u.eng_ko_p}") elif u.ruxsat_etilgan: belgila(s.notna() & ~s.isin(u.ruxsat_etilgan), f"{u.nom} ruxsat etilmagan qiymat") karantin = df[yomon].copy() if len(karantin): karantin["rad_sababi"] = sabablar[yomon] return df[~yomon].copy(), karantin, xabarlar IJARA_SXEMASI = Sxema(( Ustun("xonalar", "butun", eng_kam=1, eng_ko_p=10), Ustun("maydon", "son", eng_kam=10, eng_ko_p=500), Ustun("qavat", "butun", eng_kam=1, eng_ko_p=60), Ustun("jami_qavat", "butun", eng_kam=1, eng_ko_p=60), Ustun("narx_mln", "son", eng_kam=0.5, eng_ko_p=200), Ustun("tavsif_uzunligi", "butun", eng_kam=0, eng_ko_p=5000), Ustun("rasmlar_soni", "butun", eng_kam=0, eng_ko_p=100), Ustun("telefon_takrorlanishi", "butun", eng_kam=1, eng_ko_p=500), Ustun("kunlik_elonlar", "butun", eng_kam=1, eng_ko_p=200), Ustun("egasi_tasdiqlangan", "butun", eng_kam=0, eng_ko_p=1), ))
Toza ma'lumotda sinaymiz — hech narsa rad etilmasligi kerak:
python3 -c " import sys; sys.path.insert(0, 'src') import pandas as pd from quvur.sxema import tekshir, IJARA_SXEMASI d = pd.read_csv('../datasets/ijara.csv') toza, karantin, xabarlar = tekshir(d, IJARA_SXEMASI) print(f'kirish : {len(d):,} qator') print(f'toza : {len(toza):,}') print(f'karantin : {len(karantin):,}') print('xabarlar :', xabarlar or '(muammo yo\'q)') "
kirish : 12,000 qator toza : 12,000 karantin : 0 xabarlar : (muammo yo'q)
Endi buzilgan ma'lumotda:
python3 -c " import sys; sys.path.insert(0, 'src') import numpy as np, pandas as pd from quvur.sxema import tekshir, IJARA_SXEMASI r = np.random.default_rng(7) d = pd.read_csv('../datasets/ijara.csv') n = len(d) d.loc[r.choice(n, 300, replace=False), 'narx_mln'] *= 1_000_000 # birlik xatosi d.loc[r.choice(n, 200, replace=False), 'maydon'] = 0 # yetishmagan -> 0 d.loc[r.choice(n, 150, replace=False), 'rasmlar_soni'] = -1 # manfiy d.loc[r.choice(n, 100, replace=False), 'xonalar'] = np.nan # bo'sh toza, karantin, xabarlar = tekshir(d, IJARA_SXEMASI) print(f'kirish : {len(d):,} qator') print(f'toza : {len(toza):,}') print(f'karantin : {len(karantin):,}') print() print('TOPILGAN MUAMMOLAR:') for x in xabarlar: print(' ', x) print() print('karantin namunasi:') print(karantin[['maydon','narx_mln','rasmlar_soni','rad_sababi']].head(4).to_string(index=False)) "
kirish : 12,000 qator
toza : 11,265
karantin : 735
TOPILGAN MUAMMOLAR:
xonalar bo'sh: 100 qator
maydon < 10: 200 qator
narx_mln > 200: 300 qator
rasmlar_soni < 0: 150 qator
karantin namunasi:
maydon narx_mln rasmlar_soni rad_sababi
39.9 2.31 -1 rasmlar_soni < 0
0.0 3.85 10 maydon < 10
78.8 4730000.00 11 narx_mln > 200
75.3 4150000.00 1 narx_mln > 200
Har rad etilgan qator sababi bilan saqlandi. Endi kimdir ularni ko'rib chiqishi mumkin.
Tekshiruv modelni himoya qiladimi
Asosiy savol: bu qo'shimcha kod haqiqatan yordam beradimi? Chiziqli modelda o'lchaymiz — chunki yuqorida aynan u zarar ko'rgan edi.
import sys sys.path.insert(0, str(ISH / "src")) from quvur.sxema import tekshir, IJARA_SXEMASI r = np.random.default_rng(7) buzuq = Xte.copy() n = len(buzuq) buzuq.loc[r.choice(buzuq.index, int(n * 0.10), replace=False), "narx_mln"] *= 1_000_000 buzuq.loc[r.choice(buzuq.index, int(n * 0.08), replace=False), "maydon"] = 0 buzuq.loc[r.choice(buzuq.index, int(n * 0.06), replace=False), "rasmlar_soni"] = -1 toza_x, karantin_x, _ = tekshir(buzuq, IJARA_SXEMASI) y_toza = yte.loc[toza_x.index] qatorlar = [] for nom, m in tayyor.items(): qatorlar.append({ "model": nom, "toza (ideal)": round(f1_score(yte, m.predict(Xte)), 3), "buzuq, tekshiruvsiz": round(f1_score(yte, m.predict(buzuq)), 3), "buzuq, tekshiruvdan keyin": round(f1_score(y_toza, m.predict(toza_x)), 3), }) show(pd.DataFrame(qatorlar)) print(f"karantinga tushdi: {len(karantin_x)} / {len(buzuq)} qator " f"({100 * len(karantin_x) / len(buzuq):.1f}%)")
karantinga tushdi: 662 / 3000 qator (22.1%)
| model | toza (ideal) | buzuq, tekshiruvsiz | buzuq, tekshiruvdan keyin |
|---|---|---|---|
| RandomForest (daraxt) | 0.86 | 0.856 | 0.853 |
| LogisticRegression (chiziqli) | 0.861 | 0.8 | 0.853 |
Natijani halol o'qiymiz — u ikki xil hikoya aytadi.
Chiziqli model uchun tekshiruv aniq foyda berdi: buzuq ma'lumotda F1 0.800 ga tushgan edi, tekshiruvdan keyin 0.853 ga ko'tarildi — toza ma'lumotdagi 0.861 ga deyarli yetdi.
Daraxt modeli uchun esa foyda yo'q — 0.856 dan 0.853 ga, ya'ni arzimas darajada pastroq. U allaqachon chidamli edi, shuning uchun "himoya qilish"ga hojat bo'lmadi; karantin esa bir necha yuz to'g'ri qatorni ham olib tashladi.
Demak tekshiruvning qiymati modelga bog'liq. Lekin uni faqat model uchun qilmaslik kerak, va buning sababi keyingi bo'limda.
Tekshiruv nima uchun baribir kerak
Agar modelingiz chidamli bo'lsa, tekshiruvni tashlab yuborish mumkinmi? Yo'q, va sabablari modeldan tashqarida:
import pandas as pd show(pd.DataFrame([ {"sabab": "Yuqori oqimdagi xatoni topadi", "izoh": "narx million barobar oshgan bo'lsa, manba tizimda BUG bor — model chidasa ham"}, {"sabab": "Hisobot va tahlil buziladi", "izoh": "Model chidaydi, lekin o'rtacha narx grafigi butunlay noto'g'ri chiqadi"}, {"sabab": "Keyingi model chidamasligi mumkin", "izoh": "Bugun daraxt, ertaga chiziqli yoki neyron tarmoq"}, {"sabab": "Sabab ma'lum bo'ladi", "izoh": "Karantin 'nima noto'g'ri' degan savolga javob beradi"}, ]))
| sabab | izoh |
|---|---|
| Yuqori oqimdagi xatoni topadi | narx million barobar oshgan bo'lsa, manba tizimda BUG bor — model chidasa ham |
| Hisobot va tahlil buziladi | Model chidaydi, lekin o'rtacha narx grafigi butunlay noto'g'ri chiqadi |
| Keyingi model chidamasligi mumkin | Bugun daraxt, ertaga chiziqli yoki neyron tarmoq |
| Sabab ma'lum bo'ladi | Karantin 'nima noto'g'ri' degan savolga javob beradi |
Birinchi qator eng muhimi: buzuq ma'lumot — bu belgi. U yuqori oqimdagi tizim buzilganini bildiradi. Modelingiz chidagani uchun uni e'tiborsiz qoldirsangiz, muammo kattalashib boradi.
Taqsimot tekshiruvi: ustun to'g'ri, lekin g'alati
Sxema "qiymat oraliqda" deb aytadi. Lekin ma'lumot oraliqda bo'lib ham noto'g'ri bo'lishi mumkin — masalan, hamma narx birdan ikki barobar oshsa.
import pandas as pd def taqsimot_profili(df, ustunlar): """Har ustun uchun asosiy statistika — keyin solishtirish uchun.""" return {u: {"o'rtacha": round(float(df[u].mean()), 3), "mediana": round(float(df[u].median()), 3), "std": round(float(df[u].std()), 3), "bo'sh_ulushi": round(float(df[u].isna().mean()), 4)} for u in ustunlar} KUZATILADIGAN = ["narx_mln", "maydon", "rasmlar_soni", "telefon_takrorlanishi"] asl = taqsimot_profili(d, KUZATILADIGAN) yangi_d = pd.read_csv(DATA / "ijara_yangi.csv") yangi = taqsimot_profili(yangi_d, KUZATILADIGAN) qatorlar = [] for u in KUZATILADIGAN: e, y = asl[u]["o'rtacha"], yangi[u]["o'rtacha"] ozgarish = 100 * (y - e) / e if e else 0 qatorlar.append({"ustun": u, "avgust o'rtacha": e, "sentabr o'rtacha": y, "o'zgarish %": round(ozgarish, 1), "ogohlantirish": "HA" if abs(ozgarish) > 10 else "-"}) show(pd.DataFrame(qatorlar))
| ustun | avgust o'rtacha | sentabr o'rtacha | o'zgarish % | ogohlantirish |
|---|---|---|---|---|
| narx_mln | 5.718 | 5.668 | -0.9 | - |
| maydon | 71.875 | 71.519 | -0.5 | - |
| rasmlar_soni | 7.198 | 8.219 | 14.2 | HA |
| telefon_takrorlanishi | 3.54 | 3.688 | 4.2 | - |
Sxema bu o'zgarishlarni ko'rmaydi — hamma qiymat o'z oralig'ida, hech biri rad etilmaydi.
Lekin rasmlar_soni ning o'rtachasi 14% ga o'sgan va ogohlantirish chiqdi. 1-bobdan bilamiz:
aynan shu o'zgarish modelni buzgan edi (F1 0.860 → 0.675). Sxema tekshiruvi buni butunlay
o'tkazib yuborardi.
Shuning uchun ikki xil tekshiruv kerak:
import pandas as pd show(pd.DataFrame([ {"tur": "Sxema tekshiruvi", "savol": "Qiymat umuman mumkinmi?", "misol": "maydon = 0, rasmlar = -1", "qachon": "Har qatorda, darhol"}, {"tur": "Taqsimot tekshiruvi", "savol": "Ma'lumot odatdagidek ko'rinadimi?", "misol": "O'rtacha 15% o'zgardi", "qachon": "To'plam bo'yicha, davriy"}, ]))
| tur | savol | misol | qachon |
|---|---|---|---|
| Sxema tekshiruvi | Qiymat umuman mumkinmi? | maydon = 0, rasmlar = -1 | Har qatorda, darhol |
| Taqsimot tekshiruvi | Ma'lumot odatdagidek ko'rinadimi? | O'rtacha 15% o'zgardi | To'plam bo'yicha, davriy |
Birinchisi — bu bobda. Ikkinchisi — 35-bobda (drift), chunki u o'sha mexanizmning o'zi.
Sanoat asboblari
Yuqoridagi 90 qator kod tushunish uchun yozildi. Ishlab chiqarishda tayyor asboblar bor:
import pandas as pd show(pd.DataFrame([ {"asbob": "Pandera", "kuchli tomoni": "pandas ga mos, dekorator bilan, tur ko'rsatkichlari"}, {"asbob": "Great Expectations", "kuchli tomoni": "Boy qoidalar to'plami, HTML hisobot, ma'lumot hujjati"}, {"asbob": "pydantic", "kuchli tomoni": "Bitta yozuv uchun ideal (API kirishi, 27-bob)"}, {"asbob": "dbt tests", "kuchli tomoni": "SQL omborida, `not_null`, `unique`, `accepted_values`"}, ]))
| asbob | kuchli tomoni |
|---|---|
| Pandera | pandas ga mos, dekorator bilan, tur ko'rsatkichlari |
| Great Expectations | Boy qoidalar to'plami, HTML hisobot, ma'lumot hujjati |
| pydantic | Bitta yozuv uchun ideal (API kirishi, 27-bob) |
| dbt tests | SQL omborida, `not_null`, `unique`, `accepted_values` |
Tanlov: bitta yozuv tekshirilsa (API) — pydantic; DataFrame bo'lsa — Pandera; ombor jadvali
bo'lsa — dbt.
Qattiq tekshiruv ham xavfli
Tekshiruvni juda qattiq qilsangiz, ishlab chiqarishda hamma narsa rad etiladi va tizim to'xtaydi.
Masalan maydon <= 500 deb yozdingiz, keyin haqiqiy 600 m² ombor e'loni keldi.
Amaliy yondashuv: 1. Avval tekshiruvni kuzatuv rejimida ishga tushiring — rad etmang, faqat sanang va jurnalga yozing 2. Bir necha kun haqiqiy ma'lumotga qarang 3. Chegaralarni to'g'rilang 4. Shundan keyin rad etishni yoqing
Sifat hisoboti
shu faylni yaratingsrc/quvur/sifat.py
"""Ma'lumot sifati hisoboti — CI va kundalik kuzatuv uchun.""" from typing import Any import pandas as pd from .sxema import Sxema, tekshir def hisobot(df: pd.DataFrame, sxema: Sxema) -> dict[str, Any]: toza, karantin, xabarlar = tekshir(df, sxema) ulush = len(toza) / len(df) if len(df) else 0.0 return { "jami": len(df), "toza": len(toza), "karantin": len(karantin), "toza_ulushi": round(ulush, 4), "muammolar": xabarlar, "sabablar": (karantin["rad_sababi"].value_counts().to_dict() if len(karantin) else {}), } def darvoza(h: dict[str, Any], eng_kam_ulush: float = 0.95) -> tuple[bool, str]: """CI uchun: sifat yetarlimi? (o'tdimi, sabab)""" if h["toza_ulushi"] < eng_kam_ulush: return False, (f"toza ulush {h['toza_ulushi']:.1%} < talab {eng_kam_ulush:.0%}") return True, f"toza ulush {h['toza_ulushi']:.1%}"
python3 -c " import sys; sys.path.insert(0, 'src') import numpy as np, pandas as pd from quvur.sxema import IJARA_SXEMASI from quvur.sifat import hisobot, darvoza d = pd.read_csv('../datasets/ijara.csv') ok, sabab = darvoza(hisobot(d, IJARA_SXEMASI)) print(f'TOZA ma\'lumot -> o\'tdimi: {ok} ({sabab})') r = np.random.default_rng(7) buzuq = d.copy() buzuq.loc[r.choice(len(d), 1500, replace=False), 'maydon'] = 0 h = hisobot(buzuq, IJARA_SXEMASI) ok, sabab = darvoza(h) print(f'BUZUQ ma\'lumot -> o\'tdimi: {ok} ({sabab})') print('sabablar:', h['sabablar']) " ; echo "qaytish kodi: $?"
TOZA ma'lumot -> o'tdimi: True (toza ulush 100.0%)
BUZUQ ma'lumot -> o'tdimi: False (toza ulush 87.5% < talab 95%)
sabablar: {'maydon < 10': 1500}
qaytish kodi: 0
darvoza funksiyasi 31-bobda CI ga ulanadi: ma'lumot sifati past bo'lsa, o'qitish boshlanmaydi.
Xulosa
| Tushuncha | Asosiy fikr |
|---|---|
| Model shikoyat qilmaydi | maydon=0 va rasmlar=-1 qabul qilinadi, javob qaytadi |
| Model turi muhim | Daraxt chidadi (0.860→0.861), chiziqli qulaadi (0.861→0.732) |
| Tekshiruv joyi | Ma'lumot tizimga kirgan chegarada, bir marta |
| Karantin | Rad etilgan qator tashlanmaydi — sababi bilan saqlanadi |
| O'lchangan foyda | Chiziqli: 0.800 → 0.853; daraxt: 0.856 → 0.853 (foyda yo'q) |
| Baribir kerak | Buzuq ma'lumot — yuqori oqimdagi bug belgisi, model chidasa ham |
| Almashuv | Qamrov va sifat orasida tanlov — biznes qarori |
| Ikki xil tekshiruv | Sxema (qiymat mumkinmi) va taqsimot (odatdagidek ko'rinadimi) |
| Qattiqlik xavfi | Avval kuzatuv rejimi, keyin rad etish |
| Darvoza | Sifat past bo'lsa, o'qitish boshlanmasin |
Talaba ishi
IJARA_SXEMASIga yangi qoida qo'shing:qavat <= jami_qavat. Bu ustunlararo qoida —tekshirni qanday o'zgartirish kerak?- Tekshiruvni "kuzatuv rejimi" bilan kengaytiring:
rad_etma=Truebo'lsa, faqat sanasin. buyurtma.csvuchun sxema yozing. Qaysi ustunda eng ko'p muammo topildi?darvozaga ikkinchi shart qo'shing: bitta sabab 5% dan ko'p bo'lsa ham rad etsin. Nega bu umumiy ulushdan boshqa narsani ushlaydi?
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.