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

16.3-dars: Klasterlar sonini tanlash

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


1. Kirish va motivatsiya

k ni tanlash — klasterlashning eng ko'p savol tug'diradigan qadami. K-means dan k ni so'raydi, lekin ma'lumotning o'zi javobni bermaydi: inersiya har doim kamayadi, silhouette esa tuzilmasiz ma'lumotda ham "eng yaxshi" qiymatni ko'rsatadi.

Haqiqat shundaki, yagona to'g'ri k ko'pincha mavjud emas. Bir xil mijozlar bazasi 3 ta keng segmentga ham, 12 ta nozik segmentga ham bo'linishi mumkin — ikkalasi ham "to'g'ri", tanlov esa maqsadga bog'liq.

Bu darsda: elbow usuli va uning cheklovlari, silhouette tahlili, gap statistikasi, barqarorlik asosida tanlash, bir necha usulni birlashtirish va amaliy mezonlar.

Real vaziyat. Bank mijozlarni segmentlashda elbow 4 ni, silhouette 2 ni, gap statistikasi 7 ni ko'rsatdi. Yakuniy tanlov — 5: marketing bo'limi 5 tadan ortiq kampaniyani boshqara olmasdi va 5 ta segment domen mutaxassislariga tushunarli bo'ldi. Statistika chegarani belgiladi, qarorni esa amaliyot qabul qildi.

Bu darsda klasterlar sonini tanlashni o'rganamiz.

Bu darsda:

  • Elbow usuli
  • Silhouette tahlili
  • Gap statistikasi
  • Barqarorlik
  • Usullarni birlashtirish
  • Amaliy mezonlar
  • Tuzoqlar
  • Amaliy: to'liq tanlov

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


2. Nazariya — chuqur tushuntirish

2.1. Elbow usuli

text
Inersiyani k bo'yicha chizib, EGILISH nuqtasini qidirish

  k kichik: har qo'shimcha klaster inersiyani KESKIN kamaytiradi
  k katta:  kamayish SEKINLASHADI
  egilish  = shu ikki rejim orasidagi chegara

Avtomatlashtirish:
  - ikkinchi hosila (kamayishning kamayishi) eng katta bo'lgan k
  - "tizza" (knee) usuli: (1,J1)-(K,JK) chizig'idan eng uzoq nuqta

CHEKLOV: egilish ko'pincha NOANIQ yoki umuman yo'q

Elbow — eng mashhur va eng ishonchsiz usul: real ma'lumotlarda egri chiziq ko'pincha silliq bo'ladi va "egilish" ko'ruvchiga bog'liq bo'lib qoladi. Uni yagona mezon sifatida ishlatmang.

2.2. Silhouette tahlili

text
Har nuqta uchun:
  a = o'z klasteridagi nuqtalargacha o'rtacha masofa
  b = eng yaqin BOSHQA klasterdagi nuqtalargacha o'rtacha masofa
  s = (b - a) / max(a, b)        -1 .. +1

  s ~ +1  : to'g'ri klasterda, yaxshi ajralgan
  s ~  0  : chegarada
  s ~ -1  : ehtimol noto'g'ri klasterda

silhouette_score = barcha s larning o'rtachasi
silhouette_samples = har nuqta uchun alohida -> DIAGRAMMA

Talqin: 0.7+ kuchli, 0.5-0.7 o'rtacha, 0.25-0.5 zaif, <0.25 tuzilma yo'q

O'rtacha silhouette emas, diagrammani ko'ring: o'rtacha 0.55 bo'lgan holda bitta klaster butunlay manfiy bo'lishi mumkin. silhouette_samples har klaster uchun alohida tasvir beradi.

2.3. Gap statistikasi

text
G'oya: inersiyani TASODIFIY ma'lumotdagi inersiya bilan taqqoslash

  Gap(k) = E*[log(J_tasodifiy(k))] - log(J(k))

  tasodifiy ma'lumot: bir xil chegaralarda tekis taqsimlangan nuqtalar
  B ta namuna olinadi -> o'rtacha va standart og'ish (s_k)

Tanlov qoidasi (Tibshirani):
  eng kichik k, shunday: Gap(k) >= Gap(k+1) - s_{k+1}

