Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Algoritm qadamlari
- 2.2. Inersiya
- 2.3. k-means++ va n_init
- 2.4. Taxminlar va ularning buzilishi
- 2.5. MiniBatchKMeans
- 2.6. Amaliy maslahatlar
- 2.7. Tuzoqlar
- 2.8. Sodda, tez, taxminli
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Qo'lda K-means
- Misol 2 — Taxminlar buzilganda
- Misol 3 — Inersiya xossalari
- Misol 4 — Amaliy segmentatsiya
- 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.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
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
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
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
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
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
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
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'rK-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'q4. Batafsil misollar
Misollar real numpy/pandas/sklearn bilan (Python 3.14).
Misol 1 — Qo'lda K-means
"""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:
=== 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 qiladiNima ko'rsatdi: 2.1, 2.3-bo'limlar.
Misol 2 — Taxminlar buzilganda
"""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:
=== 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 belgisiNima ko'rsatdi: 2.4-bo'lim.
Misol 3 — Inersiya xossalari
"""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:
=== 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'lchaydiNima ko'rsatdi: 2.2-bo'lim.
Misol 4 — Amaliy segmentatsiya
"""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:
=== 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 qilingNima 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
KMeans(4).fit(X) # ⚠️
KMeans(4, n_init=10, random_state=0).fit(StandardScaler().fit_transform(X)) # ✅2. n_init=1
KMeans(4, n_init=1) # ⚠️
KMeans(4, n_init=10) # ✅3. Inersiya bo'yicha k tanlash
k = min(range(2, 15), key=lambda k: KMeans(k).fit(X).inertia_) # ⚠️
# elbow + silhouette + barqarorlik 16.3-bob # ✅4. Anomaliyalarni tekshirmaslik
KMeans(4).fit(X) # 30 ta chetlangan nuqta bor # ⚠️
# avval IsolationForest bilan tekshiring 16.10-bob # ✅5. Kichik klasterni segment deb qabul qilish
# "3-klaster (8 mijoz) - VIP segment" # ⚠️
# 8 ta nuqta segment emas - anomaliyalarni tekshiring # ✅6. Markazlarni masshtablangan holda ko'rsatish
print(km.cluster_centers_) # -0.42, 1.17 - tushunarsiz # ⚠️
print(sc.inverse_transform(km.cluster_centers_)) # ✅7. Katta ma'lumotda oddiy K-means
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
Masshtablang.
n_init=10 qo'ying.
random_state belgilang.
Anomaliyalarni oldindan ko'ring.
Klaster o'lchamlarini tekshiring.
Markazlarni asl birliklarda talqin qiling.
Barqarorlikni sinang.
Katta ma'lumotda MiniBatch.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
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
- Biriktirish va markazni yangilash
- sum ||x - markaz||^2
- Monoton kamayadi
- Ha
- Yo'q (lokal minimum)
- Tarqalgan boshlang'ich tanlaydi
- Lokal minimumdan himoya
- Sferik, teng o'lcham, teng zichlik, shovqinsiz
- Markazlarni tortadi
- Anomaliyalar guruhi
- Juda katta ma'lumotda
- inverse_transform bilan
Vazifa 2: Xatolarni tuzating
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
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:
- Iteratsiyalar
- sklearn
- Boshlang'ich ta'siri
- k-means++ va n_init
Vazifa 4: Taxminlar
Modellang:
- Besh vaziyat
- Turli o'lcham
- Anomaliyalar
- Kichik klaster
Vazifa 5: Inersiya
Modellang:
- k bo'yicha
- k = n
- Masshtab
- Shakl
Vazifa 6: Segmentatsiya
Modellang:
- Ma'lumot
- Klasterlash
- Markazlar
- 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
logtransformatsiyadan keyin ko'pincha yaqinlashadi
3. Bashoratlilik — yashirin afzallik
predict()yangi mijozni darhol segmentga joylashtiradi- Ishlab chiqarishda bu majburiy talab
- DBSCAN va ierarxik klasterlashda bu to'g'ridan-to'g'ri mumkin emas
- 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
- Taxminlar kamdan-kam bajariladi, lekin natija ko'pincha foydali
- Tezlik va bashoratlilik amaliyotda hal qiluvchi
- Masshtablash va transformatsiya taxminlarni yaqinlashtiradi
- 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:
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 uchunk-means++van_init=10kerak.Inersiya bo'yicha k tanlab bo'lmaydi. U
koshgani sari har doim kamayadi vak = nbo'lganda nolga teng bo'ladi. Bundan tashqari, inersiya masshtabga bog'liq — uni turli masshtablangan ma'lumotlar orasida taqqoslash ma'nosiz.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.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!