The Story That Explains K-Meansवह कहानी जो K-Means समझाती है一个讲清 K-Means 的故事
You did not need a label. Nobody wore a badge saying "Group A" or "Group B". You just looked at the natural patterns in how people gathered — who stands near whom, shared interests, behaviour — and your brain found the groups.
That is exactly what K-Means does with data. It looks at your data points, finds groups of similar points, and gives each group a number — without ever being told what the groups should be. No labels. No teacher. Just patterns.
आपको किसी label की ज़रूरत नहीं पड़ी। किसी ने "Group A" या "Group B" का badge नहीं पहना था। आपने बस देखा कि लोग स्वाभाविक रूप से कैसे इकट्ठा हुए — कौन किसके पास खड़ा है, साझा रुचियाँ, व्यवहार — और आपके दिमाग़ ने groups खोज लिए।
K-Means data के साथ ठीक यही करता है। यह आपके data points देखता है, मिलते-जुलते points के groups खोजता है, और हर group को एक number देता है — बिना यह बताए कि groups क्या होने चाहिए। कोई label नहीं। कोई teacher नहीं। सिर्फ़ patterns.
你不需要任何标签。没有人戴着写着“A 组”或“B 组”的胸牌。 你只是观察了人们自然聚集的规律 —— 谁站在谁旁边、共同兴趣、行为 —— 大脑就自动找出了这些小圈子。
这正是 K-Means 对数据所做的事。它查看你的数据点,找出由相似点组成的组,并给每组编一个号 —— 从来没有人告诉它这些组应该是什么。没有标签,没有老师,只有规律。
K-Means Clustering is an unsupervised machine learning algorithm that splits a dataset into K separate, non-overlapping clusters. Each data point belongs to the cluster whose centroid (centre point) is closest to it. The algorithm repeats two simple moves until the cluster assignments stop changing.
K-Means Clustering एक unsupervised machine learning algorithm है जो dataset को K अलग, बिना overlap वाले clusters में बाँटता है। हर data point उस cluster में जाता है जिसका centroid (केंद्र point) उसके सबसे पास है। Algorithm दो आसान कदम तब तक दोहराता है जब तक clusters बदलना बंद न कर दें।
K-Means 聚类是一种无监督机器学习算法(unsupervised learning),它把数据集分成 K 个互不重叠的簇(cluster)。 每个数据点属于离它最近的那个质心(centroid,中心点)所在的簇。算法反复执行两个简单动作,直到各点的归属不再变化。
In supervised learning you have labelled data — you tell the model "these emails are spam, these are not." In unsupervised learning, you have no labels at all. K-Means discovers structure that already exists in your data. That makes it very useful when labelling is expensive, impossible, or not yet known.
Supervised learning में आपके पास labelled data होता है — आप model को बताते हैं "ये emails spam हैं, ये नहीं।" Unsupervised learning में कोई label नहीं होता। K-Means वह ढाँचा खोजता है जो आपके data में पहले से मौजूद है। इसलिए यह तब बहुत काम आता है जब labelling महँगी, असंभव, या अभी अज्ञात हो।
在有监督学习中,你有带标签的数据 —— 你告诉模型“这些邮件是垃圾邮件,那些不是”。在无监督学习中, 完全没有标签。K-Means 发现的是数据中本来就存在的结构。所以当打标签很贵、不可能做到、或者根本还不知道标签是什么时,它特别有用。
K-Means in Pictures — Understand It Before the Mathsतस्वीरों में K-Means — गणित से पहले समझें图解 K-Means — 先看懂,再学公式
Before any formula, learn six words. Every picture and simulator on this page uses them.
किसी भी formula से पहले छह शब्द सीख लें। इस page की हर तस्वीर और simulator इन्हीं का इस्तेमाल करता है।
在看任何公式之前,先学会六个词。本页的每张图和每个模拟器都会用到它们。
Everyday things that work like K-Meansरोज़ की चीज़ें जो K-Means की तरह काम करती हैं日常生活中像 K-Means 一样运作的事物
| Everyday thingरोज़ की चीज़日常事物 | What it is in K-MeansK-Means में यह क्या है在 K-Means 中对应什么 |
|---|---|
| 🍕 Pizza delivery hubs🍕 Pizza delivery hubs🍕 披萨配送点 | The centroids. Each hub serves the customers nearest to it.Centroids. हर hub अपने सबसे पास वाले customers को serve करता है।质心。每个配送点服务离它最近的顾客。 |
| 🏠 Customers on a map🏠 Map पर customers🏠 地图上的顾客 | The data points. Their position = their feature values.Data points. उनकी जगह = उनकी feature values.数据点。位置 = 特征值。 |
| 📍 "Which hub is closest to me?"📍 "मेरे सबसे पास कौन सा hub है?"📍 “哪个配送点离我最近?” | The assign step.Assign step.分配(assign)步骤。 |
| 🚚 Move each hub to the middle of its customers🚚 हर hub को उसके customers के बीच में ले जाना🚚 把每个配送点搬到它所服务顾客的中间 | The update (move) step: centroid = mean.Update (move) step: centroid = mean.更新(move)步骤:质心 = 均值。 |
| 👕 A shop choosing S / M / L / XL sizes👕 Dukaan का S / M / L / XL sizes चुनना👕 服装店决定 S / M / L / XL 四个尺码 | K = 4 clusters of body measurements. Each size is a centroid that fits a group of people well enough.शरीर के नाप के K = 4 clusters. हर size एक centroid है जो लोगों के एक group पर ठीक-ठाक फ़िट होता है।身材数据的 K = 4 个簇。每个尺码就是一个质心,足够合身地覆盖一群人。 |
| 🎨 Painting a photo with only 16 paints🎨 सिर्फ़ 16 रंगों से photo पेंट करना🎨 只用 16 种颜料画一张照片 | Image compression: K = 16 colour centroids (Section 12).Image compression: K = 16 रंग centroids (Section 12).图像压缩:K = 16 个颜色质心(第 12 节)。 |
One full loop, in four picturesएक पूरा loop, चार तस्वीरों में一次完整的循环,四张图
These four panels are computed, not hand-drawn: 18 dots, K = 3, and a deliberately bad start. The shaded background shows which centroid owns each area. Watch the WCSS fall.
ये चार panels हाथ से नहीं बनाए गए, गणना करके बनाए गए हैं: 18 dots, K = 3, और जान-बूझकर ख़राब शुरुआत। पीछे का रंग दिखाता है कि हर इलाका किस centroid का है। WCSS को गिरते देखें।
这四幅图是真实计算出来的,不是手画的:18 个点,K = 3,并故意给了一个很差的起点。背景颜色表示每块区域归哪个质心。注意 WCSS 如何下降。
Real numbers: WCSS after each move is 32,597 → 7,844, then 7,844 again — nothing changed in iteration 3, so K-Means stops. Hollow circle = old centroid, ⊗ = new centroid.
असली numbers: हर move के बाद WCSS 32,597 → 7,844, फिर दोबारा 7,844 — iteration 3 में कुछ नहीं बदला, इसलिए K-Means रुक जाता है। खोखला गोला = पुराना centroid, ⊗ = नया centroid.
真实数字:每次移动后的 WCSS 为 32,597 → 7,844,然后仍是 7,844 —— 第 3 轮什么都没变,于是 K-Means 停止。空心圆 = 旧质心,⊗ = 新质心。
Join the nearest centre, then move each centre to the middle of its group — repeat until nothing changes. Everything else on this page (K-Means++, choosing K, scaling, Mini-Batch) is about doing these two moves well.
सबसे पास वाले centre से जुड़ो, फिर हर centre को उसके group के बीच में ले जाओ — तब तक दोहराओ जब तक कुछ न बदले। इस page पर बाकी सब कुछ (K-Means++, K चुनना, scaling, Mini-Batch) इन्हीं दो कदमों को अच्छे से करने के बारे में है।
加入最近的中心,再把每个中心移到它那组的正中间 —— 重复,直到什么都不再变化。 本页其他所有内容(K-Means++、选择 K、特征缩放、Mini-Batch)都是为了把这两个动作做好。
The Algorithm — Step by StepAlgorithm — एक-एक कदम算法 — 一步一步来
K-Means follows a simple loop of five steps. Once you see them as a story, you will not forget them.
K-Means पाँच कदमों का एक आसान loop है। एक बार कहानी के रूप में देख लिया, तो आप इन्हें नहीं भूलेंगे।
K-Means 是一个由五步组成的简单循环。用故事看过一遍,你就不会忘记。
1. Guess. Close your eyes and pin 3 random spots on the map as your first hub positions.
2. Assign. Every customer goes to whichever hub is closest.
3. Recompute. For each hub, find the average location of all its customers. Move the hub pin there.
4. Repeat. Reassign customers to their new nearest hub. Recompute the centres again.
5. Converge. Stop when no customer changes hub. You have found a good set of locations.
1. अंदाज़ा लगाएँ। आँखें बंद करके map पर 3 random जगह pin करें — ये पहले hub हैं।
2. Assign करें। हर customer उस hub के पास जाता है जो सबसे नज़दीक है।
3. फिर से निकालें। हर hub के सभी customers की औसत जगह निकालें। Hub pin वहाँ ले जाएँ।
4. दोहराएँ। Customers को उनके नए सबसे पास वाले hub से जोड़ें। Centres फिर से निकालें।
5. Converge. जब कोई customer hub न बदले, रुक जाएँ। आपको अच्छी जगहें मिल गईं।
1. 猜。闭上眼睛,在地图上随便钉 3 个位置作为初始配送点。
2. 分配。每位顾客归离他最近的配送点。
3. 重新计算。对每个配送点,算出它所有顾客的平均位置,把钉子移过去。
4. 重复。把顾客重新分给新的最近配送点,再重新计算中心。
5. 收敛。当没有顾客再换配送点时停止。你找到了一组不错的位置。
Drag the hubs with your mouse or finger. Each customer joins the nearest hub (coloured lines). Try to make the total squared distance as small as you can. Then press "Assign + move once" to see what K-Means would do.
Hubs को mouse या उँगली से खींचें। हर customer सबसे पास वाले hub से जुड़ता है (रंगीन lines)। कुल squared distance को जितना हो सके छोटा करने की कोशिश करें। फिर "एक बार assign + move" दबाकर देखें कि K-Means क्या करता।
用鼠标或手指拖动配送点。每位顾客会连到最近的配送点(彩色线)。试着让总平方距离尽可能小。然后点击“分配 + 移动一次”,看看 K-Means 会怎么做。
The Objective Function — What K-Means MinimisesObjective Function — K-Means क्या घटाता है目标函数 — K-Means 在最小化什么
K-Means is not guessing at random — it is making one number as small as possible. Knowing that number explains both its power and its limits.
K-Means random अंदाज़ा नहीं लगाता — यह एक number को जितना हो सके छोटा करता है। उस number को समझने से इसकी ताक़त और सीमाएँ दोनों समझ आती हैं।
K-Means 不是在乱猜 —— 它在把一个数字变得尽可能小。理解这个数字,就能同时理解它的优势和局限。
A worked example you can check by handएक हल किया उदाहरण जिसे आप हाथ से जाँच सकते हैं一个可以手算验证的例子
Six shops on a map, K = 2, and a bad start: both centroids begin next to each other at (1, 1) and (2, 1).
Map पर छह दुकानें, K = 2, और ख़राब शुरुआत: दोनों centroids पास-पास (1, 1) और (2, 1) पर शुरू होते हैं।
地图上有六家店,K = 2,起点很差:两个质心挨在一起,分别从 (1, 1) 和 (2, 1) 出发。
| IterationIteration轮次 | Assign (cluster of A…F)Assign (A…F का cluster)分配(A…F 所属簇) | Move: new centroidsMove: नए centroids移动:新质心 | WCSS |
|---|---|---|---|
| 1 | A=0 B=1 C=0 D=1 E=1 F=1 | c₀ = (1, 1.5) c₁ = (4.5, 3.75) | 76.00 |
| 2 | A=0 B=0 C=0 D=1 E=1 F=1 | c₀ = (1.33, 1.33) c₁ = (5.33, 4.67) | 7.69 |
| 3 | same as iteration 2 → stopiteration 2 जैसा → रुकें与第 2 轮相同 → 停止 | no movementकोई हलचल नहीं不再移动 | 2.67 |
Points: A(1,1) B(2,1) C(1,2) D(5,4) E(6,5) F(5,5). Check one number yourself: in iteration 1, D is √18 ≈ 4.24 from c₁ = (2,1) and 5 from c₀ = (1,1), so D joins cluster 1. The code below repeats the same steps with NumPy.
Points: A(1,1) B(2,1) C(1,2) D(5,4) E(6,5) F(5,5). एक number खुद जाँचें: iteration 1 में D, c₁ = (2,1) से √18 ≈ 4.24 और c₀ = (1,1) से 5 दूर है, इसलिए D cluster 1 में जाता है। नीचे का code NumPy से यही steps दोहराता है।
各点:A(1,1) B(2,1) C(1,2) D(5,4) E(6,5) F(5,5)。自己验证一个数:第 1 轮中,D 到 c₁ = (2,1) 的距离是 √18 ≈ 4.24,到 c₀ = (1,1) 是 5,所以 D 归入簇 1。下面的代码用 NumPy 重复了同样的步骤。
import numpy as np
# 6 shops on a map (x, y in km) and K = 2 delivery hubs
X = np.array([[1, 1], [2, 1], [1, 2], [5, 4], [6, 5], [5, 5]], dtype=float)
C = np.array([[1, 1], [2, 1]], dtype=float) # a deliberately bad start
for it in range(1, 10):
# ASSIGN: squared distance from every point to every centroid
d2 = ((X[:, None, :] - C[None, :, :]) ** 2).sum(axis=2)
labels = d2.argmin(axis=1)
wcss = d2[np.arange(len(X)), labels].sum()
print(f"Iteration {it}: labels = {labels.tolist()} WCSS = {wcss:.3f}")
# MOVE: each centroid goes to the mean of its points
newC = np.array([X[labels == k].mean(axis=0) for k in range(2)])
print(f" new centroids = {np.round(newC, 3).tolist()}")
if np.allclose(newC, C):
print(" centroids did not move → converged")
break
C = newC
K-Means always converges (each assign step and each move step can only lower WCSS), but only to a local minimum — not always the best possible answer.
A bad start can give poor clusters. That is why scikit-learn runs the whole algorithm several times (n_init) and keeps the run with the lowest WCSS.
Use K-Means++ starts (init='k-means++', the default) — they make this problem much smaller. You will see it happen in the next simulator.
K-Means हमेशा converge होता है (हर assign step और हर move step WCSS को सिर्फ़ घटा सकता है), पर सिर्फ़ एक local minimum तक — हमेशा सबसे अच्छे जवाब तक नहीं।
ख़राब शुरुआत से ख़राब clusters मिल सकते हैं। इसीलिए scikit-learn पूरा algorithm कई बार (n_init) चलाता है और सबसे कम WCSS वाला run रखता है।
K-Means++ शुरुआत (init='k-means++', default) इस्तेमाल करें — यह समस्या को बहुत छोटा कर देती है। अगले simulator में आप इसे होते देखेंगे।
K-Means 一定会收敛(每次分配和每次移动都只会降低 WCSS),但只保证收敛到局部最小值 —— 不一定是最好的答案。
糟糕的起点可能得到很差的簇。所以 scikit-learn 会把整个算法运行多次(n_init),保留 WCSS 最低的那次。
请使用 K-Means++ 初始化(init='k-means++',默认值)—— 它能大大减轻这个问题。下一个模拟器里你会亲眼看到。
K-Means++ — The Smarter StartK-Means++ — समझदार शुरुआतK-Means++ — 更聪明的起点
K-Means++ fixes this with a simple rule: choose starting centroids that are far apart. The first centroid is a random point. Every next centroid is chosen with probability proportional to its squared distance from the nearest centroid already chosen. Points far from the current centroids are more likely to be picked. Result: the starting centroids are spread over the whole data, not huddled in one corner.
K-Means++ इसे एक आसान नियम से ठीक करता है: ऐसे शुरुआती centroids चुनें जो एक-दूसरे से दूर हों। पहला centroid एक random point है। हर अगला centroid पहले से चुने सबसे पास वाले centroid से उसकी squared distance के अनुपात वाली probability से चुना जाता है। मौजूदा centroids से दूर वाले points के चुने जाने की संभावना ज़्यादा होती है। नतीजा: शुरुआती centroids पूरे data पर फैले होते हैं, एक कोने में नहीं।
K-Means++ 用一条简单规则解决这个问题:让初始质心彼此远离。第一个质心随机选一个点; 之后每个质心被选中的概率,与它到已选最近质心的距离平方成正比。离现有质心越远的点越容易被选中。 结果:初始质心分散在整个数据上,而不是挤在一个角落。
Both sides cluster the same 6 blobs with K = 6. Left starts at random points, right uses K-Means++. Press "Show how ++ picks" to watch the probability rule, and "Run 200 trials" to count how often each method gets stuck.
दोनों तरफ़ वही 6 blobs K = 6 से cluster होते हैं। बाईं ओर random points से शुरुआत, दाईं ओर K-Means++. Probability का नियम देखने के लिए "++ कैसे चुनता है, देखें" दबाएँ, और "200 trials चलाएँ" से गिनें कि कौन कितनी बार फँसता है।
两边都用 K = 6 对同样的 6 个团做聚类。左边从随机点出发,右边用 K-Means++。点击“演示 ++ 如何挑选”观看概率规则,点击“运行 200 次试验”统计各方法卡住的频率。
✗ Can miss obvious clusters✗ अक्सर कई restarts चाहिए
✗ साफ़ दिखने वाले clusters भी छूट सकते हैं✗ 往往需要多次重启
✗ 可能漏掉明显的簇
✓ Gets stuck far less often✓ आमतौर पर कम iterations
✓ बहुत कम बार फँसता है✓ 通常迭代次数更少
✓ 卡住的情况少得多
n_init="auto" means 1 run with K-Means++ and 10 runs with random init.n_init="auto" का मतलब है K-Means++ के साथ 1 run और random init के साथ 10 runs.n_init="auto" 表示:用 K-Means++ 时跑 1 次,用随机初始化时跑 10 次。✓ More stable results✓ ख़राब local minima से बचाता है
✓ ज़्यादा stable नतीजे✓ 防止陷入糟糕的局部最小值
✓ 结果更稳定
The default n_init="auto" (a single K-Means++ run) is fast, but on real data it is still worth setting n_init=10: you pay ten times the compute and you protect yourself against an unlucky start. All the code on this page does that.
Default n_init="auto" (एक K-Means++ run) तेज़ है, पर असली data पर फिर भी n_init=10 set करना फ़ायदेमंद है: दस गुना compute लगता है और बदक़िस्मत शुरुआत से बचाव होता है। इस page का सारा code यही करता है।
默认的 n_init="auto"(只跑一次 K-Means++)速度快,但在真实数据上仍然值得设置 n_init=10:花十倍计算量,换来对“倒霉起点”的保护。本页所有代码都这样做。
Choosing K — The Hardest PartK चुनना — सबसे मुश्किल हिस्सा选择 K — 最难的部分
K-Means needs K before it starts. This is its biggest weakness, and the source of the most common beginner mistake: just picking K = 3 because it sounds right. Here are the most reliable ways to choose.
K-Means को शुरू करने से पहले K चाहिए। यह इसकी सबसे बड़ी कमज़ोरी है, और शुरुआती लोगों की सबसे आम ग़लती की वजह: बस K = 3 चुन लेना क्योंकि यह ठीक लगता है। चुनने के सबसे भरोसेमंद तरीके ये हैं।
K-Means 在开始前就需要 K。这是它最大的弱点,也是初学者最常见错误的来源:只因为“听起来合适”就选 K = 3。下面是最可靠的选择方法。
✓ Fast to compute✓ आसान और दिखने वाला
✓ जल्दी निकलता है✓ 直观易懂
✓ 计算快
✗ Needs your judgement✗ Elbow साफ़ न भी हो
✗ आपकी समझ पर निर्भर✗ 肘部可能不明显
✗ 需要主观判断
✓ Helps when the elbow is unclear✓ एक साफ़ number
✓ Elbow धुँधला हो तब काम आता है✓ 一个明确的数字
✓ 肘部不明显时很有用
✗ Prefers round, compact clusters✗ धीमा: O(n²) दूरियाँ
✗ गोल, कसे clusters पसंद करता है✗ 较慢:需 O(n²) 次距离计算
✗ 偏好圆形、紧凑的簇
✓ Team agreement✓ ऐसे नतीजे जिन पर काम हो सके
✓ Team की सहमति✓ 结果可落地执行
✓ 团队容易认同
✗ Needs domain expertise✗ असली data ढाँचे को अनदेखा कर सकता है
✗ Domain की समझ चाहिए✗ 可能忽略数据的真实结构
✗ 需要领域经验
Pick how many blobs the data really has. For every K from 1 to 8 the page runs K-Means (best of 4 K-Means++ starts) and computes WCSS (blue line) and silhouette (green bars). Click a K to see that clustering.
चुनें कि data में असल में कितने blobs हैं। 1 से 8 तक हर K के लिए page K-Means चलाता है (4 K-Means++ शुरुआतों में सबसे अच्छा) और WCSS (नीली line) व silhouette (हरी bars) निकालता है। किसी K पर click करके वह clustering देखें।
选择数据中真实的团数。页面对 K = 1 到 8 分别运行 K-Means(取 4 次 K-Means++ 初始化中最好的),计算 WCSS(蓝线)和轮廓系数(绿柱)。点击某个 K 查看对应的聚类结果。
When K-Means Works — and When It FailsK-Means कब चलता है — और कब फ़ेल होता हैK-Means 何时有效 — 何时失效
Pick a dataset. The left panel shows K-Means (with the correct K, best of 8 starts) and its straight borders; the right panel shows the true groups. The bar shows how many points K-Means put in the right group.
एक dataset चुनें। बायाँ panel K-Means (सही K के साथ, 8 शुरुआतों में सबसे अच्छा) और उसकी सीधी सीमाएँ दिखाता है; दायाँ panel असली groups. Bar बताती है कि K-Means ने कितने points सही group में रखे।
选择一个数据集。左图是 K-Means(用正确的 K,取 8 次初始化中最好的)及其直线边界;右图是真实分组。进度条显示 K-Means 把多少点分进了正确的组。
| Scenarioस्थिति场景 | K-Means Suitable?K-Means ठीक है?K-Means 适合吗? | Alternativeविकल्प替代方案 |
|---|---|---|
| Compact, round clusters of similar sizeएक जैसे आकार के कसे, गोल clusters大小相近的紧凑圆形簇 | ✓ Excellentबहुत बढ़िया非常好 | — |
| Customer segmentation by behaviourव्यवहार के आधार पर customer segmentation按行为做客户分群 | ✓ Greatबढ़िया很好 | — |
| Image colour quantisation / compressionImage colour quantisation / compression图像颜色量化 / 压缩 | ✓ Greatबढ़िया很好 | — |
| Document / text clustering (TF-IDF)Document / text clustering (TF-IDF)文档 / 文本聚类(TF-IDF) | ⚠ Moderateठीक-ठाक一般 | Topic models (LDA), cosine-based clusteringTopic models (LDA), cosine-based clustering主题模型(LDA)、基于余弦距离的聚类 |
| Clusters of any shape (rings, crescents)किसी भी आकार के clusters (rings, अर्धचंद्र)任意形状的簇(圆环、月牙) | ✗ Poorख़राब差 | DBSCAN, Spectral |
| Clusters with outliers / noiseOutliers / noise वाले clusters含离群点 / 噪声的簇 | ✗ Sensitiveसंवेदनशील敏感 | DBSCAN, K-Medoids |
| Very high-dimensional sparse dataबहुत ज़्यादा dimensions वाला sparse data超高维稀疏数据 | ✗ Curse of dimensionalityCurse of dimensionality维度灾难 | Reduce dimensions first (PCA)पहले dimensions घटाएँ (PCA)先降维(PCA) |
Feature Scaling — A Must for K-MeansFeature Scaling — K-Means के लिए ज़रूरी特征缩放 — K-Means 的必做步骤
K-Means uses Euclidean distance. If one feature is "annual salary" (range 30,000–150,000) and another is "age" (range 18–65), salary will completely
control the distance. A £50,000 difference in salary will outweigh a 10-year age difference, even if age matters more to your business. Always apply
StandardScaler (mean 0, standard deviation 1) or MinMaxScaler before clustering. Forgetting this is one of the most common beginner mistakes.
K-Means Euclidean distance इस्तेमाल करता है। अगर एक feature "annual salary" (range 30,000–150,000) है और दूसरा "age" (range 18–65), तो distance पर पूरी तरह
salary का कब्ज़ा होगा। Salary में £50,000 का अंतर age के 10 साल के अंतर पर भारी पड़ेगा, भले ही आपके business के लिए age ज़्यादा ज़रूरी हो। Clustering से पहले हमेशा
StandardScaler (mean 0, standard deviation 1) या MinMaxScaler लगाएँ। इसे भूल जाना शुरुआती लोगों की सबसे आम ग़लतियों में से एक है।
K-Means 使用欧氏距离。如果一个特征是“年薪”(范围 30,000–150,000),另一个是“年龄”(范围 18–65),距离将完全被工资主导。
£50,000 的工资差会压倒 10 岁的年龄差,哪怕年龄对你的业务更重要。聚类之前务必使用
StandardScaler(均值 0,标准差 1)或 MinMaxScaler。忘记这一步是初学者最常见的错误之一。
160 people from two age groups (circles = young, triangles = older). Salary is random and has nothing to do with the groups. The plot uses the SAME scale on both axes, exactly like the distance K-Means computes. Colours = the 2 clusters K-Means finds.
दो age groups के 160 लोग (गोले = युवा, त्रिकोण = बड़ी उम्र)। Salary random है और groups से इसका कोई संबंध नहीं। Plot दोनों axes पर एक ही scale इस्तेमाल करता है, ठीक उसी distance जैसा जो K-Means निकालता है। रंग = K-Means के मिले 2 clusters.
160 个人来自两个年龄组(圆点 = 年轻,三角 = 年长)。工资是随机的,与分组无关。图的两个坐标轴使用相同的比例,和 K-Means 计算的距离完全一致。颜色 = K-Means 找到的 2 个簇。
Python Code — K-Means from Scratch to ProductionPython Code — शुरुआत से Production तक K-MeansPython 代码 — 从入门到生产
Let us build up step by step: first a minimal working example, then the standard pattern with the elbow method and silhouette scores. Every output below is the real output of the code.
चलिए एक-एक कदम बनाते हैं: पहले एक छोटा working example, फिर elbow method और silhouette scores वाला standard pattern. नीचे का हर output code का असली output है।
我们一步步来:先写一个最小可运行示例,再写包含肘部法和轮廓系数的标准流程。下面每个输出都是代码真实运行的结果。
9.1 — Minimal Example (Synthetic Data)9.1 — छोटा Example (Synthetic Data)9.1 — 最小示例(合成数据)
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
# 1. Generate synthetic data — 300 points in 4 natural clusters
X, y_true = make_blobs(n_samples=300, centers=4,
cluster_std=0.70, random_state=42)
# 2. Scale features — ALWAYS do this before K-Means
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 3. Fit K-Means with K=4 (K-Means++ initialisation is the default)
kmeans = KMeans(n_clusters=4, init='k-means++',
n_init=10, random_state=42)
kmeans.fit(X_scaled)
# 4. Results
labels = kmeans.labels_ # cluster ID for each point
centroids = kmeans.cluster_centers_ # centroid coordinates
inertia = kmeans.inertia_ # WCSS (lower = tighter clusters)
iterations = kmeans.n_iter_ # how many EM iterations ran
print(f"WCSS (Inertia): {inertia:.2f}")
print(f"Iterations: {iterations}")
print(f"Cluster counts: {np.bincount(labels)}")
The 4 blobs are far apart, so K-Means needs only 2 iterations and puts exactly 75 points in each cluster. n_iter_ is the iteration count of the best of the 10 runs.
4 blobs एक-दूसरे से बहुत दूर हैं, इसलिए K-Means को सिर्फ़ 2 iterations चाहिए और हर cluster में ठीक 75 points आते हैं। n_iter_ 10 runs में से सबसे अच्छे run की iteration गिनती है।
4 个团相距很远,所以 K-Means 只需 2 轮迭代,每个簇正好 75 个点。n_iter_ 是 10 次运行中最佳那次的迭代次数。
9.2 — Finding the Right K: Elbow + Silhouette9.2 — सही K खोजना: Elbow + Silhouette9.2 — 找到合适的 K:肘部法 + 轮廓系数
from sklearn.metrics import silhouette_score
wcss_list = []
sil_list = []
K_range = range(2, 11)
for k in K_range:
km = KMeans(n_clusters=k, init='k-means++',
n_init=10, random_state=42)
km.fit(X_scaled)
wcss_list.append(km.inertia_)
sil_list.append(silhouette_score(X_scaled, km.labels_))
# Print both metrics side by side
print(f"{'K':>3} {'WCSS':>10} {'Silhouette':>12}")
print("-" * 30)
for k, w, s in zip(K_range, wcss_list, sil_list):
print(f"{k:>3} {w:>10.2f} {s:>12.4f}")
best_k = K_range[sil_list.index(max(sil_list))]
print(f"\nBest K by Silhouette: {best_k}")
Both methods agree: K = 4. WCSS drops steeply (311.6 → 64.7 → 8.7) and then almost stops falling (7.8, 6.9 …) — that is the elbow. Notice that WCSS keeps going down after K = 4: it always does, so never pick the K with the lowest WCSS. The silhouette peaks at K = 4 with 0.86 (as a rough guide: above 0.5 is reasonable, above 0.7 is strong).
दोनों तरीके सहमत हैं: K = 4. WCSS तेज़ी से गिरता है (311.6 → 64.7 → 8.7) और फिर लगभग गिरना बंद कर देता है (7.8, 6.9 …) — यही elbow है। ध्यान दें कि K = 4 के बाद भी WCSS घटता रहता है: यह हमेशा घटता है, इसलिए सबसे कम WCSS वाला K कभी न चुनें। Silhouette K = 4 पर 0.86 के साथ सबसे ऊँचा है (मोटा अंदाज़ा: 0.5 से ऊपर ठीक, 0.7 से ऊपर मज़बूत)।
两种方法结论一致:K = 4。WCSS 急剧下降(311.6 → 64.7 → 8.7),然后几乎不再下降(7.8、6.9 …)—— 这就是肘部。 注意 K = 4 之后 WCSS 仍在下降:它总是会降,所以永远不要选 WCSS 最低的 K。轮廓系数在 K = 4 时最高,为 0.86 (粗略参考:高于 0.5 算合理,高于 0.7 算很强)。
Watch K-Means Run — LiveK-Means को चलते देखें — Live实时观看 K-Means 运行
Section 02 showed one loop as still pictures. Here the loop runs live on 140 points. Each press of "One step" does half an iteration: first ASSIGN (points change colour), then MOVE (centroids slide to the mean).
Section 02 में एक loop को रुकी हुई तस्वीरों में दिखाया था। यहाँ वही loop 140 points पर live चलता है। "एक step" का हर press आधा iteration करता है: पहले ASSIGN (points का रंग बदलता है), फिर MOVE (centroids mean पर खिसकते हैं)।
第 02 节用静态图展示了一次循环。这里同样的循环在 140 个点上实时运行。每按一次“走一步”执行半轮:先分配(点变色),再移动(质心滑向均值)。
Coloured regions show which centroid owns each area. Dashed trails show how the centroids move. Change K, or press "New random start" to see that a different start can end in a worse result.
रंगीन हिस्से दिखाते हैं कि हर इलाका किस centroid का है। Dashed निशान दिखाते हैं कि centroids कैसे चलते हैं। K बदलें, या "नई random शुरुआत" दबाएँ और देखें कि अलग शुरुआत ख़राब नतीजे पर भी ख़त्म हो सकती है।
彩色区域表示每块区域属于哪个质心,虚线轨迹显示质心如何移动。改变 K,或点击“重新随机初始化”,看看不同的起点可能得到更差的结果。
On easy data like this, K-Means usually converges in a handful of iterations. Real data with overlapping groups can need tens of iterations; scikit-learn stops at max_iter=300 or when the centroids move less than tol.
ऐसे आसान data पर K-Means आमतौर पर कुछ ही iterations में converge हो जाता है। Overlap वाले groups के असली data को दसियों iterations लग सकते हैं; scikit-learn max_iter=300 पर या जब centroids tol से कम हिलें, तब रुकता है।
在这种简单数据上,K-Means 通常几轮就收敛。组间有重叠的真实数据可能需要几十轮;scikit-learn 在达到 max_iter=300 或质心移动小于 tol 时停止。
📋 Case Study 1 — Customer Segmentation for an E-Commerce Shop📋 Case Study 1 — E-Commerce Shop के लिए Customer Segmentation📋 案例一 — 电商平台的客户分群
You have three behaviour features per customer from the last 12 months: total_spend (£), purchase_freq (orders/year) and avg_order_value (£). No labels. No predefined groups. A textbook K-Means problem.
पिछले 12 महीनों से हर customer के तीन behaviour features हैं: total_spend (£), purchase_freq (orders/साल) और avg_order_value (£). कोई label नहीं। कोई पहले से तय group नहीं। एकदम textbook K-Means problem.
你有每位顾客过去 12 个月的三个行为特征:total_spend(总消费,£)、purchase_freq(每年订单数) 和 avg_order_value(平均订单金额,£)。没有标签,没有预设分组。一道教科书式的 K-Means 题目。
Real customer data is private, so we simulate it. Important: the simulation must contain real groups. If you generate every column independently at random (a common shortcut), there are no segments to find, and K-Means will still happily cut the data into K pieces. Here we simulate 4 hidden shopping habits; K-Means is not told about them.
असली customer data private होता है, इसलिए हम उसे simulate करते हैं। ज़रूरी बात: simulation में असली groups होने चाहिए। अगर आप हर column को अलग-अलग random बनाते हैं (एक आम shortcut), तो खोजने को कोई segment नहीं होता, फिर भी K-Means data को ख़ुशी-ख़ुशी K टुकड़ों में काट देगा। यहाँ हम 4 छिपी shopping आदतें simulate करते हैं; K-Means को इनके बारे में नहीं बताया जाता।
真实客户数据是隐私数据,所以我们用模拟数据。关键点:模拟数据里必须真的存在分组。如果每一列都独立随机生成(一种常见的偷懒做法),根本没有客户群可找,但 K-Means 依然会乐呵呵地把数据切成 K 块。这里我们模拟了 4 种隐藏的购物习惯,K-Means 并不知道它们。
Step 1 — Load and Explore the DataStep 1 — Data load करें और देखें第 1 步 — 加载并查看数据
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
# Simulate 50,000 customers from 4 hidden shopping habits
# (in real life you do NOT know these types — K-Means must find them)
rng = np.random.default_rng(42)
habits = { # orders/year, avg order value (£), share of customers
'dormant': (2, 70, 0.22),
'vip': (20, 220, 0.18),
'core_regular': (8, 110, 0.38),
'bargain_hunter': (14, 35, 0.22),
}
n = 50000
parts = []
for name, (freq, aov, share) in habits.items():
m = int(n * share)
f = rng.poisson(freq, m) + 1 # at least 1 order
v = rng.lognormal(np.log(aov), 0.20, m).round(2) # order value
parts.append(pd.DataFrame({'purchase_freq': f, 'avg_order_value': v}))
df = pd.concat(parts, ignore_index=True).sample(frac=1, random_state=42).reset_index(drop=True)
df['total_spend'] = (df['purchase_freq'] * df['avg_order_value']).round(2)
df.insert(0, 'customer_id', range(1, n + 1))
print(df[['total_spend', 'purchase_freq', 'avg_order_value']].describe().round(2))
Step 2 — Scale and Find the Best KStep 2 — Scale करें और सबसे अच्छा K खोजें第 2 步 — 缩放并寻找最佳 K
# Select features. Spend and order value are skewed, so take the log first
features = ['total_spend', 'purchase_freq', 'avg_order_value']
X = df[features].copy()
X[['total_spend', 'avg_order_value']] = np.log1p(X[['total_spend', 'avg_order_value']])
scaler = StandardScaler()
X_sc = scaler.fit_transform(X)
# Evaluate K=2 to K=8
results = []
for k in range(2, 9):
km = KMeans(n_clusters=k, init='k-means++',
n_init=10, random_state=42)
km.fit(X_sc)
sil = silhouette_score(X_sc, km.labels_, sample_size=5000, random_state=42)
results.append({'K': k, 'WCSS': round(km.inertia_, 1), 'Silhouette': round(sil, 4)})
print(pd.DataFrame(results).to_string(index=False))
Real result: WCSS drops a lot until K = 4 (44,803 → 20,917) and then only slowly (17,505, 15,114 …), and the silhouette is highest at K = 4 (0.57). Note the log step: money columns are skewed (a few big spenders), and the log stops them from dominating the distances.
असली नतीजा: WCSS K = 4 तक बहुत गिरता है (44,803 → 20,917) और फिर धीरे-धीरे (17,505, 15,114 …), और silhouette K = 4 पर सबसे ऊँचा है (0.57)। Log वाला step ध्यान दें: पैसे वाले columns टेढ़े (skewed) होते हैं (कुछ बड़े ख़र्च करने वाले), और log उन्हें distances पर हावी होने से रोकता है।
真实结果:WCSS 在 K = 4 之前大幅下降(44,803 → 20,917),之后下降变慢(17,505、15,114 …),轮廓系数在 K = 4 时最高(0.57)。注意取对数这一步:金额类列是偏斜的(少数大客户),取对数能防止它们主导距离。
Step 3 — Fit the Final Model (K = 4) and Profile the SegmentsStep 3 — Final Model (K = 4) fit करें और Segments का Profile बनाएँ第 3 步 — 训练最终模型(K = 4)并给客户群画像
# Fit final model
final_km = KMeans(n_clusters=4, init='k-means++',
n_init=20, random_state=42)
df['segment'] = final_km.fit_predict(X_sc)
# Profile each segment in ORIGINAL units (easy to read)
profile = df.groupby('segment')[features].mean().round(2)
profile['count'] = df.groupby('segment').size()
profile['% share'] = (profile['count'] / n * 100).round(1)
print(profile)
Each dot is a customer, coloured by the segment K-Means gave it. The groups separate mostly by how often people buy and how much they spend per order.
हर dot एक customer है, उस segment के रंग में जो K-Means ने उसे दिया। Groups मुख्य रूप से इस बात से अलग होते हैं कि लोग कितनी बार ख़रीदते हैं और हर order पर कितना ख़र्च करते हैं।
每个点是一位顾客,颜色表示 K-Means 给它分的客户群。各组主要按购买频率和每单消费金额区分开。
Step 4 — Business Names and Action PlanStep 4 — Business नाम और Action Plan第 4 步 — 业务命名与行动方案
| SegmentSegment客户群 | Business NameBusiness नाम业务名称 | ProfileProfile画像 | % Customers% Customers顾客占比 | Recommended Actionसुझाया गया Action建议行动 |
|---|---|---|---|---|
| 2 | Dormant / At-RiskDormant / At-Risk沉睡 / 流失风险 | ~3 orders/year, £72 per order, £217 total~3 orders/साल, £72 प्रति order, कुल £217每年约 3 单,每单 £72,总计 £217 | 23.4% | Win-back campaign, discount offer, short surveyWin-back campaign, discount offer, छोटा survey召回活动、折扣优惠、简短问卷 |
| 3 | VIP ChampionsVIP ChampionsVIP 冠军客户 | ~21 orders/year, £224 per order, £4,729 total~21 orders/साल, £224 प्रति order, कुल £4,729每年约 21 单,每单 £224,总计 £4,729 | 17.9% | Loyalty programme, early access, premium supportLoyalty programme, early access, premium support会员计划、新品抢先购、专属客服 |
| 1 | Core RegularsCore Regulars核心常客 | ~9 orders/year, £113 per order, £1,034 total~9 orders/साल, £113 प्रति order, कुल £1,034每年约 9 单,每单 £113,总计 £1,034 | 37.1% | Upsell / cross-sell, new-category emailsUpsell / cross-sell, नई category वाले emails追加销售 / 交叉销售、新品类推荐邮件 |
| 0 | Frequent Bargain HuntersFrequent Bargain Hunters高频薄利客 | ~15 orders/year, only £36 per order~15 orders/साल, सिर्फ़ £36 प्रति order每年约 15 单,每单仅 £36 | 21.7% | Bundle offers, free delivery above a minimum basketBundle offers, एक तय basket से ऊपर free delivery组合优惠、满额免运费 |
ShopSmart now sends four tailored campaigns instead of one blanket email. The numbers in a story like this — say, VIP open rates rising from 9% to around 40%, or a win-back email recovering one in seven dormant customers — are illustrative, not measured. The real lesson: segment numbers (0, 1, 2, 3) mean nothing until you profile them in original units and give them business names. Then measure the effect with an A/B test before claiming any uplift.
ShopSmart अब एक ही email की जगह चार अलग campaigns भेजती है। ऐसी कहानी के numbers — जैसे VIP open rate 9% से लगभग 40% हो जाना, या win-back email से हर सात में से एक dormant customer लौट आना — उदाहरण हैं, मापे हुए नहीं। असली सबक: segment numbers (0, 1, 2, 3) का कोई मतलब नहीं जब तक आप उनका profile original units में न बनाएँ और उन्हें business नाम न दें। फिर कोई भी फ़ायदा बताने से पहले A/B test से असर मापें।
ShopSmart 现在发送四套定制化的营销活动,而不是一封通用邮件。这类故事中的数字 —— 比如 VIP 打开率从 9% 升到 40% 左右,或召回邮件挽回七分之一的沉睡客户 —— 只是示意,并非实测。 真正的启示是:客户群编号(0、1、2、3)本身毫无意义,直到你用原始单位为它们画像并起上业务名称。在宣称任何提升之前,请用 A/B 测试来衡量效果。
📋 Case Study 2 — Image Compression with K-Means📋 Case Study 2 — K-Means से Image Compression📋 案例二 — 用 K-Means 压缩图像
But most photos use far fewer colours. A sunset uses many shades of orange and blue; a forest uses many shades of green. What if, instead of storing each pixel's exact colour, you stored only K representative colours (the centroids!) and, for each pixel, the number of its nearest colour?
That is K-Means image compression. Every pixel is a point in 3-D colour space (R, G, B). With K = 64, each pixel needs only
log₂(64) = 6 bits instead of 24 — a 4× reduction in colour data.पर ज़्यादातर photos में बहुत कम रंग होते हैं। सूर्यास्त में नारंगी और नीले के कई shades होते हैं; जंगल में हरे के कई shades. क्या हो अगर हर pixel का exact रंग रखने की जगह आप सिर्फ़ K प्रतिनिधि रंग (centroids!) रखें और हर pixel के लिए उसके सबसे पास वाले रंग का number?
यही K-Means image compression है। हर pixel 3-D colour space (R, G, B) में एक point है। K = 64 के साथ हर pixel को 24 की जगह सिर्फ़
log₂(64) = 6 bits चाहिए — colour data में 4× कमी.但大多数照片实际用到的颜色少得多。日落照片里是各种橙色和蓝色;森林照片里是各种绿色。如果不存每个像素的精确颜色, 而是只存 K 种代表色(就是质心!),再给每个像素存一个“最近颜色”的编号呢?
这就是 K-Means 图像压缩。每个像素都是三维颜色空间(R, G, B)中的一个点。K = 64 时,每个像素只需
log₂(64) = 6 位,而不是 24 位 —— 颜色数据缩小 4 倍。A 160 × 100 sunset picture made in your browser. Move the slider: the page runs K-Means (K-Means++ start) on 3,000 sampled pixel colours, then repaints every pixel with its nearest palette colour.
आपके browser में बनी 160 × 100 की सूर्यास्त तस्वीर। Slider खिसकाएँ: page 3,000 sample pixel रंगों पर K-Means (K-Means++ शुरुआत) चलाता है, फिर हर pixel को उसके सबसे पास वाले palette रंग से दोबारा रंगता है।
一张在浏览器里生成的 160 × 100 日落图。拖动滑块:页面对 3,000 个抽样像素颜色运行 K-Means(K-Means++ 初始化),再用最近的调色板颜色重画每个像素。
OriginalOriginal原图
Palette (the centroids)Palette (centroids)调色板(即质心)
Step 1 — Load and Reshape the ImageStep 1 — Image load करें और Reshape करें第 1 步 — 加载并重塑图像
We use a real photo that ships with scikit-learn, so the code runs anywhere without downloading anything. Swap in your own photo with PIL as shown in the comment.
हम scikit-learn के साथ आने वाली एक असली photo इस्तेमाल करते हैं, ताकि code बिना कुछ download किए कहीं भी चले। Comment में दिखाए तरीके से PIL से अपनी photo लगाएँ।
我们使用 scikit-learn 自带的一张真实照片,这样代码无需下载任何东西就能运行。按注释所示,用 PIL 换成你自己的照片即可。
import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import load_sample_image
# Load a real photo that ships with scikit-learn (no download needed).
# For your own photo: img = np.array(PIL.Image.open('beach.jpg').convert('RGB'))
img = load_sample_image('china.jpg')
h, w, c = img.shape
print(f"Image shape: {h}×{w} pixels, {c} colour channels")
print(f"Total unique colours (theoretical): {256**3:,}")
n_unique = len(np.unique(img.reshape(-1, 3), axis=0))
print(f"Total unique colours (actual): {n_unique:,}")
# Reshape: from (H, W, 3) to (H*W, 3)
# Each row is now one pixel with [R, G, B]
pixels = img.reshape(-1, 3).astype('float32')
print(f"Pixel matrix shape: {pixels.shape}")
Step 2 — Fit K-Means on Pixel ColoursStep 2 — Pixel रंगों पर K-Means Fit करें第 2 步 — 在像素颜色上训练 K-Means
# Fit K-Means: find 64 representative colours
# Note: RGB values 0–255 are already on the same scale, so no scaling needed
K = 64
km = KMeans(n_clusters=K, init='k-means++',
n_init=3, max_iter=100, random_state=42)
# Use a random sample for speed, then predict all pixels
rng = np.random.default_rng(42)
sample_idx = rng.choice(len(pixels), size=50000, replace=False)
km.fit(pixels[sample_idx])
# Assign every pixel to its nearest centroid colour
labels = km.predict(pixels)
# Reconstruct: replace each pixel with its centroid colour
palette = km.cluster_centers_.round().astype('uint8') # 64×3 colour palette
compressed = palette[labels].reshape(h, w, 3) # back to (H, W, 3)
raw_bytes = h * w * 3
new_bytes = h * w * np.log2(K) / 8 + K * 3 # indices + the palette itself
err = np.abs(compressed.astype(int) - img.astype(int)).mean()
print(f"Original unique colours: {n_unique:,}")
print(f"Compressed unique colours: {len(np.unique(compressed.reshape(-1, 3), axis=0))}")
print(f"Original storage (raw): {raw_bytes:,} bytes")
print(f"Compressed storage: {new_bytes:,.0f} bytes")
print(f"Compression ratio: {raw_bytes / new_bytes:.1f}×")
print(f"Average colour error: {err:.1f} (out of 255)")
The "compressed storage" counts the 6-bit index of every pixel plus the 64 × 3 palette itself (192 bytes). The average error of 4.5 out of 255 per channel is hard to see with the eye.
"Compressed storage" में हर pixel का 6-bit index और 64 × 3 का palette (192 bytes) दोनों गिने गए हैं। हर channel पर 255 में से 4.5 का औसत error आँख से मुश्किल से दिखता है।
“压缩后存储”包括每个像素的 6 位索引,以及 64 × 3 的调色板本身(192 字节)。每通道平均误差 4.5(满分 255),肉眼几乎看不出来。
Step 3 — Compare Different K ValuesStep 3 — अलग-अलग K की तुलना第 3 步 — 比较不同的 K
# Compare size and quality at different K values
for k_val in [4, 8, 16, 32, 64, 128]:
km_temp = KMeans(n_clusters=k_val, init='k-means++',
n_init=3, max_iter=100, random_state=42)
km_temp.fit(pixels[sample_idx])
lbl_temp = km_temp.predict(pixels)
pal_temp = km_temp.cluster_centers_.round().astype('uint8')
err = np.abs(pal_temp[lbl_temp].astype(int) - pixels.astype(int)).mean()
bits_px = int(np.ceil(np.log2(k_val)))
bytes_tot = h * w * bits_px // 8
ratio = h * w * 3 / bytes_tot
print(f"K={k_val:4d} | Bits/pixel: {bits_px} | "
f"Size: {bytes_tot:>9,} bytes | Ratio: {ratio:4.1f}× | Avg error: {err:5.1f}")
| K (Colours)K (रंग)K(颜色数) | Compression RatioCompression Ratio压缩比 | Avg error (0–255)औसत error (0–255)平均误差(0–255) | Visual Qualityदिखने में Quality视觉质量 | Use Caseकहाँ इस्तेमाल适用场景 |
|---|---|---|---|---|
| 4 | 12× | 17.4 | Posterised — a few flat coloursPosterised — कुछ सपाट रंग海报化 —— 只剩几块平涂色 | Icons, flat-colour logosIcons, सपाट रंग वाले logos图标、纯色 logo |
| 16 | 6× | 8.0 | Visible banding, shapes clearBanding दिखती है, आकार साफ़有明显色带,形状清楚 | Thumbnails, previewsThumbnails, previews缩略图、预览 |
| 64 | 4× | 4.5 | Near-photographic, slight banding in smooth areasलगभग photo जैसी, smooth हिस्सों में थोड़ी banding接近照片,平滑区域有轻微色带 | Web images, email assetsWeb images, email assets网页图片、邮件素材 |
| 128 | 3.4× | 3.5 | Excellent — hard to tell apart from the originalबेहतरीन — original से अलग पहचानना मुश्किल极好 —— 很难和原图区分 | High-quality displayHigh-quality display高质量展示 |
Image compression shows what clustering really does: it finds K representative points (the palette colours) that summarise a much larger space with small loss. The same idea — represent a big continuous space with a small set of prototypes — is called vector quantisation, and it is used from colour palettes (GIF/PNG-8) to the indexes inside vector databases. Note: real formats like JPEG and PNG use other, stronger methods; K-Means here is about the idea, not about beating JPEG.
Image compression दिखाता है कि clustering असल में क्या करता है: यह K प्रतिनिधि points (palette रंग) खोजता है जो एक बहुत बड़े space को थोड़े नुकसान के साथ summarise करते हैं। यही विचार — एक बड़े continuous space को prototypes के छोटे set से दिखाना — vector quantisation कहलाता है, और यह colour palettes (GIF/PNG-8) से लेकर vector databases के indexes तक में इस्तेमाल होता है। ध्यान दें: JPEG और PNG जैसे असली formats दूसरे, ज़्यादा मज़बूत तरीके इस्तेमाल करते हैं; यहाँ K-Means विचार समझाने के लिए है, JPEG को हराने के लिए नहीं।
图像压缩清楚展示了聚类真正在做什么:它找到 K 个代表点(调色板颜色),以很小的损失概括一个大得多的空间。 同样的思想 —— 用一小组原型代表一个巨大的连续空间 —— 叫作向量量化(vector quantisation),从调色板格式(GIF/PNG-8)到向量数据库内部的索引都在用。 注意:JPEG、PNG 等真实格式使用其他更强的方法;这里的 K-Means 是为了讲清思想,不是为了打败 JPEG。
K-Means Limitations — What No One Tells BeginnersK-Means की सीमाएँ — जो कोई शुरुआती लोगों को नहीं बताताK-Means 的局限 — 没人告诉初学者的事
K-Means vs Other Clustering AlgorithmsK-Means vs दूसरे Clustering AlgorithmsK-Means 与其他聚类算法对比
| Propertyगुण特性 | K-Means | DBSCAN | HierarchicalHierarchical层次聚类 | GMM |
|---|---|---|---|---|
| Needs K up frontपहले से K चाहिए需要事先指定 K | Yesहाँ是 | Noनहीं否 | Chosen after (cut the tree)बाद में (tree काटकर)事后决定(切树) | Yesहाँ是 |
| Handles outliersOutliers संभालता है处理离群点 | Poorख़राब差 | Excellent (labels them noise)बहुत अच्छा (noise label देता है)优秀(标记为噪声) | Moderateठीक-ठाक一般 | Moderateठीक-ठाक一般 |
| Cluster shapeCluster का आकार簇的形状 | Round onlyसिर्फ़ गोल仅圆形 | Any shapeकोई भी आकार任意形状 | Depends on linkageLinkage पर निर्भर取决于连接方式 | EllipticalElliptical椭圆形 |
| Scales to large dataबड़े data पर चलता है适用于大数据 | Excellent (Mini-Batch)बहुत अच्छा (Mini-Batch)优秀(Mini-Batch) | Moderateठीक-ठाक一般 | Poor — O(n²) memoryख़राब — O(n²) memory差 —— O(n²) 内存 | Moderateठीक-ठाक一般 |
| Soft / probabilistic membershipSoft / probabilistic membership软 / 概率归属 | Hard assignmentHard assignment硬分配 | HardHard硬分配 | HardHard硬分配 | Yes — probabilitiesहाँ — probabilities是 —— 给出概率 |
| Best forकिसके लिए सबसे अच्छा最适合 | Customer segments, fast baselineCustomer segments, तेज़ baseline客户分群、快速基线 | Geospatial data, anomaly detectionGeospatial data, anomaly detection地理空间数据、异常检测 | Dendrograms, taxonomiesDendrograms, taxonomies树状图、分类体系 | Overlapping groupsOverlap करते groups相互重叠的分组 |
Start with K-Means as your baseline clustering algorithm. It is fast, easy to explain, and often good enough. Move to DBSCAN, GMM or spectral clustering when K-Means clearly fails — for example, when the silhouette stays low (below about 0.3) for every K, or when a 2-D PCA plot shows clearly non-round shapes.
K-Means से शुरू करें — यह आपका baseline clustering algorithm है। यह तेज़ है, समझाने में आसान है, और अक्सर काफ़ी अच्छा है। DBSCAN, GMM या spectral clustering पर तब जाएँ जब K-Means साफ़ फ़ेल हो — जैसे जब हर K के लिए silhouette कम (लगभग 0.3 से नीचे) रहे, या 2-D PCA plot में साफ़ ग़ैर-गोल आकार दिखें।
把 K-Means 作为基线聚类算法起步。它快、好解释,而且常常够用。当 K-Means 明显失效时再换 DBSCAN、GMM 或谱聚类 —— 比如所有 K 的轮廓系数都很低(低于约 0.3),或者二维 PCA 图上明显不是圆形的形状。
Mini-Batch K-Means — For Large DatasetsMini-Batch K-Means — बड़े Datasets के लिएMini-Batch K-Means — 面向大数据集
Standard K-Means looks at every data point in every iteration. Mini-Batch K-Means updates the centroids from small random samples (mini-batches) instead. Each update is very cheap, and the data can arrive in chunks, so it works even when the data does not fit in memory. The price: centroids that are slightly less accurate.
Standard K-Means हर iteration में हर data point देखता है। Mini-Batch K-Means इसकी जगह छोटे random samples (mini-batches) से centroids update करता है। हर update बहुत सस्ता है, और data टुकड़ों में आ सकता है, इसलिए यह तब भी काम करता है जब data memory में न समाए। क़ीमत: centroids थोड़े कम सटीक।
标准 K-Means 每一轮都要看所有数据点。Mini-Batch K-Means 则用小的随机样本(小批量)来更新质心。 每次更新都非常便宜,而且数据可以分块到达,所以即使数据装不进内存也能用。代价是:质心的精度略低一些。
3,000 points, K = 6, both start from the same centroids. The x-axis counts how many points each method has looked at. Blue rings = standard centroids, orange ⊗ = mini-batch centroids, orange dots = the current mini-batch.
3,000 points, K = 6, दोनों एक ही centroids से शुरू। X-axis गिनती है कि हर तरीके ने कितने points देखे। नीले गोले = standard centroids, नारंगी ⊗ = mini-batch centroids, नारंगी dots = मौजूदा mini-batch.
3,000 个点,K = 6,两者从相同的质心出发。横轴是每种方法已经看过的点数。蓝色圆环 = 标准 K-Means 质心,橙色 ⊗ = mini-batch 质心,橙色圆点 = 当前小批量。
import numpy as np
import time
from sklearn.cluster import KMeans, MiniBatchKMeans
# Simulate 1 million records: 20 overlapping groups in 10 features
rng = np.random.default_rng(42)
centres = rng.uniform(-10, 10, size=(20, 10))
X_big = centres[rng.integers(0, 20, 1_000_000)] + rng.normal(0, 3, (1_000_000, 10))
# 1) Standard K-Means: uses ALL rows in every iteration
t0 = time.time()
km_std = KMeans(n_clusters=20, n_init=3, random_state=42).fit(X_big)
print(f"Standard K-Means : {time.time()-t0:5.2f}s WCSS={km_std.inertia_:,.0f}")
# 2) Mini-Batch K-Means: each step uses only 1,024 random rows
t1 = time.time()
km_mb = MiniBatchKMeans(n_clusters=20, batch_size=1024,
n_init=3, random_state=42).fit(X_big)
print(f"Mini-Batch : {time.time()-t1:5.2f}s WCSS={km_mb.inertia_:,.0f}")
# 3) Mini-Batch with partial_fit: data arrives in chunks
# (e.g. read 100k rows at a time from a file that does not fit in RAM)
km_stream = MiniBatchKMeans(n_clusters=20, batch_size=1024, random_state=42)
t2 = time.time()
for chunk in np.array_split(X_big, 10): # 10 chunks of 100k rows
for batch in np.array_split(chunk, 100): # 100 mini-batches per chunk
km_stream.partial_fit(batch)
wcss_stream = -km_stream.score(X_big) # score() = minus WCSS
print(f"partial_fit : {time.time()-t2:5.2f}s WCSS={wcss_stream:,.0f}")
gap = (km_mb.inertia_ / km_std.inertia_ - 1) * 100
print(f"\nMini-Batch WCSS is {gap:.1f}% worse than standard K-Means.")
You may read that Mini-Batch is "10–50× faster". On this run it was not faster when fitting all 1 million rows in memory: modern scikit-learn K-Means is highly optimised and needed only a few full passes here, while Mini-Batch paid a 3.4% higher WCSS.
Mini-Batch wins in two situations: (1) the data is too big for memory — partial_fit above saw each row once, in 100k-row chunks, and still matched the Mini-Batch quality in about a second;
(2) data keeps arriving (streaming), so you update the model instead of retraining. Always time both on your data and hardware before choosing.
आपने पढ़ा होगा कि Mini-Batch "10–50× तेज़" है। इस run में पूरे 10 लाख rows को memory में fit करते समय यह तेज़ नहीं था: आज का scikit-learn K-Means बहुत optimised है और यहाँ कुछ ही full passes में हो गया, जबकि Mini-Batch का WCSS 3.4% ज़्यादा रहा।
Mini-Batch दो हालात में जीतता है: (1) data memory के लिए बहुत बड़ा हो — ऊपर partial_fit ने हर row एक बार देखी, 1 लाख rows के टुकड़ों में, और फिर भी लगभग एक second में Mini-Batch जैसी quality पाई;
(2) data लगातार आता रहे (streaming), तब आप model को दोबारा train करने की जगह update करते हैं। चुनने से पहले हमेशा अपने data और hardware पर दोनों का समय मापें।
你可能读到过 Mini-Batch “快 10–50 倍”。但在这次运行中,把 100 万行全部放进内存训练时,它并没有更快:现代 scikit-learn 的 K-Means 高度优化,这里只需几轮完整遍历,而 Mini-Batch 的 WCSS 还高了 3.4%。
Mini-Batch 在两种情况下胜出:(1) 数据大到内存装不下 —— 上面的 partial_fit 以每块 10 万行的方式把每行只看一遍,仍在约 1 秒内达到了 Mini-Batch 的质量;
(2) 数据源源不断地到来(流式数据),这时你更新模型而不是重新训练。做选择之前,一定要在你自己的数据和硬件上给两者计时。
Golden RulesGolden Rules黄金法则
StandardScaler before K-Means — unless all features are already in the same units (like pixel values). Take the log of skewed money columns first.StandardScaler लगाएँ — जब तक सभी features पहले से एक ही unit में न हों (जैसे pixel values)। टेढ़े पैसे वाले columns का पहले log लें।StandardScaler —— 除非所有特征本来就是同一单位(比如像素值)。偏斜的金额列先取对数。init='k-means++' (the sklearn default) and n_init=10 for important models. Avoid init='random' with a single run — the result depends too much on luck (see the Section 05 simulator).init='k-means++' (sklearn default) और n_init=10 इस्तेमाल करें। एक ही run के साथ init='random' से बचें — नतीजा क़िस्मत पर बहुत निर्भर करता है (Section 05 का simulator देखें)।init='k-means++'(sklearn 默认值)和 n_init=10。避免只跑一次的 init='random' —— 结果太依赖运气(见第 05 节模拟器)。MiniBatchKMeans when the data does not fit in memory or keeps arriving. Use partial_fit on chunks. On data that fits in memory, time both methods first — standard K-Means is often fast enough and gives a lower WCSS (Section 15).MiniBatchKMeans पर विचार करें। टुकड़ों पर partial_fit इस्तेमाल करें। जो data memory में समा जाए, उस पर पहले दोनों का समय मापें — standard K-Means अक्सर काफ़ी तेज़ होता है और कम WCSS देता है (Section 15)।MiniBatchKMeans。对数据块使用 partial_fit。对于内存装得下的数据,先给两种方法计时 —— 标准 K-Means 往往已经够快,而且 WCSS 更低(第 15 节)。random_state in all experiments. K-Means starts randomly. Without a fixed seed, results change every run, which makes debugging, comparison and reproducibility impossible — especially in production pipelines.random_state set करें। K-Means random शुरुआत करता है। तय seed के बिना हर run में नतीजे बदलते हैं, जिससे debugging, तुलना और reproducibility असंभव हो जाती है — ख़ासकर production pipelines में।random_state。K-Means 是随机初始化的。不固定随机种子,每次运行结果都不同,调试、比较和复现都无从谈起 —— 在生产流水线中尤其要命。