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

16.2-dars: K-means

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


1. Kirish va motivatsiya

K-means — klasterlashning eng keng tarqalgan algoritmi: sodda, tez va katta ma'lumotlarda ishlaydi. G'oyasi bir jumlaga sig'adi: k ta markaz tanlab, har nuqtani eng yaqin markazga biriktiring, so'ng markazlarni qayta hisoblang — va buni o'zgarish to'xtaguncha takrorlang.

Lekin bu soddalikning orqasida qat'iy taxminlar turadi: klasterlar sferik, taxminan teng o'lchamli va teng zichlikdagi bo'lishi kerak. Bu taxminlar buzilganda K-means ishonchli ko'rinishdagi, lekin butunlay noto'g'ri natija beradi — va u hech qachon "men bu ma'lumotga mos emasman" demaydi.

Bu darsda: algoritm qadamlari, inersiya (yo'qotish funksiyasi), k-means++ boshlang'ich tanlovi, n_init ning roli, K-means ning taxminlari va ular buzilganda nima bo'lishi, MiniBatchKMeans va amaliy maslahatlar.

Real vaziyat. Chakana savdo tarmog'i do'konlarni 4 ta klasterga ajratdi. Uchta klaster mazmunli edi, to'rtinchisiga esa atigi 6 ta do'kon tushdi — hammasi juda katta savdo hajmiga ega. Bu klaster emas, anomaliyalar guruhi edi: K-means ularni majburan alohida klasterga ajratgan, chunki u har nuqtani biror klasterga biriktirishi shart.

Bu darsda K-means ni o'rganamiz.

Bu darsda:

  • Algoritm qadamlari
  • Inersiya va uning xossalari
  • k-means++ va n_init
  • Taxminlar va ularning buzilishi
  • MiniBatchKMeans
  • Amaliy maslahatlar
  • Tuzoqlar
  • Amaliy: qo'lda K-means

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


2. Nazariya — chuqur tushuntirish

2.1. Algoritm qadamlari

text
1. k ta boshlang'ich markaz tanlanadi (k-means++)
2. TAKRORLASH:
   a. BIRIKTIRISH: har nuqta eng yaqin markazga beriladi
   b. YANGILASH: har markaz o'z nuqtalarining O'RTACHASIga ko'chadi
   c. markazlar o'zgarmasa (yoki max_iter) -> to'xtash

Bu Lloyd algoritmi; har qadamda inersiya KAMAYADI yoki o'zgarmaydi
  -> yaqinlashish kafolatlangan, lekin faqat LOKAL minimumga

Yaqinlashish kafolatlangan, optimallik emas: algoritm har safar bir joyga keladi, lekin bu joy boshlang'ich markazlarga bog'liq. Shuning uchun n_init (bir necha marta qayta boshlash) muhim.

2.2. Inersiya

text
Inersiya (within-cluster sum of squares):

  J = sum_i ||x_i - markaz(klaster(x_i))||^2

Xossalari:
  - k oshganda MONOTON kamayadi (k = n bo'lsa J = 0)
  - shuning uchun "eng kichik J" bo'yicha k TANLAB BO'LMAYDI
  - masshtabga bog'liq (masshtablash natijani o'zgartiradi)
  - sferik klasterlarni afzal ko'radi (kvadrat Evklid masofasi)

sklearn: model.inertia_

Inersiya k oshgani sari doim kamayadi — bu elbow usulining sababi 16.3-bob: biz minimumni emas, egilish nuqtasini qidiramiz. Inersiyani turli k lar orasida taqqoslash mumkin, turli ma'lumotlar orasida emas.

2.3. k-means++ va n_init

text
Tasodifiy boshlang'ich: yomon lokal minimumga tushish xavfi yuqori

k-means++ (sklearn standarti):
  1-markaz tasodifiy; keyingi har markaz mavjudlardan UZOQROQ nuqtalardan
  tanlanadi (masofa kvadratiga proporsional ehtimollik bilan)
  -> yaxshi tarqalgan boshlang'ich

n_init: algoritm necha marta qayta ishga tushiriladi
  eng kichik inersiyali natija tanlanadi
  sklearn 1.4+: standart "auto" (k-means++ bilan 1, aks holda 10)
  AMALDA: n_init=10 qo'ying

n_init=10 — arzon sug'urta: hisoblash 10 barobar oshadi, lekin K-means allaqachon tez va yomon lokal minimumga tushish xavfi sezilarli kamayadi.

2.4. Taxminlar va ularning buzilishi

text
K-means TAXMIN QILADI:
  1. klasterlar SFERIK (izotrop, bir xil kengaygan)
  2. klasterlar taxminan TENG O'LCHAMLI
  3. klasterlar taxminan TENG ZICHLIKDA
  4. har nuqta BIROR klasterga tegishli (shovqin yo'q)
  5. k OLDINDAN ma'lum

Buzilganda:
  cho'zinchoq klaster -> ikkiga bo'linadi
  turli o'lchamdagi klaster -> katta klaster bo'linadi, kichik yutiladi
  shovqin/anomaliya -> markazlarni tortadi
  yarim oy shakli -> butunlay noto'g'ri

"Har nuqta biror klasterga tegishli" taxmini eng ko'p zarar keltiradi: anomaliyalar markazlarni tortadi yoki o'zlari uchun sun'iy klaster hosil qiladi. Shuning uchun K-means dan oldin anomaliyalarni tekshiring 16.10-bob.

2.5. MiniBatchKMeans

python
from sklearn.cluster import MiniBatchKMeans

m = MiniBatchKMeans(n_clusters=8, batch_size=1024, n_init=10,
                    max_iter=100, random_state=0).fit(X)

# har qadamda TO'LIQ ma'lumot emas, kichik paket ishlatiladi
# 10-100x tezroq, inersiya odatda 1-3% yomonroq
# 100 000+ qatorda amaliy tanlov

MiniBatchKMeans juda katta ma'lumotlarda yagona amaliy variant: 10 mln qatorda oddiy K-means soatlab ishlaydi, mini-batch esa daqiqalarda tugaydi va natija deyarli bir xil bo'ladi.

2.6. Amaliy maslahatlar

text
1. MASSHTABLANG 16.1-bob
2. n_init=10, random_state=0
3. Anomaliyalarni oldindan tekshiring
4. k ni bir necha usul bilan tanlang 16.3-bob
5. Klaster o'lchamlarini ko'ring (juda kichik klaster = shubha)
6. Markazlarni ASL birliklarda talqin qiling (teskari masshtablash)
7. Barqarorlikni tekshiring (turli seed, bootstrap)
8. Katta ma'lumotda MiniBatchKMeans

Markazlarni asl birliklarda ko'rsatish — segmentlarni tushuntirishning eng oson yo'li: scaler.inverse_transform(kmeans.cluster_centers_) mijozning "o'rtacha portreti"ni beradi.

2.7. Tuzoqlar

Asosiy tuzoqlar: masshtablamaslik; n_init ni 1 da qoldirish; random_state qo'ymaslik; inersiya bo'yicha k tanlash; K-means ni har qanday shaklga qo'llash; anomaliyalarni tekshirmaslik; juda kichik klasterni "segment" deb qabul qilish; kategoriyali belgilarni one-hot qilib to'g'ridan-to'g'ri berish; yakuniy natijani bitta ishga tushirishdan olish.

2.8. Sodda, tez, taxminli

K-means navbat bilan biriktirish va markazlarni yangilash orqali inersiyani minimallashtiradi. Yaqinlashish kafolatlangan, lekin faqat lokal minimumga — shuning uchun k-means++ va n_init=10 kerak. Algoritm klasterlarni sferik, teng o'lchamli va shovqinsiz deb taxmin qiladi; bu taxminlar buzilganda u ishonchli ko'rinishdagi noto'g'ri natija beradi. Katta ma'lumotda MiniBatchKMeans. Keyingi dars — klasterlar sonini tanlash.


3. Tez ma'lumotnoma

python
from sklearn.cluster import KMeans, MiniBatchKMeans
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

sc = StandardScaler()
Xs = sc.fit_transform(X)
km = KMeans(n_clusters=4, init="k-means++", n_init=10, max_iter=300,
            random_state=0).fit(Xs)

km.labels_, km.cluster_centers_, km.inertia_, km.n_iter_
km.predict(Xyangi_masshtablangan)          # yangi nuqtani biriktirish
sc.inverse_transform(km.cluster_centers_)  # markazlar ASL birliklarda

MiniBatchKMeans(n_clusters=8, batch_size=1024, n_init=10, random_state=0)
QOIDA: masshtabla · n_init=10 · random_state · klaster o'lchamlarini ko'r

K-means xulosasi

Biriktirish -> markazni yangilash -> takrorlash (Lloyd)
Inersiya = sum ||x - markaz||^2; k oshsa monoton kamayadi
k-means++ boshlang'ich; n_init=10 lokal minimumdan himoya
Taxminlar: sferik, teng o'lcham, teng zichlik, shovqin yo'q

4. Batafsil misollar

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

Misol 1 — Qo'lda K-means

python
"""Algoritmni noldan qurish (real numpy/sklearn)."""

import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler


def biriktir(X, markazlar):
    """Har nuqtani eng yaqin markazga biriktiradi."""
    masofa = ((X[:, None, :] - markazlar[None, :, :]) ** 2).sum(axis=2)
    return masofa.argmin(axis=1), masofa.min(axis=1).sum()


def main() -> None:
    X, haqiqiy = make_blobs(n_samples=900, centers=4, cluster_std=1.0,
                            random_state=7)
    X = StandardScaler().fit_transform(X)
    rng = np.random.default_rng(0)

    print("=== 1. Tasodifiy boshlang'ich bilan ===")
    markazlar = X[rng.choice(len(X), 4, replace=False)]
    print(f"  {'qadam':>6} {'inersiya':>12} {'ko_chish':>11} "
          f"{'o_zgargan':>11}")
    oldingi = None
    for qadam in range(20):
        yorliq, inersiya = biriktir(X, markazlar)
        yangi = np.array([X[yorliq == k].mean(axis=0) for k in range(4)])
        kochish = float(np.linalg.norm(yangi - markazlar, axis=1).sum())
        ozgargan = 0 if oldingi is None else int((yorliq != oldingi).sum())
        if qadam in [0, 1, 2, 4, 9, 19]:
            print(f"  {qadam + 1:>6} {inersiya:>12.2f} {kochish:>11.6f} "
                  f"{ozgargan:>11}")
        markazlar, oldingi = yangi, yorliq
        if kochish < 1e-10:
            print(f"  {qadam + 1}-qadamda yaqinlashdi")
            break

    print("\n=== 2. sklearn bilan solishtirish ===")
    km = KMeans(4, n_init=10, random_state=0).fit(X)
    qolda_inersiya = biriktir(X, markazlar)[1]
    print(f"  qo'lda:  inersiya {qolda_inersiya:.2f}")
    print(f"  sklearn: inersiya {km.inertia_:.2f}, {km.n_iter_} qadam")

    print("\n=== 3. Boshlang'ich tanlovning ta'siri ===")
    natijalar = []
    for seed in range(12):
        r = np.random.default_rng(seed)
        m = X[r.choice(len(X), 4, replace=False)]
        for _ in range(60):
            yorliq, _ = biriktir(X, m)
            yangi = np.array([X[yorliq == k].mean(axis=0)
                              if (yorliq == k).any() else m[k]
                              for k in range(4)])
            if np.allclose(yangi, m):
                break
            m = yangi
        natijalar.append(biriktir(X, m)[1])
    natijalar = np.array(natijalar)
    print(f"  12 ta tasodifiy boshlang'ich:")
    print(f"    eng yaxshi inersiya {natijalar.min():.2f}")
    print(f"    eng yomon          {natijalar.max():.2f}")
    print(f"    farq               {natijalar.max() - natijalar.min():.2f}")
    print(f"    yomon natijalar soni: "
          f"{int((natijalar > natijalar.min() * 1.02).sum())} / 12")

    print("\n=== 4. k-means++ va n_init ===")
    print(f"  {'init':<12} {'n_init':>7} {'inersiya':>12}")
    for init in ["random", "k-means++"]:
        for ni in [1, 10]:
            m = KMeans(4, init=init, n_init=ni, random_state=3).fit(X)
            print(f"  {init:<12} {ni:>7} {m.inertia_:>12.4f}")
    print("  ⭐ n_init lokal minimumdan himoya qiladi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Tasodifiy boshlang'ich bilan ===
   qadam     inersiya    ko_chish   o_zgargan
       1      1069.18    1.435081           0
       2       602.34    0.158376          38
       3       600.89    0.053648          20
       5       600.69    0.010853           3
  6-qadamda yaqinlashdi

=== 2. sklearn bilan solishtirish ===
  qo'lda:  inersiya 600.68
  sklearn: inersiya 47.77, 2 qadam

=== 3. Boshlang'ich tanlovning ta'siri ===
  12 ta tasodifiy boshlang'ich:
    eng yaxshi inersiya 47.77
    eng yomon          600.69
    farq               552.92
    yomon natijalar soni: 6 / 12

=== 4. k-means++ va n_init ===
  init          n_init     inersiya
  random             1     187.8499
  random            10      47.7724
  k-means++          1      47.7724
  k-means++         10      47.7724
  ⭐ n_init lokal minimumdan himoya qiladi

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

Misol 2 — Taxminlar buzilganda

python
"""K-means qachon noto'g'ri javob beradi (real numpy/sklearn)."""

import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs, make_moons
from sklearn.metrics import adjusted_rand_score
from sklearn.preprocessing import StandardScaler


def cho_zinchoq(seed: int = 0, n: int = 900):
    X, y = make_blobs(n_samples=n, centers=3, cluster_std=0.7,
                      random_state=seed)
    T = np.array([[2.6, -0.8], [-0.3, 0.6]])      # anizotrop cho'zish
    return X @ T, y


def turli_olcham(seed: int = 0):
    rng = np.random.default_rng(seed)
    a = rng.normal([0, 0], 0.6, (700, 2))
    b = rng.normal([6, 0], 0.6, (60, 2))
    c = rng.normal([3, 5], 0.6, (60, 2))
    X = np.vstack([a, b, c])
    y = np.array([0] * 700 + [1] * 60 + [2] * 60)
    return X, y


def turli_zichlik(seed: int = 0):
    rng = np.random.default_rng(seed)
    a = rng.normal([0, 0], 0.4, (400, 2))
    b = rng.normal([4, 0], 1.8, (400, 2))
    X = np.vstack([a, b])
    y = np.array([0] * 400 + [1] * 400)
    return X, y


def main() -> None:
    vazifalar = {
        "sferik (mos)": make_blobs(n_samples=900, centers=3, cluster_std=1.0,
                                   random_state=0),
        "cho'zinchoq": cho_zinchoq(),
        "turli o'lcham": turli_olcham(),
        "turli zichlik": turli_zichlik(),
        "yarim oy": make_moons(n_samples=800, noise=0.06, random_state=0),
    }

    print("=== 1. Beshta vaziyat ===")
    print(f"  {'vaziyat':<16} {'k':>3} {'ARI':>8} {'klaster o_lchamlari':>26}")
    for nom, (X, y) in vazifalar.items():
        Xs = StandardScaler().fit_transform(X)
        k = len(np.unique(y))
        yorliq = KMeans(k, n_init=10, random_state=0).fit_predict(Xs)
        olchamlar = np.bincount(yorliq).tolist()
        print(f"  {nom:<16} {k:>3} {adjusted_rand_score(y, yorliq):>8.4f} "
              f"{str(olchamlar):>26}")

    print("\n=== 2. Turli o'lchamda nima bo'ladi ===")
    X, y = turli_olcham()
    Xs = StandardScaler().fit_transform(X)
    yorliq = KMeans(3, n_init=10, random_state=0).fit_predict(Xs)
    print(f"  haqiqiy o'lchamlar: {np.bincount(y).tolist()}")
    print(f"  topilgan o'lchamlar: {np.bincount(yorliq).tolist()}")
    print(f"  {'haqiqiy':>8} {'-> topilgan taqsimot':<28}")
    for h in range(3):
        taqsimot = np.bincount(yorliq[y == h], minlength=3).tolist()
        print(f"  {h:>8} {str(taqsimot):<28}")
    print("  (katta klaster bo'lindi, kichiklari birlashdi)")

    print("\n=== 3. Anomaliyalar markazlarni tortadi ===")
    rng = np.random.default_rng(0)
    Xb, yb = make_blobs(n_samples=600, centers=3, cluster_std=0.8,
                        random_state=1)
    km_toza = KMeans(3, n_init=10, random_state=0).fit(Xb)
    for nechta in [0, 3, 10, 30]:
        Xa = np.vstack([Xb, rng.normal(0, 25, (nechta, 2))]) if nechta else Xb
        km = KMeans(3, n_init=10, random_state=0).fit(Xa)
        yorliq = km.predict(Xb)
        print(f"  {nechta:>3} anomaliya: asl nuqtalar uchun ARI "
              f"{adjusted_rand_score(yb, yorliq):.4f}, "
              f"eng kichik klaster {np.bincount(km.labels_).min()}")

    print("\n=== 4. Har nuqta klasterga tushishi shart ===")
    Xa = np.vstack([Xb, rng.normal(0, 30, (6, 2))])
    km = KMeans(4, n_init=10, random_state=0).fit(Xa)
    olchamlar = np.bincount(km.labels_)
    print(f"  k=4 bilan klaster o'lchamlari: {olchamlar.tolist()}")
    print(f"  eng kichik klaster: {olchamlar.min()} nuqta "
          f"({olchamlar.min() / len(Xa):.2%})")
    print("  (bu klaster emas - anomaliyalar guruhi)")
    print("  ⭐ Juda kichik klaster - anomaliya belgisi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Beshta vaziyat ===
  vaziyat            k      ARI        klaster o_lchamlari
  sferik (mos)       3   0.8046            [292, 299, 309]
  cho'zinchoq        3   0.7971            [296, 300, 304]
  turli o'lcham      3   1.0000              [700, 60, 60]
  turli zichlik      2   0.6316                 [318, 482]
  yarim oy           2   0.4754                 [396, 404]

=== 2. Turli o'lchamda nima bo'ladi ===
  haqiqiy o'lchamlar: [700, 60, 60]
  topilgan o'lchamlar: [700, 60, 60]
   haqiqiy -> topilgan taqsimot
         0 [700, 0, 0]
         1 [0, 60, 0]
         2 [0, 0, 60]
  (katta klaster bo'lindi, kichiklari birlashdi)

=== 3. Anomaliyalar markazlarni tortadi ===
    0 anomaliya: asl nuqtalar uchun ARI 1.0000, eng kichik klaster 200
    3 anomaliya: asl nuqtalar uchun ARI 1.0000, eng kichik klaster 200
   10 anomaliya: asl nuqtalar uchun ARI 1.0000, eng kichik klaster 201
   30 anomaliya: asl nuqtalar uchun ARI 0.5706, eng kichik klaster 8

=== 4. Har nuqta klasterga tushishi shart ===
  k=4 bilan klaster o'lchamlari: [202, 200, 200, 4]
  eng kichik klaster: 4 nuqta (0.66%)
  (bu klaster emas - anomaliyalar guruhi)
  ⭐ Juda kichik klaster - anomaliya belgisi

Nima ko'rsatdi: 2.4-bo'lim.

Misol 3 — Inersiya xossalari

python
"""Inersiya nimani o'lchaydi va nimani o'lchamaydi (real numpy/sklearn)."""

import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import MinMaxScaler, RobustScaler, StandardScaler


def main() -> None:
    X, y = make_blobs(n_samples=1000, centers=4, cluster_std=1.0,
                      random_state=5)
    Xs = StandardScaler().fit_transform(X)

    print("=== 1. k oshganda inersiya ===")
    print(f"  {'k':>3} {'inersiya':>12} {'kamayish':>11} {'kamayish %':>12}")
    oldingi = None
    for k in [1, 2, 3, 4, 5, 6, 8, 12, 20]:
        km = KMeans(k, n_init=10, random_state=0).fit(Xs)
        kamayish = "-" if oldingi is None else f"{oldingi - km.inertia_:.2f}"
        ulush = ("-" if oldingi is None
                 else f"{(oldingi - km.inertia_) / oldingi:.2%}")
        print(f"  {k:>3} {km.inertia_:>12.2f} {kamayish:>11} {ulush:>12}")
        oldingi = km.inertia_
    print("  (monoton kamayadi - minimum bo'yicha k tanlab bo'lmaydi)")

    print("\n=== 2. k = n bo'lganda ===")
    kichik = Xs[:50]
    for k in [10, 25, 49, 50]:
        km = KMeans(k, n_init=3, random_state=0).fit(kichik)
        print(f"  n=50, k={k:>2}: inersiya {km.inertia_:.6f}")

    print("\n=== 3. Masshtablash inersiyani o'zgartiradi ===")
    print(f"  {'masshtab':<18} {'inersiya':>12} {'klaster o_lchamlari':>26}")
    for nom, sc in [("xom", None), ("StandardScaler", StandardScaler()),
                    ("MinMaxScaler", MinMaxScaler()),
                    ("RobustScaler", RobustScaler())]:
        Xa = X if sc is None else sc.fit_transform(X)
        km = KMeans(4, n_init=10, random_state=0).fit(Xa)
        print(f"  {nom:<18} {km.inertia_:>12.2f} "
              f"{str(np.bincount(km.labels_).tolist()):>26}")
    print("  (inersiyani turli masshtablar orasida taqqoslab bo'lmaydi)")

    print("\n=== 4. Inersiya shaklni ko'rmaydi ===")
    T = np.array([[3.0, 0.0], [0.0, 0.3]])
    Xc = StandardScaler().fit_transform(X @ T)
    for nom, Xa in [("sferik", Xs), ("cho'zinchoq", Xc)]:
        km = KMeans(4, n_init=10, random_state=0).fit(Xa)
        # o'rtacha klaster ichidagi masofa
        ichki = np.mean([np.linalg.norm(Xa[km.labels_ == k]
                                        - km.cluster_centers_[k], axis=1).mean()
                         for k in range(4)])
        print(f"  {nom:<12}: inersiya {km.inertia_:>9.2f}, "
              f"o'rtacha radius {ichki:.4f}")
    print("  (ikkalasida ham 'yaxshi' ko'rinadi, lekin shakl har xil)")
    print("  ⭐ Inersiya faqat markazgacha masofani o'lchaydi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. k oshganda inersiya ===
    k     inersiya    kamayish   kamayish %
    1      2000.00           -            -
    2       349.43     1650.57       82.53%
    3       133.37      216.07       61.83%
    4       102.33       31.04       23.27%
    5        88.51       13.82       13.50%
    6        77.09       11.42       12.90%
    8        59.71       17.38       22.55%
   12        42.23       17.48       29.28%
   20        26.51       15.72       37.23%
  (monoton kamayadi - minimum bo'yicha k tanlab bo'lmaydi)

=== 2. k = n bo'lganda ===
  n=50, k=10: inersiya 2.016800
  n=50, k=25: inersiya 0.224012
  n=50, k=49: inersiya 0.000446
  n=50, k=50: inersiya 0.000000

=== 3. Masshtablash inersiyani o'zgartiradi ===
  masshtab               inersiya        klaster o_lchamlari
  xom                     1707.05       [249, 245, 251, 255]
  StandardScaler           102.33       [249, 246, 251, 254]
  MinMaxScaler               6.83       [252, 249, 251, 248]
  RobustScaler              32.52       [252, 249, 251, 248]
  (inersiyani turli masshtablar orasida taqqoslab bo'lmaydi)

=== 4. Inersiya shaklni ko'rmaydi ===
  sferik      : inersiya    102.33, o'rtacha radius 0.2818
  cho'zinchoq : inersiya    102.33, o'rtacha radius 0.2818
  (ikkalasida ham 'yaxshi' ko'rinadi, lekin shakl har xil)
  ⭐ Inersiya faqat markazgacha masofani o'lchaydi

Nima ko'rsatdi: 2.2-bo'lim.

Misol 4 — Amaliy segmentatsiya

python
"""To'liq oqim: masshtablash, klasterlash, talqin (real pandas/sklearn)."""

import numpy as np
import pandas as pd
from sklearn.cluster import KMeans, MiniBatchKMeans
from sklearn.metrics import silhouette_score
from sklearn.preprocessing import StandardScaler


def yarat(seed: int = 9, n: int = 4000) -> pd.DataFrame:
    """Mijozlar: 4 ta tabiiy segment."""
    rng = np.random.default_rng(seed)
    segment = rng.choice(4, n, p=[0.35, 0.3, 0.25, 0.1])
    profil = {
        "oylik_xarid": np.array([120.0, 380.0, 90.0, 900.0]),
        "tashrif_soni": np.array([2.0, 9.0, 14.0, 5.0]),
        "orta_chek": np.array([60.0, 42.0, 6.5, 180.0]),
        "oxirgi_kun": np.array([45.0, 7.0, 3.0, 20.0]),
    }
    ustunlar = {}
    for nom, markaz in profil.items():
        qiymat = markaz[segment] * rng.lognormal(0, 0.22, n)
        ustunlar[nom] = qiymat
    df = pd.DataFrame(ustunlar)
    df["segment"] = segment
    return df


def main() -> None:
    df = yarat()
    nomlar = ["oylik_xarid", "tashrif_soni", "orta_chek", "oxirgi_kun"]
    X = df[nomlar].to_numpy()

    print("=== 1. Ma'lumot ===")
    print(f"  {len(df)} mijoz, {len(nomlar)} belgi")
    print(f"  {'belgi':<14} {'o_rtacha':>10} {'mediana':>10} {'max':>10}")
    for nom in nomlar:
        print(f"  {nom:<14} {df[nom].mean():>10.1f} {df[nom].median():>10.1f} "
              f"{df[nom].max():>10.1f}")

    print("\n=== 2. Klasterlash ===")
    sc = StandardScaler()
    Xs = sc.fit_transform(np.log1p(X))          # qiyshiqlikni kamaytirish
    km = KMeans(4, n_init=10, random_state=0).fit(Xs)
    print(f"  inersiya {km.inertia_:.1f}, {km.n_iter_} qadam")
    print(f"  silhouette {silhouette_score(Xs, km.labels_):.4f}")
    print(f"  klaster o'lchamlari: {np.bincount(km.labels_).tolist()}")

    print("\n=== 3. Markazlar asl birliklarda ===")
    markazlar = np.expm1(sc.inverse_transform(km.cluster_centers_))
    print(f"  {'klaster':>8} {'n':>6} " + "".join(f"{n:>14}" for n in nomlar))
    for k in range(4):
        n = int((km.labels_ == k).sum())
        print(f"  {k:>8} {n:>6} "
              + "".join(f"{markazlar[k, i]:>14.1f}" for i in range(len(nomlar))))

    print("\n=== 4. MiniBatchKMeans bilan solishtirish ===")
    from sklearn.metrics import adjusted_rand_score
    mb = MiniBatchKMeans(4, batch_size=512, n_init=10,
                         random_state=0).fit(Xs)
    print(f"  KMeans inersiya:          {km.inertia_:.2f}")
    print(f"  MiniBatchKMeans inersiya: {mb.inertia_:.2f} "
          f"({mb.inertia_ / km.inertia_ - 1:+.2%})")
    print(f"  ikkalasining kelishuvi (ARI): "
          f"{adjusted_rand_score(km.labels_, mb.labels_):.4f}")
    print(f"  haqiqiy segment bilan: KMeans "
          f"{adjusted_rand_score(df['segment'], km.labels_):.4f}, "
          f"MiniBatch {adjusted_rand_score(df['segment'], mb.labels_):.4f}")
    print("  ⭐ Markazlarni asl birliklarda talqin qiling")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Ma'lumot ===
  4000 mijoz, 4 belgi
  belgi            o_rtacha    mediana        max
  oylik_xarid         272.2      138.7     2174.9
  tashrif_soni          7.6        7.5       27.3
  orta_chek            53.4       45.8      359.4
  oxirgi_kun           20.7        8.6      100.0

=== 2. Klasterlash ===
  inersiya 914.4, 2 qadam
  silhouette 0.7490
  klaster o'lchamlari: [1376, 1232, 1018, 374]

=== 3. Markazlar asl birliklarda ===
   klaster      n    oylik_xarid  tashrif_soni     orta_chek    oxirgi_kun
         0   1376          121.4           2.0          59.8          44.7
         1   1232          378.7           9.1          41.5           7.2
         2   1018           89.5          13.8           6.5           3.0
         3    374          902.4           5.1         182.9          20.1

=== 4. MiniBatchKMeans bilan solishtirish ===
  KMeans inersiya:          914.39
  MiniBatchKMeans inersiya: 914.71 (+0.04%)
  ikkalasining kelishuvi (ARI): 1.0000
  haqiqiy segment bilan: KMeans 1.0000, MiniBatch 1.0000
  ⭐ Markazlarni asl birliklarda talqin qiling

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


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

Noto'g'ri fikr To'g'risi
"K-means global optimumni topadi" Lokal minimum
"Eng kichik inersiya — eng yaxshi k" Inersiya monoton kamayadi
"n_init ahamiyatsiz" Lokal minimumdan himoya
"K-means har qanday shaklga mos" Sferik klasterlar uchun
"Kichik klaster ham segment" Ko'pincha anomaliya
"Anomaliyalar zarar qilmaydi" Markazlarni tortadi
"MiniBatch sezilarli yomonroq" Odatda 1-3%
"Inersiyani modellar orasida taqqoslash mumkin" Faqat bir xil masshtabda

6. Keng tarqalgan xatolar va yechimlari

1. Masshtablamaslik

python
KMeans(4).fit(X)                                                  # ⚠️
KMeans(4, n_init=10, random_state=0).fit(StandardScaler().fit_transform(X)) # ✅

2. n_init=1

python
KMeans(4, n_init=1)                                               # ⚠️
KMeans(4, n_init=10)                                              # ✅

3. Inersiya bo'yicha k tanlash

python
k = min(range(2, 15), key=lambda k: KMeans(k).fit(X).inertia_)    # ⚠️
# elbow + silhouette + barqarorlik 16.3-bob                         # ✅

4. Anomaliyalarni tekshirmaslik

python
KMeans(4).fit(X)   # 30 ta chetlangan nuqta bor                   # ⚠️
# avval IsolationForest bilan tekshiring 16.10-bob                  # ✅

5. Kichik klasterni segment deb qabul qilish

python
# "3-klaster (8 mijoz) - VIP segment"                             # ⚠️
# 8 ta nuqta segment emas - anomaliyalarni tekshiring             # ✅

6. Markazlarni masshtablangan holda ko'rsatish

python
print(km.cluster_centers_)       # -0.42, 1.17 - tushunarsiz      # ⚠️
print(sc.inverse_transform(km.cluster_centers_))                  # ✅

7. Katta ma'lumotda oddiy K-means

python
KMeans(20).fit(X_10mln)                                           # ⚠️
MiniBatchKMeans(20, batch_size=1024).fit(X_10mln)                 # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 16.1-dars (o'tilgan): Masshtablash
  • 16.3-dars: Klasterlar sonini tanlash
  • 16.6-dars: Gauss aralashmasi (K-means ning umumlashmasi)
  • 16.7-dars: Klasterlashni baholash
  • 16.11-dars: Qo'llanilishi

8. Eng yaxshi amaliyotlar

  1. Masshtablang.

  2. n_init=10 qo'ying.

  3. random_state belgilang.

  4. Anomaliyalarni oldindan ko'ring.

  5. Klaster o'lchamlarini tekshiring.

  6. Markazlarni asl birliklarda talqin qiling.

  7. Barqarorlikni sinang.

  8. Katta ma'lumotda MiniBatch.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # K-means ikki qadami?
2.  # inersiya formulasi?
3.  # k oshganda inersiya?
4.  # yaqinlashish kafolatlanganmi?
5.  # optimallik-chi?
6.  # k-means++ nima qiladi?
7.  # n_init nima uchun?
8.  # to'rt asosiy taxmin?
9.  # anomaliya nima qiladi?
10. # juda kichik klaster nimani anglatadi?
11. # MiniBatch qachon?
12. # markazlarni qanday talqin qilish kerak?
Javoblar
  1. Biriktirish va markazni yangilash
  2. sum ||x - markaz||^2
  3. Monoton kamayadi
  4. Ha
  5. Yo'q (lokal minimum)
  6. Tarqalgan boshlang'ich tanlaydi
  7. Lokal minimumdan himoya
  8. Sferik, teng o'lcham, teng zichlik, shovqinsiz
  9. Markazlarni tortadi
  10. Anomaliyalar guruhi
  11. Juda katta ma'lumotda
  12. inverse_transform bilan

Vazifa 2: Xatolarni tuzating

python
1.  KMeans(4).fit(X)   # masshtablanmagan

2.  KMeans(4, n_init=1)

3.  k = min(range(2, 15), key=lambda k: KMeans(k).fit(X).inertia_)

4.  print(km.cluster_centers_)   # hisobot uchun

5.  KMeans(20).fit(X_10mln)
Javoblar
python
1.  KMeans(4, n_init=10, random_state=0).fit(StandardScaler().fit_transform(X))

2.  KMeans(4, n_init=10)

3.  # elbow + silhouette + barqarorlik

4.  print(sc.inverse_transform(km.cluster_centers_))

5.  MiniBatchKMeans(20, batch_size=1024).fit(X_10mln)

Vazifa 3: Qo'lda K-means

Modellang:

  1. Iteratsiyalar
  2. sklearn
  3. Boshlang'ich ta'siri
  4. k-means++ va n_init

Vazifa 4: Taxminlar

Modellang:

  1. Besh vaziyat
  2. Turli o'lcham
  3. Anomaliyalar
  4. Kichik klaster

Vazifa 5: Inersiya

Modellang:

  1. k bo'yicha
  2. k = n
  3. Masshtab
  4. Shakl

Vazifa 6: Segmentatsiya

Modellang:

  1. Ma'lumot
  2. Klasterlash
  3. Markazlar
  4. MiniBatch

Vazifa 7: O'ylash

K-means klasterlarni sferik deb taxmin qiladi va bu ko'p hollarda noto'g'ri. Nega u hali ham eng ko'p ishlatiladigan algoritm?

Javob

Qisqa javob: K-means noto'g'ri, lekin foydali. Uning taxminlari kamdan-kam to'liq bajariladi, lekin natija ko'pincha yetarlicha yaxshi bo'ladi — va uning tezligi, soddaligi va bashoratliligi boshqa algoritmlarning aniqligidan ko'ra ko'proq qadrlanadi.

1. Amaliy afzalliklar

Jihat K-means Muqobillar
Tezlik O(n·k·p·i) chiziqli Ierarxik O(n^2 log n), DBSCAN O(n log n)
Xotira Faqat markazlar Ierarxik — n×n masofa matritsasi
Yangi nuqta predict() — bir qadam DBSCAN da yo'q
Parametr Faqat k DBSCAN: eps va min_samples
Natija Har doim k ta klaster DBSCAN: 1 yoki 50 ta bo'lishi mumkin

2. "Yetarlicha yaxshi" nima degani

  • Segmentatsiyada maqsad — harakatga yaroqli guruhlar, matematik jihatdan mukammal emas
  • Klaster chegarasidagi 5% mijoz noto'g'ri tushsa, marketing natijasi deyarli o'zgarmaydi
  • Sferiklik taxmini masshtablash va log transformatsiyadan keyin ko'pincha yaqinlashadi

3. Bashoratlilik — yashirin afzallik

  1. predict() yangi mijozni darhol segmentga joylashtiradi
  2. Ishlab chiqarishda bu majburiy talab
  3. DBSCAN va ierarxik klasterlashda bu to'g'ridan-to'g'ri mumkin emas
  4. Markazlar — kichik, tushunarli, versiyalanadigan model

4. Qachon boshqasiga o'tish kerak

  • Klasterlar aniq nosferik (yarim oy, halqa) — DBSCAN yoki spektral
  • Shovqin ko'p va u alohida ajratilishi kerak — DBSCAN
  • Klasterlar bir-biriga kirib ketgan, ehtimollik kerak — GMM (16.6)
  • k oldindan noma'lum va ierarxiya muhim — ierarxik (16.4)

5. Xulosa

  1. Taxminlar kamdan-kam bajariladi, lekin natija ko'pincha foydali
  2. Tezlik va bashoratlilik amaliyotda hal qiluvchi
  3. Masshtablash va transformatsiya taxminlarni yaqinlashtiradi
  4. Muqobilni sabab bilan tanlang, moda bilan emas

Nimani mustahkamlaydi: 2.4, 2.6-bo'limlar.


Xulosa

Bu darsda K-means ni o'rgandik.

Eng muhim uch fikr:

  1. Ikki qadam, takrorlanadigan. Biriktirish (har nuqta eng yaqin markazga) va yangilash (markaz o'z nuqtalarining o'rtachasiga ko'chadi) — shu ikkisi inersiyani (sum ||x - markaz||^2) monoton kamaytiradi va yaqinlashishni kafolatlaydi. Lekin faqat lokal minimumga: shuning uchun k-means++ va n_init=10 kerak.

  2. Inersiya bo'yicha k tanlab bo'lmaydi. U k oshgani sari har doim kamayadi va k = n bo'lganda nolga teng bo'ladi. Bundan tashqari, inersiya masshtabga bog'liq — uni turli masshtablangan ma'lumotlar orasida taqqoslash ma'nosiz.

  3. Taxminlar jim buziladi. K-means klasterlarni sferik, teng o'lchamli, teng zichlikdagi va shovqinsiz deb hisoblaydi. Buzilganda u xato haqida ogohlantirmaydi: cho'zinchoq klasterni ikkiga bo'ladi, kattasini parchalaydi, anomaliyalar esa markazlarni tortadi yoki o'zlariga sun'iy klaster oladi. Juda kichik klaster — deyarli har doim anomaliya belgisi.

Keyingi darsda klasterlar sonini tanlashni o'rganamiz: elbow, silhouette, gap statistikasi va barqarorlik.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
16.2-dars: K-means — IlmHamroh