Asosiy qismga o'tish

Model testlari: kod testi yetarli emas

25-bob 12 kod bloki 2796 so'z

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

Har doim 70 kilogramm ko'rsatadigan tarozi

Do'konda tarozi bor. Uni tekshiramiz:

  • Yoqilganda ishlaydimi? Ha.
  • Ekranda raqam chiqadimi? Ha.
  • Raqam sonmi, matn emasmi? Ha.
  • Manfiy chiqadimi? Yo'q.

Hamma test o'tdi. Tarozi soz.

Endi unga 10 kilogramm olma qo'yamiz. Ekranda: 70.

Bolani qo'yamiz. 70. Hech narsa qo'ymaymiz. 70.

Tarozi buzuq emas — u ishlayapti, raqam beryapti, xato bermayapti. U faqat noto'g'ri.

Kod testi va model testi

Mana ML dagi eng muhim ajratish.

Python muhandisligi kitobida kod testlarini yozgandik: funksiya to'g'ri natija qaytaradimi, xato holatni ushlaydimi. Bular tarozining yonishini tekshiradi.

Model uchun bu yetarli emas, chunki kod to'g'ri, model esa yomon bo'lishi mumkin. Kod hech qachon xato bermaydi — u har doim 70 qaytaradi.

Demak bizga boshqa turdagi test kerak: "javob mantiqiymi?" degan savolga javob beradigan test. Masalan: telefon raqami ko'proq e'londa takrorlansa, broker ehtimoli oshishi kerak. Agar tushsa — kod ishlayapti, lekin model buzuq.

Uch xil test

Python muhandisligi kitobida kod testlarini yozgandik: funksiya to'g'ri natija qaytaradimi. ML da bu yetarli emas, chunki kod to'g'ri, model esa yomon bo'lishi mumkin.

python10 qator
import pandas as pd
show(pd.DataFrame([
    {"tur": "Kod testi", "savol": "Funksiya to'g'ri hisoblaydimi?",
     "misol": "tayyorla() 13 ta ustun qaytaradimi", "qachon buziladi": "Refaktoring"},
    {"tur": "Ma'lumot testi", "savol": "Kirish ma'lumot to'g'rimi?",
     "misol": "maydon > 0 (6-bob)", "qachon buziladi": "Manba o'zgarganda"},
    {"tur": "Model testi", "savol": "Model MANTIQIY xulq qiladimi?",
     "misol": "Telefon ko'p takrorlansa, broker ehtimoli oshishi kerak",
     "qachon buziladi": "Model qayta o'qitilganda"},
]))
tursavolmisolqachon buziladi
Kod testiFunksiya to'g'ri hisoblaydimi?tayyorla() 13 ta ustun qaytaradimiRefaktoring
Ma'lumot testiKirish ma'lumot to'g'rimi?maydon > 0 (6-bob)Manba o'zgarganda
Model testiModel MANTIQIY xulq qiladimi?Telefon ko'p takrorlansa, broker ehtimoli oshishi kerakModel qayta o'qitilganda

Uchinchisi eng kam yoziladi va eng ko'p kerak bo'ladi.

To'rt xil model testi

python17 qator
diagramma(
    {
        "MINIMAL\nAniq holatlar": (0, 0, 2.6, 1.1, "manba"),
        "YO'NALISH\nX oshsa, Y oshsin": (3.4, 0, 2.6, 1.1, "qayta"),
        "O'ZGARMASLIK\nAhamiyatsiz belgi": (6.8, 0, 2.6, 1.1, "saqlash"),
        "REGRESSIYA\nEskidan yomon emas": (10.2, 0, 2.6, 1.1, "kuzatuv"),
        "Model chiqarilsin": (5.1, 2.2, 3.0, 1.1, "xizmat"),
    },
    [
        ("MINIMAL\nAniq holatlar", "Model chiqarilsin"),
        ("YO'NALISH\nX oshsa, Y oshsin", "Model chiqarilsin"),
        ("O'ZGARMASLIK\nAhamiyatsiz belgi", "Model chiqarilsin"),
        ("REGRESSIYA\nEskidan yomon emas", "Model chiqarilsin"),
    ],
    nom="model_testlari.png", kenglik=13,
    izoh="To'rttasi ham o'tsagina model chiqariladi. Har biri boshqa turdagi nosozlikni ushlaydi.",
)

