Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Elbow usuli
- 2.2. Silhouette tahlili
- 2.3. Gap statistikasi
- 2.4. Barqarorlik
- 2.5. Usullarni birlashtirish
- 2.6. Amaliy mezonlar
- 2.7. Tuzoqlar
- 2.8. Yagona to'g'ri k yo'q
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Elbow va silhouette
- Misol 2 — Gap statistikasi
- Misol 3 — Barqarorlik
- Misol 4 — To'liq tanlov jarayoni
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
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
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'qElbow — 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
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
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
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'llaniladiBarqarorlik — 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
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 tekshiringUsullar 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
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 tasdiqlaydiBiznes 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
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 tekshirk 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 cheklovi4. Batafsil misollar
Misollar real numpy/pandas/sklearn bilan (Python 3.14).
Misol 1 — Elbow va silhouette
"""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:
=== 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 yashiradiNima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — Gap statistikasi
"""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:
=== 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 oladiNima ko'rsatdi: 2.3-bo'lim.
Misol 3 — Barqarorlik
"""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:
=== 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 tayanmaydiNima ko'rsatdi: 2.4-bo'lim.
Misol 4 — To'liq tanlov jarayoni
"""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:
=== 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 qiladiNima 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
# inersiya grafigiga qarab k=4 deb qaror qilish # ⚠️
# elbow + silhouette + barqarorlik + mazmun # ✅2. O'rtacha silhouette
silhouette_score(Xs, yorliq) # ⚠️
silhouette_samples(Xs, yorliq) # har klaster uchun alohida # ✅3. Tuzilma borligini tekshirmaslik
# darhol k=5 bilan klasterlash # ⚠️
# avval gap statistikasi bilan tuzilma bormi # ✅4. Masshtablanmagan ma'lumotda k tanlash
for k in range(2, 10): KMeans(k).fit(X) # ⚠️
Xs = StandardScaler().fit_transform(X) # ✅5. Juda ko'p k ni sinash
for k in range(2, 50): ... # eng yaxshisini olish # ⚠️
for k in range(2, 10): ... # oqilona oraliq # ✅6. Kichik klasterni e'tiborsiz qoldirish
# k=8 tanlandi, bitta klasterda 12 mijoz # ⚠️
# eng kichik klaster ulushini mezon qiling # ✅7. Biznes cheklovini hisobga olmaslik
# "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
Bir necha usulni birlashtiring.
Silhouette diagrammasini ko'ring.
Gap bilan tuzilmani tekshiring.
Barqarorlikni o'lchang.
Masshtablang.
Oqilona k oralig'ini oling.
Klaster o'lchamlarini tekshiring.
Mazmun va biznes cheklovini hisobga oling.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
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
- Egilish nuqtasini
- Egilish ko'pincha noaniq
- (b-a)/max(a,b)
- Ehtimol noto'g'ri klasterda
- Klasterlararo farqni
- Tasodifiy tekis ma'lumot bilan
- k=1 (tuzilma yo'q) ni topa oladi
- Ikki namunada ARI
- Geometrik taxminlarga tayanmaydi
- Tuzilma zaif yoki ierarxik
- Boshqariladigan son, klaster ulushi
- Amaliyot (mazmun va biznes)
Vazifa 2: Xatolarni tuzating
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
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 oladiVazifa 3: Elbow va silhouette
Modellang:
- Inersiya
- Tizza usuli
- Silhouette
- Diagramma
Vazifa 4: Gap
Modellang:
- Klasterli ma'lumot
- Tuzilmasiz
- Boshqa usullar
- Turli k
Vazifa 5: Barqarorlik
Modellang:
- Aniq klasterlar
- Tuzilmasiz
- Ierarxik tuzilma
- Birga ko'rish
Vazifa 6: To'liq tanlov
Modellang:
- Mezonlar jadvali
- Har mezon tanlovi
- Amaliy cheklovlar
- 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:
- Bu yorliq — demak nazoratli masala
- Klasterlash o'rniga klassifikatsiya ishlating (14-qism)
- 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
- Metrikalar mavjud belgilarni to'g'ri aks ettiradi
- Ajralmagan segment — belgilar muammosi
- Tashqi bilim bo'lsa, nazoratli yondashuv to'g'riroq
- 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:
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.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
kbarqaror bo'lishi mumkin — bu ham foydali ma'lumot.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.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!