Asosiy qismga o'tish

Ma'lumot sifati: yomon ma'lumot modelga yetib bormasin

6-bob 12 kod bloki 3783 so'z

Bu bobdagi kod shu fayllar bilan ishlaydio'z kompyuteringizda ishga tushiring

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.

python51 qator
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}")
Chiqish
  birlik   = narx birligi almashgan (mln -> so'm)
  nol      = maydon = 0 (yetishmagan qiymat)
  manfiy   = rasmlar_soni = -1 (mumkin emas)
modeltozabirliknolmanfiy
RandomForest (daraxt)0.860.8610.8610.846
LogisticRegression (chiziqli)0.8610.7320.8610.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.

python15 qator
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.

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

python81 qator
"""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:

python12 qator
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)')
"
Chiqish (qaytish kodi 0, 338 ms)
kirish   : 12,000 qator
toza     : 12,000
karantin : 0
xabarlar : (muammo yo'q)

Endi buzilgan ma'lumotda:

python25 qator
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))
"
Chiqish (qaytish kodi 0, 463 ms)
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.

python25 qator
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}%)")
Chiqish
karantinga tushdi: 662 / 3000 qator (22.1%)
modeltoza (ideal)buzuq, tekshiruvsizbuzuq, tekshiruvdan keyin
RandomForest (daraxt)0.860.8560.853
LogisticRegression (chiziqli)0.8610.80.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:

python11 qator
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"},
]))
sababizoh
Yuqori oqimdagi xatoni topadinarx million barobar oshgan bo'lsa, manba tizimda BUG bor — model chidasa ham
Hisobot va tahlil buziladiModel chidaydi, lekin o'rtacha narx grafigi butunlay noto'g'ri chiqadi
Keyingi model chidamasligi mumkinBugun daraxt, ertaga chiziqli yoki neyron tarmoq
Sabab ma'lum bo'ladiKarantin '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.

python23 qator
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))
ustunavgust o'rtachasentabr o'rtachao'zgarish %ogohlantirish
narx_mln5.7185.668-0.9-
maydon71.87571.519-0.5-
rasmlar_soni7.1988.21914.2HA
telefon_takrorlanishi3.543.6884.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:

python7 qator
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"},
]))
tursavolmisolqachon
Sxema tekshiruviQiymat umuman mumkinmi?maydon = 0, rasmlar = -1Har qatorda, darhol
Taqsimot tekshiruviMa'lumot odatdagidek ko'rinadimi?O'rtacha 15% o'zgardiTo'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:

python7 qator
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`"},
]))
asbobkuchli tomoni
Panderapandas ga mos, dekorator bilan, tur ko'rsatkichlari
Great ExpectationsBoy qoidalar to'plami, HTML hisobot, ma'lumot hujjati
pydanticBitta yozuv uchun ideal (API kirishi, 27-bob)
dbt testsSQL 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

python26 qator
"""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%}"
python18 qator
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: $?"
Chiqish (qaytish kodi 0, 464 ms)
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

  1. IJARA_SXEMASI ga yangi qoida qo'shing: qavat <= jami_qavat. Bu ustunlararo qoida — tekshir ni qanday o'zgartirish kerak?
  2. Tekshiruvni "kuzatuv rejimi" bilan kengaytiring: rad_etma=True bo'lsa, faqat sanasin.
  3. buyurtma.csv uchun sxema yozing. Qaysi ustunda eng ko'p muammo topildi?
  4. darvoza ga 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.

Telegramda yozish Narxlar