To'rttasi ham o'tsagina model chiqariladi. Har biri boshqa turdagi nosozlikni ushlaydi.

To'rttasi ham o'tsagina model chiqariladi. Har biri boshqa turdagi nosozlikni ushlaydi.

Har birini yozamiz va haqiqiy modelda sinaymiz.

Sinov uchun yordamchi

shu faylni yaratingsrc/quvur/sinov_yordam.py

python24 qator
"""Model testlari uchun namuna yasovchi."""
from typing import Any

import pandas as pd

from .xususiyat import XOM_USTUNLAR

ODATIY = {
    "xonalar": 2, "maydon": 55.0, "qavat": 3, "jami_qavat": 9,
    "narx_mln": 4.5, "tavsif_uzunligi": 300, "rasmlar_soni": 8,
    "telefon_takrorlanishi": 1, "kunlik_elonlar": 1, "egasi_tasdiqlangan": 1,
}


def namuna(**ozgarishlar: Any) -> pd.DataFrame:
    """Odatiy e'lon; berilgan maydonlar almashtiriladi."""
    q = {**ODATIY, **ozgarishlar}
    return pd.DataFrame([{u: q[u] for u in XOM_USTUNLAR}])


def ehtimol(model, **ozgarishlar: Any) -> float:
    """Shu e'lon uchun broker ehtimoli."""
    from .xususiyat import tayyorla
    return float(model.predict_proba(tayyorla(namuna(**ozgarishlar)))[0, 1])

1. Minimal funksionallik testi

Eng aniq holatlarni model to'g'ri tushunishi kerak:

python23 qator
python3 -c "
import sys; sys.path.insert(0, 'src')
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from quvur.xususiyat import XUSUSIYATLAR, tayyorla
from quvur.sinov_yordam import ehtimol

d = pd.read_csv('../datasets/ijara.csv')
x, y = tayyorla(d), d['broker']
Xtr, _, ytr, _ = train_test_split(x, y, test_size=0.25, stratify=y, random_state=42)
m = RandomForestClassifier(n_estimators=150, min_samples_leaf=3, random_state=42, n_jobs=1).fit(Xtr, ytr)
import joblib; joblib.dump(m, 'sinov_model.joblib')

aniq_ega = ehtimol(m, telefon_takrorlanishi=1, kunlik_elonlar=1,
                   tavsif_uzunligi=600, rasmlar_soni=15, egasi_tasdiqlangan=1)
aniq_broker = ehtimol(m, telefon_takrorlanishi=18, kunlik_elonlar=9,
                      tavsif_uzunligi=60, rasmlar_soni=2, egasi_tasdiqlangan=0)
