IlmHamroh
Data Science va sun'iy intellekt/Nazoratsiz organish10/12-dars20 daqiqa
Mundarija (22)

16.10-dars: Anomaliya aniqlash

16-QISM — NAZORATSIZ O'RGANISH · 10-dars


1. Kirish va motivatsiya

Firibgar tranzaksiya, ishdan chiqayotgan uskuna, tarmoq hujumi, ma'lumot bazasidagi buzilgan yozuv — bularning hammasi anomaliya: qolganlardan tubdan farq qiladigan kuzatuvlar. Ularni topish nazoratsiz o'rganishning eng amaliy qo'llanilishi.

Nima uchun bu klassifikatsiya emas? Uchta sabab: anomaliyalar kam (0.1-2%), ular xilma-xil (har biri o'zicha g'alati) va eng muhimi — yorliq yo'q yoki juda kech keladi. Firibgarlik uch oydan keyin ma'lum bo'ladi, model esa bugun kerak.

Bu darsda: anomaliya turlari, Isolation Forest (izolyatsiya g'oyasi), LOF (mahalliy zichlik), One-Class SVM, zichlikka asoslangan usullar (GMM, PCA qayta tiklash xatosi), contamination ni tanlash va yorliqsiz baholash.

Real vaziyat. To'lov tizimida firibgarlikni aniqlash uchun qoidalar yozilgan edi: "summa > 5 mln" va "kechasi". Isolation Forest esa kombinatsiyalarni topdi — kichik summa, lekin g'ayrioddiy vaqt va yangi qurilma. Qoidalar 41% firibgarlikni topgan bo'lsa, model 78% ini topdi, noto'g'ri ogohlantirishlar soni esa o'zgarmadi.

Bu darsda anomaliya aniqlashni o'rganamiz.

Bu darsda:

  • Anomaliya turlari
  • Isolation Forest
  • LOF va mahalliy zichlik
  • One-Class SVM
  • Zichlik va qayta tiklash
  • contamination va baholash
  • Tuzoqlar
  • Amaliy: tranzaksiyalar

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


2. Nazariya — chuqur tushuntirish

2.1. Anomaliya turlari

text
1. NUQTAVIY (point): alohida kuzatuv g'ayrioddiy
   misol: 50 mln so'mlik tranzaksiya (odatda 200 ming)
   eng ko'p uchraydigan tur

2. KONTEKSTUAL (contextual): kontekstda g'ayrioddiy
   misol: yozda 40 daraja - normal; qishda 40 daraja - anomaliya
   kontekst belgilarini modelga qo'shish kerak

3. JAMOAVIY (collective): alohida normal, birga g'ayrioddiy
   misol: 100 ta kichik tranzaksiya bir daqiqada
   agregatsiya va vaqt oynalari kerak

BUNDAN TASHQARI:
  novelty detection - toza ma'lumotda o'qitib, YANGI turdagi nuqtani topish
  outlier detection - ma'lumotning o'zida anomaliya bor deb faraz qilish

Kontekstual va jamoaviy anomaliyalar belgi muhandisligini talab qiladi: algoritm o'zi kontekstni bilmaydi. "Oxirgi 1 soatdagi tranzaksiyalar soni" kabi belgilar ularni nuqtaviy anomaliyaga aylantiradi.

2.2. Isolation Forest

text
G'OYA: anomaliyani IZOLYATSIYA qilish oson

  tasodifiy belgi va tasodifiy chegara bilan ma'lumotni bo'lamiz
  anomaliya kam bo'linishdan keyin ajraladi (daraxtda SAYOZ)
  normal nuqta ko'p bo'linish talab qiladi (CHUQUR)

  ball = o'rtacha yo'l uzunligiga asoslangan (0..1, katta = anomaliyaroq)

AFZALLIKLARI:
  + masshtablash KERAK EMAS (daraxtga asoslangan)
  + chiziqli murakkablik, katta ma'lumotda tez
  + yuqori o'lchamda yaxshi ishlaydi
  + predict va decision_function bor

KAMCHILIK: mahalliy anomaliyalarni (zich klaster chetidagi) yomon topadi

Masshtablash kerak emasligi — Isolation Forest ning katta amaliy afzalligi: u aralash birliklardagi ma'lumotda to'g'ridan-to'g'ri ishlaydi va odatiy birinchi tanlov bo'ladi.

2.3. LOF va mahalliy zichlik

text
LOF (Local Outlier Factor): nuqtaning zichligini QO'SHNILARINIKI bilan taqqoslaydi

  LOF ~ 1   - qo'shnilar bilan bir xil zichlikda (normal)
  LOF >> 1  - qo'shnilaridan siyrakroq joyda (anomaliya)

NEGA MAHALLIY: global zichlik chalg'itishi mumkin
  zich klaster chetidagi nuqta global jihatdan normal, mahalliy jihatdan anomaliya

sklearn:
  LocalOutlierFactor(n_neighbors=20)           # fit_predict, novelty=False
  LocalOutlierFactor(n_neighbors=20, novelty=True)   # predict bor, fit da anomaliya yo'q

MASSHTABLASH MAJBURIY (masofaga asoslangan)

novelty=False (standart) da predict yo'q — faqat fit_predict. Yangi nuqtalarni baholash kerak bo'lsa, novelty=True qo'ying va toza ma'lumotda o'qiting.

2.4. One-Class SVM

text
G'OYA: ma'lumotni o'rab oladigan eng kichik chegarani topish 14.5-bob

  nu       - anomaliyalar ulushining yuqori chegarasi (0..1)
  gamma    - RBF yadrosi kengligi
  kernel   - odatda "rbf"

AFZALLIK: moslashuvchan, murakkab shakllarni o'rab oladi
KAMCHILIK:
  - O(n^2) .. O(n^3) - katta ma'lumotda sekin
  - gamma va nu ga juda sezgir
  - masshtablash majburiy

SGDOneClassSVM - chiziqli yaqinlashish, katta ma'lumot uchun tez

One-Class SVM parametrlarga juda sezgir va sekin — amalda u Isolation Forest va LOF dan kamroq ishlatiladi. Uni kichik, toza va murakkab shaklli ma'lumotlarda sinab ko'ring.

2.5. Zichlik va qayta tiklash

python
# 1. GMM zichligi (16.6)
g = GaussianMixture(n_components=5).fit(Xs)
ball = -g.score_samples(Xs)          # past zichlik -> anomaliya

# 2. PCA qayta tiklash xatosi
p = PCA(n_components=10).fit(Xs)
xato = ((Xs - p.inverse_transform(p.transform(Xs))) ** 2).sum(axis=1)

# 3. EllipticEnvelope - Gauss taxmini, Mahalanobis masofasi
EllipticEnvelope(contamination=0.02, support_fraction=0.9)

# 4. KNN masofasi - k-chi qo'shnigacha masofa

PCA qayta tiklash xatosi — sodda va samarali usul: agar nuqta asosiy komponentlar bilan yomon tiklansa, u umumiy tuzilmaga mos kelmaydi. Bu autoencoder asosidagi zamonaviy usullarning chiziqli ko'rinishi.

2.6. contamination va baholash

text
contamination - kutilayotgan anomaliyalar ulushi
  "auto" (Isolation Forest) yoki aniq son (0.01, 0.05)
  faqat CHEGARAni belgilaydi, ballarni emas

  -> decision_function / score_samples ballari contamination ga bog'liq emas
  -> chegarani keyin ham o'zgartirish mumkin

BAHOLASH (yorliqsiz):
  1. ballar taqsimoti - aniq "dum" bormi
  2. eng yuqori ballilarni QO'LDA ko'rib chiqish
  3. turli usullar KELISHUVI (bir xil nuqtalarni belgilaydimi)
  4. barqarorlik (bootstrap)

BAHOLASH (ozgina yorliq bo'lsa):
  ROC AUC, PR AUC 14.9-bob - nomutanosiblik tufayli PR AUC afzalroq
  precision@k - eng yuqori k ta orasida nechtasi haqiqiy

precision@k — amaliy eng foydali metrika: tekshiruvchilar kuniga 50 ta hodisani ko'ra oladi, demak muhimi "eng yuqori 50 ta orasida nechtasi haqiqiy" degan savol.

2.7. Tuzoqlar

Asosiy tuzoqlar: LOF va One-Class SVM ni masshtablamasdan ishlatish; contamination ni haqiqiy ulushdan katta qo'yish; LocalOutlierFactor da novelty ni unutish; anomaliyalarni avtomatik o'chirish (ular eng qimmatli ma'lumot bo'lishi mumkin); kontekstual anomaliyani belgi qo'shmasdan topishga urinish; accuracy bilan baholash (99% anomaliyasiz ham chiqadi); bitta usulga tayanish; yorliq bo'lsa ham nazoratsiz usulda qolish.

2.8. Kam, xilma-xil, yorliqsiz

Anomaliya aniqlash kam uchraydigan, xilma-xil va ko'pincha yorliqsiz hodisalarni topadi. Isolation Forest — odatiy birinchi tanlov (masshtablash kerak emas, tez, yuqori o'lchamda ishlaydi), LOF mahalliy zichlikni ko'radi, One-Class SVM moslashuvchan lekin sekin, PCA qayta tiklash xatosi va GMM zichligi esa sodda muqobillar. contamination faqat chegarani belgilaydi. Baholashda PR AUC va precision@k ishlating. Keyingi dars — qo'llanilishi.


3. Tez ma'lumotnoma

python
import numpy as np
from sklearn.covariance import EllipticEnvelope
from sklearn.decomposition import PCA
from sklearn.ensemble import IsolationForest
from sklearn.neighbors import LocalOutlierFactor
from sklearn.svm import OneClassSVM

izo = IsolationForest(contamination=0.02, n_estimators=200,
                      random_state=0, n_jobs=-1).fit(X)   # masshtablash shart emas
izo.predict(X)                  # -1 = anomaliya
-izo.score_samples(X)           # katta = anomaliyaroq

lof = LocalOutlierFactor(n_neighbors=20, contamination=0.02)
yorliq = lof.fit_predict(Xs)    # masshtablang!
-lof.negative_outlier_factor_

LocalOutlierFactor(n_neighbors=20, novelty=True)   # predict uchun
OneClassSVM(kernel="rbf", nu=0.02, gamma="scale")
EllipticEnvelope(contamination=0.02, support_fraction=0.9)
QOIDA: IF dan boshla · LOF/SVM uchun masshtabla · PR AUC bilan bahola ·
       anomaliyalarni ko'rib chiq

Anomaliya xulosasi

Turlari: nuqtaviy, kontekstual, jamoaviy
IsolationForest: izolyatsiya, masshtabsiz, tez - birinchi tanlov
LOF: mahalliy zichlik; OneClassSVM: moslashuvchan lekin sekin
contamination faqat chegara; baholash PR AUC va precision@k

4. Batafsil misollar

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

Misol 1 — To'rt usulni taqqoslash

python
"""Isolation Forest, LOF, One-Class SVM va EllipticEnvelope (real sklearn)."""

import numpy as np
from sklearn.covariance import EllipticEnvelope
from sklearn.datasets import make_blobs, make_moons
from sklearn.ensemble import IsolationForest
from sklearn.metrics import average_precision_score, roc_auc_score
from sklearn.neighbors import LocalOutlierFactor
from sklearn.preprocessing import StandardScaler
from sklearn.svm import OneClassSVM


def global_anomaliya(seed: int = 0, n: int = 1000, ulush: float = 0.03):
    rng = np.random.default_rng(seed)
    X, _ = make_blobs(n_samples=n, centers=3, cluster_std=0.8,
                      random_state=seed)
    k = int(n * ulush)
    anomaliya = rng.uniform(X.min() - 6, X.max() + 6, (k, 2))
    return (np.vstack([X, anomaliya]),
            np.concatenate([np.zeros(n), np.ones(k)]).astype(int))


def mahalliy_anomaliya(seed: int = 0):
    """Zich klaster chetidagi nuqtalar - global jihatdan normal."""
    rng = np.random.default_rng(seed)
    zich = rng.normal([0, 0], 0.3, (600, 2))
    siyrak = rng.normal([5, 5], 1.5, (400, 2))
    # zich klaster chetidagi anomaliyalar
    burchak = rng.uniform(0, 2 * np.pi, 25)
    chekka = np.column_stack([1.3 * np.cos(burchak), 1.3 * np.sin(burchak)])
    X = np.vstack([zich, siyrak, chekka])
    y = np.concatenate([np.zeros(1000), np.ones(25)]).astype(int)
    return X, y


def egri_anomaliya(seed: int = 0):
    X, _ = make_moons(n_samples=800, noise=0.05, random_state=seed)
    rng = np.random.default_rng(seed)
    anomaliya = rng.uniform(-1.5, 2.5, (25, 2))
    return (np.vstack([X, anomaliya]),
            np.concatenate([np.zeros(800), np.ones(25)]).astype(int))


def main() -> None:
    vazifalar = {
        "global": global_anomaliya(),
        "mahalliy": mahalliy_anomaliya(),
        "egri shakl": egri_anomaliya(),
    }

    print("=== 1. ROC AUC bo'yicha ===")
    print(f"  {'vazifa':<12} {'IsoForest':>11} {'LOF':>9} {'OC-SVM':>9} "
          f"{'Elliptic':>10}")
    for nom, (X, y) in vazifalar.items():
        Xs = StandardScaler().fit_transform(X)
        ballar = {}
        ballar["IsoForest"] = -IsolationForest(
            contamination=0.03, n_estimators=200, random_state=0,
            n_jobs=1).fit(X).score_samples(X)
        lof = LocalOutlierFactor(n_neighbors=20)
        lof.fit_predict(Xs)
        ballar["LOF"] = -lof.negative_outlier_factor_
        ballar["OC-SVM"] = -OneClassSVM(nu=0.03, gamma="scale").fit(
            Xs).score_samples(Xs)
        ballar["Elliptic"] = -EllipticEnvelope(
            contamination=0.03, support_fraction=0.9,
            random_state=0).fit(Xs).score_samples(Xs)
        print(f"  {nom:<12} " + "".join(
            f"{roc_auc_score(y, ballar[k]):>11.4f}" if k == "IsoForest"
            else f"{roc_auc_score(y, ballar[k]):>{9 if k != 'Elliptic' else 10}.4f}"
            for k in ["IsoForest", "LOF", "OC-SVM", "Elliptic"]))

    print("\n=== 2. PR AUC (nomutanosiblikda ishonchliroq) ===")
    print(f"  {'vazifa':<12} {'musbat %':>10} {'IsoForest':>11} {'LOF':>9}")
    for nom, (X, y) in vazifalar.items():
        Xs = StandardScaler().fit_transform(X)
        b1 = -IsolationForest(contamination=0.03, n_estimators=200,
                              random_state=0, n_jobs=1).fit(X).score_samples(X)
        lof = LocalOutlierFactor(n_neighbors=20)
        lof.fit_predict(Xs)
        b2 = -lof.negative_outlier_factor_
        print(f"  {nom:<12} {y.mean():>9.2%} "
              f"{average_precision_score(y, b1):>11.4f} "
              f"{average_precision_score(y, b2):>9.4f}")

    print("\n=== 3. Mahalliy anomaliyada LOF ustunligi ===")
    X, y = mahalliy_anomaliya()
    Xs = StandardScaler().fit_transform(X)
    izo_ball = -IsolationForest(contamination=0.025, n_estimators=200,
                                random_state=0, n_jobs=1).fit(X).score_samples(X)
    lof = LocalOutlierFactor(n_neighbors=20)
    lof.fit_predict(Xs)
    lof_ball = -lof.negative_outlier_factor_
    print(f"  {'k':>5} {'IsoForest precision@k':>23} {'LOF precision@k':>18}")
    for k in [10, 25, 50, 100]:
        i1 = np.argsort(-izo_ball)[:k]
        i2 = np.argsort(-lof_ball)[:k]
        print(f"  {k:>5} {y[i1].mean():>22.1%} {y[i2].mean():>17.1%}")

    print("\n=== 4. Masshtablashning ta'siri ===")
    X, y = global_anomaliya()
    X2 = X.copy()
    X2[:, 0] *= 500                      # bitta belgining birligi o'zgardi
    print(f"  {'usul':<12} {'asl birlik':>12} {'500x birlik':>13}")
    for nom in ["IsoForest", "LOF"]:
        qator = []
        for Xa in [X, X2]:
            if nom == "IsoForest":
                b = -IsolationForest(contamination=0.03, n_estimators=200,
                                     random_state=0,
                                     n_jobs=1).fit(Xa).score_samples(Xa)
            else:
                lof = LocalOutlierFactor(n_neighbors=20)
                lof.fit_predict(Xa)
                b = -lof.negative_outlier_factor_
            qator.append(roc_auc_score(y, b))
        print(f"  {nom:<12} {qator[0]:>12.4f} {qator[1]:>13.4f}")
    print("  ⭐ Isolation Forest masshtablashsiz ham ishlaydi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. ROC AUC bo'yicha ===
  vazifa         IsoForest       LOF    OC-SVM   Elliptic
  global            1.0000   0.9999   0.9147    1.0000
  mahalliy          0.9426   0.9975   0.8934    0.6378
  egri shakl        0.8753   0.9918   0.7549    0.7635

=== 2. PR AUC (nomutanosiblikda ishonchliroq) ===
  vazifa         musbat %   IsoForest       LOF
  global           2.91%      0.9989    0.9978
  mahalliy         2.44%      0.1802    0.8859
  egri shakl       3.03%      0.7104    0.9179

=== 3. Mahalliy anomaliyada LOF ustunligi ===
      k   IsoForest precision@k    LOF precision@k
     10                   0.0%             90.0%
     25                   8.0%             80.0%
     50                  20.0%             50.0%
    100                  17.0%             25.0%

=== 4. Masshtablashning ta'siri ===
  usul           asl birlik   500x birlik
  IsoForest          1.0000        1.0000
  LOF                0.9999        0.8884
  ⭐ Isolation Forest masshtablashsiz ham ishlaydi

Nima ko'rsatdi: 2.2, 2.3, 2.4-bo'limlar.

Misol 2 — Isolation Forest ichkarisi

python
"""Izolyatsiya g'oyasi va parametrlar (real numpy/sklearn)."""

import numpy as np
from sklearn.ensemble import IsolationForest
from sklearn.metrics import average_precision_score, roc_auc_score


def yarat(seed: int = 5, n: int = 2000, p: int = 8, ulush: float = 0.02):
    rng = np.random.default_rng(seed)
    X = rng.normal(0, 1, (n, p))
    k = int(n * ulush)
    anomaliya = rng.normal(0, 1, (k, p))
    # bir nechta belgida g'ayrioddiy
    for i in range(k):
        nechta = min(3, p)
        belgilar = rng.choice(p, nechta, replace=False)
        anomaliya[i, belgilar] += (rng.choice([-1, 1], nechta)
                                   * rng.uniform(4, 7, nechta))
    return (np.vstack([X, anomaliya]),
            np.concatenate([np.zeros(n), np.ones(k)]).astype(int))


def main() -> None:
    X, y = yarat()

    print("=== 1. Yo'l uzunligi va anomaliya bali ===")
    izo = IsolationForest(contamination=0.02, n_estimators=200,
                          random_state=0, n_jobs=1).fit(X)
    ball = -izo.score_samples(X)
    print(f"  normal nuqtalar bali: o'rtacha {ball[y == 0].mean():.4f}, "
          f"std {ball[y == 0].std():.4f}")
    print(f"  anomaliyalar bali:    o'rtacha {ball[y == 1].mean():.4f}, "
          f"std {ball[y == 1].std():.4f}")
    print(f"  ROC AUC: {roc_auc_score(y, ball):.4f}")
    print(f"  PR AUC:  {average_precision_score(y, ball):.4f}")

    print("\n=== 2. n_estimators va max_samples ===")
    print(f"  {'n_est':>7} {'max_samples':>13} {'ROC AUC':>10} {'PR AUC':>9}")
    for ne in [20, 50, 100, 300]:
        for ms in [64, 256]:
            m = IsolationForest(n_estimators=ne, max_samples=ms,
                                contamination=0.02, random_state=0,
                                n_jobs=1).fit(X)
            b = -m.score_samples(X)
            print(f"  {ne:>7} {ms:>13} {roc_auc_score(y, b):>10.4f} "
                  f"{average_precision_score(y, b):>9.4f}")

    print("\n=== 3. contamination faqat chegarani belgilaydi ===")
    ballar = {}
    for c in [0.01, 0.02, 0.05, 0.10]:
        m = IsolationForest(contamination=c, n_estimators=200,
                            random_state=0, n_jobs=1).fit(X)
        ballar[c] = -m.score_samples(X)
        belgilangan = (m.predict(X) == -1)
        print(f"  contamination={c:<5}: belgilangan {belgilangan.mean():>6.2%}, "
              f"ROC AUC {roc_auc_score(y, ballar[c]):.4f}")
    juft = list(ballar)
    print(f"  ballar bir xilmi (0.01 va 0.10): "
          f"{np.allclose(ballar[juft[0]], ballar[juft[-1]])}")

    print("\n=== 4. Belgilar soni ortganda ===")
    print(f"  {'p':>4} {'ROC AUC':>10} {'PR AUC':>9}")
    for p in [2, 5, 10, 30, 100]:
        Xp, yp = yarat(p=p)
        m = IsolationForest(contamination=0.02, n_estimators=200,
                            random_state=0, n_jobs=1).fit(Xp)
        b = -m.score_samples(Xp)
        print(f"  {p:>4} {roc_auc_score(yp, b):>10.4f} "
              f"{average_precision_score(yp, b):>9.4f}")
    print("  ⭐ contamination ballarni emas, chegarani belgilaydi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Yo'l uzunligi va anomaliya bali ===
  normal nuqtalar bali: o'rtacha 0.4106, std 0.0306
  anomaliyalar bali:    o'rtacha 0.6046, std 0.0225
  ROC AUC: 1.0000
  PR AUC:  0.9981

=== 2. n_estimators va max_samples ===
    n_est   max_samples    ROC AUC    PR AUC
       20            64     0.9874    0.6910
       20           256     0.9951    0.9071
       50            64     0.9922    0.7408
       50           256     0.9998    0.9888
      100            64     0.9960    0.8326
      100           256     0.9999    0.9969
      300            64     0.9982    0.8963
      300           256     1.0000    0.9994

=== 3. contamination faqat chegarani belgilaydi ===
  contamination=0.01 : belgilangan  1.03%, ROC AUC 1.0000
  contamination=0.02 : belgilangan  2.01%, ROC AUC 1.0000
  contamination=0.05 : belgilangan  5.00%, ROC AUC 1.0000
  contamination=0.1  : belgilangan 10.00%, ROC AUC 1.0000
  ballar bir xilmi (0.01 va 0.10): True

=== 4. Belgilar soni ortganda ===
     p    ROC AUC    PR AUC
     2     1.0000    1.0000
     5     1.0000    1.0000
    10     0.9999    0.9961
    30     0.9891    0.6578
   100     0.7986    0.0857
  ⭐ contamination ballarni emas, chegarani belgilaydi

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

Misol 3 — Zichlik va qayta tiklash

python
"""GMM, PCA va KNN asosidagi usullar (real numpy/sklearn)."""

import numpy as np
from sklearn.decomposition import PCA
from sklearn.ensemble import IsolationForest
from sklearn.metrics import average_precision_score, roc_auc_score
from sklearn.mixture import GaussianMixture
from sklearn.neighbors import NearestNeighbors
from sklearn.preprocessing import StandardScaler


def yarat(seed: int = 9, n: int = 2000, p: int = 20, ulush: float = 0.02):
    """5 ta yashirin omil; anomaliyalar manifolddan tashqarida."""
    rng = np.random.default_rng(seed)
    omil = rng.normal(0, 1, (n, 5))
    A = rng.normal(0, 1, (5, p))
    X = omil @ A + rng.normal(0, 0.3, (n, p))
    k = int(n * ulush)
    # anomaliyalar: tasodifiy yo'nalishda, manifoldga mos kelmaydi
    anomaliya = rng.normal(0, X.std(), (k, p))
    return (np.vstack([X, anomaliya]),
            np.concatenate([np.zeros(n), np.ones(k)]).astype(int))


def main() -> None:
    X, y = yarat()
    Xs = StandardScaler().fit_transform(X)

    print("=== 1. Besh usul ===")
    ballar = {}
    ballar["IsolationForest"] = -IsolationForest(
        contamination=0.02, n_estimators=200, random_state=0,
        n_jobs=1).fit(X).score_samples(X)

    g = GaussianMixture(3, covariance_type="diag", n_init=5,
                        reg_covar=1e-4, random_state=0).fit(Xs)
    ballar["GMM zichligi"] = -g.score_samples(Xs)

    p = PCA(n_components=5, random_state=0).fit(Xs)
    tiklangan = p.inverse_transform(p.transform(Xs))
    ballar["PCA qayta tiklash"] = ((Xs - tiklangan) ** 2).sum(axis=1)

    nn = NearestNeighbors(n_neighbors=21).fit(Xs)
    d, _ = nn.kneighbors(Xs)
    ballar["KNN masofasi"] = d[:, -1]
    ballar["KNN o'rtacha"] = d[:, 1:].mean(axis=1)

    print(f"  {'usul':<20} {'ROC AUC':>10} {'PR AUC':>9} "
          f"{'precision@40':>14}")
    for nom, b in ballar.items():
        top = np.argsort(-b)[:40]
        print(f"  {nom:<20} {roc_auc_score(y, b):>10.4f} "
              f"{average_precision_score(y, b):>9.4f} {y[top].mean():>13.1%}")

    print("\n=== 2. PCA komponentlari soni ===")
    print(f"  {'komponentlar':>13} {'saqlangan %':>13} {'ROC AUC':>10}")
    pt = PCA(random_state=0).fit(Xs)
    jamlangan = np.cumsum(pt.explained_variance_ratio_)
    for k in [2, 5, 10, 15]:
        pk = PCA(n_components=k, random_state=0).fit(Xs)
        xato = ((Xs - pk.inverse_transform(pk.transform(Xs))) ** 2).sum(axis=1)
        print(f"  {k:>13} {jamlangan[k - 1]:>12.1%} "
              f"{roc_auc_score(y, xato):>10.4f}")

    print("\n=== 3. Usullar kelishuvi ===")
    belgilangan = {}
    for nom, b in ballar.items():
        chegara = np.quantile(b, 0.98)
        belgilangan[nom] = b >= chegara
    nomlar = list(belgilangan)
    print(f"  {'':<20}" + "".join(f"{n[:9]:>11}" for n in nomlar))
    for a in nomlar:
        qator = []
        for c in nomlar:
            kesishma = (belgilangan[a] & belgilangan[c]).sum()
            birlashma = (belgilangan[a] | belgilangan[c]).sum()
            qator.append(kesishma / max(birlashma, 1))
        print(f"  {a[:19]:<20}" + "".join(f"{v:>11.3f}" for v in qator))

    print("\n=== 4. Ansambl: ballarni birlashtirish ===")
    from scipy.stats import rankdata
    darajalar = np.array([rankdata(b) / len(b) for b in ballar.values()])
    ansambl = darajalar.mean(axis=0)
    print(f"  {'usul':<20} {'ROC AUC':>10} {'PR AUC':>9}")
    for nom, b in ballar.items():
        print(f"  {nom:<20} {roc_auc_score(y, b):>10.4f} "
              f"{average_precision_score(y, b):>9.4f}")
    print(f"  {'ANSAMBL (daraja)':<20} {roc_auc_score(y, ansambl):>10.4f} "
          f"{average_precision_score(y, ansambl):>9.4f}")
    print("  ⭐ Turli usullar turli anomaliyalarni topadi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Besh usul ===
  usul                    ROC AUC    PR AUC   precision@40
  IsolationForest          0.8064    0.0499          2.5%
  GMM zichligi             0.9069    0.1111          5.0%
  PCA qayta tiklash        1.0000    1.0000        100.0%
  KNN masofasi             0.9909    0.7244         70.0%
  KNN o'rtacha             0.9959    0.8669         77.5%

=== 2. PCA komponentlari soni ===
   komponentlar   saqlangan %    ROC AUC
              2        54.2%     0.9375
              5        96.0%     1.0000
             10        98.4%     1.0000
             15        99.4%     1.0000

=== 3. Usullar kelishuvi ===
                        Isolation  GMM zichl  PCA qayta  KNN masof  KNN o'rta
  IsolationForest           1.000      0.608      0.012      0.188      0.155
  GMM zichligi              0.608      1.000      0.038      0.224      0.188
  PCA qayta tiklash         0.012      0.038      1.000      0.547      0.608
  KNN masofasi              0.188      0.224      0.547      1.000      0.907
  KNN o'rtacha              0.155      0.188      0.608      0.907      1.000

=== 4. Ansambl: ballarni birlashtirish ===
  usul                    ROC AUC    PR AUC
  IsolationForest          0.8064    0.0499
  GMM zichligi             0.9069    0.1111
  PCA qayta tiklash        1.0000    1.0000
  KNN masofasi             0.9909    0.7244
  KNN o'rtacha             0.9959    0.8669
  ANSAMBL (daraja)         0.9822    0.5809
  ⭐ Turli usullar turli anomaliyalarni topadi

Nima ko'rsatdi: 2.5-bo'lim.

Misol 4 — Tranzaksiyalar: kontekstual anomaliya

python
"""Belgi muhandisligi anomaliya aniqlashda (real pandas/sklearn)."""

import numpy as np
import pandas as pd
from sklearn.ensemble import IsolationForest
from sklearn.metrics import average_precision_score, roc_auc_score


def yarat(seed: int = 3, n: int = 8000) -> pd.DataFrame:
    """Tranzaksiyalar: firibgarlik KONTEKSTUAL (odat bilan solishtirilganda)."""
    rng = np.random.default_rng(seed)
    mijoz = rng.integers(0, 400, n)
    # har mijozning o'z odati
    odat_summa = rng.lognormal(12.0, 0.6, 400)
    odat_soat = rng.integers(8, 20, 400)
    summa = odat_summa[mijoz] * rng.lognormal(0, 0.35, n)
    soat = np.clip(odat_soat[mijoz] + rng.normal(0, 2, n), 0, 23)
    qurilma = rng.integers(0, 3, n)              # 0 = odatiy qurilma
    qurilma = np.where(rng.random(n) < 0.9, 0, qurilma)
    firibgar = rng.random(n) < 0.015
    # firibgarlik: mijozning odatidan 6-15 barobar katta summa, kechasi, yangi qurilma
    summa[firibgar] = odat_summa[mijoz[firibgar]] * rng.uniform(6, 15,
                                                               firibgar.sum())
    soat[firibgar] = rng.uniform(1, 5, firibgar.sum())
    qurilma[firibgar] = rng.integers(1, 3, firibgar.sum())
    return pd.DataFrame({"mijoz": mijoz, "summa": summa, "soat": soat,
                         "qurilma": qurilma, "firibgar": firibgar.astype(int)})


def main() -> None:
    df = yarat()
    print("=== 1. Ma'lumot ===")
    print(f"  {len(df)} tranzaksiya, {df['mijoz'].nunique()} mijoz")
    print(f"  firibgarlik: {int(df['firibgar'].sum())} "
          f"({df['firibgar'].mean():.2%})")
    print(f"  summa: mediana {df['summa'].median():,.0f}, "
          f"max {df['summa'].max():,.0f}")

    y = df["firibgar"].to_numpy()

    print("\n=== 2. Xom belgilar bilan ===")
    xom = df[["summa", "soat", "qurilma"]].to_numpy()
    b1 = -IsolationForest(contamination=0.02, n_estimators=200,
                          random_state=0, n_jobs=1).fit(xom).score_samples(xom)
    print(f"  ROC AUC {roc_auc_score(y, b1):.4f}, "
          f"PR AUC {average_precision_score(y, b1):.4f}")

    print("\n=== 3. Kontekstual belgilar qo'shilgandan keyin ===")
    ortacha = df.groupby("mijoz")["summa"].transform("median")
    ortacha_soat = df.groupby("mijoz")["soat"].transform("median")
    df["summa_nisbati"] = df["summa"] / ortacha
    df["soat_farqi"] = (df["soat"] - ortacha_soat).abs()
    df["yangi_qurilma"] = (df["qurilma"] > 0).astype(int)
    kontekst = df[["summa_nisbati", "soat_farqi", "yangi_qurilma",
                   "summa"]].to_numpy()
    b2 = -IsolationForest(contamination=0.02, n_estimators=200,
                          random_state=0,
                          n_jobs=1).fit(kontekst).score_samples(kontekst)
    print(f"  ROC AUC {roc_auc_score(y, b2):.4f}, "
          f"PR AUC {average_precision_score(y, b2):.4f}")
    print(f"  yaxshilanish: ROC {roc_auc_score(y, b2) - roc_auc_score(y, b1):+.4f}, "
          f"PR {average_precision_score(y, b2) - average_precision_score(y, b1):+.4f}")

    print("\n=== 4. precision@k: tekshiruvchilar uchun ===")
    print(f"  {'k':>5} {'xom belgilar':>15} {'kontekst bilan':>17} "
          f"{'qamrov (kontekst)':>19}")
    jami = int(y.sum())
    for k in [20, 50, 100, 200]:
        i1 = np.argsort(-b1)[:k]
        i2 = np.argsort(-b2)[:k]
        print(f"  {k:>5} {y[i1].mean():>14.1%} {y[i2].mean():>16.1%} "
              f"{y[i2].sum() / jami:>18.1%}")
    print(f"  (jami {jami} ta firibgarlik)")
    print("  ⭐ Kontekstual belgilar anomaliyani ko'rinadigan qiladi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Ma'lumot ===
  8000 tranzaksiya, 400 mijoz
  firibgarlik: 137 (1.71%)
  summa: mediana 166,245, max 11,268,431

=== 2. Xom belgilar bilan ===
  ROC AUC 0.9994, PR AUC 0.9683

=== 3. Kontekstual belgilar qo'shilgandan keyin ===
  ROC AUC 1.0000, PR AUC 0.9998
  yaxshilanish: ROC +0.0006, PR +0.0315

=== 4. precision@k: tekshiruvchilar uchun ===
      k    xom belgilar    kontekst bilan   qamrov (kontekst)
     20         100.0%           100.0%              14.6%
     50         100.0%           100.0%              36.5%
    100          96.0%           100.0%              73.0%
    200          67.5%            68.5%             100.0%
  (jami 137 ta firibgarlik)
  ⭐ Kontekstual belgilar anomaliyani ko'rinadigan qiladi

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


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

Noto'g'ri fikr To'g'risi
"Anomaliya = katta qiymat" Kombinatsiya ham bo'ladi
"Isolation Forest masshtablash talab qiladi" Yo'q
"LOF masshtablashsiz ishlaydi" Masshtablang
"contamination ballarni o'zgartiradi" Faqat chegarani
"Anomaliyalarni o'chirish kerak" Ular qimmatli bo'lishi mumkin
"Accuracy yaxshi metrika" 99% anomaliyasiz ham chiqadi
"Bitta usul yetarli" Ansambl yaxshiroq
"Kontekstni algoritm o'zi biladi" Belgi qo'shish kerak

6. Keng tarqalgan xatolar va yechimlari

1. LOF ni masshtablamasdan

python
LocalOutlierFactor(20).fit_predict(X)     # turli birliklar       # ⚠️
LocalOutlierFactor(20).fit_predict(StandardScaler().fit_transform(X)) # ✅

2. contamination ni katta qo'yish

python
IsolationForest(contamination=0.2)    # haqiqiy ulush 1%          # ⚠️
IsolationForest(contamination=0.01)   # yoki "auto" + qo'lda chegara # ✅

3. LOF da novelty ni unutish

python
lof = LocalOutlierFactor(20).fit(Xtr); lof.predict(Xte)   # xato   # ⚠️
LocalOutlierFactor(20, novelty=True).fit(Xtr).predict(Xte)         # ✅

4. Accuracy bilan baholash

python
accuracy_score(y, bashorat)     # 99% anomaliyasiz ham            # ⚠️
average_precision_score(y, ball)                                   # ✅

5. Anomaliyalarni avtomatik o'chirish

python
X = X[izo.predict(X) == 1]      # eng qimmatli ma'lumot yo'qoldi  # ⚠️
# avval ko'rib chiqing, keyin qaror qiling                        # ✅

6. Kontekstni hisobga olmaslik

python
IsolationForest().fit(df[["summa", "soat"]])                      # ⚠️
# "mijoz odatiga nisbatan" belgilarini qo'shing                   # ✅

7. Bitta usulga tayanish

python
ball = -izo.score_samples(X)                                      # ⚠️
# 3-4 usul ballarini darajaga aylantirib o'rtachalang             # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 16.5-dars (o'tilgan): DBSCAN shovqini
  • 16.6-dars (o'tilgan): GMM zichligi
  • 16.8-dars (o'tilgan): PCA qayta tiklash
  • 14.9-dars (o'tilgan): Nomutanosib sinflar
  • 06-qism (o'tilgan): Ma'lumot sifati

8. Eng yaxshi amaliyotlar

  1. Isolation Forest dan boshlang.

  2. Masofaga asoslangan usullarni masshtablang.

  3. Kontekstual belgilar qo'shing.

  4. PR AUC va precision@k bilan baholang.

  5. Anomaliyalarni ko'rib chiqing.

  6. Bir necha usulni birlashtiring.

  7. contamination ni oqilona qo'ying.

  8. Yorliq kelsa, nazoratli modelga o'ting.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # anomaliya turlari?
2.  # Isolation Forest g'oyasi?
3.  # anomaliya daraxtda qayerda?
4.  # IF masshtablash talab qiladimi?
5.  # LOF nimani taqqoslaydi?
6.  # LOF ~ 1 nimani anglatadi?
7.  # novelty=True qachon kerak?
8.  # One-Class SVM ning kamchiligi?
9.  # PCA qayta tiklash xatosi nima?
10. # contamination nimani belgilaydi?
11. # qaysi metrika afzal?
12. # precision@k nima?
Javoblar
  1. Nuqtaviy, kontekstual, jamoaviy
  2. Anomaliyani izolyatsiya qilish oson
  3. Sayoz (kam bo'linishdan keyin)
  4. Yo'q
  5. Nuqta zichligini qo'shnilarniki bilan
  6. Normal
  7. Yangi nuqtalarni baholash uchun
  8. Sekin, parametrga sezgir
  9. Komponentlar bilan tiklash xatosi
  10. Faqat chegarani
  11. PR AUC
  12. Eng yuqori k ta orasidagi haqiqiylar ulushi

Vazifa 2: Xatolarni tuzating

python
1.  LocalOutlierFactor(20).fit_predict(X)   # turli birliklar

2.  IsolationForest(contamination=0.2)   # haqiqiy 1%

3.  lof = LocalOutlierFactor(20).fit(Xtr); lof.predict(Xte)

4.  accuracy_score(y, bashorat)

5.  X = X[izo.predict(X) == 1]
Javoblar
python
1.  LocalOutlierFactor(20).fit_predict(StandardScaler().fit_transform(X))

2.  IsolationForest(contamination=0.01)

3.  LocalOutlierFactor(20, novelty=True).fit(Xtr).predict(Xte)

4.  average_precision_score(y, ball)

5.  # avval ko'rib chiqing, keyin qaror qiling

Vazifa 3: To'rt usul

Modellang:

  1. ROC AUC
  2. PR AUC
  3. Mahalliy anomaliya
  4. Masshtablash

Vazifa 4: Isolation Forest

Modellang:

  1. Ballar
  2. Parametrlar
  3. contamination
  4. Belgilar soni

Vazifa 5: Zichlik

Modellang:

  1. Besh usul
  2. PCA komponentlari
  3. Kelishuv
  4. Ansambl

Vazifa 6: Tranzaksiyalar

Modellang:

  1. Ma'lumot
  2. Xom belgilar
  3. Kontekst
  4. precision@k

Vazifa 7: O'ylash

Anomaliya aniqlash modeli ishga tushdi va kuniga 200 ta ogohlantirish beradi. Tekshiruvchilar 30 tasini ko'ra oladi. Nima qilish kerak?

Javob

Qisqa javob: modelni emas, chegarani va tartiblashni sozlang. Muammo aniqlikda emas — quvvat cheklovida. Maqsad: eng yuqori 30 ta orasida haqiqiy hodisalar ulushini maksimallashtirish (precision@30).

1. Darhol qilinadigan ishlar

Harakat Natija
Chegarani ko'tarish 200 → 30 ogohlantirish
precision@30 ni o'lchash Joriy holat ma'lum bo'ladi
Ballar taqsimotini ko'rish Aniq "dum" bormi
Ogohlantirishlarni tartiblash Eng ishonchlilari birinchi

2. precision@30 ni oshirish

  1. Ansambl: 3-4 usul ballarini darajaga aylantirib o'rtachalang (Misol 3)
  2. Kontekstual belgilar: "odatga nisbatan" belgilari ko'pincha eng katta foyda beradi (Misol 4)
  3. Qoidalar bilan filtrlash: aniq normal holatlarni oldindan chiqarib tashlash
  4. Yorliqlardan foydalanish: tekshiruvchilar qarorlari — bu yorliq, ularni to'plang

3. Uzoq muddatli: nazoratli modelga o'tish

1. Tekshiruvchilar qarorlarini saqlang (tasdiqlandi / rad etildi)
2. 500-1000 yorliq to'planganda nazoratli model quring (14.9)
3. Nazoratsiz ball - shu modelning BELGISI bo'ladi
4. Natija odatda sezilarli yaxshilanadi

Bu — anomaliya aniqlashning tabiiy evolyutsiyasi: nazoratsizdan yarim nazoratliga, keyin nazoratliga.

4. Biznes tomonidan

  • Har ogohlantirishning qiymatini hisoblang (topilgan firibgarlik qancha saqlaydi)
  • Tekshiruvchi vaqtining narxini hisoblang
  • Optimal chegara — chegaraviy foyda chegaraviy narxga teng bo'lgan nuqta
  • Ba'zan javob: ko'proq tekshiruvchi yollash

5. Xulosa

  1. Chegarani quvvatga moslang
  2. precision@k ni asosiy metrika qiling
  3. Ansambl va kontekstual belgilar bilan yaxshilang
  4. Yorliq to'plab, nazoratli modelga o'ting

Nimani mustahkamlaydi: 2.6-bo'lim.


Xulosa

Bu darsda anomaliya aniqlashni o'rgandik.

Eng muhim uch fikr:

  1. Isolation Forest — odatiy birinchi tanlov. U anomaliyani izolyatsiya qilish oson degan g'oyaga asoslanadi: tasodifiy bo'linishlarda anomaliya sayoz darajada ajraladi. Afzalliklari: masshtablash kerak emas, chiziqli murakkablik, yuqori o'lchamda ishlaydi. Kamchiligi — mahalliy anomaliyalarni (zich klaster chetidagi) yomon topadi; u yerda LOF ustun.

  2. contamination faqat chegarani belgilaydi. score_samples ballari undan bog'liq emas — shuning uchun modelni bir marta o'qitib, chegarani keyin quvvatga qarab sozlash mumkin. Baholashda accuracy yaroqsiz (99% anomaliyasiz ham chiqadi): PR AUC va ayniqsa precision@k ishlating — tekshiruvchilar kuniga cheklangan sonda hodisani ko'radi.

  3. Kontekstual belgilar hal qiluvchi. Algoritm kontekstni bilmaydi: "50 ming so'm" normalmi yoki yo'qmi — bu mijozning odatiga bog'liq. "Mijoz medianasiga nisbati", "odatiy soatdan farqi" kabi belgilar kontekstual anomaliyani nuqtaviy anomaliyaga aylantiradi va natijani sezilarli yaxshilaydi. Turli usullar turli anomaliyalarni topadi — ballarni darajaga aylantirib birlashtiring.

Keyingi darsda nazoratsiz o'rganishning qo'llanilishini ko'rib chiqamiz: segmentatsiya, tavsiya, mavzu modellashtirish va siqish.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
16.10-dars: Anomaliya aniqlash — IlmHamroh