IlmHamroh
Data Science va sun'iy intellekt/Klassifikatsiya3/14-dars19 daqiqa
Mundarija (22)

14.3-dars: Naive Bayes

14-QISM — KLASSIFIKATSIYA · 3-dars


1. Kirish va motivatsiya

Naive Bayes — ehtimollar nazariyasiga (9-qism) to'g'ridan-to'g'ri asoslangan klassifikator. U Bayes formulasini qo'llaydi va bitta "sodda" (naive) taxmin qiladi: belgilar sinf berilganda o'zaro mustaqil. Bu taxmin deyarli har doim noto'g'ri — lekin model baribir ajoyib ishlaydi, ayniqsa matn bilan.

Naive Bayes muhim, chunki u: eng tez klassifikator (bitta o'tish yetarli), kam ma'lumotda barqaror, minglab belgi bilan bemalol ishlaydi va spam filtrlar, matn tasniflagichlar, tibbiy skriningda hali ham qo'llaniladi.

Bu darsda: Bayes formulasidan modelgacha, "sodda" taxminning ma'nosi, uch variant (Gaussian, Multinomial, Bernoulli), silliqlash (Laplace), matn bilan ishlash va nega ehtimollari kalibrlanmagan.

Real vaziyat. Qo'llab-quvvatlash xizmati kuniga 4 000 ta xat oladi va ularni 9 ta kategoriyaga ajratishi kerak. Neyron tarmoq 87% aniqlik berdi, lekin har o'zgarishda 40 daqiqa o'qitish va GPU talab qildi. Multinomial Naive Bayes + TF-IDF 83% berdi va 1.2 soniyada o'qitiladi — jamoa uni tanladi: har kuni yangilanadi, hech qanday infratuzilma kerak emas.

Bu darsda Naive Bayes ni o'rganamiz.

Bu darsda:

  • Bayes formulasidan modelgacha
  • "Sodda" taxmin
  • Uch variant
  • Silliqlash
  • Matn bilan ishlash
  • Kalibrlash muammosi
  • Tuzoqlar
  • Amaliy: matn tasniflash

ℹ Misollar real numpy/sklearn bilan (Python 3.14).


2. Nazariya — chuqur tushuntirish

2.1. Bayes formulasidan modelgacha

text
Bayes (9-qism):  P(y | x) = P(x | y) · P(y) / P(x)

Bashorat: argmax_k P(y=k) · P(x | y=k)          (P(x) hammaga bir xil — tushib qoladi)

Muammo: P(x | y) — ko'p o'lchamli taqsimot, uni baholash uchun juda ko'p ma'lumot kerak
        (10 ta binar belgi → 2^10 = 1024 kombinatsiya har sinf uchun)

NAIVE taxmin: belgilar sinf berilganda mustaqil
  P(x | y) = P(x1 | y) · P(x2 | y) · ... · P(xp | y)
  → har belgi uchun alohida bir o'lchovli taqsimot yetarli

"Sodda" taxmin hisoblash muammosini hal qiladi: 2^p ta parametr o'rniga p ta bir o'lchovli taqsimot. Amalda ehtimollar logarifmda yig'iladi (log P(y) + sum log P(xj|y)) — bu ko'paytmaning nolga aylanishini oldini oladi va tezroq ishlaydi.

2.2. "Sodda" taxmin nega ishlaydi

text
Taxmin deyarli HAR DOIM noto'g'ri:
  matnda "mashina" va "o'rganish" so'zlari mustaqil emas

Lekin klassifikatsiya uchun ehtimol QIYMATI emas, TARTIBI muhim:
  argmax to'g'ri sinfni tanlasa yetarli

Bog'liq belgilar "ovozni ikki marta sanaydi" → ehtimollar 0 yoki 1 ga siljiydi
  → BASHORAT ko'pincha to'g'ri, EHTIMOL esa haddan tashqari ishonchli

Bu — Naive Bayes ning asosiy paradoksi: noto'g'ri taxmin, to'g'ri bashorat. Sabab: qaror uchun argmax yetarli, aniq ehtimol emas. Shuning uchun NB ni reyting yoki yorliq uchun ishlating, predict_proba natijasini esa ehtimol sifatida ishlatmang (14.10 — kalibrlash).

2.3. Uch variant

text
GaussianNB       — uzluksiz belgilar; har belgi sinf ichida normal taqsimlangan deb
                   parametrlar: har sinf va belgi uchun o'rtacha va dispersiya
MultinomialNB    — SANOQ belgilar (so'z chastotasi, TF-IDF); matn uchun standart
BernoulliNB      — BINAR belgilar (so'z bor/yo'q); qisqa matnlarda yaxshi
CategoricalNB    — kategorik belgilar

Aralash belgilar bo'lsa: har turga alohida NB va ehtimollarni ko'paytirish
                         yoki boshqa algoritm

Variant belgi turidan kelib chiqadi — bu eng ko'p xato qilinadigan joy. Matnda MultinomialNB (chastota) yoki BernoulliNB (mavjudlik); jadval ma'lumotida GaussianNB. Noto'g'ri variant tanlansa, natija keskin yomonlashadi.

2.4. Silliqlash

text
Muammo: o'quvda uchramagan so'z → P(so'z | sinf) = 0 → butun ko'paytma 0

Laplace (additive) silliqlash:
  P(xj | y) = (sanoq + alpha) / (jami + alpha · V)
  alpha = 1 — Laplace; alpha < 1 — Lidstone; alpha = 0 — silliqlashsiz (xavfli)

sklearn: MultinomialNB(alpha=1.0), BernoulliNB(alpha=1.0)
alpha — CV bilan tanlanadi (odatda 0.01..1.0)

Silliqlash — NB ning majburiy qismi: usiz bitta noma'lum so'z butun bashoratni nolga tushiradi. alpha regularizatsiya rolini ham bajaradi: katta alpha modelni bir tekisroq (ehtiyotkorroq) qiladi. Uni CV bilan tanlash odatda sezilarli yaxshilanish beradi.

2.5. Matn bilan ishlash

python
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.naive_bayes import ComplementNB, MultinomialNB
from sklearn.pipeline import Pipeline

Pipeline([("vec", TfidfVectorizer(ngram_range=(1, 2), min_df=2)),
          ("m", MultinomialNB(alpha=0.1))])

ComplementNB — nomutanosib matn to'plamlari uchun MultinomialNB ning yaxshilangan varianti

Matn — NB ning tabiiy sohasi: minglab siyrak belgi, ko'p sinf, tez o'qitish. TfidfVectorizer (chastota × teskari hujjat chastotasi) odatda oddiy sanoqdan yaxshiroq. ComplementNB nomutanosib to'plamlarda MultinomialNB dan barqarorroq.

2.6. Kalibrlash muammosi

text
NB ehtimollari haddan tashqari ishonchli: 0.999 yoki 0.001 ga intiladi
  sabab: bog'liq belgilar "dalilni" bir necha marta sanaydi

Oqibat:
  · reyting (AUC) yaxshi bo'lishi mumkin
  · ehtimol qiymati yaroqsiz (narx formulalariga kiritib bo'lmaydi — 9.9)

Yechim: CalibratedClassifierCV (sigmoid yoki isotonic) — 14.10

Bu — NB ni logistik regressiyadan ajratadigan asosiy amaliy farq 13.10-bob: LogReg kalibrlangan ehtimol beradi, NB esa yo'q. Agar sizga faqat yorliq yoki reyting kerak bo'lsa, farq yo'q; ehtimol kerak bo'lsa — kalibrlash shart.

2.7. Tuzoqlar

Asosiy tuzoqlar: noto'g'ri variant tanlash (matnda GaussianNB); silliqlashsiz ishlatish; predict_proba ni ehtimol deb ishlatish; GaussianNB ni kuchli qiyshiq belgilar bilan (avval log yoki quantile transformatsiya); korrelyatsiyalangan belgilar ko'p bo'lsa ishonchni oshirib yuborishi; alpha ni CV siz qoldirish; matnda stop so'zlar va min_df ni sozlamaslik; NB ni jadval ma'lumotida boshqa modellarsiz tanlash.

2.8. Tez, sodda va kutilmaganda kuchli

Naive Bayes Bayes formulasini "belgilar sinf ichida mustaqil" taxmini bilan qo'llaydi: p ta bir o'lchovli taqsimot yetarli bo'ladi. Taxmin deyarli har doim noto'g'ri, lekin argmax to'g'ri chiqadi — shuning uchun bashorat yaxshi, ehtimol esa kalibrlanmagan. Variant belgi turidan kelib chiqadi: Gaussian (uzluksiz), Multinomial (sanoq/TF-IDF), Bernoulli (binar). Silliqlash (alpha) majburiy. Keyingi dars — LDA va QDA.


3. Tez ma'lumotnoma

python
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import GridSearchCV
from sklearn.naive_bayes import BernoulliNB, ComplementNB, GaussianNB, MultinomialNB
from sklearn.pipeline import Pipeline

GaussianNB()                                   # uzluksiz belgilar
MultinomialNB(alpha=1.0)                       # sanoq / TF-IDF
BernoulliNB(alpha=1.0, binarize=0.0)           # binar

matn = Pipeline([("vec", TfidfVectorizer(min_df=2, ngram_range=(1, 2))),
                 ("m", MultinomialNB())])
GridSearchCV(matn, {"m__alpha": [0.01, 0.05, 0.1, 0.5, 1.0]}, cv=5)

model.feature_log_prob_        # log P(belgi | sinf)
model.class_log_prior_         # log P(sinf)
QOIDA: variantni belgi turiga moslang · alpha ni sozlang · ehtimolga ishonmang

Naive Bayes xulosasi

argmax P(y) · prod P(xj|y) · log fazoda yig'indi
Taxmin noto'g'ri, bashorat to'g'ri; ehtimol kalibrlanmagan
Gaussian / Multinomial / Bernoulli — belgi turiga qarab
alpha silliqlash majburiy · matn uchun eng tez tanlov

4. Batafsil misollar

Misollar real numpy/sklearn bilan (Python 3.14).

Misol 1 — Qo'lda Bayes: spam filtri

python
"""Naive Bayes ni nolldan hisoblash (real numpy/sklearn)."""

import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB


def main() -> None:
    xatlar = [
        ("bepul chegirma yutuq hoziroq bosing", 1),
        ("yutuq bepul sovg'a bosing havola", 1),
        ("chegirma aksiya bepul yetkazib berish", 1),
        ("hisobot tayyor uchrashuv ertaga", 0),
        ("loyiha hisobot jamoa uchrashuv", 0),
        ("ertaga jamoa yig'ilish rejasi", 0),
    ]
    matn = [m for m, _ in xatlar]
    y = np.array([t for _, t in xatlar])

    vec = CountVectorizer()
    X = vec.fit_transform(matn).toarray()
    sozlar = vec.get_feature_names_out()

    print("=== 1. Lug'at ===")
    print(f"  {len(sozlar)} ta so'z, {len(matn)} ta xat "
          f"({y.sum()} spam, {(y == 0).sum()} oddiy)")

    print("\n=== 2. Qo'lda hisoblash (alpha = 1) ===")
    alpha = 1.0
    V = len(sozlar)
    log_oldin = {}
    log_ehtimol = {}
    for k in [0, 1]:
        mos = X[y == k]
        log_oldin[k] = np.log((y == k).sum() / len(y))
        sanoq = mos.sum(axis=0)
        log_ehtimol[k] = np.log((sanoq + alpha) / (sanoq.sum() + alpha * V))
    print(f"  log P(spam) = {log_oldin[1]:.4f}, log P(oddiy) = {log_oldin[0]:.4f}")

    print("\n=== 3. Yangi xatni tasniflash ===")
    yangi = "bepul yutuq hoziroq"
    x = vec.transform([yangi]).toarray()[0]
    ballar = {k: log_oldin[k] + float(x @ log_ehtimol[k]) for k in [0, 1]}
    print(f"  xat: '{yangi}'")
    print(f"  log-ball: oddiy {ballar[0]:.4f}, spam {ballar[1]:.4f}")
    maks = max(ballar.values())
    norm = {k: np.exp(v - maks) for k, v in ballar.items()}
    jami = sum(norm.values())
    print(f"  ehtimollar: oddiy {norm[0] / jami:.4f}, spam {norm[1] / jami:.4f}")

    print("\n=== 4. sklearn bilan tekshirish ===")
    m = MultinomialNB(alpha=1.0).fit(X, y)
    p = m.predict_proba(x.reshape(1, -1))[0]
    print(f"  sklearn ehtimollari: oddiy {p[0]:.4f}, spam {p[1]:.4f}")
    print(f"  qo'lda hisoblangan bilan mos: "
          f"{np.allclose([norm[0] / jami, norm[1] / jami], p)}")
    eng = np.argsort(m.feature_log_prob_[1] - m.feature_log_prob_[0])[::-1][:4]
    print(f"  eng 'spamli' so'zlar: {[sozlar[i] for i in eng]}")
    print("  ⭐ NB — bir necha satr kod va bitta o'tish")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Lug'at ===
  19 ta so'z, 6 ta xat (3 spam, 3 oddiy)

=== 2. Qo'lda hisoblash (alpha = 1) ===
  log P(spam) = -0.6931, log P(oddiy) = -0.6931

=== 3. Yangi xatni tasniflash ===
  xat: 'bepul yutuq hoziroq'
  log-ball: oddiy -11.0904, spam -8.0942
  ehtimollar: oddiy 0.0476, spam 0.9524

=== 4. sklearn bilan tekshirish ===
  sklearn ehtimollari: oddiy 0.0476, spam 0.9524
  qo'lda hisoblangan bilan mos: True
  eng 'spamli' so'zlar: ['bepul', 'chegirma', 'yutuq', 'bosing']
  ⭐ NB — bir necha satr kod va bitta o'tish

Nima ko'rsatdi: 2.1, 2.4-bo'limlar.

Misol 2 — "Sodda" taxmin buzilganda

python
"""Bog'liq belgilar bashoratga va ehtimolga qanday ta'sir qiladi (real numpy/sklearn)."""

import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import brier_score_loss, log_loss, roc_auc_score
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler


def yarat(takror: int, seed: int = 5, n: int = 4000):
    """Bitta ma'noli belgi 'takror' marta nusxalanadi (kuchli bog'liqlik)."""
    rng = np.random.default_rng(seed)
    y = rng.integers(0, 2, n)
    asos = rng.normal(y * 1.2, 1.0, n)
    ustunlar = [asos + rng.normal(0, 0.05, n) for _ in range(takror)]
    shovqin = rng.normal(0, 1, (n, 3))
    X = np.column_stack(ustunlar + [shovqin])
    return X, y


def main() -> None:
    print("=== 1. Nusxalar soni ortganda ===")
    print(f"  {'nusxa':>6} {'NB aniqlik':>11} {'NB AUC':>8} {'NB log-loss':>12} "
          f"{'NB Brier':>9}")
    for takror in [1, 2, 5, 15]:
        X, y = yarat(takror)
        Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0,
                                              stratify=y)
        m = GaussianNB().fit(Xtr, ytr)
        p = m.predict_proba(Xte)[:, 1]
        print(f"  {takror:>6} {(m.predict(Xte) == yte).mean():>11.4f} "
              f"{roc_auc_score(yte, p):>8.4f} {log_loss(yte, p):>12.4f} "
              f"{brier_score_loss(yte, p):>9.4f}")
    print("  (aniqlik va AUC deyarli o'zgarmaydi, ehtimol sifati yomonlashadi)")

    print("\n=== 2. Ehtimollar taqsimoti ===")
    for takror in [1, 15]:
        X, y = yarat(takror)
        Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0,
                                              stratify=y)
        p = GaussianNB().fit(Xtr, ytr).predict_proba(Xte)[:, 1]
        chekka = ((p < 0.01) | (p > 0.99)).mean()
        print(f"  nusxa {takror:>2}: chekka ehtimollar (<0.01 yoki >0.99) ulushi "
              f"{chekka:.1%}, o'rtacha {p.mean():.3f}")

    print("\n=== 3. Logistik regressiya bilan solishtirish ===")
    X, y = yarat(15)
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0,
                                          stratify=y)
    log = Pipeline([("sc", StandardScaler()),
                    ("m", LogisticRegression(max_iter=2000))]).fit(Xtr, ytr)
    nb = GaussianNB().fit(Xtr, ytr)
    for nom, m in [("GaussianNB", nb), ("LogReg", log)]:
        p = m.predict_proba(Xte)[:, 1]
        print(f"  {nom:<11}: aniqlik {(m.predict(Xte) == yte).mean():.4f}, "
              f"AUC {roc_auc_score(yte, p):.4f}, "
              f"log-loss {log_loss(yte, p):.4f}, Brier {brier_score_loss(yte, p):.4f}")

    print("\n=== 4. Kalibrlash egri chizig'i ===")
    from sklearn.calibration import calibration_curve
    p_nb = nb.predict_proba(Xte)[:, 1]
    haqiqiy, bashorat = calibration_curve(yte, p_nb, n_bins=5, strategy="quantile")
    for b, h in zip(bashorat, haqiqiy):
        print(f"  NB bashorat {b:.4f} → haqiqiy ulush {h:.4f}")
    print("  ⭐ Bashorat to'g'ri, ehtimol haddan tashqari ishonchli")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Nusxalar soni ortganda ===
   nusxa  NB aniqlik   NB AUC  NB log-loss  NB Brier
       1      0.7325   0.7982       0.5454    0.1833
       2      0.7275   0.7993       0.6140    0.1952
       5      0.7275   0.7999       1.1042    0.2306
      15      0.7258   0.7997       3.0388    0.2591
  (aniqlik va AUC deyarli o'zgarmaydi, ehtimol sifati yomonlashadi)

=== 2. Ehtimollar taqsimoti ===
  nusxa  1: chekka ehtimollar (<0.01 yoki >0.99) ulushi 0.3%, o'rtacha 0.510
  nusxa 15: chekka ehtimollar (<0.01 yoki >0.99) ulushi 83.7%, o'rtacha 0.519

=== 3. Logistik regressiya bilan solishtirish ===
  GaussianNB : aniqlik 0.7258, AUC 0.7997, log-loss 3.0388, Brier 0.2591
  LogReg     : aniqlik 0.7183, AUC 0.7975, log-loss 0.5462, Brier 0.1837

=== 4. Kalibrlash egri chizig'i ===
  NB bashorat 0.0000 → haqiqiy ulush 0.1375
  NB bashorat 0.0010 → haqiqiy ulush 0.3250
  NB bashorat 0.5959 → haqiqiy ulush 0.5000
  NB bashorat 0.9999 → haqiqiy ulush 0.6958
  NB bashorat 1.0000 → haqiqiy ulush 0.8417
  ⭐ Bashorat to'g'ri, ehtimol haddan tashqari ishonchli

Nima ko'rsatdi: 2.2, 2.6-bo'limlar.

Misol 3 — Uch variant va belgi turi

python
"""GaussianNB, MultinomialNB, BernoulliNB (real numpy/sklearn)."""

import numpy as np
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.naive_bayes import BernoulliNB, GaussianNB, MultinomialNB


def main() -> None:
    rng = np.random.default_rng(8)
    cv = StratifiedKFold(5, shuffle=True, random_state=0)
    n = 3000

    print("=== 1. Uzluksiz belgilar (normal) ===")
    y = rng.integers(0, 2, n)
    X_uzluksiz = rng.normal(y[:, None] * 0.9, 1.0, (n, 6))
    for nom, m in [("GaussianNB", GaussianNB()),
                   ("MultinomialNB", MultinomialNB()),
                   ("BernoulliNB", BernoulliNB())]:
        try:
            # MultinomialNB manfiy qiymat qabul qilmaydi — siljitamiz
            Xi = X_uzluksiz - X_uzluksiz.min() if nom == "MultinomialNB" else X_uzluksiz
            b = cross_val_score(m, Xi, y, cv=cv).mean()
            print(f"  {nom:<14}: CV aniqlik {b:.4f}")
        except ValueError as xato:
            print(f"  {nom:<14}: xato — {xato}")

    print("\n=== 2. Sanoq belgilari (so'z chastotasi) ===")
    y2 = rng.integers(0, 2, n)
    tezlik = np.where(y2[:, None] == 1,
                      np.array([3.0, 0.5, 2.0, 0.4, 1.0, 0.3]),
                      np.array([0.4, 2.5, 0.5, 2.2, 0.8, 1.2]))
    X_sanoq = rng.poisson(tezlik)
    for nom, m in [("GaussianNB", GaussianNB()),
                   ("MultinomialNB", MultinomialNB()),
                   ("BernoulliNB", BernoulliNB())]:
        print(f"  {nom:<14}: CV aniqlik "
              f"{cross_val_score(m, X_sanoq, y2, cv=cv).mean():.4f}")

    print("\n=== 3. Binar belgilar (so'z bor/yo'q) ===")
    X_binar = (X_sanoq > 0).astype(int)
    for nom, m in [("GaussianNB", GaussianNB()),
                   ("MultinomialNB", MultinomialNB()),
                   ("BernoulliNB", BernoulliNB())]:
        print(f"  {nom:<14}: CV aniqlik "
              f"{cross_val_score(m, X_binar, y2, cv=cv).mean():.4f}")

    print("\n=== 4. Qiyshiq belgilar: transformatsiya yordam beradi ===")
    y3 = rng.integers(0, 2, n)
    X_qiyshiq = rng.lognormal(y3[:, None] * 0.5, 1.0, (n, 5))
    print(f"  xom (lognormal)   : CV aniqlik "
          f"{cross_val_score(GaussianNB(), X_qiyshiq, y3, cv=cv).mean():.4f}")
    print(f"  log olingandan keyin: CV aniqlik "
          f"{cross_val_score(GaussianNB(), np.log(X_qiyshiq), y3, cv=cv).mean():.4f}")
    print("  ⭐ Variantni belgi turiga moslang, taqsimotni tekshiring")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Uzluksiz belgilar (normal) ===
  GaussianNB    : CV aniqlik 0.8697
  MultinomialNB : CV aniqlik 0.5053
  BernoulliNB   : CV aniqlik 0.7903

=== 2. Sanoq belgilari (so'z chastotasi) ===
  GaussianNB    : CV aniqlik 0.9607
  MultinomialNB : CV aniqlik 0.9630
  BernoulliNB   : CV aniqlik 0.9137

=== 3. Binar belgilar (so'z bor/yo'q) ===
  GaussianNB    : CV aniqlik 0.9107
  MultinomialNB : CV aniqlik 0.9133
  BernoulliNB   : CV aniqlik 0.9137

=== 4. Qiyshiq belgilar: transformatsiya yordam beradi ===
  xom (lognormal)   : CV aniqlik 0.6057
  log olingandan keyin: CV aniqlik 0.7063
  ⭐ Variantni belgi turiga moslang, taqsimotni tekshiring

Nima ko'rsatdi: 2.3-bo'lim.

Misol 4 — Matn tasniflash: NB va boshqalar

python
"""Matn tasniflash: NB, LogReg va chiziqli SVM (real sklearn)."""

import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, f1_score
from sklearn.model_selection import GridSearchCV, StratifiedKFold
from sklearn.naive_bayes import ComplementNB, MultinomialNB
from sklearn.pipeline import Pipeline
from sklearn.svm import LinearSVC

LUGAT = {
    0: ["kosmos", "raketa", "orbita", "yulduz", "sayyora", "modul", "teleskop"],
    1: ["mashina", "dvigatel", "gildirak", "tezlik", "yoqilgi", "salon", "tormoz"],
    2: ["siyosat", "hukumat", "saylov", "qonun", "parlament", "vazir", "byudjet"],
    3: ["grafika", "piksel", "render", "ekran", "rang", "kadr", "soya"],
}
UMUMIY = ["va", "bu", "uchun", "bilan", "juda", "ham", "lekin", "keyin",
          "tizim", "loyiha", "tahlil", "natija", "sinov", "guruh"]


def yarat(n: int, seed: int):
    """Har hujjat: 4 ta mavzu so'zi, 12 ta umumiy, 9 ta CHALKASHTIRUVCHI

    (chalkashtiruvchilar tasodifiy mavzulardan — vazifani qiyinlashtiradi).
    """
    rng = np.random.default_rng(seed)
    matnlar, yorliqlar = [], []
    for _ in range(n):
        k = int(rng.integers(0, 4))
        sozlar = list(rng.choice(LUGAT[k], 4))
        sozlar += list(rng.choice(UMUMIY, 12))
        for _ in range(9):
            boshqa = int(rng.integers(0, 4))
            sozlar.append(str(rng.choice(LUGAT[boshqa])))
        rng.shuffle(sozlar)
        matnlar.append(" ".join(sozlar))
        yorliqlar.append(k)
    return matnlar, np.array(yorliqlar)


def main() -> None:
    tr_matn, ytr = yarat(2400, seed=1)
    te_matn, yte = yarat(1200, seed=2)

    print("=== 1. Ma'lumot ===")
    print(f"  o'quv {len(tr_matn)}, test {len(te_matn)}, "
          f"{len(np.unique(ytr))} kategoriya")
    print(f"  namuna hujjat: '{tr_matn[0][:60]}...'")

    print("\n=== 2. Modellar ===")
    modellar = {
        "MultinomialNB": MultinomialNB(alpha=0.1),
        "ComplementNB": ComplementNB(alpha=0.1),
        "LogReg": LogisticRegression(max_iter=2000, C=5.0),
        "LinearSVC": LinearSVC(C=1.0, max_iter=10_000),
    }
    for nom, m in modellar.items():
        quvur = Pipeline([("vec", TfidfVectorizer(min_df=2)), ("m", m)])
        quvur.fit(tr_matn, ytr)
        pred = quvur.predict(te_matn)
        lugat = len(quvur.named_steps["vec"].get_feature_names_out())
        print(f"  {nom:<14}: aniqlik {accuracy_score(yte, pred):.4f}, "
              f"F1 macro {f1_score(yte, pred, average='macro'):.4f}, "
              f"lug'at {lugat}")

    print("\n=== 3. alpha ni sozlash ===")
    quvur = Pipeline([("vec", TfidfVectorizer(min_df=2)), ("m", MultinomialNB())])
    qidiruv = GridSearchCV(quvur, {"m__alpha": [0.01, 0.05, 0.1, 0.5, 1.0]},
                           cv=StratifiedKFold(3, shuffle=True, random_state=0),
                           scoring="f1_macro").fit(tr_matn, ytr)
    print(f"  eng yaxshi alpha = {qidiruv.best_params_['m__alpha']}")
    print(f"  CV F1 macro = {qidiruv.best_score_:.4f}")
    print(f"  test F1 macro = "
          f"{f1_score(yte, qidiruv.predict(te_matn), average='macro'):.4f}")

    print("\n=== 4. Har sinf uchun eng ma'noli so'zlar ===")
    eng_model = qidiruv.best_estimator_
    sozlar = eng_model.named_steps["vec"].get_feature_names_out()
    nb = eng_model.named_steps["m"]
    for k in range(3):
        farq = nb.feature_log_prob_[k] - nb.feature_log_prob_.mean(axis=0)
        top = np.argsort(farq)[::-1][:5]
        print(f"  sinf {k}: {[sozlar[i] for i in top]}")
    print("  ⭐ NB — matn uchun eng tez va tushunarli baza")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Ma'lumot ===
  o'quv 2400, test 1200, 4 kategoriya
  namuna hujjat: 'tormoz tezlik juda sinov bilan loyiha salon tormoz mashina h...'

=== 2. Modellar ===
  MultinomialNB : aniqlik 0.9117, F1 macro 0.9116, lug'at 42
  ComplementNB  : aniqlik 0.9117, F1 macro 0.9115, lug'at 42
  LogReg        : aniqlik 0.9108, F1 macro 0.9106, lug'at 42
  LinearSVC     : aniqlik 0.9125, F1 macro 0.9124, lug'at 42

=== 3. alpha ni sozlash ===
  eng yaxshi alpha = 0.5
  CV F1 macro = 0.9097
  test F1 macro = 0.9107

=== 4. Har sinf uchun eng ma'noli so'zlar ===
  sinf 0: ['teleskop', 'kosmos', 'orbita', 'modul', 'yulduz']
  sinf 1: ['tezlik', 'salon', 'dvigatel', 'yoqilgi', 'tormoz']
  sinf 2: ['qonun', 'hukumat', 'parlament', 'byudjet', 'vazir']
  ⭐ NB — matn uchun eng tez va tushunarli baza

Nima ko'rsatdi: 2.5-bo'lim.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"Taxmin noto'g'ri — model yaroqsiz" Bashorat baribir yaxshi
"predict_proba — haqiqiy ehtimol" Kalibrlanmagan
"Bitta NB varianti bor" Belgi turiga qarab uchta
"Silliqlash ixtiyoriy" Majburiy
"alpha ni sozlash kerak emas" CV bilan sezilarli foyda
"NB eskirgan" Matnda hali ham baza
"NB har qanday belgi bilan" Taqsimot muhim
"NB sekin" Eng tez klassifikator

6. Keng tarqalgan xatolar va yechimlari

1. Noto'g'ri variant

python
GaussianNB().fit(tfidf_matritsa, y)                               # ⚠️
MultinomialNB(alpha=0.1).fit(tfidf_matritsa, y)                   # ✅

2. Silliqlashsiz

python
MultinomialNB(alpha=0.0)                                          # ⚠️
MultinomialNB(alpha=0.1)                                          # ✅

3. Ehtimolni qaror formulasiga kiritish

python
foyda = nb.predict_proba(X)[:, 1] * LTV - narx                    # ⚠️
CalibratedClassifierCV(nb, method="sigmoid", cv=5)   # 14.10      # ✅

4. Qiyshiq belgilar bilan GaussianNB

python
GaussianNB().fit(X_lognormal, y)                                  # ⚠️
GaussianNB().fit(np.log(X_lognormal), y)                          # ✅

5. alpha ni sozlamaslik

python
MultinomialNB()                        # alpha = 1.0              # ⚠️
GridSearchCV(pipe, {"m__alpha": [0.01, 0.05, 0.1, 0.5, 1]}, cv=5) # ✅

6. Matnda vektorizatorni sozlamaslik

python
TfidfVectorizer()                                                 # ⚠️
TfidfVectorizer(min_df=2, ngram_range=(1, 2))                     # ✅

7. Vektorizator pipeline'dan tashqarida

python
X = TfidfVectorizer().fit_transform(hamma_matn)   # leakage       # ⚠️
Pipeline([("vec", TfidfVectorizer()), ("m", MultinomialNB())])    # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 9-qism (o'tilgan): Bayes formulasi va ehtimol
  • 12.9-dars (o'tilgan): Pipeline va leakage
  • 14.1-dars (o'tilgan): Generativ modellar
  • 14.10-dars: Kalibrlash
  • 14.11-dars: Matn klassifikatsiyasi

8. Eng yaxshi amaliyotlar

  1. Variantni belgi turiga moslang.

  2. alpha ni CV bilan tanlang.

  3. Matnda pipeline ichida vektorlashtiring.

  4. Ehtimolni kalibrlang (kerak bo'lsa).

  5. Qiyshiq belgilarni transformatsiya qiling.

  6. NB ni baza sifatida ishlating.

  7. ComplementNB ni nomutanosib to'plamda sinang.

  8. Eng ma'noli belgilarni ko'ring.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # Bayes formulasi?
2.  # "naive" taxmin nima?
3.  # nega bu taxmin kerak?
4.  # nega noto'g'ri taxmin ishlaydi?
5.  # uch variant?
6.  # matn uchun qaysi biri?
7.  # silliqlash nima uchun?
8.  # alpha = 0 bo'lsa?
9.  # NB ehtimollari qanday?
10. # kalibrlash qanday qilinadi?
11. # NB ning asosiy afzalligi?
12. # ComplementNB qachon?
Javoblar
  1. P(y|x) = P(x|y)P(y)/P(x)
  2. Belgilar sinf ichida mustaqil
  3. 2^p o'rniga p parametr
  4. argmax to'g'ri chiqadi
  5. Gaussian, Multinomial, Bernoulli
  6. Multinomial (yoki Bernoulli)
  7. Ko'rilmagan belgi nolga tushirmasligi uchun
  8. Bitta yangi so'z bashoratni buzadi
  9. Haddan tashqari ishonchli
  10. CalibratedClassifierCV
  11. Tezlik va soddalik
  12. Nomutanosib matn to'plamlarida

Vazifa 2: Xatolarni tuzating

python
1.  GaussianNB().fit(tfidf, y)

2.  MultinomialNB(alpha=0.0)

3.  foyda = nb.predict_proba(X)[:, 1] * 500000

4.  GaussianNB().fit(daromad_ustuni, y)   # lognormal

5.  X = TfidfVectorizer().fit_transform(hammasi); cross_val_score(nb, X, y)
Javoblar
python
1.  MultinomialNB(alpha=0.1).fit(tfidf, y)

2.  MultinomialNB(alpha=0.1)

3.  CalibratedClassifierCV(nb, method="sigmoid", cv=5)

4.  GaussianNB().fit(np.log(daromad_ustuni), y)

5.  Pipeline([("vec", TfidfVectorizer()), ("m", nb)])

Vazifa 3: Qo'lda NB

Modellang:

  1. Kichik matn to'plami
  2. Qo'lda hisoblash
  3. sklearn bilan tekshirish
  4. Eng ma'noli so'zlar

Vazifa 4: Taxmin buzilishi

Modellang:

  1. Nusxalangan belgilar
  2. Aniqlik va ehtimol
  3. Kalibrlash egri chizig'i
  4. Xulosa

Vazifa 5: Variantlar

Modellang:

  1. Uch xil belgi turi
  2. Uch variant
  3. Taqqoslash
  4. Tavsiya

Vazifa 6: Matn

Modellang:

  1. TF-IDF pipeline
  2. NB va boshqalar
  3. alpha sozlash
  4. Tezlik

Vazifa 7: O'ylash

Naive Bayes ning taxmini deyarli har doim buzilgan bo'lsa ham, u o'nlab yillar davomida amaliyotda qoladi. "Noto'g'ri, lekin foydali" modellar haqida bu bizga nima deydi?

Javob

Qisqa javob: model taxminlarining to'g'riligi bilan emas, qarorning to'g'riligi bilan baholanadi. Naive Bayes — "barcha modellar noto'g'ri, ba'zilari foydali" tamoyilining eng toza namunasi.

1. Nega noto'g'ri taxmin ishlaydi

  • Klassifikatsiya uchun argmax yetarli, aniq ehtimol emas
  • Bog'liqlik ko'pincha barcha sinflarga bir xil ta'sir qiladi va tartibni buzmaydi
  • Kuchli taxmin = kuchli regularizatsiya: kam ma'lumotda variance kamayadi (12.5)

2. Qayerda buziladi

Vazifa NB mosmi
Yorliq bashorat Ha
Reyting (AUC) Odatda ha
Ehtimol (narx formulasi) Yo'q — kalibrlash kerak
Koeffitsiyent talqini Ehtiyot bilan

3. Umumiy saboq

  • Taxminlarni tekshirish kerak, lekin maqsad kontekstida (13.4 bilan bir xil mantiq)
  • Soddalashtirish — kamchilik emas, almashinuv: bias ↑, variance ↓
  • Modelni baholash mezoni — CV va biznes metrikasi, taxminlar ro'yxati emas

4. Amaliy tavsiya

  1. NB ni baza sifatida ishlating (ayniqsa matnda)
  2. Ehtimol kerak bo'lsa kalibrlang
  3. Murakkab model NB ni sezilarli yengmasa — NB ni qoldiring
  4. Taxmin buzilishini natija orqali o'lchang

5. Xulosa

  1. Barcha modellar noto'g'ri
  2. Foydalilik — qarorda
  3. Sodda taxmin — regularizatsiya shakli
  4. Baholash mezonini aralashtirmang

Nimani mustahkamlaydi: 2.2, 2.6-bo'limlar.


Xulosa

Bu darsda Naive Bayes ni o'rgandik.

Eng muhim uch fikr:

  1. Bayes + mustaqillik taxmini. argmax_k P(y=k) · prod_j P(x_j | y=k) — ko'p o'lchovli taqsimot o'rniga p ta bir o'lchovli taqsimot yetarli bo'ladi. Amalda ehtimollar logarifmda yig'iladi. Taxmin deyarli har doim buzilgan, lekin argmax to'g'ri chiqadi.

  2. Bashorat to'g'ri, ehtimol kalibrlanmagan. Bog'liq belgilar "dalilni bir necha marta sanaydi", shuning uchun NB ehtimollari 0 yoki 1 ga siljiydi: aniqlik va AUC yaxshi qoladi, log-loss va Brier yomonlashadi. Ehtimol kerak bo'lsa — CalibratedClassifierCV 14.10-bob.

  3. Variant belgi turidan kelib chiqadi. GaussianNB (uzluksiz, taqsimot normal bo'lsa yoki log bilan tuzatilsa), MultinomialNB (sanoq/TF-IDF — matn uchun standart), BernoulliNB (binar). Silliqlash (alpha) majburiy va CV bilan tanlanadi. NB — eng tez klassifikator: matn vazifalarida u har doim birinchi baza bo'lishga arziydi.

Keyingi darsda LDA va QDAni o'rganamiz: normal taqsimotga asoslangan generativ modellar, chiziqli va kvadratik chegaralar, o'lchamni kamaytirish uchun LDA.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
14.3-dars: Naive Bayes — IlmHamroh