Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. FunctionTransformer
- 2.2. TransformedTargetRegressor
- 2.3. FeatureUnion
- 2.4. Ustun tanlash quvur ichida
- 2.5. Qaysi vositani qachon
- 2.6. Kompozitsiyani sozlash
- 2.7. Tuzoqlar
- 2.8. To'rt g'isht
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — FunctionTransformer
- Misol 2 — TransformedTargetRegressor
- Misol 3 — FeatureUnion
- Misol 4 — Uchtasini birga va sozlash
- 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
19.5-dars: Kompozitsiya vositalari
19-QISM — SCIKIT-LEARN TO'LIQ · 5-dars
1. Kirish va motivatsiya
Pipeline qadamlarni ketma-ket ulaydi, ColumnTransformer — ustunlar bo'yicha parallel. Lekin haqiqiy loyihalarda boshqa naqshlar ham kerak bo'ladi:
- bir xil ustunlardan bir necha xil belgi to'plamini yasash va ularni birlashtirish;
- juda sodda, holatsiz o'zgartirishni (
log,sqrt, bayroq) sinf yozmasdan quvurga qo'shish; - maqsad o'zgaruvchini o'zgartirish (
log(y)bilan o'rgatib, bashoratni asl shkalaga qaytarish); - ustunlarni nom bilan tanlab olishni quvur ichida bajarish.
scikit-learn da bularning har biri uchun tayyor vosita bor: FeatureUnion, FunctionTransformer, TransformedTargetRegressor. Ular kichik, lekin ularni bilmaslik odamlarni quvurdan tashqarida kod yozishga majbur qiladi — va leakage qaytib keladi.
Bu darsda: FunctionTransformer (holatsiz o'zgartirish), FeatureUnion (parallel belgilar), TransformedTargetRegressor (maqsadni o'zgartirish), ularni birga ishlatish va qachon qaysi birini tanlash.
Real vaziyat. Uy narxini bashorat qilishda RMSE juda yuqori chiqardi: narxlar o'ng tomonga cho'zilgan, model qimmat uylarga moslashib, arzonlarida xato qilardi. TransformedTargetRegressor(func=np.log1p, inverse_func=np.expm1) qo'shilgach MAPE ikki barobar yaxshilandi — model kodining boshqa hech bir qatori o'zgarmadi.
Bu darsda kompozitsiya vositalarini o'rganamiz.
Bu darsda:
- FunctionTransformer
- TransformedTargetRegressor
- FeatureUnion
- Ustun tanlash quvur ichida
- Qaysi vositani qachon
- Kompozitsiyani sozlash
- Tuzoqlar
- Amaliy: uchtasini birga
ℹ Misollar real numpy/pandas/sklearn bilan (Python 3.14, sklearn 1.9).
2. Nazariya — chuqur tushuntirish
2.1. FunctionTransformer
from sklearn.preprocessing import FunctionTransformer
log_t = FunctionTransformer(
func=np.log1p,
inverse_func=np.expm1, # inverse_transform uchun
feature_names_out="one-to-one", # nomlar o'zgarmaydi
validate=False, # DataFrame ni o'tkazadi
kw_args={"out": None}, # func ga qo'shimcha argument
)
QACHON:
fit da HECH NARSA o'rganilmasa
o'zgartirish sodda va parametrsiz bo'lsa
feature_names_out:
"one-to-one" -> kirish nomlari saqlanadi
funksiya -> lambda self, nomlar: [...]
None (sukut) -> get_feature_names_out ISHLAMAYDI
DIQQAT: func lambda bo'lsa model PICKLE QILINMAYDI
modul darajasidagi funksiya yozing func sifatida lambda yozmang — model joblib bilan saqlanmay qoladi (19.6-dars).
2.2. TransformedTargetRegressor
from sklearn.compose import TransformedTargetRegressor
ttr = TransformedTargetRegressor(
regressor=Ridge(),
func=np.log1p, inverse_func=np.expm1)
# yoki
ttr = TransformedTargetRegressor(regressor=Ridge(),
transformer=QuantileTransformer(...))
ISHLASHI:
fit: y' = func(y) -> regressor.fit(X, y')
predict: y' = regressor.predict(X) -> inverse_func(y')
NIMA UCHUN QUVUR ICHIDA:
y ni QO'LDA log qilsangiz, CV metrikasi log shkalada bo'ladi
va MAE/RMSE ASL birlikda emas -> taqqoslab bo'lmaydi
TTR esa bashoratni AVTOMATIK qaytaradi
DIQQAT: func va inverse_func bir-birining teskarisi bo'lishi SHART
(check_inverse=True sukut bo'yicha buni tekshiradi) y ni qo'lda o'zgartirmang: TransformedTargetRegressor bashoratni asl shkalaga qaytaradi va metrikalar taqqoslanadigan bo'lib qoladi.
2.3. FeatureUnion
from sklearn.pipeline import FeatureUnion
fu = FeatureUnion([
("xom", "passthrough"),
("pca", PCA(n_components=5)),
("tanlov", SelectKBest(k=10)),
], transformer_weights={"pca": 0.5})
ISHLASHI:
har transformer AYNI kirishni oladi
natijalar GORIZONTAL birlashtiriladi
ColumnTransformer BILAN FARQI:
ColumnTransformer - TURLI ustunlarga turli transformer
FeatureUnion - AYNI ustunlarga turli transformer
QACHON:
bir xil ma'lumotdan bir necha ko'rinish kerak bo'lsa
(xom + PCA, TF-IDF + matn statistikasi) ColumnTransformer ustunlarni bo'ladi, FeatureUnion esa ko'paytiradi — ikkalasi bir-birini almashtirmaydi.
2.4. Ustun tanlash quvur ichida
# a) ColumnTransformer bilan (eng keng tarqalgan)
ColumnTransformer([("tanlangan", StandardScaler(), ["a", "b"])])
# b) FunctionTransformer bilan
def ustun_tanla(df):
return df[["a", "b"]]
tanlagich = FunctionTransformer(ustun_tanla, validate=False)
# c) ColumnTransformer + passthrough (ustunni o'zgartirmasdan olish)
ColumnTransformer([("olingan", "passthrough", ["a", "b"])])
TAVSIYA: ColumnTransformer - u nomlarni ham to'g'ri hosil qiladi Ustun tanlash uchun ColumnTransformer afzal: u get_feature_names_out ni ham to'g'ri qo'llab-quvvatlaydi.
2.5. Qaysi vositani qachon
Turli USTUNLARGA turli ishlov -> ColumnTransformer
Bir xil ustunlardan KO'P ko'rinish -> FeatureUnion
Ketma-ket bosqichlar -> Pipeline
Holatsiz sodda o'zgartirish -> FunctionTransformer
MAQSAD o'zgaruvchini o'zgartirish -> TransformedTargetRegressor
Holatli murakkab mantiq -> o'z transformeringiz 19.4-bob
ODATIY TUZILMA:
TransformedTargetRegressor(
regressor=Pipeline([
("tayyor", ColumnTransformer([...])),
("model", ...)]),
func=..., inverse_func=...) TransformedTargetRegressor eng tashqarida bo'ladi: u butun quvurni o'rab oladi.
2.6. Kompozitsiyani sozlash
Parametr yo'llari ichma-ich nomlardan yig'iladi:
ttr__regressor__tayyor__son__sc__with_mean
| | | | | |
| | | | | parametr
| | | | qadam (Pipeline)
| | | transformer (ColumnTransformer)
| | qadam (Pipeline)
| TTR ning regressor argumenti
tashqi qadam nomi
TEKSHIRISH: sorted(model.get_params(deep=True)) ni chop eting
va kerakli yo'lni ko'chiring - qo'lda yozmang Parametr yo'lini qo'lda yozmang: get_params(deep=True) dan ko'chiring, aks holda xato param_grid jim ishlamaydi.
2.7. Tuzoqlar
Asosiy tuzoqlar: FunctionTransformer da lambda; feature_names_out ni qo'ymaslik; y ni qo'lda log qilish; func va inverse_func mos kelmasligi; FeatureUnion va ColumnTransformer ni chalkashtirish; FeatureUnion da ustunlar ikki marta chiqishi; parametr yo'lini qo'lda yozish; TransformedTargetRegressor ni klassifikatsiyada ishlatishga urinish.
2.8. To'rt g'isht
Kompozitsiyaning to'rt g'ishti bor: Pipeline (ketma-ket), ColumnTransformer (ustunlar bo'yicha), FeatureUnion (ayni kirishdan ko'p ko'rinish) va TransformedTargetRegressor (maqsadni o'zgartirish). FunctionTransformer esa ularning orasidagi yopishtiruvchi. Bu to'rttasi bilan deyarli har qanday tayyorlash mantiqini quvur ichida ifodalash mumkin — va shuning uchun leakage dan himoyalangan holda.
3. Tez ma'lumotnoma
import numpy as np
from sklearn.compose import ColumnTransformer, TransformedTargetRegressor
from sklearn.pipeline import FeatureUnion, Pipeline
from sklearn.preprocessing import FunctionTransformer, StandardScaler
def log_ozgartir(X): # lambda EMAS - pickle uchun
return np.log1p(np.abs(X))
log_t = FunctionTransformer(log_ozgartir, feature_names_out="one-to-one")
fu = FeatureUnion([("xom", "passthrough"), ("log", log_t)])
model = TransformedTargetRegressor(
regressor=Pipeline([("tayyor", ColumnTransformer([...])),
("m", Ridge())]),
func=np.log1p, inverse_func=np.expm1)
sorted(model.get_params(deep=True)) # parametr yo'llarini ko'chiring
QOIDA: lambda yozma · feature_names_out qo'y · y ni qo'lda o'zgartirma ·
yo'llarni get_params dan olKompozitsiya xulosasi
Pipeline: ketma-ket
ColumnTransformer: ustunlar bo'yicha
FeatureUnion: ayni kirishdan ko'p ko'rinish
FunctionTransformer: holatsiz o'zgartirish
TransformedTargetRegressor: maqsadni o'zgartirish (eng tashqarida)4. Batafsil misollar
Misollar real numpy/pandas/sklearn bilan (Python 3.14).
Misol 1 — FunctionTransformer
"""Holatsiz o'zgartirishlar quvur ichida (real numpy/pandas/sklearn)."""
import io
import pickle
import numpy as np
import pandas as pd
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import FunctionTransformer, StandardScaler
def log_absolyut(X):
"""Modul darajasidagi funksiya - pickle qilinadi."""
return np.log1p(np.abs(np.asarray(X, dtype=float)))
def nomlarni_yasa(transformer, input_features):
return np.asarray([f"log_{n}" for n in input_features], dtype=object)
def main() -> None:
rng = np.random.default_rng(0)
df = pd.DataFrame({
"summa": rng.lognormal(10, 1.2, 300),
"masofa": rng.gamma(2, 100, 300),
})
print("=== 1. Oddiy ishlatish ===")
t = FunctionTransformer(log_absolyut, inverse_func=np.expm1,
feature_names_out="one-to-one")
chiqish = t.fit_transform(df)
print(f" kirish min/max: {df['summa'].min():.1f} / "
f"{df['summa'].max():.1f}")
print(f" chiqish min/max: {chiqish[:, 0].min():.3f} / "
f"{chiqish[:, 0].max():.3f}")
print(f" nomlar: {t.get_feature_names_out().tolist()}")
print("\n=== 2. inverse_transform ===")
qaytgan = t.inverse_transform(chiqish)
print(f" asl birinchi qiymat: {df['summa'].iloc[0]:.4f}")
print(f" qaytgan birinchi qiymat: {qaytgan[0, 0]:.4f}")
print(f" maksimal farq: "
f"{np.abs(qaytgan - df.to_numpy()).max():.2e}")
print("\n=== 3. feature_names_out variantlari ===")
variantlar = {
"one-to-one": FunctionTransformer(log_absolyut,
feature_names_out="one-to-one"),
"funksiya": FunctionTransformer(log_absolyut,
feature_names_out=nomlarni_yasa),
}
for nom, tr in variantlar.items():
tr.fit(df)
print(f" {nom:<12} -> {tr.get_feature_names_out().tolist()}")
yoq = FunctionTransformer(log_absolyut).fit(df)
try:
yoq.get_feature_names_out()
print(" None -> ishladi (kutilmagan)")
except Exception as xato:
print(f" None -> {type(xato).__name__}: "
f"{str(xato).splitlines()[0][:50]}")
print("\n=== 4. lambda va pickle ===")
modul_bilan = Pipeline([("log", FunctionTransformer(
log_absolyut, feature_names_out="one-to-one")),
("sc", StandardScaler())]).fit(df)
buf = io.BytesIO()
pickle.dump(modul_bilan, buf)
print(f" modul funksiyasi bilan: saqlandi ({buf.tell()} bayt)")
lambda_bilan = Pipeline([
("log", FunctionTransformer(lambda X: np.log1p(np.abs(X)))),
("sc", StandardScaler())]).fit(df)
try:
pickle.dump(lambda_bilan, io.BytesIO())
print(" lambda bilan: saqlandi (kutilmagan)")
except Exception as xato:
print(f" lambda bilan: {type(xato).__name__}: "
f"{str(xato).splitlines()[0][:52]}")
print(" ⭐ FunctionTransformer ga modul darajasidagi funksiya bering")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Oddiy ishlatish ===
kirish min/max: 529.7 / 872610.1
chiqish min/max: 6.274 / 13.679
nomlar: ['summa', 'masofa']
=== 2. inverse_transform ===
asl birinchi qiymat: 25613.5366
qaytgan birinchi qiymat: 25613.5366
maksimal farq: 6.98e-10
=== 3. feature_names_out variantlari ===
one-to-one -> ['summa', 'masofa']
funksiya -> ['log_summa', 'log_masofa']
None -> AttributeError: This 'FunctionTransformer' has no attribute 'get_f
=== 4. lambda va pickle ===
modul funksiyasi bilan: saqlandi (944 bayt)
lambda bilan: PicklingError: Can't pickle local object <function main.<locals>.<l
⭐ FunctionTransformer ga modul darajasidagi funksiya beringNima ko'rsatdi: 2.1-bo'lim.
Misol 2 — TransformedTargetRegressor
"""Cho'zilgan maqsadni o'zgartirish (real numpy/sklearn)."""
import numpy as np
from sklearn.compose import TransformedTargetRegressor
from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.linear_model import Ridge
from sklearn.metrics import (mean_absolute_error,
mean_absolute_percentage_error,
r2_score)
from sklearn.model_selection import KFold, cross_val_score, train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
def yarat(n: int = 3000, seed: int = 0):
"""Narx: log-normal taqsimot, chiziqli bog'liqlik log shkalada."""
rng = np.random.default_rng(seed)
X = rng.normal(0, 1, (n, 6))
log_narx = (11.0 + 0.6 * X[:, 0] + 0.4 * X[:, 1] - 0.3 * X[:, 2]
+ rng.normal(0, 0.35, n))
y = np.exp(log_narx)
return X, y
def main() -> None:
X, y = yarat()
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3,
random_state=0)
print("=== 1. Maqsad taqsimoti ===")
print(f" min: {y.min():,.0f}, median: {np.median(y):,.0f}, "
f"max: {y.max():,.0f}")
print(f" o'rtacha / median: {y.mean() / np.median(y):.2f}")
print(f" log(y) assimetriyasi ancha kichik: "
f"{float(np.abs(np.log(y).mean() - np.median(np.log(y)))):.4f}")
print("\n=== 2. Uch variant ===")
asos = make_pipeline(StandardScaler(), Ridge(alpha=1.0))
ttr = TransformedTargetRegressor(
regressor=make_pipeline(StandardScaler(), Ridge(alpha=1.0)),
func=np.log, inverse_func=np.exp)
boost = HistGradientBoostingRegressor(max_iter=200,
early_stopping=False,
random_state=0)
ttr_boost = TransformedTargetRegressor(
regressor=HistGradientBoostingRegressor(max_iter=200,
early_stopping=False,
random_state=0),
func=np.log, inverse_func=np.exp)
modellar = {"Ridge (xom y)": asos, "Ridge + log(y)": ttr,
"Boosting (xom y)": boost, "Boosting + log(y)": ttr_boost}
print(f" {'model':<22} {'MAE':>12} {'MAPE':>9} {'R2':>8}")
for nom, m in modellar.items():
m.fit(Xtr, ytr)
p = m.predict(Xte)
print(f" {nom:<22} {mean_absolute_error(yte, p):>12,.0f} "
f"{mean_absolute_percentage_error(yte, p):>9.4f} "
f"{r2_score(yte, p):>8.4f}")
print("\n=== 3. Bashoratlar asl shkalada ===")
m = modellar["Ridge + log(y)"]
p = m.predict(Xte[:5])
print(f" haqiqiy: {np.round(yte[:5], 0).tolist()}")
print(f" bashorat: {np.round(p, 0).tolist()}")
print(" TTR bashoratni AVTOMATIK asl birlikka qaytardi")
print("\n=== 4. Qo'lda log qilish nima uchun yomon ===")
cv = KFold(5, shuffle=True, random_state=0)
qolda = make_pipeline(StandardScaler(), Ridge(alpha=1.0))
log_ball = -cross_val_score(qolda, X, np.log(y), cv=cv,
scoring="neg_mean_absolute_error").mean()
ttr_ball = -cross_val_score(
TransformedTargetRegressor(
regressor=make_pipeline(StandardScaler(), Ridge(alpha=1.0)),
func=np.log, inverse_func=np.exp),
X, y, cv=cv, scoring="neg_mean_absolute_error").mean()
print(f" qo'lda log(y) bilan CV MAE: {log_ball:.4f} (LOG birlikda)")
print(f" TTR bilan CV MAE: {ttr_ball:,.0f} (ASL birlikda)")
print(" birinchisini boshqa modellar bilan taqqoslab bo'lmaydi")
print(" ⭐ y ni qo'lda o'zgartirsangiz metrikalar taqqoslanmaydi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Maqsad taqsimoti ===
min: 2,643, median: 62,289, max: 1,053,234
o'rtacha / median: 1.38
log(y) assimetriyasi ancha kichik: 0.0161
=== 2. Uch variant ===
model MAE MAPE R2
Ridge (xom y) 32,645 0.6577 0.6008
Ridge + log(y) 22,838 0.2798 0.7727
Boosting (xom y) 26,421 0.3368 0.7190
Boosting + log(y) 25,320 0.3101 0.7165
=== 3. Bashoratlar asl shkalada ===
haqiqiy: [302588.0, 39955.0, 132663.0, 32777.0, 278549.0]
bashorat: [125609.0, 56462.0, 104079.0, 22226.0, 245479.0]
TTR bashoratni AVTOMATIK asl birlikka qaytardi
=== 4. Qo'lda log qilish nima uchun yomon ===
qo'lda log(y) bilan CV MAE: 0.2750 (LOG birlikda)
TTR bilan CV MAE: 23,084 (ASL birlikda)
birinchisini boshqa modellar bilan taqqoslab bo'lmaydi
⭐ y ni qo'lda o'zgartirsangiz metrikalar taqqoslanmaydiNima ko'rsatdi: 2.2-bo'lim.
Misol 3 — FeatureUnion
"""Ayni kirishdan bir necha ko'rinish (real numpy/sklearn)."""
import numpy as np
from sklearn.datasets import make_classification
from sklearn.decomposition import PCA
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.pipeline import FeatureUnion, Pipeline
from sklearn.preprocessing import StandardScaler
def main() -> None:
X, y = make_classification(n_samples=1500, n_features=30,
n_informative=8, n_redundant=12,
flip_y=0.15, class_sep=0.85, random_state=0)
cv = StratifiedKFold(4, shuffle=True, random_state=0)
print("=== 1. FeatureUnion tuzilishi ===")
birlashma = FeatureUnion([
("xom", "passthrough"),
("pca", PCA(n_components=6, random_state=0)),
("tanlov", SelectKBest(f_classif, k=8)),
])
quvur = Pipeline([("sc", StandardScaler()),
("fu", birlashma),
("m", LogisticRegression(max_iter=3000))])
quvur.fit(X, y)
print(f" kirish ustunlari: {X.shape[1]}")
print(f" FeatureUnion chiqishi: "
f"{quvur[:-1].transform(X).shape[1]}")
print(f" hisob: 30 (xom) + 6 (pca) + 8 (tanlov) = 44")
print("\n=== 2. Har tarmoqning hissasi ===")
tarmoqlar = {
"faqat xom": FeatureUnion([("xom", "passthrough")]),
"faqat pca": FeatureUnion([("pca", PCA(n_components=6,
random_state=0))]),
"faqat tanlov": FeatureUnion([("tanlov",
SelectKBest(f_classif, k=8))]),
"xom + pca": FeatureUnion([("xom", "passthrough"),
("pca", PCA(n_components=6,
random_state=0))]),
"uchalasi": birlashma,
}
print(f" {'tarmoqlar':<16} {'ustunlar':>9} {'CV AUC':>9}")
for nom, fu in tarmoqlar.items():
q = Pipeline([("sc", StandardScaler()), ("fu", fu),
("m", LogisticRegression(max_iter=3000))])
ustunlar = q[:-1].fit(X, y).transform(X).shape[1]
b = cross_val_score(q, X, y, cv=cv, scoring="roc_auc")
print(f" {nom:<16} {ustunlar:>9} {b.mean():>9.4f}")
print("\n=== 3. Chiqish nomlari ===")
nomlar = quvur[:-1].get_feature_names_out()
print(f" jami {len(nomlar)} ta")
print(f" birinchi 3: {nomlar[:3].tolist()}")
print(f" pca qismi: "
f"{[n for n in nomlar if n.startswith('pca')][:3]}")
print(f" tanlov qismi: "
f"{[n for n in nomlar if n.startswith('tanlov')][:3]}")
print("\n=== 4. ColumnTransformer bilan farqi ===")
from sklearn.compose import ColumnTransformer
ct = ColumnTransformer([
("birinchi_yarim", PCA(n_components=4, random_state=0),
list(range(15))),
("ikkinchi_yarim", StandardScaler(), list(range(15, 30)))])
print(f" ColumnTransformer: ustunlarni BO'LADI")
print(f" kirish 30 -> chiqish {ct.fit_transform(X).shape[1]} "
f"(4 + 15)")
print(f" FeatureUnion: ustunlarni KO'PAYTIRADI")
print(f" kirish 30 -> chiqish "
f"{birlashma.fit(StandardScaler().fit_transform(X), y).transform(StandardScaler().fit_transform(X)).shape[1]}")
print(" ⭐ ColumnTransformer bo'ladi, FeatureUnion ko'paytiradi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. FeatureUnion tuzilishi ===
kirish ustunlari: 30
FeatureUnion chiqishi: 44
hisob: 30 (xom) + 6 (pca) + 8 (tanlov) = 44
=== 2. Har tarmoqning hissasi ===
tarmoqlar ustunlar CV AUC
faqat xom 30 0.8726
faqat pca 6 0.8293
faqat tanlov 8 0.8738
xom + pca 36 0.8726
uchalasi 44 0.8726
=== 3. Chiqish nomlari ===
jami 44 ta
birinchi 3: ['xom__x0', 'xom__x1', 'xom__x2']
pca qismi: ['pca__pca0', 'pca__pca1', 'pca__pca2']
tanlov qismi: ['tanlov__x1', 'tanlov__x2', 'tanlov__x6']
=== 4. ColumnTransformer bilan farqi ===
ColumnTransformer: ustunlarni BO'LADI
kirish 30 -> chiqish 19 (4 + 15)
FeatureUnion: ustunlarni KO'PAYTIRADI
kirish 30 -> chiqish 44
⭐ ColumnTransformer bo'ladi, FeatureUnion ko'paytiradiNima ko'rsatdi: 2.3-bo'lim.
Misol 4 — Uchtasini birga va sozlash
"""To'liq kompozitsiya va parametr yo'llari (real numpy/pandas/sklearn)."""
import numpy as np
import pandas as pd
from sklearn.compose import (ColumnTransformer, TransformedTargetRegressor,
make_column_selector)
from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.impute import SimpleImputer
from sklearn.metrics import mean_absolute_error
from sklearn.model_selection import (GridSearchCV, KFold, train_test_split)
from sklearn.pipeline import FeatureUnion, Pipeline
from sklearn.preprocessing import (FunctionTransformer, OneHotEncoder,
StandardScaler)
def log_absolyut(X):
return np.log1p(np.abs(np.asarray(X, dtype=float)))
def yarat(n: int = 2500, seed: int = 0):
rng = np.random.default_rng(seed)
df = pd.DataFrame({
"maydon": rng.gamma(4, 25, n),
"yosh": rng.integers(0, 60, n).astype(float),
"xonalar": rng.integers(1, 7, n).astype(float),
"tuman": rng.choice(["markaz", "shimol", "janub", "chekka"], n),
})
tuman_qiymat = {"markaz": 0.55, "shimol": 0.2, "janub": 0.1,
"chekka": -0.3}
log_narx = (10.2 + 0.012 * df["maydon"] - 0.008 * df["yosh"]
+ 0.08 * df["xonalar"]
+ df["tuman"].map(tuman_qiymat)
+ rng.normal(0, 0.3, n))
return df, np.exp(log_narx)
def main() -> None:
df, y = yarat()
Xtr, Xte, ytr, yte = train_test_split(df, y, test_size=0.3,
random_state=0)
print("=== 1. Tuzilma ===")
son_quvur = Pipeline([
("imp", SimpleImputer(strategy="median")),
("ko_rinishlar", FeatureUnion([
("xom", "passthrough"),
("log", FunctionTransformer(log_absolyut,
feature_names_out="one-to-one")),
])),
("sc", StandardScaler()),
])
tayyor = ColumnTransformer([
("son", son_quvur, make_column_selector(dtype_include=np.number)),
("kat", OneHotEncoder(handle_unknown="ignore", sparse_output=False),
make_column_selector(dtype_include="str")),
])
model = TransformedTargetRegressor(
regressor=Pipeline([
("tayyor", tayyor),
("m", HistGradientBoostingRegressor(max_iter=200,
early_stopping=False,
random_state=0)),
]),
func=np.log, inverse_func=np.exp)
model.fit(Xtr, ytr)
print(" TransformedTargetRegressor")
print(" +- Pipeline")
print(" +- ColumnTransformer")
print(" | +- son: Pipeline(imp -> FeatureUnion(xom, log) -> sc)")
print(" | +- kat: OneHotEncoder")
print(" +- HistGradientBoostingRegressor")
print("\n=== 2. Belgilar ===")
ichki = model.regressor_
nomlar = ichki[:-1].get_feature_names_out()
print(f" jami belgilar: {len(nomlar)}")
for i in range(0, min(len(nomlar), 12), 4):
print(f" {nomlar[i:i + 4].tolist()}")
print("\n=== 3. Parametr yo'llari ===")
yollar = [k for k in sorted(model.get_params(deep=True))
if k.count("__") >= 3][:6]
for yol in yollar:
print(f" {yol}")
print(f" jami parametr: {len(model.get_params(deep=True))}")
print("\n=== 4. Sozlash ===")
setka = {
"regressor__m__max_leaf_nodes": [8, 31],
"regressor__tayyor__son__ko_rinishlar__log": [
"drop", FunctionTransformer(log_absolyut,
feature_names_out="one-to-one")],
}
g = GridSearchCV(model, setka, cv=KFold(4, shuffle=True, random_state=0),
scoring="neg_mean_absolute_error", n_jobs=1)
g.fit(Xtr, ytr)
print(f" {'barglar':>9} {'log tarmog_i':>14} {'CV MAE':>12}")
for par, ball in zip(g.cv_results_["params"],
g.cv_results_["mean_test_score"]):
log_bor = par["regressor__tayyor__son__ko_rinishlar__log"] != "drop"
print(f" {par['regressor__m__max_leaf_nodes']:>9} "
f"{str(log_bor):>14} {-ball:>12,.0f}")
print(f" eng yaxshi CV MAE: {-g.best_score_:,.0f}")
print("\n=== 5. Test ===")
p = g.best_estimator_.predict(Xte)
print(f" test MAE: {mean_absolute_error(yte, p):,.0f}")
print(f" haqiqiy: {np.round(yte[:4], 0).tolist()}")
print(f" bashorat: {np.round(p[:4], 0).tolist()}")
print(" ⭐ To'rt g'isht bilan butun mantiq quvur ichida")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Tuzilma ===
TransformedTargetRegressor
+- Pipeline
+- ColumnTransformer
| +- son: Pipeline(imp -> FeatureUnion(xom, log) -> sc)
| +- kat: OneHotEncoder
+- HistGradientBoostingRegressor
=== 2. Belgilar ===
jami belgilar: 10
['son__xom__maydon', 'son__xom__yosh', 'son__xom__xonalar', 'son__log__maydon']
['son__log__yosh', 'son__log__xonalar', 'kat__tuman_chekka', 'kat__tuman_janub']
['kat__tuman_markaz', 'kat__tuman_shimol']
=== 3. Parametr yo'llari ===
regressor__tayyor__kat__categories
regressor__tayyor__kat__drop
regressor__tayyor__kat__dtype
regressor__tayyor__kat__feature_name_combiner
regressor__tayyor__kat__handle_unknown
regressor__tayyor__kat__max_categories
jami parametr: 80
=== 4. Sozlash ===
barglar log tarmog_i CV MAE
8 False 36,909
8 True 36,909
31 False 38,910
31 True 38,910
eng yaxshi CV MAE: 36,909
=== 5. Test ===
test MAE: 40,209
haqiqiy: [50874.0, 336447.0, 28654.0, 78837.0]
bashorat: [35906.0, 375558.0, 77185.0, 113379.0]
⭐ To'rt g'isht bilan butun mantiq quvur ichidaNima ko'rsatdi: 2.5, 2.6-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"FeatureUnion va ColumnTransformer bir xil" |
Biri ko'paytiradi, biri bo'ladi |
"lambda qulay" |
Model pickle qilinmaydi |
"y ni qo'lda log qilsa bo'ladi" |
Metrikalar taqqoslanmaydi |
"feature_names_out ixtiyoriy" |
Usiz nomlar ishlamaydi |
"TransformedTargetRegressor klassifikatsiyada ham" |
Faqat regressiya |
| "Parametr yo'lini yozish oson" | get_params dan ko'chiring |
"FunctionTransformer ga fit kerak emas" |
fit chaqiriladi (bo'sh) |
"inverse_func ixtiyoriy" |
inverse_transform uchun shart |
6. Keng tarqalgan xatolar va yechimlari
1. lambda ishlatish
FunctionTransformer(lambda X: np.log1p(X)) # pickle xato # ⚠️
def log_t(X): return np.log1p(X)
FunctionTransformer(log_t) # ✅2. y ni qo'lda o'zgartirish
model.fit(X, np.log(y)); p = np.exp(model.predict(X)) # ⚠️
TransformedTargetRegressor(regressor=model, func=np.log,
inverse_func=np.exp) # ✅3. feature_names_out yo'q
FunctionTransformer(log_t) # get_feature_names_out xato # ⚠️
FunctionTransformer(log_t, feature_names_out="one-to-one") # ✅4. Mos kelmaydigan teskari funksiya
func=np.log, inverse_func=np.log # teskari emas # ⚠️
func=np.log, inverse_func=np.exp # ✅5. Noto'g'ri vosita
FeatureUnion([("son", StandardScaler()), ("kat", OneHotEncoder())]) # ⚠️
ColumnTransformer([("son", StandardScaler(), sonli),
("kat", OneHotEncoder(), kategoriya)]) # ✅6. Parametr yo'lini taxmin qilish
setka = {"m__max_depth": [3, 5]} # TTR ichida ishlamaydi # ⚠️
setka = {"regressor__m__max_depth": [3, 5]} # ✅7. Klassifikatsiyada TTR
TransformedTargetRegressor(regressor=LogisticRegression()) # ⚠️
# klassifikatsiyada sinf og'irliklari yoki chegara ishlatiladi # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 19.2-dars (o'tilgan): Pipeline
- 19.3-dars (o'tilgan): ColumnTransformer
- 19.4-dars (o'tilgan): O'z transformeringiz
- 19.6-dars: Model saqlash (lambda muammosi)
- 19.10-dars: To'liq loyiha
8. Eng yaxshi amaliyotlar
Modul darajasidagi funksiya.
feature_names_outni qo'ying.yniTransformedTargetRegressorbilan.inverse_funcni tekshiring.To'g'ri vositani tanlang.
Parametr yo'llarini
get_paramsdan oling.TTReng tashqarida.Tuzilmani hujjatlashtiring.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # FunctionTransformer qachon?
2. # nima uchun lambda yaramaydi?
3. # feature_names_out variantlari?
4. # TTR nima qiladi?
5. # nima uchun y ni qo'lda o'zgartirmaslik kerak?
6. # FeatureUnion nima qiladi?
7. # ColumnTransformer bilan farqi?
8. # TTR quvurning qayerida?
9. # parametr yo'li qanday tuziladi?
10. # yo'lni qayerdan olish kerak?
11. # inverse_func nima uchun?
12. # TTR klassifikatsiyada ishlaydimi?Javoblar
- Holatsiz sodda o'zgartirish
- Pickle qilinmaydi
"one-to-one", funksiya,Noneyni o'zgartiradi va bashoratni qaytaradi- Metrikalar log shkalada qoladi
- Ayni kirishdan ko'p ko'rinish
ColumnTransformerbo'ladi,FeatureUnionko'paytiradi- Eng tashqarida
- Ichma-ich nomlar
__bilan get_params(deep=True)inverse_transformva TTR uchun- Yo'q, faqat regressiya
Vazifa 2: Xatolarni tuzating
1. FunctionTransformer(lambda X: np.log1p(X))
2. model.fit(X, np.log(y)); p = np.exp(model.predict(X))
3. FunctionTransformer(log_t) # get_feature_names_out kerak
4. func=np.log, inverse_func=np.log
5. setka = {"m__max_depth": [3, 5]} # TTR ichidaJavoblar
1. def log_t(X): return np.log1p(X)
FunctionTransformer(log_t)
2. TransformedTargetRegressor(regressor=model, func=np.log,
inverse_func=np.exp)
3. FunctionTransformer(log_t, feature_names_out="one-to-one")
4. func=np.log, inverse_func=np.exp
5. setka = {"regressor__m__max_depth": [3, 5]}Vazifa 3: FunctionTransformer
Modellang:
- Oddiy ishlatish
inverse_transform- Nomlar
lambdava pickle
Vazifa 4: TTR
Modellang:
- Taqsimot
- Uch variant
- Bashoratlar
- Qo'lda log
Vazifa 5: FeatureUnion
Modellang:
- Tuzilish
- Hissalar
- Nomlar
- Farq
Vazifa 6: Birga
Modellang:
- Tuzilma
- Belgilar
- Yo'llar
- Sozlash
Vazifa 7: O'ylash
TransformedTargetRegressor(func=np.log, inverse_func=np.exp) ishlatdingiz va CV MAE juda yaxshi chiqdi. Lekin ishlab chiqarishda ba'zi bashoratlar juda katta (millionlab) chiqmoqda. Nima bo'lishi mumkin?
Javob
Qisqa javob: exp eksponensial kuchaytirgich: log shkaladagi kichik xato asl shkalada ulkan xatoga aylanadi. Bu, ayniqsa, model ko'rmagan hududda yuz beradi.
1. Matematika
log shkalada xato: +0.5
asl shkalada: exp(+0.5) = 1.65 barobar
log shkalada xato: +3.0
asl shkalada: exp(+3.0) = 20 barobarYa'ni log shkaladagi kichik xato asl shkalada ko'paytiruvchi bo'lib ta'sir qiladi.
2. Qayerda yuz beradi
| Holat | Natija |
|---|---|
| Chegaradan tashqaridagi kirish | Model ekstrapolyatsiya qiladi → katta log(y) |
| Chiziqli model + katta belgi qiymati | Koeffitsiyent × katta qiymat |
| Yo'qolgan qiymat noto'g'ri to'ldirilgan | Masalan 0 o'rniga median |
3. Diagnostika
ichki = model.regressor_ # ichki quvur
log_bashorat = ichki.predict(X_yangi) # LOG shkalada
print(np.percentile(log_bashorat, [0, 1, 50, 99, 100]))
# o'quvdagi log(y) diapazoni bilan solishtiring
print(np.percentile(np.log(y_oquv), [0, 100]))Agar log_bashorat o'quv diapazonidan chiqib ketgan bo'lsa — ekstrapolyatsiya.
4. Yechimlar
a) Bashoratni log shkalada cheklash
class CheklanganTTR(TransformedTargetRegressor):
def predict(self, X, **kw):
log_p = self.regressor_.predict(X)
log_p = np.clip(log_p, self.past_, self.yuqori_)
return self.inverse_func(log_p)Chegaralarni o'quv log(y) ning [0.1%, 99.9%] kvantillaridan oling.
b) Kirishlarni cheklash — vinzorlash transformeri (19.4-dars) quvur boshida.
c) Daraxtli model ishlatish — HistGradientBoostingRegressor ekstrapolyatsiya qilmaydi: u o'quvda ko'rilgan barglar qiymatidan chiqmaydi.
d) log o'rniga boshqa o'zgartirish — QuantileTransformer(output_distribution="normal") chegaralangan va xavfsizroq.
5. Monitoring
katta = (bashorat > oquv_max * 3).mean()
if katta > 0.001:
ogohlantir(f"bashoratlarning {katta:.2%} i o'quv maksimumidan 3x katta")6. Xulosa
expxatoni ko'paytiruvchi qiladi- Log shkaladagi bashoratni tekshiring
- Cheklash yoki daraxtli model
- Chegaradan chiqishni kuzating
Nimani mustahkamlaydi: 2.2-bo'lim.
Xulosa
Bu darsda kompozitsiya vositalarini o'rgandik.
Eng muhim uch fikr:
FunctionTransformer— holatsiz o'zgartirishlar uchun yopishtiruvchi. Unga modul darajasidagi funksiya bering (lambdamodelpickleqilinishini buzadi) vafeature_names_out="one-to-one"ni qo'shing, aks holda ustun nomlari ishlamaydi.fitda biror narsa o'rganilishi kerak bo'lsa — bu endiFunctionTransformeremas, o'z transformeringiz (19.4-dars).Maqsadni
TransformedTargetRegressorbilan o'zgartiring.yni qo'ldalogqilsangiz CV metrikasi log shkalada qoladi va boshqa modellar bilan taqqoslab bo'lmaydi.TTResafitdafunc,predictdainverse_funcqo'llaydi va bashoratni asl birlikka qaytaradi. U quvurning eng tashqarisida turadi.ColumnTransformerbo'ladi,FeatureUnionko'paytiradi. Birinchisi turli ustunlarga turli ishlov beradi, ikkinchisi esa ayni kirishdan bir necha ko'rinish yasab birlashtiradi (xom + PCA, TF-IDF + statistika). Ikkalasi bir-birini almashtirmaydi va ko'pincha birga ishlatiladi.
Keyingi darsda modelni saqlash ni ko'ramiz: joblib, versiya muammolari, pickle ning xavfsizlik jihatlari va ishlab chiqarishga topshirish paketi.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!