print(f'aniq EGA    -> broker ehtimoli {aniq_ega:.3f}   (past bo\'lishi kerak)')
print(f'aniq BROKER -> broker ehtimoli {aniq_broker:.3f}   (yuqori bo\'lishi kerak)')
print()
print('o\'tdimi:', aniq_ega < 0.3 and aniq_broker > 0.7)
"
Chiqish (qaytish kodi 0, 2133 ms)
aniq EGA    -> broker ehtimoli 0.056   (past bo'lishi kerak)
aniq BROKER -> broker ehtimoli 0.898   (yuqori bo'lishi kerak)

o'tdimi: True

Bu test oddiy ko'rinadi, lekin u eng ko'p nosozlikni ushlaydi: ustun tartibi buzilgan (3-bob), model noto'g'ri yuklangan, yoki nishon teskari o'rgatilgan.

2. Yo'nalish testi

Ba'zi belgilarning ta'siri oldindan ma'lum. Telefon ko'p takrorlansa, broker ehtimoli oshishi kerak — kamaymasligi:

python18 qator
python3 -c "
import sys; sys.path.insert(0, 'src')
import joblib
from quvur.sinov_yordam import ehtimol
m = joblib.load('sinov_model.joblib')

print('telefon_takrorlanishi oshgan sari:')
oldingi = -1
buzildi = False
for t in (1, 3, 6, 10, 15, 20):
    e = ehtimol(m, telefon_takrorlanishi=t)
    belgi = '' if e >= oldingi else '  <- KAMAYDI'
    if e < oldingi: buzildi = True
    print(f'  telefon={t:3}  ehtimol={e:.3f}{belgi}')
    oldingi = e
print()
print('monoton oshdimi:', not buzildi)
"
Chiqish (qaytish kodi 0, 1222 ms)
telefon_takrorlanishi oshgan sari:
  telefon=  1  ehtimol=0.052
  telefon=  3  ehtimol=0.040  <- KAMAYDI
  telefon=  6  ehtimol=0.460
  telefon= 10  ehtimol=0.650
  telefon= 15  ehtimol=0.645  <- KAMAYDI
  telefon= 20  ehtimol=0.645

monoton oshdimi: False
python10 qator
python3 -c "
import sys; sys.path.insert(0, 'src')
import joblib
from quvur.sinov_yordam import ehtimol
m = joblib.load('sinov_model.joblib')

print('tavsif uzaygan sari (teskari yo\'nalish kutiladi):')
for t in (50, 150, 300, 500, 800):
    print(f'  tavsif={t:4}  ehtimol={ehtimol(m, tavsif_uzunligi=t):.3f}')
"
Chiqish (qaytish kodi 0, 937 ms)
tavsif uzaygan sari (teskari yo'nalish kutiladi):
  tavsif=  50  ehtimol=0.091
  tavsif= 150  ehtimol=0.056
  tavsif= 300  ehtimol=0.052
  tavsif= 500  ehtimol=0.042
  tavsif= 800  ehtimol=0.053

Natijani diqqat bilan o'qing — u kutilganidek emas.

Telefon 1 dan 3 ga oshganda ehtimol kamaydi (0.052 → 0.040), 10 dan 15 ga oshganda yana kamaydi. Umumiy tendensiya to'g'ri (0.052 dan 0.645 ga), lekin yo'l monoton emas.

Tavsifda ham xuddi shunday: 500 dan 800 ga o'tganda ehtimol biroz oshdi (0.042 → 0.053).

Sabab: daraxt modeli monoton bo'lishga majbur emas. U ma'lumotni bo'laklarga bo'ladi va har bo'lakda o'z qaroriga keladi. Oraliqda kichik tebranish — normal hodisa.

Shuning uchun testni qadam-baqadam monotonlikka emas, umumiy tendensiyaga qurish kerak: birinchi va oxirgi qiymatni solishtirish. Yuqoridagi yonalish funksiyasi aynan shunday yozilgan.

Agar umumiy tendensiya ham teskari bo'lsa — o'shanda model mantiqni emas, tasodifiy naqshni o'rgangan bo'ladi va bu haqiqiy muammo.

Yo'nalish testini to'g'ri e'londan boshlang

Yuqoridagi tavsif o'lchovida ehtimol 0.09 dan 0.05 gacha tushdi — atigi 0.04. Sabab: boshlang'ich e'lon allaqachon aniq ega (telefon=1, tasdiqlangan=1), ehtimol nolga yaqin va tushishga joy yo'q.

Yo'nalish testini shubhali e'londan boshlang — o'shanda belgining ta'siri ko'rinadi. Aks holda test modelni emas, boshlang'ich nuqtani sinaydi.

3. O'zgarmaslik testi

Ba'zi belgilar natijaga ta'sir qilmasligi kerak. Masalan qavat raqami brokerlikni belgilamaydi:

python12 qator
python3 -c "
import sys; sys.path.insert(0, 'src')
import joblib
from quvur.sinov_yordam import ehtimol
m = joblib.load('sinov_model.joblib')

qiymatlar = [ehtimol(m, qavat=q, jami_qavat=12) for q in (1, 3, 5, 8, 11)]
print('qavat o\'zgarganda ehtimol:', [round(v, 3) for v in qiymatlar])
tarqalish = max(qiymatlar) - min(qiymatlar)
print(f'tarqalish: {tarqalish:.3f}')
print('o\'zgarmaslik o\'tdimi (< 0.15):', tarqalish < 0.15)
"
Chiqish (qaytish kodi 0, 916 ms)
qavat o'zgarganda ehtimol: [0.08, 0.032, 0.027, 0.018, 0.043]
tarqalish: 0.062
o'zgarmaslik o'tdimi (< 0.15): True

Agar qavat natijani keskin o'zgartirsa, model ahamiyatsiz belgiga tayanayapti — bu qayta moslashish (overfit) belgisi.

4. Regressiya testi

Eng muhimi: yangi model eskisidan yomon bo'lmasin.

Bu oddiy ko'rinadi — F1 ni solishtirasiz, tamom. Lekin bir tuzoq bor.

Tasavvur qiling, yangi model F1 ni 0.860 dan 0.865 ga ko'tardi. Yaxshi, chiqaramiz.

Lekin o'rtacha ko'tarilgani hamma joyda ko'tarilgan degani emas. Yangi model Yunusobodda yaxshiroq, Chilonzorda esa yomonroq bo'lishi mumkin. O'rtachada bu ko'rinmaydi.

Shifokor misolini eslang: "o'rtacha harorat normal" degan gap bitta bemor isitmalab, ikkinchisi muzlab yotganini yashiradi.

Shuning uchun regressiya testi ikki darajali bo'lishi kerak:

  1. Umumiy metrika tushmadimi?
  2. Alohida guruhlarda metrika tushmadimi?

Ikkinchisi muhimroq, chunki foydalanuvchi o'rtachada yashamaydi — u aniq bir tumanda yashaydi.

Va yana bir narsa: taqqoslash uchun bir xil test to'plami kerak. Har safar boshqa namuna olsangiz, farq modeldan emas, namunadan kelib chiqadi (2-bobdagi seed muammosi yana qaytadi).

shu faylni yaratingsrc/quvur/model_test.py

python57 qator
"""Model testlari — pytest bilan ishlatiladi."""
import json
from pathlib import Path
from typing import Any

import pandas as pd

from .sinov_yordam import ehtimol
from .xususiyat import tayyorla


def minimal_funksionallik(model) -> tuple[bool, str]:
    ega = ehtimol(model, telefon_takrorlanishi=1, kunlik_elonlar=1,
                  tavsif_uzunligi=600, rasmlar_soni=15, egasi_tasdiqlangan=1)
    brok = ehtimol(model, telefon_takrorlanishi=18, kunlik_elonlar=9,
                   tavsif_uzunligi=60, rasmlar_soni=2, egasi_tasdiqlangan=0)
    ok = ega < 0.3 and brok > 0.7
    return ok, f"ega={ega:.3f} broker={brok:.3f}"


def yonalish(model, belgi: str, qiymatlar: list, oshishi_kerak: bool,
             eng_kam_farq: float = 0.05, **asos: Any) -> tuple[bool, str]:
    """UMUMIY tendensiyani tekshiradi, qadam-baqadam monotonlikni EMAS.

    Daraxt modellari monoton bo'lishga majbur emas — oraliqda tebranish normal.
    Shuning uchun birinchi va oxirgi qiymat solishtiriladi.

    `asos` — boshlang'ich e'lonni o'zgartiradi. Bu MUHIM: agar e'lon allaqachon
    aniq ega bo'lsa, ehtimol 0.05 atrofida bo'ladi va tushishga JOY QOLMAYDI.
    """
    e = [ehtimol(model, **{**asos, belgi: q}) for q in qiymatlar]
    farq = e[-1] - e[0]
    ok = farq >= eng_kam_farq if oshishi_kerak else farq <= -eng_kam_farq
    yonalish_matni = "oshdi" if farq > 0 else "kamaydi"
    return ok, f"{belgi}: {[round(v, 3) for v in e]} ({yonalish_matni} {abs(farq):.3f})"


def ozgarmaslik(model, belgi: str, qiymatlar: list, chegara: float = 0.15) -> tuple[bool, str]:
    e = [ehtimol(model, **{belgi: q}) for q in qiymatlar]
    t = max(e) - min(e)
    return t < chegara, f"{belgi} tarqalishi={t:.3f}"


def regressiya(yangi_metrikalar: dict[str, float], asos_yoli: str | Path,
               ruxsat: float = 0.01) -> tuple[bool, str]:
    """Yangi model asosdan `ruxsat` dan ko'proq yomon bo'lmasin."""
    p = Path(asos_yoli)
    if not p.exists():
        p.write_text(json.dumps(yangi_metrikalar, indent=2), encoding="utf-8")
        return True, "asos yaratildi (birinchi marta)"
    asos = json.loads(p.read_text(encoding="utf-8"))
    yomonlashgan = []
    for k, eski in asos.items():
        yangi = yangi_metrikalar.get(k)
        if yangi is not None and yangi < eski - ruxsat:
            yomonlashgan.append(f"{k}: {eski:.4f} -> {yangi:.4f}")
    return (not yomonlashgan), ("; ".join(yomonlashgan) or "hammasi asos darajasida")
python15 qator
python3 -c "
import sys; sys.path.insert(0, 'src')
import joblib, json
from quvur.model_test import regressiya

m = joblib.load('sinov_model.joblib')
# asos yaratamiz
print('1)', regressiya({'f1': 0.8595, 'toliqlik': 0.8285}, 'asos.json'))
# bir xil natija — o'tadi
print('2)', regressiya({'f1': 0.8595, 'toliqlik': 0.8285}, 'asos.json'))
# biroz yaxshiroq — o'tadi
print('3)', regressiya({'f1': 0.8700, 'toliqlik': 0.8400}, 'asos.json'))
# sezilarli yomonroq — YIQILADI
print('4)', regressiya({'f1': 0.8100, 'toliqlik': 0.7900}, 'asos.json'))
"
Chiqish (qaytish kodi 0, 1015 ms)
1) (True, 'asos yaratildi (birinchi marta)')
2) (True, 'hammasi asos darajasida')
3) (True, 'hammasi asos darajasida')
4) (False, 'f1: 0.8595 -> 0.8100; toliqlik: 0.8285 -> 0.7900')

