Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. To'liq oqim
- 2.2. Pipeline va ColumnTransformer
- 2.3. Baza modeldan boshlash
- 2.4. Modellarni solishtirish
- 2.5. Giperparametrni sozlash
- 2.6. Yakuniy baho va xatolar tahlili
- 2.7. Oqim tuzoqlari
- 2.8. To'liq oqim — takrorlanadigan shablon
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Ma'lumot, ajratish va pipeline
- Misol 2 — Baza va modellarni solishtirish
- Misol 3 — Giperparametrni sozlash
- Misol 4 — Yakuniy baho va xatolar tahlili
- 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
12.6-dars: Birinchi to'liq model
12-QISM — MACHINE LEARNING ASOSLARI · 6-dars
1. Kirish va motivatsiya
Oldingi beshta darsda nazariyani yig'dik: ML nima 12.1-bob, vazifani qanday qo'yish 12.2-bob, qanday ajratish 12.3-bob, overfitting va bias-variance (12.4-12.5). Endi ularni bitta ishchi oqimga birlashtiramiz: ma'lumotdan boshlab, baholangan modelgacha.
Bu dars — amaliy shablon: ma'lumotni yuklash va ajratish, belgilarni tayyorlash (pipeline ichida), baza modeldan boshlash, bir necha modelni cross-validation bilan solishtirish, giperparametrni sozlash, yakuniy modelni bir marta test to'plamida baholash va natijani talqin qilish. Shu shablon keyingi barcha loyihalarda takrorlanadi — faqat modellar va belgilar o'zgaradi.
Real vaziyat. Yangi Data Scientist birinchi vazifasini oladi: uy narxini bashorat qilish. U darhol Random Forest o'qitadi, R^2 = 0.86 oladi va hisobot yozadi. Katta hamkasbi savol beradi: "Baza model qancha? Oddiy chiziqli regressiya-chi? Natijaning noaniqligi qancha? Xato qaysi uylarda katta?". Javoblar yo'q. Qayta ishlangan tahlil: baza (o'rtacha) MAE = 42 ming, chiziqli regressiya 18 ming, o'rmon 14 ming ± 1.2 (CV SD); eng katta xatolar — juda katta va noyob uylarda. Endi hisobot to'liq va ishonchli.
Bu darsda to'liq ML oqimini quramiz.
Bu darsda:
- To'liq oqim: 8 qadam
- Pipeline va ColumnTransformer
- Baza modeldan boshlash
- Modellarni cross-validation bilan solishtirish
- Giperparametrni sozlash (GridSearchCV)
- Yakuniy baho va xatolarni tahlil qilish
- Oqim tuzoqlari
- Amaliy: uy narxi modeli
ℹ Misollar real numpy/pandas/sklearn bilan (Python 3.14).
2. Nazariya — chuqur tushuntirish
2.1. To'liq oqim
1. MA'LUMOT — yuklash, tekshirish, dublikatlarni olib tashlash
2. AJRATISH — test to'plamini darhol ajratib, yopib qo'yish 12.3-bob
3. EDA (o'quvda) — taqsimotlar, yetishmovchilik, outlierlar (8-qism)
4. TAYYORLASH — pipeline: imputer, scaler, one-hot 12.9-bob
5. BAZA — DummyRegressor / DummyClassifier 12.1-bob
6. MODELLAR — bir nechta nomzodni CV bilan solishtirish
7. SOZLASH — GridSearchCV / RandomizedSearchCV (validatsiyada)
8. YAKUNIY BAHO — test to'plamida BIR MARTA + xatolar tahliliBu tartib muhim: test to'plami 2-qadamda ajratiladi va 8-qadamgacha tegilmaydi 12.3-bob; EDA va barcha qarorlar faqat o'quv ma'lumotida (aks holda leakage — 12.2). Har qadamda natija yoziladi: baza, har model CV balli (± SD), tanlangan giperparametrlar, yakuniy test balli.
2.2. Pipeline va ColumnTransformer
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
son = ["maydon", "yosh"]; kategoriya = ["hudud", "tur"]
tayyorlash = ColumnTransformer([
("son", Pipeline([("imp", SimpleImputer(strategy="median")),
("sc", StandardScaler())]), son),
("kat", Pipeline([("imp", SimpleImputer(strategy="most_frequent")),
("oh", OneHotEncoder(handle_unknown="ignore"))]), kategoriya),
])
model = Pipeline([("tayyor", tayyorlash), ("model", Ridge(alpha=1.0))])
model.fit(X_train, y_train) # barcha qadamlar faqat o'quvda fit bo'ladi Pipeline — barcha tayyorlash qadamlari va modelni bitta obyekt qiladi. Bu uch muammoni hal qiladi: (1) leakage — fit faqat o'quv qismida bajariladi, CV da ham har bo'lakda alohida 12.9-bob; (2) takrorlanuvchanlik — bir xil qadamlar test va ishlab chiqarishda; (3) soddalik — giperparametrlarni butun oqim bo'ylab sozlash mumkin (model__alpha).
2.3. Baza modeldan boshlash
Baza 12.1-bob — har qanday natijaning o'lchovi: regressiyada DummyRegressor(strategy="mean") yoki "oddiy qoida" (masalan, narx = maydon × o'rtacha kvadrat metr narxi); klassifikatsiyada DummyClassifier(strategy="most_frequent"/"stratified"). Agar murakkab model bazadan sezilarli yaxshi bo'lmasa — muammo belgilarda yoki vazifada 12.2-bob. Baza natijasi hisobotda majburiy: menejer "MAE 14 ming" ni faqat "42 ming" bilan solishtirganda tushunadi.
2.4. Modellarni solishtirish
Nomzodlar (jadval ma'lumoti uchun odatiy tartib):
1. Chiziqli (Ridge / LogisticRegression) — tez, talqin qilinadi
2. KNN — oddiy, masofaga asoslangan (masshtablash shart)
3. Qaror daraxti — nochiziqli, talqin qilinadi
4. Random Forest / Gradient Boosting — odatda eng kuchli
Solishtirish: bir xil CV bo'linishi, bir xil metrika, ± SD bilan
cross_validate(model, X_tr, y_tr, cv=5, scoring="neg_mean_absolute_error") Modellarni bir xil sharoitda solishtirish kerak: bir xil CV bo'linishi (cv obyektini bir marta yaratib, hammasiga bering), bir xil metrika, bir xil tayyorlash. Natijani ± SD bilan bering: farq SD dan kichik bo'lsa, u ishonchli emas 11.1-bob. Jadval ma'lumotida ko'pincha gradient boosting yutadi, lekin chiziqli model tezligi va talqin qilinishi bilan qimmatli.
2.5. Giperparametrni sozlash
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
setka = {"model__alpha": [0.01, 0.1, 1, 10, 100]}
qidiruv = GridSearchCV(pipeline, setka, cv=5, scoring="neg_mean_absolute_error", n_jobs=-1)
qidiruv.fit(X_train, y_train)
qidiruv.best_params_, -qidiruv.best_score_
qidiruv.best_estimator_ # eng yaxshi parametrlar bilan qayta o'qitilgan model GridSearchCV — barcha kombinatsiyalarni CV bilan sinaydi va eng yaxshisini tanlaydi; RandomizedSearchCV — tasodifiy nomzodlar (ko'p parametrda tezroq — 9.2 dagi kombinatorik portlash). Muhim: qidiruv faqat o'quv ma'lumotida; best_score_ — CV balli, u yakuniy baho emas (11.9 — tanlov optimizmi). Yakuniy baho — test to'plamida.
2.6. Yakuniy baho va xatolar tahlili
1. Yakuniy modelni butun o'quv to'plamida qayta o'qitish (GridSearchCV buni o'zi qiladi)
2. TEST to'plamida BIR MARTA baholash
3. Xatolar tahlili:
eng katta xatolar qayerda? (segmentlar, diapazonlar)
xato taqsimoti (qiyshiqmi?)
qoldiqlar va bashorat grafigi 10.6-bob
4. Talqin: koeffitsiyentlar yoki belgi muhimligi (ehtiyotkorlik bilan — 10.5)Xatolar tahlili — modelni yaxshilashning eng samarali yo'li: xatolar qayerda to'planganini ko'rish (masalan, katta uylarda, yangi hududlarda, kam ma'lumotli segmentlarda) yangi belgilar yoki alohida model g'oyasini beradi. Yakuniy hisobotda: baza, CV natijalari, test natijasi, xatolar tahlili va cheklovlar 8.9-bob.
2.7. Oqim tuzoqlari
Asosiy tuzoqlar: pipeline'siz tayyorlash (leakage — 12.9); test bilan tanlov 12.3-bob; bazani o'tkazib yuborish; turli CV bo'linishlarida solishtirish; SD siz taqqoslash; metrikani natijadan keyin tanlash 8.8-bob; best_score_ ni yakuniy natija deb e'lon qilish; xatolar tahlilini qilmaslik; random_state yo'qligi (takrorlanmaydi).
2.8. To'liq oqim — takrorlanadigan shablon
Oqim: ma'lumot → test ajratish → EDA (o'quvda) → pipeline bilan tayyorlash → baza → nomzod modellarni CV bilan solishtirish (± SD, bir xil bo'linish) → giperparametr sozlash (GridSearch/RandomizedSearch, faqat o'quvda) → test'da bir marta baho → xatolar tahlili va hisobot. Pipeline leakage'dan himoya qiladi va butun oqimni bitta obyektga jamlaydi. Keyingi dars — klassifikatsiya metrikalari: aniqlik nega yetarli emas va nimalar bilan almashtiriladi.
3. Tez ma'lumotnoma
import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.dummy import DummyRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.impute import SimpleImputer
from sklearn.linear_model import Ridge
from sklearn.model_selection import GridSearchCV, KFold, cross_validate, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=0)
tayyor = ColumnTransformer([
("son", Pipeline([("i", SimpleImputer(strategy="median")), ("s", StandardScaler())]), son_ust),
("kat", OneHotEncoder(handle_unknown="ignore"), kat_ust),
])
pipe = Pipeline([("t", tayyor), ("m", Ridge())])
cv = KFold(5, shuffle=True, random_state=0)
cross_validate(pipe, X_tr, y_tr, cv=cv, scoring="neg_mean_absolute_error")
gs = GridSearchCV(pipe, {"m__alpha": [0.1, 1, 10]}, cv=cv,
scoring="neg_mean_absolute_error", n_jobs=-1).fit(X_tr, y_tr)
yakuniy = gs.best_estimator_
QOIDA: pipeline · bir xil cv · baza · SD bilan · test oxirida bir martaTo'liq oqim xulosasi
1 ma'lumot → 2 test ajratish → 3 EDA (o'quvda) → 4 pipeline
5 baza → 6 modellar (CV, ± SD) → 7 sozlash → 8 test (bir marta) + xatolar tahlili
Pipeline — leakage himoyasi va takrorlanuvchanlik
best_score_ — CV balli, yakuniy natija emas
Hisobot: baza, CV, test, xatolar, cheklovlar4. Batafsil misollar
Misollar real numpy/pandas/sklearn bilan (Python 3.14). Barcha misollar bir xil
yarat()generatoridan foydalanadi.
Misol 1 — Ma'lumot, ajratish va pipeline
"""To'liq oqim: ma'lumot, test ajratish, pipeline bilan tayyorlash (real pandas/sklearn)."""
import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
def yarat(seed: int = 7) -> pd.DataFrame:
rng = np.random.default_rng(seed)
n = 3000
hudud = rng.choice(["markaz", "shimol", "janub", "chekka"], n, p=[0.3, 0.25, 0.25, 0.2])
tur = rng.choice(["yangi", "ikkilamchi"], n, p=[0.35, 0.65])
maydon = rng.lognormal(np.log(65), 0.35, n).clip(25, 250)
xona = np.clip((maydon / 24).round(), 1, 7)
yosh = np.where(tur == "yangi", rng.integers(0, 4, n), rng.integers(4, 45, n))
hudud_koef = pd.Series(hudud).map({"markaz": 1.45, "shimol": 1.05,
"janub": 1.0, "chekka": 0.8}).to_numpy()
narx = (1.55 * maydon + 5 * xona - 0.6 * yosh) * hudud_koef + rng.normal(0, 11, n)
df = pd.DataFrame({"hudud": hudud, "tur": tur, "maydon": maydon.round(1),
"xona": xona, "yosh": yosh, "narx": narx.round(1)})
df.loc[rng.choice(n, 90, replace=False), "yosh"] = np.nan # yetishmovchilik
return df
def main() -> None:
df = yarat()
X = df.drop(columns=["narx"])
y = df["narx"]
print("=== 1. Ma'lumot ===")
print(f" {df.shape[0]} qator, {df.shape[1]} ustun; dublikatlar: {df.duplicated().sum()}")
print(f" yetishmovchilik: {df.isna().sum().loc[lambda s: s > 0].to_dict()}")
print("\n=== 2. Test to'plamini darhol ajratish ===")
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=0)
print(f" o'quv {len(X_tr)}, test {len(X_te)} (test yopiladi)")
print("\n=== 3. EDA (faqat o'quvda) ===")
print(f" narx: median {y_tr.median():.1f}, IQR "
f"{y_tr.quantile(0.25):.1f}..{y_tr.quantile(0.75):.1f}")
print(f" hudud bo'yicha median narx: "
f"{X_tr.assign(narx=y_tr).groupby('hudud')['narx'].median().round(1).to_dict()}")
print("\n=== 4. Pipeline ===")
son = ["maydon", "xona", "yosh"]
kat = ["hudud", "tur"]
tayyor = ColumnTransformer([
("son", Pipeline([("imp", SimpleImputer(strategy="median")),
("sc", StandardScaler())]), son),
("kat", OneHotEncoder(handle_unknown="ignore"), kat),
])
pipe = Pipeline([("tayyor", tayyor), ("model", Ridge(alpha=1.0))])
pipe.fit(X_tr, y_tr)
print(f" qadamlar: {[nom for nom, _ in pipe.steps]}")
print(f" belgilar soni (one-hot dan keyin): "
f"{pipe.named_steps['tayyor'].transform(X_tr.head(5)).shape[1]}")
print(f" o'quv R^2 = {pipe.score(X_tr, y_tr):.3f}")
print(" ⭐ Pipeline — tayyorlash va model bitta obyektda")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Ma'lumot ===
3000 qator, 6 ustun; dublikatlar: 0
yetishmovchilik: {'yosh': 90}
=== 2. Test to'plamini darhol ajratish ===
o'quv 2400, test 600 (test yopiladi)
=== 3. EDA (faqat o'quvda) ===
narx: median 113.7, IQR 83.0..150.6
hudud bo'yicha median narx: {'chekka': 87.8, 'janub': 106.9, 'markaz': 151.5, 'shimol': 107.7}
=== 4. Pipeline ===
qadamlar: ['tayyor', 'model']
belgilar soni (one-hot dan keyin): 9
o'quv R^2 = 0.927
⭐ Pipeline — tayyorlash va model bitta obyektdaNima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — Baza va modellarni solishtirish
"""Baza modeldan boshlab, nomzodlarni bir xil CV bilan solishtirish (real pandas/sklearn)."""
import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.dummy import DummyRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.impute import SimpleImputer
from sklearn.linear_model import Ridge
from sklearn.model_selection import KFold, cross_validate, train_test_split
from sklearn.neighbors import KNeighborsRegressor
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.tree import DecisionTreeRegressor
def yarat(seed: int = 7) -> pd.DataFrame:
rng = np.random.default_rng(seed)
n = 3000
hudud = rng.choice(["markaz", "shimol", "janub", "chekka"], n, p=[0.3, 0.25, 0.25, 0.2])
tur = rng.choice(["yangi", "ikkilamchi"], n, p=[0.35, 0.65])
maydon = rng.lognormal(np.log(65), 0.35, n).clip(25, 250)
xona = np.clip((maydon / 24).round(), 1, 7)
yosh = np.where(tur == "yangi", rng.integers(0, 4, n), rng.integers(4, 45, n))
hudud_koef = pd.Series(hudud).map({"markaz": 1.45, "shimol": 1.05,
"janub": 1.0, "chekka": 0.8}).to_numpy()
narx = (1.55 * maydon + 5 * xona - 0.6 * yosh) * hudud_koef + rng.normal(0, 11, n)
df = pd.DataFrame({"hudud": hudud, "tur": tur, "maydon": maydon.round(1),
"xona": xona, "yosh": yosh, "narx": narx.round(1)})
df.loc[rng.choice(n, 90, replace=False), "yosh"] = np.nan
return df
def tayyorlash() -> ColumnTransformer:
return ColumnTransformer([
("son", Pipeline([("imp", SimpleImputer(strategy="median")),
("sc", StandardScaler())]), ["maydon", "xona", "yosh"]),
("kat", OneHotEncoder(handle_unknown="ignore"), ["hudud", "tur"]),
])
def main() -> None:
df = yarat()
X, y = df.drop(columns=["narx"]), df["narx"]
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=0)
cv = KFold(5, shuffle=True, random_state=0)
nomzodlar = {
"baza (o'rtacha)": DummyRegressor(strategy="mean"),
"Ridge": Pipeline([("t", tayyorlash()), ("m", Ridge(alpha=1.0))]),
"KNN (k=10)": Pipeline([("t", tayyorlash()), ("m", KNeighborsRegressor(10))]),
"daraxt (d=6)": Pipeline([("t", tayyorlash()),
("m", DecisionTreeRegressor(max_depth=6, random_state=0))]),
"o'rmon": Pipeline([("t", tayyorlash()),
("m", RandomForestRegressor(n_estimators=200, random_state=0,
min_samples_leaf=2, n_jobs=-1))]),
}
print("=== CV natijalari (MAE, ming $) ===")
print(f" {'model':<18} {'CV MAE':>10} {'SD':>7} {'o\"quv MAE':>11}")
for nom, m in nomzodlar.items():
r = cross_validate(m, X_tr, y_tr, cv=cv, scoring="neg_mean_absolute_error",
return_train_score=True)
cv_mae = -r["test_score"].mean()
tr_mae = -r["train_score"].mean()
print(f" {nom:<18} {cv_mae:>10.2f} {r['test_score'].std():>7.2f} {tr_mae:>11.2f}")
print("\n baza bilan solishtirish — har qanday natijaning o'lchovi")
print(" ⭐ Bir xil CV bo'linishi, bir xil metrika, SD bilan")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== CV natijalari (MAE, ming $) ===
model CV MAE SD o"quv MAE
baza (o'rtacha) 42.93 0.89 42.92
Ridge 11.76 0.21 11.72
KNN (k=10) 10.42 0.29 9.42
daraxt (d=6) 11.55 0.34 9.95
o'rmon 9.96 0.17 5.55
baza bilan solishtirish — har qanday natijaning o'lchovi
⭐ Bir xil CV bo'linishi, bir xil metrika, SD bilanNima ko'rsatdi: 2.3, 2.4-bo'limlar.
Misol 3 — Giperparametrni sozlash
"""GridSearchCV bilan sozlash: qidiruv faqat o'quv ma'lumotida (real pandas/sklearn)."""
import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestRegressor
from sklearn.impute import SimpleImputer
from sklearn.model_selection import GridSearchCV, KFold, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
def yarat(seed: int = 7) -> pd.DataFrame:
rng = np.random.default_rng(seed)
n = 3000
hudud = rng.choice(["markaz", "shimol", "janub", "chekka"], n, p=[0.3, 0.25, 0.25, 0.2])
tur = rng.choice(["yangi", "ikkilamchi"], n, p=[0.35, 0.65])
maydon = rng.lognormal(np.log(65), 0.35, n).clip(25, 250)
xona = np.clip((maydon / 24).round(), 1, 7)
yosh = np.where(tur == "yangi", rng.integers(0, 4, n), rng.integers(4, 45, n))
hudud_koef = pd.Series(hudud).map({"markaz": 1.45, "shimol": 1.05,
"janub": 1.0, "chekka": 0.8}).to_numpy()
narx = (1.55 * maydon + 5 * xona - 0.6 * yosh) * hudud_koef + rng.normal(0, 11, n)
df = pd.DataFrame({"hudud": hudud, "tur": tur, "maydon": maydon.round(1),
"xona": xona, "yosh": yosh, "narx": narx.round(1)})
df.loc[rng.choice(n, 90, replace=False), "yosh"] = np.nan
return df
def main() -> None:
df = yarat()
X, y = df.drop(columns=["narx"]), df["narx"]
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=0)
tayyor = ColumnTransformer([
("son", Pipeline([("imp", SimpleImputer(strategy="median")),
("sc", StandardScaler())]), ["maydon", "xona", "yosh"]),
("kat", OneHotEncoder(handle_unknown="ignore"), ["hudud", "tur"]),
])
pipe = Pipeline([("t", tayyor),
("m", RandomForestRegressor(random_state=0))])
setka = {
"m__n_estimators": [100, 300],
"m__max_depth": [6, 12, None],
"m__min_samples_leaf": [1, 5],
}
print("=== 1. Qidiruv hajmi ===")
print(f" kombinatsiyalar: {2 * 3 * 2} × 5 fold = {2 * 3 * 2 * 5} ta o'qitish")
gs = GridSearchCV(pipe, setka, cv=KFold(5, shuffle=True, random_state=0),
scoring="neg_mean_absolute_error", n_jobs=-1)
gs.fit(X_tr, y_tr)
print("\n=== 2. Eng yaxshi natija ===")
print(f" parametrlar: {gs.best_params_}")
print(f" CV MAE = {-gs.best_score_:.2f}")
print("\n=== 3. Eng yaxshi 3 kombinatsiya ===")
nat = pd.DataFrame(gs.cv_results_)
nat = nat.sort_values("rank_test_score").head(3)
for _, q in nat.iterrows():
print(f" MAE {-q['mean_test_score']:.2f} ± {q['std_test_score']:.2f}: "
f"depth={q['param_m__max_depth']}, leaf={q['param_m__min_samples_leaf']}, "
f"n={q['param_m__n_estimators']}")
print("\n=== 4. best_score_ — yakuniy natija emas ===")
print(" u CV bahosi va tanlov tufayli biroz optimistik 11.9-bob")
print(" ⭐ Yakuniy baho — test to'plamida (Misol 4)")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Qidiruv hajmi ===
kombinatsiyalar: 12 × 5 fold = 60 ta o'qitish
=== 2. Eng yaxshi natija ===
parametrlar: {'m__max_depth': 12, 'm__min_samples_leaf': 5, 'm__n_estimators': 300}
CV MAE = 9.85
=== 3. Eng yaxshi 3 kombinatsiya ===
MAE 9.85 ± 0.16: depth=12, leaf=5, n=300
MAE 9.85 ± 0.16: depth=12, leaf=5, n=100
MAE 9.85 ± 0.16: depth=None, leaf=5, n=100
=== 4. best_score_ — yakuniy natija emas ===
u CV bahosi va tanlov tufayli biroz optimistik 11.9-bob
⭐ Yakuniy baho — test to'plamida (Misol 4)Nima ko'rsatdi: 2.5-bo'lim.
Misol 4 — Yakuniy baho va xatolar tahlili
"""Test to'plamida bir martalik baho va xatolar tahlili (real pandas/sklearn)."""
import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.dummy import DummyRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.impute import SimpleImputer
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_absolute_error, r2_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
def yarat(seed: int = 7) -> pd.DataFrame:
rng = np.random.default_rng(seed)
n = 3000
hudud = rng.choice(["markaz", "shimol", "janub", "chekka"], n, p=[0.3, 0.25, 0.25, 0.2])
tur = rng.choice(["yangi", "ikkilamchi"], n, p=[0.35, 0.65])
maydon = rng.lognormal(np.log(65), 0.35, n).clip(25, 250)
xona = np.clip((maydon / 24).round(), 1, 7)
yosh = np.where(tur == "yangi", rng.integers(0, 4, n), rng.integers(4, 45, n))
hudud_koef = pd.Series(hudud).map({"markaz": 1.45, "shimol": 1.05,
"janub": 1.0, "chekka": 0.8}).to_numpy()
narx = (1.55 * maydon + 5 * xona - 0.6 * yosh) * hudud_koef + rng.normal(0, 11, n)
df = pd.DataFrame({"hudud": hudud, "tur": tur, "maydon": maydon.round(1),
"xona": xona, "yosh": yosh, "narx": narx.round(1)})
df.loc[rng.choice(n, 90, replace=False), "yosh"] = np.nan
return df
def tayyor() -> ColumnTransformer:
return ColumnTransformer([
("son", Pipeline([("imp", SimpleImputer(strategy="median")),
("sc", StandardScaler())]), ["maydon", "xona", "yosh"]),
("kat", OneHotEncoder(handle_unknown="ignore"), ["hudud", "tur"]),
])
def main() -> None:
df = yarat()
X, y = df.drop(columns=["narx"]), df["narx"]
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=0)
modellar = {
"baza": DummyRegressor(strategy="mean"),
"Ridge": Pipeline([("t", tayyor()), ("m", Ridge(alpha=1.0))]),
"o'rmon": Pipeline([("t", tayyor()),
("m", RandomForestRegressor(n_estimators=300, max_depth=12,
min_samples_leaf=1, random_state=0,
n_jobs=-1))]),
}
print("=== 1. Test natijalari (bir marta) ===")
bashoratlar = {}
for nom, m in modellar.items():
m.fit(X_tr, y_tr)
p = m.predict(X_te)
bashoratlar[nom] = p
print(f" {nom:<8}: MAE {mean_absolute_error(y_te, p):6.2f}, R^2 {r2_score(y_te, p):6.3f}")
print("\n=== 2. Xatolar tahlili (o'rmon) ===")
xato = np.abs(y_te.to_numpy() - bashoratlar["o'rmon"])
te = X_te.assign(xato=xato, haqiqiy=y_te.to_numpy())
print(f" xato: median {np.median(xato):.2f}, 90-persentil {np.percentile(xato, 90):.2f}, "
f"maks {xato.max():.2f}")
print("\n=== 3. Segmentlar bo'yicha o'rtacha xato ===")
print(f" hudud: {te.groupby('hudud')['xato'].mean().round(2).to_dict()}")
te["maydon_guruh"] = pd.cut(te["maydon"], [0, 50, 80, 120, 300],
labels=["<50", "50-80", "80-120", ">120"])
print(f" maydon: {te.groupby('maydon_guruh', observed=True)['xato'].mean().round(2).to_dict()}")
print("\n=== 4. Xulosa ===")
print(" eng katta xatolar — katta maydonli uylarda (kam ma'lumot, yuqori dispersiya)")
print(" keyingi qadam: shu segment uchun ko'proq ma'lumot yoki alohida model")
print(" ⭐ Xatolar tahlili — yaxshilash yo'nalishini beradi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Test natijalari (bir marta) ===
baza : MAE 44.14, R^2 -0.000
Ridge : MAE 11.95, R^2 0.926
o'rmon : MAE 9.66, R^2 0.953
=== 2. Xatolar tahlili (o'rmon) ===
xato: median 7.80, 90-persentil 19.41, maks 48.73
=== 3. Segmentlar bo'yicha o'rtacha xato ===
hudud: {'chekka': 9.63, 'janub': 9.1, 'markaz': 10.27, 'shimol': 9.57}
maydon: {'<50': 9.28, '50-80': 9.34, '80-120': 10.45, '>120': 11.42}
=== 4. Xulosa ===
eng katta xatolar — katta maydonli uylarda (kam ma'lumot, yuqori dispersiya)
keyingi qadam: shu segment uchun ko'proq ma'lumot yoki alohida model
⭐ Xatolar tahlili — yaxshilash yo'nalishini beradiNima ko'rsatdi: 2.6, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Tayyorlashni oldin, ajratishni keyin" | Avval ajratish (leakage) |
| "Scaler'ni butun X da fit qilsa bo'ladi" | Faqat o'quvda (pipeline) |
| "Baza model — vaqt isrofi" | Har natijaning o'lchovi |
| "best_score_ — yakuniy natija" | CV balli (optimistik) |
| "Eng murakkab model — eng yaxshi" | CV bilan tekshiring |
| "Model tayyor — ish tugadi" | Xatolar tahlili kerak |
| "SD muhim emas" | Farq SD dan kichik bo'lishi mumkin |
| "GridSearch har doim kerak" | Kichik setka yoki Randomized |
6. Keng tarqalgan xatolar va yechimlari
1. Pipeline'siz tayyorlash
X_scaled = StandardScaler().fit_transform(X) # butun ma'lumot # ⚠️
Pipeline([("sc", StandardScaler()), ("m", Ridge())]) # ✅2. Bazani o'tkazib yuborish
print("MAE:", mean_absolute_error(y_te, p)) # ⚠️
print("baza MAE:", mean_absolute_error(y_te, DummyRegressor()...)) # ✅3. Turli CV bo'linishlari
cross_val_score(m1, X, y, cv=5); cross_val_score(m2, X, y, cv=5) # ⚠️ (shuffle yo'q/har xil)
cv = KFold(5, shuffle=True, random_state=0) # bir marta yarating # ✅4. best_score_ ni hisobot qilish
print("model natijasi:", -gs.best_score_) # ⚠️
print("test natijasi:", mean_absolute_error(y_te, gs.predict(X_te))) # ✅5. One-hot da yangi kategoriya
OneHotEncoder() # testda yangi qiymat → xato # ⚠️
OneHotEncoder(handle_unknown="ignore") # ✅6. Xatolar tahlilisiz
print("R^2:", r2_score(y_te, p)) # ⚠️
# segmentlar bo'yicha xato, eng katta xatolar ro'yxati # ✅7. random_state yo'q
RandomForestRegressor(n_estimators=300) # ⚠️
RandomForestRegressor(n_estimators=300, random_state=0) # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 12.1-12.5-darslar (o'tilgan): Vazifa, ajratish, overfitting
- 6-qism (o'tilgan): Tozalash, kodlash, masshtablash
- 12.7-12.8-darslar: Metrikalar
- 12.9-dars: Pipeline va leakage chuqurroq
- 12.10-dars: To'liq loyiha
8. Eng yaxshi amaliyotlar
Test to'plamini birinchi qadamda ajrating.
Barcha tayyorlashni pipeline ichida qiling.
Bazadan boshlang.
Bir xil CV bo'linishida solishtiring.
Natijani ± SD bilan bering.
Sozlashni faqat o'quvda qiling.
Testda bir marta baholang.
Xatolar tahlilini o'tkazing.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # oqimning birinchi qadami?
2. # test qachon ajratiladi?
3. # EDA qayerda qilinadi?
4. # pipeline nima uchun?
5. # baza model nima?
6. # modellarni qanday solishtirish kerak?
7. # GridSearchCV nima qiladi?
8. # best_score_ nima?
9. # yakuniy baho qayerda?
10. # xatolar tahlili nima beradi?
11. # handle_unknown nima uchun?
12. # ColumnTransformer nima uchun?Javoblar
- Ma'lumotni yuklash va tekshirish
- Darhol (2-qadam)
- Faqat o'quv ma'lumotida
- Leakage himoyasi va takrorlanuvchanlik
- Oddiy qoida/o'rtacha
- Bir xil CV, bir xil metrika, SD bilan
- Giperparametr kombinatsiyalarini CV bilan sinaydi
- Eng yaxshi CV balli
- Test to'plamida (bir marta)
- Yaxshilash yo'nalishini
- Testdagi yangi kategoriyalar uchun
- Turli ustun turlariga turli tayyorlash
Vazifa 2: Xatolarni tuzating
1. X_s = StandardScaler().fit_transform(X); train_test_split(X_s, y)
2. print("natija:", -gs.best_score_) # yakuniy hisobot
3. cross_val_score(m1, X, y, cv=5); cross_val_score(m2, X, y, cv=KFold(5, shuffle=True))
4. print("MAE:", mae) # bazasiz
5. OneHotEncoder().fit(X_tr[["hudud"]]) # testda yangi hudud borJavoblar
1. pipe = Pipeline([("sc", StandardScaler()), ("m", model)]); pipe.fit(X_tr, y_tr)
2. print("test:", mean_absolute_error(y_te, gs.predict(X_te)))
3. cv = KFold(5, shuffle=True, random_state=0) # ikkalasiga bir xil
4. print("baza MAE:", ...); print("model MAE:", mae)
5. OneHotEncoder(handle_unknown="ignore")Vazifa 3: To'liq oqim
Modellang:
- O'z ma'lumotingiz (yoki sklearn dataset)
- 8 qadam
- Har qadamda natija
- Yakuniy hisobot
Vazifa 4: Modellar jadvali
Modellang:
- 5 nomzod model
- Bir xil CV
- MAE ± SD jadvali
- Tanlov asosi
Vazifa 5: Sozlash
Modellang:
- GridSearchCV (kichik setka)
- RandomizedSearchCV (katta setka)
- Vaqt va natija solishtiruvi
- Tavsiya
Vazifa 6: Integratsiya
Modellang:
- Tozalash (6-qism)
- CV (12.3)
- Overfitting tashxisi (12.4)
- Xatolar tahlili
Vazifa 7: O'ylash
Ko'p boshlovchi Data Scientistlar modelni tanlashga va giperparametrlarni sozlashga ko'p vaqt sarflaydi, lekin natija kam yaxshilanadi. Tajribali mutaxassislar esa ko'proq vaqtni ma'lumot va belgilarga sarflaydi. Nima uchun bu farq bor va vaqtni qanday taqsimlash kerak?
Javob
Qisqa javob: model tanlash odatda bir necha foiz yaxshilanish beradi, ma'lumot sifati va belgilar esa o'nlab foiz. Bundan tashqari, model almashtirish oson va "qiziqarli", ma'lumot bilan ishlash esa mashaqqatli — shuning uchun boshlovchilar oson yo'ldan boradi.
1. Odatiy hissa (jadval ma'lumoti)
| Manba | Taxminiy ta'sir |
|---|---|
| Vazifani to'g'ri qo'yish (12.2) | Juda katta (noto'g'ri bo'lsa — hammasi behuda) |
| Ma'lumot sifati va hajmi | Katta |
| Belgi muhandisligi | Katta |
| Model turi | O'rtacha |
| Giperparametr sozlash | Kichik-o'rtacha |
2. Nega shunday
- Zamonaviy modellar (boosting) standart parametrlar bilan ham kuchli
- Ma'lumotdagi xato yoki leakage hech qanday model bilan tuzatilmaydi
- Yangi belgi modelga yangi ma'lumot beradi, sozlash esa faqat mavjudini optimallashtiradi
3. Vaqtni taqsimlash tavsiyasi
- Vazifa va metrikani aniqlash — 15%
- Ma'lumot tekshiruvi, tozalash, leakage ovi — 30%
- Belgi muhandisligi — 25%
- Model tanlash — 15%
- Sozlash va yakuniy baho — 15%
4. Data Scientist qanday
- Oddiy model + yaxshi belgilar bilan boshlaydi
- Xatolar tahlilidan yangi belgi g'oyalarini oladi
- Sozlashni oxirida, cheklangan byudjet bilan qiladi
5. Xulosa
- Model tanlash — eng kichik hissa
- Ma'lumot va belgilar — eng katta hissa
- Xatolar tahlili — yaxshilash kompasi
- Sozlash — oxirgi, kichik qadam
Nimani mustahkamlaydi: 2.3, 2.6-bo'limlar.
Xulosa
Bu darsda to'liq ML oqimini qurdik.
Eng muhim uch fikr:
Sakkiz qadam. Ma'lumot → test ajratish (darhol) → EDA (faqat o'quvda) → pipeline bilan tayyorlash → baza → nomzodlarni CV bilan solishtirish → sozlash → test'da bir marta baho va xatolar tahlili.
Pipeline.
ColumnTransformer+Pipelinebarcha tayyorlash qadamlarini modelga bog'laydi:fitfaqat o'quv qismida bajariladi (CV da ham har bo'lakda alohida) — bu leakage'dan himoya 12.9-bob va takrorlanuvchanlikni ta'minlaydi; giperparametrlar butun oqim bo'ylab sozlanadi (m__alpha).Halol taqqoslash va tahlil. Modellar bir xil CV bo'linishida, bir xil metrikada, ± SD bilan solishtiriladi;
best_score_— CV balli, yakuniy natija emas. Yakuniy hisobot: baza, CV natijalari, test natijasi, xatolar tahlili (qaysi segmentlarda xato katta) va cheklovlar.
Keyingi darsda klassifikatsiya metrikalarini o'rganamiz: aniqlik nega aldaydi, precision/recall/F1, ROC va PR egri chiziqlari, chegarani tanlash va nomutanosib sinflar.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!