17-bo‘lim

Ma'lumotni tayyorlash

Normalizatsiya, kategorik belgilar, yetishmayotgan qiymatlar va ma'lumot sizib chiqishi.

🕑 16 daqiqa o‘qish 📄 1 053 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Masshtab muammosi
  2. Normalizatsiyasiz o'qitish
  3. Z-normalizatsiya
  4. Min-max masshtablash
  5. Kategorik belgilar
  6. Yetishmayotgan qiymatlar
  7. Nomutanosib sinflar
  8. To'liq quvur
  9. Xulosa

Model sifatining katta qismi arxitekturada emas, ma'lumot tayyorlashda hal bo'ladi. Bu bo'lim shu haqda.

Masshtab muammosi #

Python
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
Python
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}")
Natija
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.

Turli masshtab - turli gradient Normalizatsiyasiz xonalar: 3.4 -> gradient kichik maydon: 69 -> gradient o'rtacha narx: 5.0e8 -> gradient DEVASTAL Bitta tezlik uchalasiga ham to'g'ri kelmaydi (15-bo'limdagi tor vodiy - aynan shu) Normalizatsiyadan keyin xonalar: -0.2 ... 1.5 maydon: -1.9 ... 2.1 narx: -2.0 ... 1.8 Hammasi bir xil masshtabda Bitta tezlik hammasiga mos keladi Ikki usul z-normalizatsiya: (x - o'rtacha) / std o'rtacha 0, std 1 - standart tanlov min-max: (x - min) / (max - min) 0 dan 1 gacha - rasm piksellari uchun Statistikani FAQAT o'qitish to'plamida hisoblang (pastda).
Normalizatsiya - eng arzon va eng samarali qadam

Normalizatsiyasiz o'qitish #

Python
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))
Natija
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.

Bu holat osongina nan ga ham aylanishi mumkin

Yuqorida 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:

SababYechim
Normalizatsiya qilinmaganShu bo'lim
O'qitish tezligi juda katta10 barobar kamaytiring
log(0) krossentropiyadanp.clip (6-bo'lim)
Nolga bo'lish+ eps qo'shing
Gradient portlashiKesish (15-bo'lim)

Tashxis usuli: np.isnan(...).any() ni har qadamdan keyin tekshiring va birinchi nan qayerda paydo bo'lganini toping.

Z-normalizatsiya #

Python
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))
Natija
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]
Statistikani faqat o'qitish to'plamida hisoblang

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:

QadamQayerda
1. Bo'lishAvval o'qitish/tekshiruvga ajrating
2. Statistikani hisoblashFaqat o'qitishda
3. Qo'llashO'qitishga va tekshiruvga - bir xil qiymatlar bilan
4. Saqlashortacha 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.

Python
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))
Natija
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 #

Python
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))
Natija
o'qitish oralig'i:  [0. 0. 0.] ... [1. 1. 1.]
tekshiruv oralig'i: [0.     0.2078 0.0333] ... [1.     0.9453 0.8942]
UsulQachon
Z-normalizatsiyaStandart tanlov, chetlangan qiymatlarga chidamli
Min-maxChegara ma'lum bo'lganda (rasm: 0-255)
Robust (median, IQR)Ko'p chetlangan qiymat bo'lganda
Log o'zgartirishJuda qiyshiq taqsimot (narx, daromad)
Min-max chetlangan qiymatga sezgir

Bitta g'alati qiymat butun masshtabni buzadi:

Ma'lumotMin-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 #

Python
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())
Natija
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']
Kategoriyani raqam bilan almashtirmang

Toshkent = 0, Namangan = 1, Samarqand = 2 deb yozsangiz, model soxta tartib o'rganadi:

  • Samarqand > Namangan > Toshkent;
  • Namangan ikkalasining o'rtasida;
  • Samarqand Toshkent dan 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.

VaziyatUsul
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 #

Python
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))
Natija
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]
"Yetishmayotgan" ning o'zi ham ma'lumot

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:

MaydonBo'sh bo'lsa nima anglatadi
DaromadOdam aytishni istamadi
Oxirgi xarid sanasiHech qachon xarid qilmagan
Tibbiy tahlilShifokor buyurmagan - demak shubha yo'q

Yaxshiroq yechim - ikkita ustun:

Python
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.

Python
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)
Natija
asl shakl: (6, 2)  -> yakuniy shakl: (6, 4)
bayroq ustunlari:
[[0. 0.]
 [1. 0.]
 [0. 0.]
 [0. 0.]
 [0. 1.]
 [0. 0.]]

Nomutanosib sinflar #

Python
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))
Natija
musbat sinf ulushi: 0.053
'hammasi 0' deb aytadigan model aniqligi: 0.947
95% aniqlik - bu yerda hech nima anglatmaydi

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:

ChoraQanday
Sinf og'irliklariKam uchraydigan sinf xatosini kuchliroq jazolash
Kam sinfni ko'paytirishTakrorlash yoki sun'iy namuna (SMOTE)
Ko'p sinfni kamaytirishMa'lumot yo'qoladi - ehtiyot bo'ling
Chegarani o'zgartirish0.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 #

Python
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()))
Natija
o'qitish: (350, 3)  tekshiruv: (150, 3)
nan qoldimi: False
o'qitish o'rtachasi: [-0.  0. -0.]
saqlangan parametrlar: ['ortacha', 'std']
Amaliy topshiriq
  1. Uch xil masshtabdagi belgilar yarating va statistikasini chop eting.
  2. Normalizatsiyasiz o'qitib, nan ni oling.
  3. nan ning beshta sababini sanang.
  4. Z-normalizatsiya qo'llang va natijani solishtiring.
  5. Statistikani butun to'plamda hisoblash nima uchun xato ekanini tushuntiring.
  6. Min-max ni chetlangan qiymatli ma'lumotda sinab ko'ring.
  7. Kategoriyani one-hot ga aylantiring.
  8. Raqamlash nima uchun soxta tartib yaratishini ayting.
  9. Yetishmayotgan qiymatlarni bayroq ustuni bilan to'ldiring.
  10. To'liq tayyorlash quvurini yozing va parametrlarni saqlang.

Xulosa #

  • Turli masshtabdagi belgilar - 15-bo'limdagi tor vodiy muammosi.
  • Normalizatsiyasiz yo'qotish nan bo'lishi mumkin.
  • nan sabablari: masshtab, tezlik, log(0), nolga bo'lish, portlash.
  • Z-normalizatsiya - standart tanlov; min-max chetlangan qiymatga sezgir.
  • Statistikani faqat o'qitish to'plamida hisoblang.
  • ortacha va std ni 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.

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.