17-bo‘lim
Ma'lumotni tayyorlash
Normalizatsiya, kategorik belgilar, yetishmayotgan qiymatlar va ma'lumot sizib chiqishi.
Ushbu bo‘lim mundarijasi
Model sifatining katta qismi arxitekturada emas, ma'lumot tayyorlashda hal bo'ladi. Bu bo'lim shu haqda.
Masshtab muammosi #
import numpy as np
def sigmoid(z):
return 1.0 / (1.0 + np.exp(-z))
class Tarmoq:
def __init__(self, olchamlar, urug=42):
gen = np.random.default_rng(urug)
self.q = len(olchamlar) - 1
self.W = [gen.normal(0, np.sqrt(2.0 / olchamlar[i]),
(olchamlar[i], olchamlar[i + 1])) for i in range(self.q)]
self.b = [np.zeros(olchamlar[i + 1]) for i in range(self.q)]
def oldinga(self, X):
A = X
kesh = {"A0": X}
for i in range(self.q):
Z = A @ self.W[i] + self.b[i]
A = sigmoid(Z) if i == self.q - 1 else np.maximum(0.0, Z)
kesh[f"Z{i+1}"] = Z
kesh[f"A{i+1}"] = A
return A, kesh
def qadam(self, X, y, tezlik):
A, kesh = self.oldinga(X)
dZ = (A - y) / len(y)
for i in range(self.q - 1, -1, -1):
dW = kesh[f"A{i}"].T @ dZ
db = dZ.sum(axis=0)
if i > 0:
dZ = (dZ @ self.W[i].T) * (kesh[f"Z{i}"] > 0)
self.W[i] -= tezlik * dW
self.b[i] -= tezlik * db
def yoqotish(self, X, y, eps=1e-12):
A, _ = self.oldinga(X)
A = np.clip(A, eps, 1 - eps)
return float(-np.mean(y * np.log(A) + (1 - y) * np.log(1 - A)))
def aniqlik(self, X, y):
A, _ = self.oldinga(X)
return float(((A > 0.5).astype(float) == y).mean())
def uy_malumoti(n=500, urug=0):
"""Uch belgi, uch xil masshtab: xona soni, maydon, narx."""
gen = np.random.default_rng(urug)
xonalar = gen.integers(1, 7, n).astype(float) # 1 - 6
maydon = gen.normal(70, 25, n) # 20 - 120
narx = gen.normal(500_000_000, 150_000_000, n) # yuz millionlar
X = np.column_stack([xonalar, maydon, narx])
y = ((maydon > 70) & (narx < 550_000_000)).astype(float).reshape(-1, 1)
return X, y
def normallash(Xo, Xt):
ortacha = Xo.mean(axis=0)
std = Xo.std(axis=0)
std = np.where(std == 0, 1.0, std)
return (Xo - ortacha) / std, (Xt - ortacha) / std, ortacha, std
def min_max(Xo, Xt):
eng_kichik = Xo.min(axis=0)
eng_katta = Xo.max(axis=0)
oraliq = np.where(eng_katta - eng_kichik == 0, 1.0, eng_katta - eng_kichik)
return (Xo - eng_kichik) / oraliq, (Xt - eng_kichik) / oraliq
X, y = uy_malumoti()
print("belgi o'rtacha std")
for i, nom in enumerate(["xonalar", "maydon", "narx"]):
print(f"{nom:<18} {X[:, i].mean():>14.2f} {X[:, i].std():>14.2f}")
belgi o'rtacha std
xonalar 3.64 1.75
maydon 69.06 24.70
narx 491965645.54 143040231.09
Uchinchi belgining o'rtachasi birinchisidan yuz milliondan ortiq barobar katta, standart og'ishi esa sakson million barobar.
Normalizatsiyasiz o'qitish #
X, y = uy_malumoti()
chegara = 350
Xo, yo, Xt, yt = X[:chegara], y[:chegara], X[chegara:], y[chegara:]
t = Tarmoq([3, 16, 16, 1], urug=1)
for _ in range(2000):
t.qadam(Xo, yo, 0.01)
print("normalizatsiyasiz:")
print(" yo'qotish:", round(t.yoqotish(Xo, yo), 6))
print(" o'qitish aniqligi: ", round(t.aniqlik(Xo, yo), 4))
print(" tekshiruv aniqligi:", round(t.aniqlik(Xt, yt), 4))
normalizatsiyasiz:
yo'qotish: 0.626878
o'qitish aniqligi: 0.68
tekshiruv aniqligi: 0.6867
<stdin>:5: RuntimeWarning: overflow encountered in exp
Model o'qidi, lekin yomon: aniqlik atigi 0.69 va
np.exp da toshib ketish ogohlantirishi chiqdi.
Ogohlantirish tasodifiy emas: narx belgisi 5 × 10⁸
tartibida bo'lgani uchun birinchi qatlamdagi z qiymatlari
ham juda katta, va np.exp(-z) toshib ketadi.
nan ga ham aylanishi mumkinYuqorida model omon qoldi - lekin bu omad. O'qitish
tezligini biroz oshirsangiz yoki tarmoqni kattalashtirsangiz,
og'irliklar inf ga aylanadi, keyin inf - inf = nan paydo
bo'ladi va u butun tarmoqqa tarqaladi.
Toshib ketish ogohlantirishi - birinchi qo'ng'iroq. Uni e'tiborsiz qoldirmang.
nan ning odatiy sabablari:
| Sabab | Yechim |
|---|---|
| Normalizatsiya qilinmagan | Shu bo'lim |
| O'qitish tezligi juda katta | 10 barobar kamaytiring |
log(0) krossentropiyada | np.clip (6-bo'lim) |
| Nolga bo'lish | + eps qo'shing |
| Gradient portlashi | Kesish (15-bo'lim) |
Tashxis usuli: np.isnan(...).any() ni har qadamdan keyin
tekshiring va birinchi nan qayerda paydo bo'lganini
toping.
Z-normalizatsiya #
def normallash(Xo, Xt):
ortacha = Xo.mean(axis=0)
std = Xo.std(axis=0)
std = np.where(std == 0, 1.0, std) # nolga bo'linishdan himoya
return (Xo - ortacha) / std, (Xt - ortacha) / std, ortacha, std
X, y = uy_malumoti()
chegara = 350
Xo, yo, Xt, yt = X[:chegara], y[:chegara], X[chegara:], y[chegara:]
Xo_n, Xt_n, ortacha, std = normallash(Xo, Xt)
print("normalizatsiyadan keyin (o'qitish to'plami):")
print(" o'rtacha:", np.round(Xo_n.mean(axis=0), 6))
print(" std: ", np.round(Xo_n.std(axis=0), 6))
print("tekshiruv to'plami:")
print(" o'rtacha:", np.round(Xt_n.mean(axis=0), 4))
normalizatsiyadan keyin (o'qitish to'plami):
o'rtacha: [0. 0. 0.]
std: [1. 1. 1.]
tekshiruv to'plami:
o'rtacha: [ 0.0635 -0.0566 0.1051]
Tekshiruv to'plamining o'rtachasi aynan nol emas
(-0.03, 0.03, 0.08) - va shunday bo'lishi kerak.
Agar siz X.mean() ni butun to'plamda hisoblasangiz,
tekshiruv ma'lumoti haqidagi bilim o'qitishga sizib
o'tadi (data leakage).
Oqibati: tekshiruv natijasi haqiqiydan yaxshiroq ko'rinadi, ishlab chiqarishda esa model kutilganidan yomonroq ishlaydi.
To'g'ri tartib:
| Qadam | Qayerda |
|---|---|
| 1. Bo'lish | Avval o'qitish/tekshiruvga ajrating |
| 2. Statistikani hisoblash | Faqat o'qitishda |
| 3. Qo'llash | O'qitishga va tekshiruvga - bir xil qiymatlar bilan |
| 4. Saqlash | ortacha va std ni model bilan birga saqlang |
To'rtinchi qadam ko'pincha unutiladi: ishlab chiqarishda
kelgan yangi ma'lumot ham aynan o'sha ortacha va
std bilan normallanishi kerak.
X, y = uy_malumoti()
chegara = 350
Xo, yo, Xt, yt = X[:chegara], y[:chegara], X[chegara:], y[chegara:]
Xo_n, Xt_n, _, _ = normallash(Xo, Xt)
t = Tarmoq([3, 16, 16, 1], urug=1)
for _ in range(2000):
t.qadam(Xo_n, yo, 0.1)
print("normalizatsiya bilan:")
print(" yo'qotish:", round(t.yoqotish(Xo_n, yo), 6))
print(" o'qitish aniqligi: ", round(t.aniqlik(Xo_n, yo), 4))
print(" tekshiruv aniqligi:", round(t.aniqlik(Xt_n, yt), 4))
normalizatsiya bilan:
yo'qotish: 0.012552
o'qitish aniqligi: 1.0
tekshiruv aniqligi: 0.9867
Aniqlik 0.69 dan 0.97 ga ko'tarildi, yo'qotish esa
0.63 dan 0.05 ga tushdi - va hech qanday ogohlantirish
chiqmadi.
Bitta qadam - normalizatsiya - modelni ishlamaydigan holatdan yaxshi holatga o'tkazdi.
Min-max masshtablash #
def min_max(Xo, Xt):
eng_kichik = Xo.min(axis=0)
eng_katta = Xo.max(axis=0)
oraliq = np.where(eng_katta - eng_kichik == 0, 1.0, eng_katta - eng_kichik)
return (Xo - eng_kichik) / oraliq, (Xt - eng_kichik) / oraliq
X, y = uy_malumoti()
Xo, Xt = X[:350], X[350:]
Xo_mm, Xt_mm = min_max(Xo, Xt)
print("o'qitish oralig'i: ", np.round(Xo_mm.min(axis=0), 4), "...", np.round(Xo_mm.max(axis=0), 4))
print("tekshiruv oralig'i:", np.round(Xt_mm.min(axis=0), 4), "...", np.round(Xt_mm.max(axis=0), 4))
o'qitish oralig'i: [0. 0. 0.] ... [1. 1. 1.]
tekshiruv oralig'i: [0. 0.2078 0.0333] ... [1. 0.9453 0.8942]
| Usul | Qachon |
|---|---|
| Z-normalizatsiya | Standart tanlov, chetlangan qiymatlarga chidamli |
| Min-max | Chegara ma'lum bo'lganda (rasm: 0-255) |
| Robust (median, IQR) | Ko'p chetlangan qiymat bo'lganda |
| Log o'zgartirish | Juda qiyshiq taqsimot (narx, daromad) |
Bitta g'alati qiymat butun masshtabni buzadi:
| Ma'lumot | Min-max natija |
|---|---|
[1, 2, 3, 4, 5] | [0, 0.25, 0.5, 0.75, 1] - yaxshi |
[1, 2, 3, 4, 1000] | [0, 0.001, 0.002, 0.003, 1] - buzildi |
Ikkinchi holatda foydali ma'lumot 0 va 0.003 orasiga
siqilib qoldi.
Z-normalizatsiya bunday holatda ham ishlaydi, chunki u o'rtacha va standart og'ishga tayanadi.
Shuning uchun shubha bo'lsa - z-normalizatsiya.
Kategorik belgilar #
shaharlar = np.array(["Toshkent", "Namangan", "Samarqand", "Namangan", "Toshkent"])
# XATO: raqamlash
raqamli = np.array([0, 1, 2, 1, 0])
# TO'G'RI: one-hot
noyob = np.array(["Namangan", "Samarqand", "Toshkent"])
one_hot = (shaharlar[:, None] == noyob[None, :]).astype(float)
print("raqamli:", raqamli)
print("one-hot:")
print(one_hot)
print("ustunlar:", noyob.tolist())
raqamli: [0 1 2 1 0]
one-hot:
[[0. 0. 1.]
[1. 0. 0.]
[0. 1. 0.]
[1. 0. 0.]
[0. 0. 1.]]
ustunlar: ['Namangan', 'Samarqand', 'Toshkent']
Toshkent = 0, Namangan = 1, Samarqand = 2 deb yozsangiz,
model soxta tartib o'rganadi:
Samarqand > Namangan > Toshkent;Namanganikkalasining o'rtasida;SamarqandToshkentdan ikki barobar katta.
Bularning hech biri to'g'ri emas.
One-hot kodlash bu muammoni yo'q qiladi: har kategoriya o'z ustuniga ega va ular orasida hech qanday tartib yo'q.
| Vaziyat | Usul |
|---|---|
| Tartibsiz kategoriya (shahar, rang) | One-hot |
| Tartibli kategoriya (kichik/o'rta/katta) | Raqamlash to'g'ri |
| Juda ko'p kategoriya (10000+ so'z) | Embedding |
Uchinchi holat muhim: one-hot bilan 10000 kategoriya 10000 ustun beradi. Embedding esa har kategoriyani kichik vektor bilan ifodalaydi - va bu vektorlar o'qitiladi.
Yetishmayotgan qiymatlar #
gen = np.random.default_rng(0)
X = gen.normal(50, 10, (10, 3))
X[2, 0] = np.nan
X[5, 1] = np.nan
X[7, 0] = np.nan
print("yetishmayotgan qiymatlar soni ustun bo'yicha:")
print(np.isnan(X).sum(axis=0))
ortacha = np.nanmean(X, axis=0)
X_tuldirilgan = np.where(np.isnan(X), ortacha, X)
print("o'rtacha bilan to'ldirilgandan keyin nan bormi:",
bool(np.isnan(X_tuldirilgan).any()))
print("to'ldirilgan qiymatlar:", np.round(X_tuldirilgan[[2, 5, 7], [0, 1, 0]], 4))
yetishmayotgan qiymatlar soni ustun bo'yicha:
[2 1 0]
o'rtacha bilan to'ldirilgandan keyin nan bormi: False
to'ldirilgan qiymatlar: [45.3766 49.3898 45.3766]
O'rtacha bilan to'ldirish - eng oddiy usul, lekin u bitta narsani yo'qotadi: qiymat yetishmagani haqidagi ma'lumot.
Ko'pincha bu juda ma'noli bo'ladi:
| Maydon | Bo'sh bo'lsa nima anglatadi |
|---|---|
| Daromad | Odam aytishni istamadi |
| Oxirgi xarid sanasi | Hech qachon xarid qilmagan |
| Tibbiy tahlil | Shifokor buyurmagan - demak shubha yo'q |
Yaxshiroq yechim - ikkita ustun:
X_tuldirilgan = np.where(np.isnan(X), ortacha, X)
bayroq = np.isnan(X).astype(float)
X_yakuniy = np.hstack([X_tuldirilgan, bayroq])
Endi model "qiymat 50 edi" va "qiymat noma'lum edi, biz 50 deb taxmin qildik" holatlarini ajrata oladi.
Va yana: nanmean ni faqat o'qitish to'plamida
hisoblang.
gen = np.random.default_rng(0)
X = gen.normal(50, 10, (6, 2))
X[1, 0] = np.nan
X[4, 1] = np.nan
ortacha = np.nanmean(X, axis=0)
tuldirilgan = np.where(np.isnan(X), ortacha, X)
bayroq = np.isnan(X).astype(float)
yakuniy = np.hstack([tuldirilgan, bayroq])
print("asl shakl:", X.shape, " -> yakuniy shakl:", yakuniy.shape)
print("bayroq ustunlari:")
print(bayroq)
asl shakl: (6, 2) -> yakuniy shakl: (6, 4)
bayroq ustunlari:
[[0. 0.]
[1. 0.]
[0. 0.]
[0. 0.]
[0. 1.]
[0. 0.]]
Nomutanosib sinflar #
gen = np.random.default_rng(0)
n = 1000
X = gen.normal(0, 1, (n, 5))
y = (gen.uniform(0, 1, (n, 1)) < 0.05).astype(float) # atigi 5% musbat
print("musbat sinf ulushi:", round(float(y.mean()), 4))
print("'hammasi 0' deb aytadigan model aniqligi:",
round(float((y == 0).mean()), 4))
musbat sinf ulushi: 0.053
'hammasi 0' deb aytadigan model aniqligi: 0.947
Hech nima o'rganmagan, doim 0 deydigan model 95.7%
aniqlik beradi.
Nomutanosib ma'lumotda aniqlik yaroqsiz o'lchov. Buning o'rniga 19-bo'limdagi o'lchovlar ishlatiladi: aniqlik (precision), qamrov (recall), F1.
O'qitish paytidagi choralar:
| Chora | Qanday |
|---|---|
| Sinf og'irliklari | Kam uchraydigan sinf xatosini kuchliroq jazolash |
| Kam sinfni ko'paytirish | Takrorlash yoki sun'iy namuna (SMOTE) |
| Ko'p sinfni kamaytirish | Ma'lumot yo'qoladi - ehtiyot bo'ling |
| Chegarani o'zgartirish | 0.5 emas, 0.2 yoki 0.8 |
Oxirgisi eng arzon va ko'pincha yetarli: model ehtimollikni to'g'ri o'rgansa, chegarani keyin sozlash mumkin (19-bo'lim).
To'liq quvur #
def tayyorla(X_xom, y, ulush=0.7, urug=0):
gen = np.random.default_rng(urug)
tartib = gen.permutation(len(X_xom))
chegara = int(len(X_xom) * ulush)
o, t = tartib[:chegara], tartib[chegara:]
Xo, Xt = X_xom[o], X_xom[t]
yo, yt = y[o], y[t]
ortacha = np.nanmean(Xo, axis=0)
Xo = np.where(np.isnan(Xo), ortacha, Xo)
Xt = np.where(np.isnan(Xt), ortacha, Xt)
std = Xo.std(axis=0)
std = np.where(std == 0, 1.0, std)
Xo = (Xo - ortacha) / std
Xt = (Xt - ortacha) / std
return Xo, yo, Xt, yt, {"ortacha": ortacha, "std": std}
X, y = uy_malumoti(500)
X[10, 1] = np.nan
Xo, yo, Xt, yt, parametrlar = tayyorla(X, y)
print("o'qitish:", Xo.shape, " tekshiruv:", Xt.shape)
print("nan qoldimi:", bool(np.isnan(Xo).any() or np.isnan(Xt).any()))
print("o'qitish o'rtachasi:", np.round(Xo.mean(axis=0), 6))
print("saqlangan parametrlar:", sorted(parametrlar.keys()))
o'qitish: (350, 3) tekshiruv: (150, 3)
nan qoldimi: False
o'qitish o'rtachasi: [-0. 0. -0.]
saqlangan parametrlar: ['ortacha', 'std']
- Uch xil masshtabdagi belgilar yarating va statistikasini chop eting.
- Normalizatsiyasiz o'qitib,
nanni oling. nanning beshta sababini sanang.- Z-normalizatsiya qo'llang va natijani solishtiring.
- Statistikani butun to'plamda hisoblash nima uchun xato ekanini tushuntiring.
- Min-max ni chetlangan qiymatli ma'lumotda sinab ko'ring.
- Kategoriyani one-hot ga aylantiring.
- Raqamlash nima uchun soxta tartib yaratishini ayting.
- Yetishmayotgan qiymatlarni bayroq ustuni bilan to'ldiring.
- To'liq tayyorlash quvurini yozing va parametrlarni saqlang.
Xulosa #
- Turli masshtabdagi belgilar - 15-bo'limdagi tor vodiy muammosi.
- Normalizatsiyasiz yo'qotish
nanbo'lishi mumkin. nansabablari: masshtab, tezlik,log(0), nolga bo'lish, portlash.- Z-normalizatsiya - standart tanlov; min-max chetlangan qiymatga sezgir.
- Statistikani faqat o'qitish to'plamida hisoblang.
ortachavastdni model bilan birga saqlang.- Kategoriyani raqamlash soxta tartib yaratadi - one-hot ishlating.
- Ko'p kategoriya uchun embedding.
- Yetishmayotgan qiymatga bayroq ustuni qo'shing - "yo'qligi" ham ma'lumot.
- Nomutanosib sinfda aniqlik yaroqsiz o'lchov.
Keyingi bo'limda ko'p sinfli tasniflashni ko'ramiz: softmax va uning krossentropiyasi.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.