To'rtinchi holat yiqildi va qaysi metrika qancha tushganini aytdi. Bu CI da PR ni to'xtatadi (31-bob).

Hammasini pytest ga yig'amiz

shu faylni yaratingtests/test_model.py

bash53 qator
"""Model testlari. `pytest tests/test_model.py -v` bilan ishlaydi."""
import sys
from pathlib import Path

import joblib
import pytest

sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))

from quvur.model_test import minimal_funksionallik, ozgarmaslik, yonalish


@pytest.fixture(scope="module")
def model():
    yol = Path(__file__).resolve().parents[1] / "sinov_model.joblib"
    if not yol.exists():
        pytest.skip("model topilmadi — avval o'qitish quvurini ishga tushiring")
    return joblib.load(yol)


def test_minimal_funksionallik(model):
    ok, tafsilot = minimal_funksionallik(model)
    assert ok, f"aniq holatlar noto'g'ri: {tafsilot}"


def test_telefon_kop_bolsa_broker_ehtimoli_oshadi(model):
    ok, tafsilot = yonalish(model, "telefon_takrorlanishi", [1, 5, 10, 18], oshishi_kerak=True)
    assert ok, f"yo'nalish buzildi: {tafsilot}"


def test_tavsif_uzun_bolsa_broker_ehtimoli_kamayadi(model):
    # Shubhali e'londan boshlaymiz: aniq egada ehtimol allaqachon ~0.05,
    # tushishga joy qolmaydi va test sababsiz yiqiladi.
    ok, tafsilot = yonalish(model, "tavsif_uzunligi", [60, 200, 400, 700],
                            oshishi_kerak=False,
                            telefon_takrorlanishi=7, egasi_tasdiqlangan=0,
                            rasmlar_soni=3, kunlik_elonlar=4)
    assert ok, f"yo'nalish buzildi: {tafsilot}"