Afzalligi: k = 1 ni ham (tuzilma YO'Q) topa oladi
Kamchiligi: hisoblash qimmat (B * K ta klasterlash)

Gap statistikasi yagona usul bo'lib, "klaster yo'q" degan javobni bera oladi (k = 1). Elbow va silhouette esa har doim biror k > 1 ni ko'rsatadi — hatto butunlay tasodifiy ma'lumotda ham.

2.4. Barqarorlik

text
G'oya: to'g'ri k da klasterlash ma'lumot o'zgarishiga CHIDAMLI bo'ladi

Usul:
  1. Ma'lumotni ikki qismga bo'lish (yoki bootstrap)
  2. Har qismda klasterlash
  3. Umumiy nuqtalarda yorliqlarni taqqoslash (ARI)
  4. B marta takrorlab, o'rtacha ARI

  yuqori ARI -> k barqaror
  past ARI   -> k noto'g'ri yoki tuzilma yo'q

Bu usul ko'pincha eng ISHONCHLI, lekin kam qo'llaniladi

Barqarorlik — amalda eng ishonchli mezon: u geometrik taxminlarga tayanmaydi va to'g'ridan-to'g'ri "bu natija takrorlanadimi?" degan savolga javob beradi.

2.5. Usullarni birlashtirish

text
Hech bir usul yakka o'zi yetarli emas:

  elbow       -> nomzodlar oralig'ini beradi
  silhouette  -> geometrik ajralishni tekshiradi
  gap         -> tuzilma umuman bormi
  barqarorlik -> natija takrorlanadimi
  MAZMUN      -> segmentlar tushunarli va harakatga yaroqlimi

Amaliy tartib:
  1. gap bilan tuzilma borligini tekshiring
  2. elbow + silhouette bilan 2-3 nomzod tanlang
  3. nomzodlar orasidan barqarorligi yuqorisini oling
  4. domen mutaxassisi bilan mazmunni tekshiring

Usullar kelishmasa — bu ham ma'lumot: ehtimol tuzilma zaif yoki ierarxik (turli darajada turli k). Bunday holda ierarxik klasterlash 16.4-bob ko'proq ma'lumot beradi.

2.6. Amaliy mezonlar

text
Statistikadan tashqari:
  - segmentlar soni BOSHQARILADIGAN bo'lsin (marketing: 3-7)
  - har segment YETARLICHA KATTA bo'lsin (odatda > 5%)
  - segmentlar bir-biridan AMALIY jihatdan farq qilsin
  - segmentga yangi obyektni joylashtirish mumkin bo'lsin
  - segmentlar vaqt o'tishi bilan barqaror qolsin

Ko'pincha: k ni biznes cheklovi belgilaydi, statistika esa tasdiqlaydi

Biznes cheklovi ko'pincha statistikadan ustun turadi — va bu to'g'ri: 12 ta statistik jihatdan mukammal segment, agar ular bo'yicha harakat qilib bo'lmasa, 4 ta "yetarlicha yaxshi" segmentdan foydasizroq.

2.7. Tuzoqlar

Asosiy tuzoqlar: faqat elbow ga tayanish; o'rtacha silhouette ni diagramma o'rniga ishlatish; tuzilma borligini tekshirmaslik (gap); barqarorlikni o'lchamaslik; masshtablanmagan ma'lumotda k tanlash; k ni maksimal metrika bo'yicha mexanik tanlash; juda ko'p k (30+) ni sinash va eng yaxshisini olish (ko'p taqqoslash muammosi); biznes cheklovini e'tiborsiz qoldirish.

2.8. Yagona to'g'ri k yo'q

k ni tanlash bir nechta mezonni birlashtirishni talab qiladi: elbow nomzodlar oralig'ini, silhouette geometrik ajralishni, gap statistikasi tuzilma umuman borligini, barqarorlik esa natija takrorlanishini ko'rsatadi. Inersiya monoton kamaygani uchun uni yakka mezon qilib bo'lmaydi, silhouette esa tasodifiy ma'lumotda ham javob beradi. Yakuniy qarorda mazmun va biznes cheklovi hal qiluvchi. Keyingi dars — ierarxik klasterlash.


3. Tez ma'lumotnoma

python
import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import adjusted_rand_score, silhouette_samples, silhouette_score

for k in range(2, 11):
    km = KMeans(k, n_init=10, random_state=0).fit(Xs)
    print(k, km.inertia_, silhouette_score(Xs, km.labels_))

s = silhouette_samples(Xs, yorliq)         # har nuqta uchun
for k in np.unique(yorliq):
    print(k, s[yorliq == k].mean(), (s[yorliq == k] < 0).mean())

# barqarorlik
a = KMeans(k, n_init=10, random_state=0).fit_predict(Xs[idx1])
b = KMeans(k, n_init=10, random_state=0).fit_predict(Xs[idx2])
adjusted_rand_score(a[umumiy1], b[umumiy2])
QOIDA: bir necha usul · diagrammani ko'r · barqarorlikni o'lcha ·
       mazmunni tekshir

k tanlash xulosasi

Elbow: egilish nuqtasi; ko'pincha noaniq
Silhouette: (b-a)/max(a,b); diagrammani ko'ring, o'rtachani emas
Gap: tasodifiy ma'lumot bilan taqqoslash; k=1 ni topa oladi
Barqarorlik: ikki yarimda ARI; eng ishonchli
Yakunda: mazmun va biznes cheklovi

4. Batafsil misollar

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

Misol 1 — Elbow va silhouette

python
"""Ikki klassik usul va ularning cheklovlari (real numpy/sklearn)."""

import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import silhouette_samples, silhouette_score
from sklearn.preprocessing import StandardScaler


def main() -> None:
    X, haqiqiy = make_blobs(n_samples=1200, centers=4, cluster_std=1.0,
                            random_state=3)
    Xs = StandardScaler().fit_transform(X)

    print("=== 1. Inersiya va elbow ===")
    kk = list(range(1, 11))
    inersiya = []
    for k in kk:
        inersiya.append(KMeans(k, n_init=10, random_state=0).fit(Xs).inertia_)
    inersiya = np.array(inersiya)
    print(f"  {'k':>3} {'inersiya':>11} {'kamayish':>11} {'kamayish %':>12}")
    for i, k in enumerate(kk):
        if i == 0:
            print(f"  {k:>3} {inersiya[i]:>11.2f} {'-':>11} {'-':>12}")
        else:
            d = inersiya[i - 1] - inersiya[i]
            print(f"  {k:>3} {inersiya[i]:>11.2f} {d:>11.2f} "
                  f"{d / inersiya[i - 1]:>12.2%}")

    print("\n=== 2. Elbow ni avtomatik topish (tizza usuli) ===")
    # (k1,J1) va (kK,JK) orasidagi chiziqdan eng uzoq nuqta
    x = np.array(kk, dtype=float)
    yv = inersiya / inersiya[0]
    xn = (x - x[0]) / (x[-1] - x[0])
    chiziq = yv[0] + (yv[-1] - yv[0]) * xn
    masofa = chiziq - yv
    print(f"  {'k':>3} {'chiziqdan masofa':>18}")
    for i, k in enumerate(kk):
        print(f"  {k:>3} {masofa[i]:>18.4f}")
    print(f"  tizza: k = {kk[int(np.argmax(masofa))]}")

    print("\n=== 3. Silhouette bo'yicha ===")
    print(f"  {'k':>3} {'o_rtacha':>10} {'eng past klaster':>18} "
          f"{'manfiy %':>10}")
    for k in range(2, 11):
        yorliq = KMeans(k, n_init=10, random_state=0).fit_predict(Xs)
        s = silhouette_samples(Xs, yorliq)
        klaster_ort = [s[yorliq == c].mean() for c in range(k)]
        print(f"  {k:>3} {s.mean():>10.4f} {min(klaster_ort):>18.4f} "
              f"{(s < 0).mean():>10.2%}")

    print("\n=== 4. Silhouette diagrammasi (k = 4 va k = 6) ===")
    for k in [4, 6]:
        yorliq = KMeans(k, n_init=10, random_state=0).fit_predict(Xs)
        s = silhouette_samples(Xs, yorliq)
        print(f"  k = {k} (o'rtacha {s.mean():.4f}):")
        print(f"    {'klaster':>8} {'n':>6} {'o_rtacha s':>12} "
              f"{'manfiy':>8}")
        for c in range(k):
            m = yorliq == c
            print(f"    {c:>8} {int(m.sum()):>6} {s[m].mean():>12.4f} "
                  f"{int((s[m] < 0).sum()):>8}")
    print("  ⭐ O'rtacha silhouette klasterlararo farqni yashiradi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Inersiya va elbow ===
    k    inersiya    kamayish   kamayish %
    1     2400.00           -            -
    2      613.05     1786.95       74.46%
    3      283.30      329.75       53.79%
    4       80.03      203.27       71.75%
    5       71.90        8.12       10.15%
    6       64.02        7.88       10.96%
    7       56.60        7.43       11.60%
    8       49.85        6.75       11.92%
    9       46.00        3.85        7.72%
   10       42.28        3.72        8.09%

=== 2. Elbow ni avtomatik topish (tizza usuli) ===
    k   chiziqdan masofa
    1             0.0000
    2             0.6354
    3             0.6637
    4             0.6392
    5             0.5334
    6             0.4276
    7             0.3215
    8             0.2152
    9             0.1076
   10            -0.0000
  tizza: k = 3

=== 3. Silhouette bo'yicha ===
    k   o_rtacha   eng past klaster   manfiy %
    2     0.6320             0.6229      0.00%
    3     0.6207             0.4275      0.17%
    4     0.7299             0.6968      0.00%
    5     0.6282             0.3286      0.08%
    6     0.5323             0.3207      1.00%
    7     0.4415             0.3317      0.67%
    8     0.3372             0.3011      1.08%
    9     0.3380             0.3035      1.58%
   10     0.3420             0.3071      2.08%

=== 4. Silhouette diagrammasi (k = 4 va k = 6) ===
  k = 4 (o'rtacha 0.7299):
     klaster      n   o_rtacha s   manfiy
           0    300       0.7080        0
           1    300       0.7569        0
           2    300       0.7578        0
           3    300       0.6968        0
  k = 6 (o'rtacha 0.5323):
     klaster      n   o_rtacha s   manfiy
           0    137       0.3595        0
           1    299       0.6866        0
           2    142       0.3207        8
           3    300       0.7574        0
           4    164       0.3224        4
           5    158       0.3711        0
  ⭐ O'rtacha silhouette klasterlararo farqni yashiradi

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

Misol 2 — Gap statistikasi

python
"""Tuzilma umuman bormi degan savolga javob (real numpy/sklearn)."""

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


def gap_statistika(X, kk, B: int = 10, seed: int = 0):
    """Tibshirani gap statistikasi: log(J_tasodifiy) - log(J)."""
    rng = np.random.default_rng(seed)
    past, yuqori = X.min(axis=0), X.max(axis=0)
    gaplar, sklar, loglar = [], [], []
    for k in kk:
        J = KMeans(k, n_init=10, random_state=0).fit(X).inertia_
        J = max(J, 1e-12)
        tasodifiy = []
        for b in range(B):
            Xr = rng.uniform(past, yuqori, X.shape)
            Jr = KMeans(k, n_init=5, random_state=b).fit(Xr).inertia_
            tasodifiy.append(np.log(max(Jr, 1e-12)))
        tasodifiy = np.array(tasodifiy)
        gaplar.append(tasodifiy.mean() - np.log(J))
        sklar.append(tasodifiy.std() * np.sqrt(1 + 1 / B))
        loglar.append(np.log(J))
    return np.array(gaplar), np.array(sklar), np.array(loglar)


def tanla(kk, gaplar, sklar) -> int:
    """Eng kichik k: Gap(k) >= Gap(k+1) - s_{k+1}."""
    for i in range(len(kk) - 1):
        if gaplar[i] >= gaplar[i + 1] - sklar[i + 1]:
            return kk[i]
    return kk[-1]


def main() -> None:
    kk = list(range(1, 9))
    rng = np.random.default_rng(0)

    print("=== 1. Uch klasterli ma'lumot ===")
    X, _ = make_blobs(n_samples=800, centers=3, cluster_std=1.0,
                      random_state=1)
    Xs = StandardScaler().fit_transform(X)
    g, s, _ = gap_statistika(Xs, kk)
    print(f"  {'k':>3} {'gap':>9} {'s_k':>8} {'gap(k+1)-s':>12}")
    for i, k in enumerate(kk):
        keyingi = (f"{g[i + 1] - s[i + 1]:.4f}" if i + 1 < len(kk) else "-")
        print(f"  {k:>3} {g[i]:>9.4f} {s[i]:>8.4f} {keyingi:>12}")
    print(f"  tanlangan k = {tanla(kk, g, s)}")

    print("\n=== 2. Tuzilmasiz (tasodifiy) ma'lumot ===")
    Xr = StandardScaler().fit_transform(rng.normal(0, 1, (800, 2)))
    g2, s2, _ = gap_statistika(Xr, kk)
    print(f"  {'k':>3} {'gap':>9} {'s_k':>8}")
    for i, k in enumerate(kk):
        print(f"  {k:>3} {g2[i]:>9.4f} {s2[i]:>8.4f}")
    print(f"  tanlangan k = {tanla(kk, g2, s2)} (1 = tuzilma yo'q)")

    print("\n=== 3. Elbow va silhouette shu ma'lumotda nima deydi ===")
    from sklearn.metrics import silhouette_score
    print(f"  {'k':>3} {'inersiya':>11} {'silhouette':>12}")
    for k in range(2, 7):
        km = KMeans(k, n_init=10, random_state=0).fit(Xr)
        print(f"  {k:>3} {km.inertia_:>11.2f} "
              f"{silhouette_score(Xr, km.labels_):>12.4f}")
    print("  (ikkalasi ham 'eng yaxshi' k ni ko'rsatadi - tuzilma yo'q bo'lsa ham)")

    print("\n=== 4. Klasterlar soni oshganda ===")
    for haqiqiy_k in [2, 5]:
        Xa, _ = make_blobs(n_samples=900, centers=haqiqiy_k, cluster_std=0.9,
                           random_state=2)
        Xa = StandardScaler().fit_transform(Xa)
        ga, sa, _ = gap_statistika(Xa, kk, B=8, seed=1)
        print(f"  haqiqiy k = {haqiqiy_k}: gap tanlagan k = "
              f"{tanla(kk, ga, sa)}")
    print("  ⭐ Gap statistikasi 'klaster yo'q' javobini bera oladi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Uch klasterli ma'lumot ===
    k       gap      s_k   gap(k+1)-s
    1    0.1373   0.0162       1.3566
    2    1.3756   0.0190       2.0418
    3    2.0563   0.0146       1.7931
    4    1.8151   0.0219       1.7731
    5    1.7906   0.0174       1.7947
    6    1.8123   0.0176       1.7299
    7    1.7571   0.0271       1.6833
    8    1.7070   0.0237            -
  tanlangan k = 3

=== 2. Tuzilmasiz (tasodifiy) ma'lumot ===
    k       gap      s_k
    1    1.3711   0.0156
    2    1.2750   0.0219
    3    1.2046   0.0232
    4    1.0112   0.0190
    5    1.0052   0.0158
    6    1.0332   0.0211
    7    1.0021   0.0164
    8    0.9402   0.0216
  tanlangan k = 1 (1 = tuzilma yo'q)

=== 3. Elbow va silhouette shu ma'lumotda nima deydi ===
    k    inersiya   silhouette
    2     1075.13       0.3093
    3      731.31       0.3300
    4      569.26       0.3169
    5      478.12       0.3170
    6      394.44       0.3303
  (ikkalasi ham 'eng yaxshi' k ni ko'rsatadi - tuzilma yo'q bo'lsa ham)

=== 4. Klasterlar soni oshganda ===
  haqiqiy k = 2: gap tanlagan k = 4
  haqiqiy k = 5: gap tanlagan k = 5
  ⭐ Gap statistikasi 'klaster yo'q' javobini bera oladi

Nima ko'rsatdi: 2.3-bo'lim.

Misol 3 — Barqarorlik

python
"""To'g'ri k ma'lumot o'zgarishiga chidamli (real numpy/sklearn)."""

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


def barqarorlik(X, k: int, B: int = 20, seed: int = 0) -> tuple[float, float]:
    """Ikki yarimda klasterlab, umumiy nuqtalarda ARI ni o'lchaydi."""
    rng = np.random.default_rng(seed)
    n = len(X)
    ballar = []
    for _ in range(B):
        a = rng.choice(n, int(n * 0.7), replace=False)
        b = rng.choice(n, int(n * 0.7), replace=False)
        umumiy = np.intersect1d(a, b)
        if len(umumiy) < 30:
            continue
        ya = KMeans(k, n_init=10, random_state=0).fit(X[a])
        yb = KMeans(k, n_init=10, random_state=0).fit(X[b])
        ballar.append(adjusted_rand_score(ya.predict(X[umumiy]),
                                          yb.predict(X[umumiy])))
    return float(np.mean(ballar)), float(np.std(ballar))


def main() -> None:
    print("=== 1. Uch aniq klaster ===")
    X, y = make_blobs(n_samples=900, centers=3, cluster_std=0.9,
                      random_state=4)
    Xs = StandardScaler().fit_transform(X)
    print(f"  {'k':>3} {'barqarorlik':>13} {'std':>8}")
    for k in range(2, 8):
        o, s = barqarorlik(Xs, k)
        print(f"  {k:>3} {o:>13.4f} {s:>8.4f}")

    print("\n=== 2. Tuzilmasiz ma'lumot ===")
    rng = np.random.default_rng(0)
    Xr = StandardScaler().fit_transform(rng.normal(0, 1, (900, 2)))
    print(f"  {'k':>3} {'barqarorlik':>13} {'std':>8}")
    for k in range(2, 8):
        o, s = barqarorlik(Xr, k)
        print(f"  {k:>3} {o:>13.4f} {s:>8.4f}")
    print("  (barqarorlik past - tuzilma yo'qligini ko'rsatadi)")

    print("\n=== 3. Ierarxik tuzilma: 2 ta katta, 6 ta kichik guruh ===")
    markazlar = []
    for katta in [[-6.0, 0.0], [6.0, 0.0]]:
        for burchak in [0, 2 * np.pi / 3, 4 * np.pi / 3]:
            markazlar.append([katta[0] + 1.6 * np.cos(burchak),
                              katta[1] + 1.6 * np.sin(burchak)])
    Xh, yh = make_blobs(n_samples=1200, centers=np.array(markazlar),
                        cluster_std=0.45, random_state=0)
    Xh = StandardScaler().fit_transform(Xh)
    print(f"  {'k':>3} {'barqarorlik':>13} {'std':>8}")
    for k in range(2, 9):
        o, s = barqarorlik(Xh, k)
        print(f"  {k:>3} {o:>13.4f} {s:>8.4f}")
    print("  (ikki daraja ham barqaror - k = 2 va k = 6)")

    print("\n=== 4. Barqarorlik va silhouette birga ===")
    from sklearn.metrics import silhouette_score
    print(f"  {'k':>3} {'silhouette':>12} {'barqarorlik':>13}")
    for k in range(2, 9):
        yorliq = KMeans(k, n_init=10, random_state=0).fit_predict(Xh)
        o, _ = barqarorlik(Xh, k, B=12)
        print(f"  {k:>3} {silhouette_score(Xh, yorliq):>12.4f} {o:>13.4f}")
    print("  ⭐ Barqarorlik geometrik taxminlarga tayanmaydi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Uch aniq klaster ===
    k   barqarorlik      std
    2        1.0000   0.0000
    3        0.9896   0.0096
    4        0.8856   0.1307
    5        0.7630   0.1490
    6        0.9530   0.0323
    7        0.8697   0.0475

=== 2. Tuzilmasiz ma'lumot ===
    k   barqarorlik      std
    2        0.4096   0.4269
    3        0.4958   0.2046
    4        0.6518   0.1631
    5        0.5456   0.1994
    6        0.7904   0.1484
    7        0.7423   0.1368
  (barqarorlik past - tuzilma yo'qligini ko'rsatadi)

=== 3. Ierarxik tuzilma: 2 ta katta, 6 ta kichik guruh ===
    k   barqarorlik      std
    2        1.0000   0.0000
    3        0.5931   0.2551
    4        0.9720   0.0243
    5        0.7157   0.1876
    6        0.9764   0.0125
    7        0.8166   0.0770
    8        0.7781   0.1132
  (ikki daraja ham barqaror - k = 2 va k = 6)

=== 4. Barqarorlik va silhouette birga ===
    k   silhouette   barqarorlik
    2       0.4978        1.0000
    3       0.4792        0.5047
    4       0.5709        0.9622
    5       0.5856        0.7057
    6       0.6070        0.9773
    7       0.5779        0.8376
    8       0.5381        0.7680
  ⭐ Barqarorlik geometrik taxminlarga tayanmaydi

Nima ko'rsatdi: 2.4-bo'lim.

Misol 4 — To'liq tanlov jarayoni

python
"""Real segmentatsiyada k ni tanlash (real pandas/sklearn)."""

import numpy as np
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.metrics import (adjusted_rand_score, calinski_harabasz_score,
                             davies_bouldin_score, silhouette_samples,
                             silhouette_score)
from sklearn.preprocessing import StandardScaler


def yarat(seed: int = 21, n: int = 3000) -> pd.DataFrame:
    """5 ta segment, ikkitasi bir-biriga yaqin."""
    rng = np.random.default_rng(seed)
    segment = rng.choice(5, n, p=[0.3, 0.25, 0.2, 0.15, 0.1])
    profil = np.array([
        [120.0, 3.0, 55.0, 40.0],
        [140.0, 4.0, 48.0, 33.0],          # 0 ga yaqin
        [420.0, 10.0, 45.0, 6.0],
        [95.0, 15.0, 7.0, 3.0],
        [980.0, 6.0, 175.0, 18.0],
    ])
    X = profil[segment] * rng.lognormal(0, 0.20, (n, 4))
    return pd.DataFrame(X, columns=["oylik_xarid", "tashrif", "orta_chek",
                                    "oxirgi_kun"]).assign(segment=segment)


def barqarorlik(X, k: int, B: int = 12, seed: int = 0) -> float:
    rng = np.random.default_rng(seed)
    ballar = []
    for _ in range(B):
        a = rng.choice(len(X), int(len(X) * 0.7), replace=False)
        b = rng.choice(len(X), int(len(X) * 0.7), replace=False)
        umumiy = np.intersect1d(a, b)
        ya = KMeans(k, n_init=10, random_state=0).fit(X[a])
        yb = KMeans(k, n_init=10, random_state=0).fit(X[b])
        ballar.append(adjusted_rand_score(ya.predict(X[umumiy]),
                                          yb.predict(X[umumiy])))
    return float(np.mean(ballar))


def main() -> None:
    df = yarat()
    nomlar = ["oylik_xarid", "tashrif", "orta_chek", "oxirgi_kun"]
    Xs = StandardScaler().fit_transform(np.log1p(df[nomlar].to_numpy()))

    print("=== 1. Barcha mezonlar bir jadvalda ===")
    print(f"  {'k':>3} {'inersiya':>10} {'silh':>8} {'DB':>7} {'CH':>9} "
          f"{'barqaror':>10} {'eng kichik %':>13}")
    natijalar = {}
    for k in range(2, 10):
        km = KMeans(k, n_init=10, random_state=0).fit(Xs)
        s = silhouette_score(Xs, km.labels_)
        db = davies_bouldin_score(Xs, km.labels_)
        ch = calinski_harabasz_score(Xs, km.labels_)
        b = barqarorlik(Xs, k)
        kichik = np.bincount(km.labels_).min() / len(Xs)
        natijalar[k] = (s, db, ch, b, kichik)
        print(f"  {k:>3} {km.inertia_:>10.1f} {s:>8.4f} {db:>7.4f} "
              f"{ch:>9.1f} {b:>10.4f} {kichik:>12.1%}")

    print("\n=== 2. Har mezon qaysi k ni tanlaydi ===")
    print(f"  silhouette (max):   k = "
          f"{max(natijalar, key=lambda k: natijalar[k][0])}")
    print(f"  Davies-Bouldin (min): k = "
          f"{min(natijalar, key=lambda k: natijalar[k][1])}")
    print(f"  Calinski-Harabasz (max): k = "
          f"{max(natijalar, key=lambda k: natijalar[k][2])}")
    print(f"  barqarorlik (max):  k = "
          f"{max(natijalar, key=lambda k: natijalar[k][3])}")
    print(f"  haqiqiy segmentlar soni: {df['segment'].nunique()}")

    print("\n=== 3. Amaliy cheklovlar ===")
    print(f"  {'k':>3} {'eng kichik %':>13} {'boshqariladimi':>15} "
          f"{'ARI (haqiqiy)':>15}")
    for k in range(2, 10):
        kichik = natijalar[k][4]
        yorliq = KMeans(k, n_init=10, random_state=0).fit_predict(Xs)
        ari = adjusted_rand_score(df["segment"], yorliq)
        boshqariladi = "ha" if 3 <= k <= 7 and kichik >= 0.05 else "yo'q"
        print(f"  {k:>3} {kichik:>12.1%} {boshqariladi:>15} {ari:>15.4f}")

    print("\n=== 4. Yakuniy tanlov va silhouette diagrammasi ===")
    nomzodlar = [k for k in range(3, 8) if natijalar[k][4] >= 0.05]
    eng = max(nomzodlar, key=lambda k: natijalar[k][3])
    print(f"  nomzodlar (3-7, eng kichik klaster >= 5%): {nomzodlar}")
    print(f"  barqarorligi eng yuqorisi: k = {eng}")
    yorliq = KMeans(eng, n_init=10, random_state=0).fit_predict(Xs)
    s = silhouette_samples(Xs, yorliq)
    print(f"  {'klaster':>8} {'n':>6} {'ulush':>8} {'o_rtacha s':>12} "
          f"{'manfiy':>8}")
    for c in range(eng):
        m = yorliq == c
        print(f"  {c:>8} {int(m.sum()):>6} {m.mean():>7.1%} "
              f"{s[m].mean():>12.4f} {int((s[m] < 0).sum()):>8}")
    print("  ⭐ Statistika chegara qo'yadi, qarorni amaliyot qabul qiladi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Barcha mezonlar bir jadvalda ===
    k   inersiya     silh      DB        CH   barqaror  eng kichik %
    2     5835.9   0.5505  0.8590    3166.6     1.0000        34.8%
    3     2015.4   0.6919  0.5538    7423.8     1.0000        15.4%
    4      865.3   0.7440  0.3661   12851.4     1.0000        10.7%
    5      708.8   0.4815  0.7887   11928.0     0.9680        10.7%
    6      662.5   0.4468  0.9979   10248.0     0.7901        10.7%
    7      622.9   0.3704  1.1930    9110.7     0.7236         7.3%
    8      584.6   0.2751  1.3815    8346.1     0.7407         7.3%
    9      549.4   0.2647  1.3833    7793.0     0.8470         7.3%

=== 2. Har mezon qaysi k ni tanlaydi ===
  silhouette (max):   k = 4
  Davies-Bouldin (min): k = 4
  Calinski-Harabasz (max): k = 4
  barqarorlik (max):  k = 2
  haqiqiy segmentlar soni: 5

=== 3. Amaliy cheklovlar ===
    k  eng kichik %  boshqariladimi   ARI (haqiqiy)
    2        34.8%            yo'q          0.3837
    3        15.4%              ha          0.5801
    4        10.7%              ha          0.6543
    5        10.7%              ha          0.7508
    6        10.7%              ha          0.6531
    7         7.3%              ha          0.6079
    8         7.3%            yo'q          0.5319
    9         7.3%            yo'q          0.4656

=== 4. Yakuniy tanlov va silhouette diagrammasi ===
  nomzodlar (3-7, eng kichik klaster >= 5%): [3, 4, 5, 6, 7]
  barqarorligi eng yuqorisi: k = 3
   klaster      n    ulush   o_rtacha s   manfiy
         0   1637   54.6%       0.7562        0
         1    902   30.1%       0.5076        0
         2    461   15.4%       0.8240        0
  ⭐ Statistika chegara qo'yadi, qarorni amaliyot qabul qiladi

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
"Elbow aniq javob beradi" Ko'pincha noaniq
"Eng yuqori silhouette — to'g'ri k" Tuzilmasiz ma'lumotda ham javob beradi
"Yagona to'g'ri k bor" Ko'pincha yo'q
"Gap statistikasi keraksiz" Faqat u k=1 ni topa oladi
"Barqarorlik murakkab" Bir necha qator kod
"Metrikalar kelishishi kerak" Kelishmasa — ma'lumot zaif
"Ko'proq klaster — nozikroq tahlil" Boshqarib bo'lmaydi
"Statistika yakuniy qaror" Mazmun va biznes ham

6. Keng tarqalgan xatolar va yechimlari

1. Faqat elbow

python
# inersiya grafigiga qarab k=4 deb qaror qilish                   # ⚠️
# elbow + silhouette + barqarorlik + mazmun                       # ✅

2. O'rtacha silhouette

python
silhouette_score(Xs, yorliq)                                      # ⚠️
silhouette_samples(Xs, yorliq)   # har klaster uchun alohida      # ✅

3. Tuzilma borligini tekshirmaslik

python
# darhol k=5 bilan klasterlash                                    # ⚠️
# avval gap statistikasi bilan tuzilma bormi                      # ✅

4. Masshtablanmagan ma'lumotda k tanlash

python
for k in range(2, 10): KMeans(k).fit(X)                           # ⚠️
Xs = StandardScaler().fit_transform(X)                            # ✅

5. Juda ko'p k ni sinash

python
for k in range(2, 50): ...   # eng yaxshisini olish               # ⚠️
for k in range(2, 10): ...   # oqilona oraliq                     # ✅

6. Kichik klasterni e'tiborsiz qoldirish

python
# k=8 tanlandi, bitta klasterda 12 mijoz                          # ⚠️
# eng kichik klaster ulushini mezon qiling                        # ✅

7. Biznes cheklovini hisobga olmaslik

python
# "silhouette k=11 da maksimal, shuni olamiz"                     # ⚠️
# marketing 3-7 segmentni boshqara oladi                          # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 16.2-dars (o'tilgan): K-means va inersiya
  • 16.4-dars: Ierarxik klasterlash (k ni keyin tanlash)
  • 16.5-dars: DBSCAN (k kerak emas)
  • 16.7-dars: Klasterlashni baholash
  • 16.12-dars: Amaliyot

8. Eng yaxshi amaliyotlar

  1. Bir necha usulni birlashtiring.

  2. Silhouette diagrammasini ko'ring.

  3. Gap bilan tuzilmani tekshiring.

  4. Barqarorlikni o'lchang.

  5. Masshtablang.

  6. Oqilona k oralig'ini oling.

  7. Klaster o'lchamlarini tekshiring.

  8. Mazmun va biznes cheklovini hisobga oling.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # elbow nimani qidiradi?
2.  # elbow ning asosiy cheklovi?
3.  # silhouette formulasi?
4.  # s = -1 nimani anglatadi?
5.  # o'rtacha silhouette nimani yashiradi?
6.  # gap statistikasi nima bilan taqqoslaydi?
7.  # gap ning noyob imkoniyati?
8.  # barqarorlik qanday o'lchanadi?
9.  # nega barqarorlik ishonchli?
10. # usullar kelishmasa?
11. # amaliy cheklovlar?
12. # yakuniy qarorni kim qabul qiladi?
Javoblar
  1. Egilish nuqtasini
  2. Egilish ko'pincha noaniq
  3. (b-a)/max(a,b)
  4. Ehtimol noto'g'ri klasterda
  5. Klasterlararo farqni
  6. Tasodifiy tekis ma'lumot bilan
  7. k=1 (tuzilma yo'q) ni topa oladi
  8. Ikki namunada ARI
  9. Geometrik taxminlarga tayanmaydi
  10. Tuzilma zaif yoki ierarxik
  11. Boshqariladigan son, klaster ulushi
  12. Amaliyot (mazmun va biznes)

Vazifa 2: Xatolarni tuzating

python
1.  # faqat elbow grafigiga qarab k tanlash

2.  silhouette_score(Xs, yorliq)   # hisobot uchun

3.  for k in range(2, 10): KMeans(k).fit(X)   # masshtablanmagan

4.  for k in range(2, 50): ...   # eng yaxshisini olish

5.  # "silhouette k=11 da maksimal, shuni olamiz"
Javoblar
python
1.  # elbow + silhouette + barqarorlik + mazmun

2.  silhouette_samples(Xs, yorliq)

3.  Xs = StandardScaler().fit_transform(X)

4.  for k in range(2, 10): ...

5.  # biznes 3-7 segmentni boshqara oladi

Vazifa 3: Elbow va silhouette

Modellang:

  1. Inersiya
  2. Tizza usuli
  3. Silhouette
  4. Diagramma

Vazifa 4: Gap

Modellang:

  1. Klasterli ma'lumot
  2. Tuzilmasiz
  3. Boshqa usullar
  4. Turli k

Vazifa 5: Barqarorlik

Modellang:

  1. Aniq klasterlar
  2. Tuzilmasiz
  3. Ierarxik tuzilma
  4. Birga ko'rish

Vazifa 6: To'liq tanlov

Modellang:

  1. Mezonlar jadvali
  2. Har mezon tanlovi
  3. Amaliy cheklovlar
  4. Yakuniy tanlov

Vazifa 7: O'ylash

Ma'lumotda haqiqatan 5 ta segment bor, lekin ikkitasi bir-biriga juda yaqin. Barcha usullar k=4 ni ko'rsatmoqda. Bu xatomi?

Javob

Qisqa javob: yo'q, bu to'g'ri javob — ma'lumot darajasida. Ikki segment belgilar fazosida ajralmasa, ular shu belgilar bo'yicha bitta segment. Savol algoritmga emas, belgilarga qaratilishi kerak.

1. Nega usullar k=4 ni ko'rsatadi

Barcha ichki metrikalar geometrik ajralishni o'lchaydi. Ikki segment ustma-ust tushsa:

  • silhouette ularni ajratganda pasayadi (chegara nuqtalar ko'payadi)
  • inersiyaning kamayishi kichik bo'ladi
  • barqarorlik pasayadi (chegara har safar boshqa joyda)

Ya'ni metrikalar to'g'ri ishlaydi — mavjud belgilarda 5-chi segment ko'rinmaydi.

2. Nima qilish kerak

Yondashuv Izoh
Yangi belgi qo'shish Segmentlarni ajratadigan o'lcham izlash
Domen bilimi Segment ta'rifi belgilarga tayanadimi?
Ierarxik klasterlash 4 ta klasterni ichkaridan bo'lish
Yarim nazoratli Ozgina yorliq bo'lsa, undan foydalanish
Qabul qilish 4 segment yetarli bo'lishi mumkin

3. "Segment bor" deb qayerdan bilamiz

Agar bu bilim tashqi manbadan kelsa (mahsulot turi, shartnoma shakli), unda:

  1. Bu yorliq — demak nazoratli masala
  2. Klasterlash o'rniga klassifikatsiya ishlating (14-qism)
  3. Yoki segmentni qoida bilan ajrating, modelsiz

4. Yashirin xavf

k=5 ni majburan qo'yish:

  • Klasterlar chegarasi tasodifiy bo'ladi
  • Har qayta o'qitishda mijozlar segmentdan segmentga sakraydi
  • Marketing natijasi tushunarsiz bo'ladi
  • Barqarorlik past ekanini raqamda ko'rsatish mumkin

5. Xulosa

  1. Metrikalar mavjud belgilarni to'g'ri aks ettiradi
  2. Ajralmagan segment — belgilar muammosi
  3. Tashqi bilim bo'lsa, nazoratli yondashuv to'g'riroq
  4. Majburan k oshirish beqaror natija beradi

Nimani mustahkamlaydi: 2.4, 2.5-bo'limlar.


Xulosa

Bu darsda klasterlar sonini tanlashni o'rgandik.

Eng muhim uch fikr:

  1. Bitta usul yetarli emas. Elbow egilish nuqtasini qidiradi, lekin real ma'lumotda egri chiziq ko'pincha silliq bo'ladi. Silhouette geometrik ajralishni o'lchaydi, lekin tuzilmasiz ma'lumotda ham "eng yaxshi k" ni ko'rsatadi. Ularni birga va gap statistikasi bilan ishlating — u yagona usul bo'lib, k = 1 (tuzilma yo'q) degan javobni bera oladi.

  2. Barqarorlik — eng ishonchli mezon. Ma'lumotni ikki namunaga bo'lib, umumiy nuqtalarda yorliqlarni ARI bilan solishtiring. Bu usul geometrik taxminlarga tayanmaydi va to'g'ridan-to'g'ri "natija takrorlanadimi?" degan savolga javob beradi. Ierarxik tuzilmada bir nechta k barqaror bo'lishi mumkin — bu ham foydali ma'lumot.

  3. Yakuniy qarorni amaliyot qabul qiladi. Statistika nomzodlar oralig'ini beradi, tanlovni esa mazmun va biznes cheklovi hal qiladi: segmentlar boshqariladigan sonda (odatda 3-7), har biri yetarlicha katta (>5%), bir-biridan amaliy jihatdan farq qiladigan va domen mutaxassisiga tushunarli bo'lishi kerak.

Keyingi darsda ierarxik klasterlashni o'rganamiz: k ni oldindan bermay, butun ierarxiyani qurish.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!