def test_qavat_natijaga_tasir_qilmaydi(model):
    ok, tafsilot = ozgarmaslik(model, "qavat", [1, 4, 7, 10])
    assert ok, f"ahamiyatsiz belgiga tayanmoqda: {tafsilot}"


@pytest.mark.parametrize("belgi, qiymat", [
    ("maydon", 30.0), ("maydon", 120.0),
    ("xonalar", 1), ("xonalar", 4),
])
def test_ehtimol_oraliqda(model, belgi, qiymat):
    from quvur.sinov_yordam import ehtimol
    e = ehtimol(model, **{belgi: qiymat})
    assert 0.0 <= e <= 1.0
matn1 qator
python3 -m pytest tests/test_model.py -v 2>&1 | tail -16
Chiqish (qaytish kodi 0, 2095 ms)
cachedir: .pytest_cache
rootdir: /mnt/c/Users/Admin/Desktop/Course Material/MLOps_Kitob/ish
plugins: cov-7.0.0, hydra-core-1.3.2, langsmith-0.5.1, asyncio-1.3.0, anyio-4.12.0, typeguard-4.4.4
asyncio: mode=strict, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collecting ... collected 8 items

tests/test_model.py::test_minimal_funksionallik PASSED                   [ 12%]
tests/test_model.py::test_telefon_kop_bolsa_broker_ehtimoli_oshadi PASSED [ 25%]
tests/test_model.py::test_tavsif_uzun_bolsa_broker_ehtimoli_kamayadi PASSED [ 37%]
tests/test_model.py::test_qavat_natijaga_tasir_qilmaydi PASSED           [ 50%]
tests/test_model.py::test_ehtimol_oraliqda[maydon-30.0] PASSED           [ 62%]
tests/test_model.py::test_ehtimol_oraliqda[maydon-120.0] PASSED          [ 75%]
tests/test_model.py::test_ehtimol_oraliqda[xonalar-1] PASSED             [ 87%]
tests/test_model.py::test_ehtimol_oraliqda[xonalar-4] PASSED             [100%]

============================== 8 passed in 1.24s ===============================

Nima ushlanadi, nima yo'q

python9 qator
import pandas as pd
show(pd.DataFrame([
    {"nosozlik": "Ustun tartibi buzildi (3-bob)", "qaysi test ushlaydi": "Minimal funksionallik"},
    {"nosozlik": "Nishon teskari o'rgatildi", "qaysi test ushlaydi": "Minimal funksionallik"},
    {"nosozlik": "Model ahamiyatsiz belgiga tayanadi", "qaysi test ushlaydi": "O'zgarmaslik"},
    {"nosozlik": "Mantiq teskari o'rganildi", "qaysi test ushlaydi": "Yo'nalish"},
    {"nosozlik": "Yangi model yomonroq", "qaysi test ushlaydi": "Regressiya"},
    {"nosozlik": "Ma'lumot drifti", "qaysi test ushlaydi": "HECH BIRI — 35-bob kerak"},
]))
nosozlikqaysi test ushlaydi
Ustun tartibi buzildi (3-bob)Minimal funksionallik
Nishon teskari o'rgatildiMinimal funksionallik
Model ahamiyatsiz belgiga tayanadiO'zgarmaslik
Mantiq teskari o'rganildiYo'nalish
Yangi model yomonroqRegressiya
Ma'lumot driftiHECH BIRI — 35-bob kerak

Oxirgi qator muhim: model testlari o'qitish paytida ishlaydi. Drift esa ishlab chiqarishda, oylar o'tib yuz beradi — uni faqat kuzatuv ushlaydi.

Yo'nalish testini juda qat'iy qilmang

Yuqorida qadam-baqadam monotonlik o'rniga umumiy tendensiya tekshiriladi. Sababi yuqorida o'lchandi: daraxt modelida telefon 1→3 da ehtimol kamaydi, garchi umumiy yo'nalish to'g'ri bo'lsa ham.

Juda qat'iy qilsangiz, test har qayta o'qitishda tasodifan yiqiladi va jamoa uni o'chirib qo'yadi — bu eng yomon natija. Test ishonchli bo'lishi, "mukammal" bo'lishidan muhimroq.

Xulosa

Tushuncha Asosiy fikr
Uch xil test Kod, ma'lumot, model — uchinchisi eng kam yoziladi
Minimal funksionallik Aniq holatlar; eng ko'p nosozlikni ushlaydi
Yo'nalish Belgining ta'siri mantiqqa mosmi
O'zgarmaslik Ahamiyatsiz belgi natijani o'zgartirmasin
Regressiya Yangi model asosdan yomon bo'lmasin; qaysi metrika tushganini aytsin
Bag'rikenglik +0.02 — beqaror test o'chirib tashlanadi
Chegara Model testlari drift ni ushlamaydi (35-bob)

Talaba ishi

  1. tests/test_model.py ga yangi yo'nalish testi qo'shing: egasi_tasdiqlangan=1 bo'lsa broker ehtimoli kamayishi kerak. O'tadimi?
  2. Modelni ataylab buzing: tayyorla da ikki ustunni almashtiring. Qaysi test birinchi yiqiladi?
  3. regressiya ga "ruxsat" ni 0.0 qiling. Testlar beqaror bo'lib qoladimi? Nega?
  4. ozgarmaslik chegarasini 0.05 qiling. O'tadimi? Agar yo'q bo'lsa — bu model muammosimi yoki test muammosimi?

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar