Machine Learning 📂 Unsupervised Learning · 2 of 3 418 min read

K-Means Clustering

A comprehensive, story-driven tutorial on K-Means clustering covering the algorithm mechanics, choosing K, worked Python code, two real-world case studies (customer segmentation & image compression), pitfalls, and golden rules. Designed for beginner-to-intermediate data science practitioners.

🌐
SectionSection第 01 节

The Story That Explains K-Meansवह कहानी जो K-Means समझाती है一个讲清 K-Means 的故事

The New City — Finding Your Friend Groupsनया शहर — अपने दोस्तों के Groups ढूँढना新城市 — 找到你的朋友圈
Imagine you move to a new city and walk into a big party where you know nobody. You look around and notice something: people are not standing at random. By the drinks, a group in gym clothes is talking about marathons. Near the bookshelf, a quieter group is arguing about science fiction. On the dance floor, a loud crowd is sharing playlists.

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.
कल्पना करें कि आप एक नए शहर में आए हैं और एक बड़ी party में जाते हैं जहाँ आप किसी को नहीं जानते। आप चारों ओर देखते हैं और कुछ notice करते हैं: लोग random तरीके से नहीं खड़े हैं। Drinks के पास gym कपड़ों में एक group marathon की बातें कर रहा है। Bookshelf के पास एक शांत group science fiction पर बहस कर रहा है। Dance floor पर एक जोशीली भीड़ playlists share कर रही है।

आपको किसी 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,中心点)所在的簇。算法反复执行两个简单动作,直到各点的归属不再变化。

💡
Supervised vs Unsupervised — The Key DifferenceSupervised vs Unsupervised — मुख्य अंतर有监督 vs 无监督 — 关键区别

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 发现的是数据中本来就存在的结构。所以当打标签很贵、不可能做到、或者根本还不知道标签是什么时,它特别有用。


SectionSection第 02 节

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 इन्हीं का इस्तेमाल करता है।

在看任何公式之前,先学会六个词。本页的每张图和每个模拟器都会用到它们。

🖼️ PICTURE DICTIONARY — THE SIX WORDS OF K-MEANSतस्वीरों वाला शब्दकोश — K-MEANS के छह शब्द图片词典 — K-MEANS 的六个关键词
K-Means picture dictionary DATA POINTDATA POINT数据点 spend = 1,240orders = 14 one customer = one row = one dotएक customer = एक row = एक dot一位顾客 = 一行数据 = 一个点 CLUSTERCLUSTER簇(cluster) a group of dots close togetherपास-पास dots का एक group靠在一起的一组点 CENTROIDCENTROID质心(centroid) the average position of a clustercluster की औसत जगह一个簇的平均位置 DISTANCEDISTANCE距离(distance) d straight-line gap between two dotsदो dots के बीच सीधी दूरी两点之间的直线距离 K K = 3 how many clusters you ask forआप कितने clusters माँगते हैं你要求的簇的个数 WCSS (INERTIA)WCSS (INERTIA)WCSS(惯性) add up every dot-to-centroid distance²हर dot से centroid तक की दूरी² जोड़ें把每个点到质心的距离平方加起来

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 如何下降。

▶ THE K-MEANS LOOP — ASSIGN, MOVE, REPEATK-MEANS LOOP — ASSIGN, MOVE, दोहराएँK-MEANS 循环 — 分配、移动、重复
K-Means loop, computed STARTशुरुआत开始 WCSS = ? 3 centroids placed badly3 centroids ख़राब जगह पर3 个质心放得很差 two of them near the same groupदो एक ही group के पास其中两个挨着同一组 ITERATION 1ITERATION 1第 1 轮 WCSS = 32,597 assign → colours; move →assign → रंग; move →分配 → 上色;移动 → each ⊗ jumps to its meanहर ⊗ अपने mean पर每个 ⊗ 跳到均值 ITERATION 2ITERATION 2第 2 轮 WCSS = 7,844 re-assign with new centroidsनए centroids से फिर assign用新质心重新分配 colours fix themselvesरंग खुद ठीक हो जाते हैं颜色自己纠正了 ITERATION 3 = DONEITERATION 3 = पूरा第 3 轮 = 完成 WCSS = 7,844 no dot changes colourकोई dot रंग नहीं बदलता没有点改变颜色 → stop: converged→ रुकें: converged→ 停止:已收敛

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 停止。空心圆 = 旧质心,⊗ = 新质心。

🧠
The Whole Algorithm in One Sentenceपूरा Algorithm एक वाक्य में一句话讲完整个算法

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)都是为了把这两个动作做好。


SectionSection第 03 节

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 是一个由五步组成的简单循环。用故事看过一遍,你就不会忘记。

The Pizza Shop Owner and the Delivery HubsPizza Shop का मालिक और Delivery Hubs披萨店老板和配送点
You own a pizza chain with 100 customers spread across a city. You want to open 3 delivery hubs so that the total travel distance is as small as possible. Here is how you would do it by common sense — and this is exactly the K-Means algorithm:

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.
आपकी एक pizza chain है जिसके 100 customers पूरे शहर में फैले हैं। आप 3 delivery hubs खोलना चाहते हैं ताकि कुल travel distance जितना हो सके उतना कम हो। आम समझ से आप यह ऐसे करेंगे — और यही ठीक K-Means algorithm है:

1. अंदाज़ा लगाएँ। आँखें बंद करके map पर 3 random जगह pin करें — ये पहले hub हैं।
2. Assign करें। हर customer उस hub के पास जाता है जो सबसे नज़दीक है।
3. फिर से निकालें। हर hub के सभी customers की औसत जगह निकालें। Hub pin वहाँ ले जाएँ।
4. दोहराएँ। Customers को उनके नए सबसे पास वाले hub से जोड़ें। Centres फिर से निकालें।
5. Converge. जब कोई customer hub न बदले, रुक जाएँ। आपको अच्छी जगहें मिल गईं।
你经营一家披萨连锁店,有 100 位顾客分布在城市各处。你想开 3 个配送点,让总配送距离尽可能短。 凭常识你会这样做 —— 而这正是 K-Means 算法:

1. 猜。闭上眼睛,在地图上随便钉 3 个位置作为初始配送点。
2. 分配。每位顾客归离他最近的配送点。
3. 重新计算。对每个配送点,算出它所有顾客的平均位置,把钉子移过去。
4. 重复。把顾客重新分给新的最近配送点,再重新计算中心。
5. 收敛。当没有顾客再换配送点时停止。你找到了一组不错的位置。
LIVELIVE互动Be the Algorithm — Place the Pizza Hubs Yourselfखुद Algorithm बनें — Pizza Hubs खुद रखें亲自当一回算法 — 自己摆放披萨配送点

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 会怎么做。

Your WCSS (bar full = best)आपका WCSS (भरी bar = सबसे अच्छा)你的 WCSS(满格 = 最佳)
—

⚙️ K-Means Algorithm — Formal StepsK-Means Algorithm — औपचारिक StepsK-Means 算法 — 正式步骤
Step 1
Choose K. Decide how many clusters you want. This is the one setting you must give. K = 3 means three clusters. K चुनें। तय करें कि आपको कितने clusters चाहिए। यही एक setting है जो आपको देनी ही होगी। K = 3 मतलब तीन clusters. 选择 K。决定要几个簇。这是你必须提供的唯一设置。K = 3 表示三个簇。
Step 2
Initialise centroids. Place K centroid points in the feature space — at random, or with the smarter K-Means++ method (Section 05). Centroids initialise करें। Feature space में K centroid points रखें — random, या smarter K-Means++ तरीके से (Section 05)। 初始化质心。在特征空间中放置 K 个质心 —— 随机放,或者用更聪明的 K-Means++ 方法(第 05 节)。
Step 3
Assign each point to the nearest centroid using Euclidean distance: d = √Σ(xᵢ − cᵢ)² हर point को Euclidean distance से सबसे पास वाले centroid को assign करें: d = √Σ(xᵢ − cᵢ)² 把每个点分配给欧氏距离(Euclidean distance)最近的质心:d = √Σ(xᵢ − cᵢ)²
Step 4
Recompute centroids. Move each centroid to the mean of all points assigned to it: cₖ = (1/nₖ) Σ xᵢ Centroids फिर से निकालें। हर centroid को उसके सभी points के mean पर ले जाएँ: cₖ = (1/nₖ) Σ xᵢ 重新计算质心。把每个质心移到分配给它的所有点的均值处:cₖ = (1/nₖ) Σ xᵢ
Step 5
Repeat Steps 3–4 until no point changes its cluster (convergence), or a maximum number of iterations is reached. Steps 3–4 दोहराएँ जब तक कोई point अपना cluster न बदले (convergence), या iterations की अधिकतम सीमा न आ जाए। 重复第 3–4 步,直到没有点再改变所属簇(收敛),或达到最大迭代次数。
Done
Output: a cluster label for every data point, and the final centroid coordinates of each cluster. Output: हर data point का cluster label, और हर cluster के final centroid coordinates. 输出:每个数据点的簇标签,以及每个簇最终的质心坐标。

SectionSection第 04 节

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 不是在乱猜 —— 它在把一个数字变得尽可能小。理解这个数字,就能同时理解它的优势和局限。

Objective (WCSS)Objective (WCSS)目标(WCSS)
J = Σₖ Σ xᵢ∈Cₖ ‖xᵢ − μₖ‖²
Within-Cluster Sum of Squares (WCSS): the total squared distance from every point to its cluster centroid. K-Means tries to make this as small as possible.
Within-Cluster Sum of Squares (WCSS): हर point से उसके cluster centroid तक की squared distance का जोड़। K-Means इसे जितना हो सके छोटा करने की कोशिश करता है।
簇内平方和(WCSS):每个点到其簇质心的距离平方之和。K-Means 力求让它尽可能小。
Euclidean DistanceEuclidean Distance欧氏距离
d(a,b) = √[(a₁−b₁)² + (a₂−b₂)²]
The distance used to decide which centroid a point is closest to. It works in any number of dimensions — 2D, 10D, 1000D.
यह distance तय करती है कि point किस centroid के सबसे पास है। यह कितनी भी dimensions में काम करती है — 2D, 10D, 1000D.
用来判断一个点离哪个质心最近的距离。适用于任意维度 —— 2 维、10 维、1000 维。
Centroid UpdateCentroid Update质心更新
μₖ = (1/|Cₖ|) Σ xᵢ∈Cₖ xᵢ
The new centroid is simply the average (mean) of all points now in cluster k. That is why it is called K-Means. The mean is exactly the point that makes the squared distances smallest.
नया centroid बस cluster k के सभी points का औसत (mean) है। इसीलिए इसे K-Means कहते हैं। Mean ठीक वही point है जो squared distances को सबसे छोटा करता है।
新的质心就是簇 k 中所有点的平均值(mean)。这就是它叫 K-Means 的原因。均值恰好是让平方距离之和最小的那个点。
Silhouette ScoreSilhouette Score轮廓系数
s(i) = (b−a) / max(a,b)
Measures cluster quality: a = average distance to points in the same cluster, b = average distance to the nearest other cluster. Ranges from −1 to +1. Higher is better.
Cluster की quality मापता है: a = अपने cluster के points से औसत दूरी, b = सबसे पास वाले दूसरे cluster से औसत दूरी। Range −1 से +1. ज़्यादा बेहतर।
衡量聚类质量:a = 到同簇点的平均距离,b = 到最近的其他簇的平均距离。范围 −1 到 +1,越高越好。

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
1A=0  B=1  C=0  D=1  E=1  F=1c₀ = (1, 1.5)   c₁ = (4.5, 3.75)76.00
2A=0  B=0  C=0  D=1  E=1  F=1c₀ = (1.33, 1.33)   c₁ = (5.33, 4.67)7.69
3same 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
OUTPUT
Iteration 1: labels = [0, 1, 0, 1, 1, 1] WCSS = 76.000 new centroids = [[1.0, 1.5], [4.5, 3.75]] Iteration 2: labels = [0, 0, 0, 1, 1, 1] WCSS = 7.688 new centroids = [[1.333, 1.333], [5.333, 4.667]] Iteration 3: labels = [0, 0, 0, 1, 1, 1] WCSS = 2.667 new centroids = [[1.333, 1.333], [5.333, 4.667]] centroids did not move → converged
⚠️
The Local Minimum TrapLocal Minimum का जाल局部最小值陷阱

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++',默认值)—— 它能大大减轻这个问题。下一个模拟器里你会亲眼看到。


SectionSection第 05 节

K-Means++ — The Smarter StartK-Means++ — समझदार शुरुआतK-Means++ — 更聪明的起点

Why You Don't Put All Three Pizza Hubs in the Same Neighbourhoodतीनों Pizza Hubs एक ही मोहल्ले में क्यों नहीं रखते为什么不能把三个披萨配送点都放在同一个街区
Imagine you pick your three starting hub locations at random and, by bad luck, they all land in the north-east corner of the city. In the first assign step, all 100 customers are squeezed into those three nearby hubs — three clusters fighting over the same patch while the rest of the city is ignored.

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.
कल्पना करें कि आप तीनों शुरुआती hub जगहें random चुनते हैं और बदक़िस्मती से तीनों शहर के उत्तर-पूर्वी कोने में आ जाती हैं। पहले assign step में सभी 100 customers उन तीन पास-पास वाले hubs में ठूँस दिए जाते हैं — तीन clusters एक ही टुकड़े के लिए लड़ते हैं और बाकी शहर अनदेखा रह जाता है।

K-Means++ इसे एक आसान नियम से ठीक करता है: ऐसे शुरुआती centroids चुनें जो एक-दूसरे से दूर हों। पहला centroid एक random point है। हर अगला centroid पहले से चुने सबसे पास वाले centroid से उसकी squared distance के अनुपात वाली probability से चुना जाता है। मौजूदा centroids से दूर वाले points के चुने जाने की संभावना ज़्यादा होती है। नतीजा: शुरुआती centroids पूरे data पर फैले होते हैं, एक कोने में नहीं।
想象你随机挑了三个初始配送点,运气不好,三个都落在了城市东北角。 在第一次分配时,100 位顾客全被挤进这三个挨在一起的配送点 —— 三个簇争抢同一块地盘,城市其他地方却没人管。

K-Means++ 用一条简单规则解决这个问题:让初始质心彼此远离。第一个质心随机选一个点; 之后每个质心被选中的概率,与它到已选最近质心的距离平方成正比。离现有质心越远的点越容易被选中。 结果:初始质心分散在整个数据上,而不是挤在一个角落。
LIVELIVE互动Random Start vs K-Means++ — Same Data, Same KRandom शुरुआत vs K-Means++ — वही Data, वही K随机初始化 vs K-Means++ — 同样的数据,同样的 K

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 次试验”统计各方法卡住的频率。

random: stuck runsrandom: फँसे runsrandom:卡住比例
—
k-means++: stuck runsk-means++: फँसे runsk-means++:卡住比例
—

🎲
Random InitRandom Init随机初始化
init='random'
Picks K random data points as starting centroids. Fast, but can give poor clusters when the starting centroids land close together.
K random data points को शुरुआती centroids बनाता है। तेज़, पर जब शुरुआती centroids पास-पास आ जाएँ तो ख़राब clusters दे सकता है।
随机挑 K 个数据点作为初始质心。速度快,但如果初始质心挤在一起,就可能得到很差的簇。
✗ Often needs many restarts
✗ Can miss obvious clusters
✗ अक्सर कई restarts चाहिए
✗ साफ़ दिखने वाले clusters भी छूट सकते हैं
✗ 往往需要多次重启
✗ 可能漏掉明显的簇
🎯
K-Means++ InitK-Means++ InitK-Means++ 初始化
init='k-means++'
Spreads the starting centroids using distance-weighted probability. Each new centroid is more likely to be far from all existing ones.
Distance-weighted probability से शुरुआती centroids को फैलाता है। हर नया centroid मौजूदा सभी से दूर होने की ज़्यादा संभावना रखता है।
用按距离加权的概率把初始质心分散开。每个新质心更可能远离所有已有质心。
✓ Usually fewer iterations
✓ Gets stuck far less often
✓ आमतौर पर कम iterations
✓ बहुत कम बार फँसता है
✓ 通常迭代次数更少
✓ 卡住的情况少得多
🔍
Multiple Restartsकई Restarts多次重启
n_init (sklearn: 'auto')
Run the full algorithm N times from different starts and keep the run with the lowest WCSS. In scikit-learn 1.4+ the default n_init="auto" means 1 run with K-Means++ and 10 runs with random init.
पूरा algorithm अलग-अलग शुरुआत से N बार चलाएँ और सबसे कम WCSS वाला run रखें। scikit-learn 1.4+ में default n_init="auto" का मतलब है K-Means++ के साथ 1 run और random init के साथ 10 runs.
从不同起点把整个算法运行 N 次,保留 WCSS 最低的一次。在 scikit-learn 1.4+ 中,默认 n_init="auto" 表示:用 K-Means++ 时跑 1 次,用随机初始化时跑 10 次。
✓ Protects against bad local minima
✓ More stable results
✓ ख़राब local minima से बचाता है
✓ ज़्यादा stable नतीजे
✓ 防止陷入糟糕的局部最小值
✓ 结果更稳定
💡
Practical Tipकाम का Tip实用建议

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:花十倍计算量,换来对“倒霉起点”的保护。本页所有代码都这样做。


SectionSection第 06 节

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。下面是最可靠的选择方法。

💱
The Elbow MethodElbow Method肘部法
WCSS vs K plotWCSS vs K plotWCSS–K 曲线
Plot WCSS against K for K = 1 to 10. As K grows, WCSS always falls (more clusters = shorter distances). Look for the elbow — the point where the curve bends and adding more clusters gives only small gains. That bend is a good K.
K = 1 से 10 तक WCSS का plot बनाएँ। K बढ़ने पर WCSS हमेशा घटता है (ज़्यादा clusters = छोटी दूरियाँ)। Elbow खोजें — वह जगह जहाँ curve मुड़ती है और ज़्यादा clusters से बहुत कम फ़ायदा होता है। वह मोड़ एक अच्छा K है।
画出 K = 1 到 10 时的 WCSS。K 越大,WCSS 总会越小(簇越多 = 距离越短)。寻找肘部 —— 曲线拐弯、再加簇收益很小的那个点。那个拐点就是一个好的 K。
✓ Simple and visual
✓ Fast to compute
✓ आसान और दिखने वाला
✓ जल्दी निकलता है
✓ 直观易懂
✓ 计算快
✗ The elbow can be unclear
✗ Needs your judgement
✗ Elbow साफ़ न भी हो
✗ आपकी समझ पर निर्भर
✗ 肘部可能不明显
✗ 需要主观判断
📈
Silhouette ScoreSilhouette Score轮廓系数
−1 to +1 scale−1 से +1 scale−1 到 +1
For each K, compute the average silhouette over all points. Near +1: points sit well inside their own cluster and far from others. Near 0: clusters overlap. Negative: points are probably in the wrong cluster. Pick the K with the highest score.
हर K के लिए सभी points का औसत silhouette निकालें। +1 के पास: points अपने cluster के अंदर अच्छे से हैं और दूसरों से दूर। 0 के पास: clusters overlap करते हैं। Negative: points शायद ग़लत cluster में हैं। सबसे ऊँचे score वाला K चुनें।
对每个 K 计算所有点的平均轮廓系数。接近 +1:点稳稳待在自己的簇里,远离其他簇。接近 0:簇相互重叠。负数:点很可能分错了簇。选分数最高的 K。
✓ One clear number
✓ Helps when the elbow is unclear
✓ एक साफ़ number
✓ Elbow धुँधला हो तब काम आता है
✓ 一个明确的数字
✓ 肘部不明显时很有用
✗ Slower: O(n²) distances
✗ Prefers round, compact clusters
✗ धीमा: O(n²) दूरियाँ
✗ गोल, कसे clusters पसंद करता है
✗ 较慢:需 O(n²) 次距离计算
✗ 偏好圆形、紧凑的簇
📋
Domain KnowledgeDomain Knowledge领域知识
Business contextBusiness context业务背景
Sometimes the best K is the one that makes business sense. A retailer with budget for exactly 4 email campaigns may fix K = 4, whatever the elbow says.
कभी-कभी सबसे अच्छा K वह होता है जो business के हिसाब से सही हो। जिस retailer के पास ठीक 4 email campaigns का budget है, वह elbow कुछ भी कहे, K = 4 रख सकता है।
有时最好的 K 是最符合业务需要的那个。一个只够做 4 套邮件营销预算的零售商,不管肘部图怎么说,都可以把 K 定为 4。
✓ Results people can act on
✓ Team agreement
✓ ऐसे नतीजे जिन पर काम हो सके
✓ Team की सहमति
✓ 结果可落地执行
✓ 团队容易认同
✗ May ignore the real data structure
✗ Needs domain expertise
✗ असली data ढाँचे को अनदेखा कर सकता है
✗ Domain की समझ चाहिए
✗ 可能忽略数据的真实结构
✗ 需要领域经验
LIVELIVE互动Choosing K — Elbow and Silhouette, Computed LiveK चुनना — Elbow और Silhouette, live निकाले गए选择 K — 实时计算肘部与轮廓系数

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 查看对应的聚类结果。


SectionSection第 07 节

When K-Means Works — and When It FailsK-Means कब चलता है — और कब फ़ेल होता हैK-Means 何时有效 — 何时失效

✅
Round, Compact Clustersगोल, कसे हुए Clusters圆形、紧凑的簇
K-Means does well hereयहाँ K-Means अच्छा हैK-Means 擅长
K-Means uses Euclidean distance and works best when clusters are roughly round, of similar spread, and well separated. On data like that it is fast and close to perfect.
K-Means Euclidean distance इस्तेमाल करता है और तब सबसे अच्छा है जब clusters लगभग गोल, एक जैसे फैलाव वाले और अच्छी तरह अलग हों। ऐसे data पर यह तेज़ और लगभग perfect है।
K-Means 使用欧氏距离,当簇大致呈圆形、分散程度相近且彼此分开时效果最好。在这类数据上它又快又接近完美。
❌
Rings, Moons, SpiralsRings, Moons, Spirals圆环、月牙、螺旋
K-Means failsK-Means फ़ेलK-Means 失效
Two rings one inside the other, two crescents, two spirals — K-Means cannot find these, because the border between two centroids is always a straight line. Use DBSCAN or spectral clustering instead.
एक के अंदर दूसरी ring, दो अर्धचंद्र, दो spirals — K-Means इन्हें नहीं खोज सकता, क्योंकि दो centroids के बीच की सीमा हमेशा सीधी line होती है। इनके लिए DBSCAN या spectral clustering इस्तेमाल करें।
套在一起的两个圆环、两个月牙、两条螺旋 —— K-Means 都找不出来,因为两个质心之间的边界永远是直线。请改用 DBSCAN 或谱聚类(spectral clustering)。
⚠️
Very Different Cluster Spreadsबहुत अलग फैलाव वाले Clusters分散程度差异很大的簇
K-Means strugglesK-Means को मुश्किलK-Means 吃力
If one cluster is large and spread out and the others are small and tight, K-Means tends to move the borders and hand part of the big cluster to the small ones. Gaussian Mixture Models (GMM) handle this better.
अगर एक cluster बड़ा और फैला हो और बाकी छोटे और कसे हुए, तो K-Means सीमाएँ खिसकाकर बड़े cluster का हिस्सा छोटों को दे देता है। Gaussian Mixture Models (GMM) इसे बेहतर संभालते हैं।
如果一个簇又大又散,其他簇又小又紧,K-Means 往往会移动边界,把大簇的一部分分给小簇。高斯混合模型(GMM)处理得更好。
LIVELIVE互动Break K-Means — Six Datasets, One AlgorithmK-Means को तोड़ें — छह Datasets, एक Algorithm挑战 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 把多少点分进了正确的组。

Points in the right groupसही group में points分对的点
—

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)

SectionSection第 08 节

Feature Scaling — A Must for K-MeansFeature Scaling — K-Means के लिए ज़रूरी特征缩放 — K-Means 的必做步骤

🚨
Always Scale Your Features Before K-MeansK-Means से पहले हमेशा Features Scale करें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。忘记这一步是初学者最常见的错误之一。

LIVELIVE互动See the Data the Way K-Means Sees ItData को वैसे देखें जैसे K-Means देखता है用 K-Means 的眼睛看数据

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 个簇。

Agreement with age groupsAge groups से मेल与年龄组的一致率
—

StandardScaler
z = (x − μ) / σ
Range: usually −3 to +3Range: आमतौर पर −3 से +3范围:通常 −3 到 +3
Best default choice for K-Means. One very extreme value still affects μ and σ.
K-Means के लिए सबसे अच्छा default. बहुत extreme value अब भी μ और σ पर असर डालती है।
K-Means 的最佳默认选择。极端值仍会影响 μ 和 σ。
MinMaxScaler
x' = (x−min)/(max−min)
Range: 0 to 1Range: 0 से 1范围:0 到 1
Use when you need bounded features. Very sensitive to outliers (one huge value squashes all others).
जब features की सीमा चाहिए तब इस्तेमाल करें। Outliers से बहुत प्रभावित (एक बड़ी value बाकी सबको दबा देती है)।
需要有界特征时使用。对离群点非常敏感(一个超大值会把其他值都压扁)。
RobustScaler
x' = (x−Q2)/(Q3−Q1)
IQR-based scalingIQR-based scaling基于 IQR 的缩放
Best when data has many outliers. Uses the median (Q2) and the IQR.
जब data में बहुत outliers हों तब सबसे अच्छा। Median (Q2) और IQR इस्तेमाल करता है।
数据离群点很多时最好。使用中位数(Q2)和 IQR。
No Scalingकोई Scaling नहीं不缩放
x' = x
Original unitsOriginal units原始单位
Only fine when all features are already in the same units (for example RGB pixel values). Rare.
सिर्फ़ तब ठीक जब सभी features पहले से एक ही unit में हों (जैसे RGB pixel values)। ऐसा कम होता है।
只有当所有特征本来就是同一单位时才可以(比如 RGB 像素值)。这种情况很少见。

SectionSection第 09 节

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)}")
OUTPUT
WCSS (Inertia): 8.70 Iterations: 2 Cluster counts: [75 75 75 75]

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}")
OUTPUT
K WCSS Silhouette ------------------------------ 2 311.56 0.5761 3 64.65 0.7744 4 8.70 0.8592 5 7.79 0.7256 6 6.90 0.5910 7 6.05 0.4640 8 5.38 0.3371 9 4.88 0.3569 10 4.41 0.3668 Best K by Silhouette: 4
🎯
Reading the Resultsनतीजे पढ़ना解读结果

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 算很强)。


SectionSection第 10 节

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 个点上实时运行。每按一次“走一步”执行半轮:先分配(点变色),再移动(质心滑向均值)。

LIVELIVE互动K-Means Step by StepK-Means एक-एक StepK-Means 逐步演示

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 时停止。


SectionSection第 11 节

📋 Case Study 1 — Customer Segmentation for an E-Commerce Shop📋 Case Study 1 — E-Commerce Shop के लिए Customer Segmentation📋 案例一 — 电商平台的客户分群

ShopSmart — "We Send Everyone the Same Email"ShopSmart — "हम सबको एक ही Email भेजते हैं"ShopSmart —“我们给所有人发同一封邮件”
ShopSmart is an online shop with 50,000 customers. Every Monday, the marketing team sends the same promotional email to every customer, and only 9% open it. The head of marketing asks you: "We have to be smarter. Can you find natural groups in our customers so we can send targeted campaigns?"

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.
ShopSmart 50,000 customers वाली एक online shop है। हर सोमवार marketing team हर customer को वही promotional email भेजती है, और सिर्फ़ 9% लोग उसे खोलते हैं। Marketing head आपसे पूछती हैं: "हमें समझदार बनना होगा। क्या आप हमारे customers में स्वाभाविक groups खोज सकते हैं ताकि हम targeted campaigns भेज सकें?"

पिछले 12 महीनों से हर customer के तीन behaviour features हैं: total_spend (£), purchase_freq (orders/साल) और avg_order_value (£). कोई label नहीं। कोई पहले से तय group नहीं। एकदम textbook K-Means problem.
ShopSmart 是一家拥有 50,000 名顾客的网店。每周一,市场团队给所有顾客发同一封促销邮件,打开率只有 9%。 市场负责人找到你:“我们得更聪明些。你能在顾客中找出自然形成的群体,让我们做有针对性的营销吗?”

你有每位顾客过去 12 个月的三个行为特征:total_spend(总消费,£)、purchase_freq(每年订单数) 和 avg_order_value(平均订单金额,£)。没有标签,没有预设分组。一道教科书式的 K-Means 题目。
ℹ️
About the DataData के बारे में关于数据

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))
OUTPUT
total_spend purchase_freq avg_order_value count 50000.00 50000.00 50000.00 mean 1396.08 11.15 106.51 std 1710.27 6.85 67.22 min 35.09 1.00 16.85 25% 380.63 6.00 56.22 50% 724.60 10.00 92.98 75% 1334.70 16.00 131.31 max 14242.90 38.00 492.40

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))
OUTPUT
K WCSS Silhouette 2 74894.1 0.5018 3 44803.4 0.5025 4 20917.2 0.5699 5 17504.9 0.4734 6 15113.8 0.4438 7 12746.9 0.4024 8 10991.2 0.3784

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)
OUTPUT
total_spend purchase_freq avg_order_value count % share segment 0 537.81 15.09 35.60 10852 21.7 1 1034.04 9.15 113.31 18526 37.1 2 216.55 3.05 71.60 11682 23.4 3 4729.47 21.11 224.07 8940 17.9
📊 THE 4 SEGMENTS K-MEANS FOUND (900 SAMPLED CUSTOMERS)K-MEANS को मिले 4 SEGMENTS (900 SAMPLE CUSTOMERS)K-MEANS 找到的 4 个客户群(抽样 900 位顾客)
Customer segments 0 10 20 30 40 £20 £50 £100 £200 £500 purchase frequency (orders / year) →purchase frequency (orders / साल) →购买频率(每年订单数)→ ↑ average order value (log scale)↑ average order value (log scale)↑ 平均订单金额(对数刻度) VIP ChampionsVIP ChampionsVIP 冠军客户 Core RegularsCore Regulars核心常客 Bargain HuntersBargain Hunters薄利常客 Dormant / At-RiskDormant / At-Risk沉睡 / 流失风险

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建议行动
2Dormant / At-RiskDormant / At-Risk沉睡 / 流失风险~3 orders/year, £72 per order, £217 total~3 orders/साल, £72 प्रति order, कुल £217每年约 3 单,每单 £72,总计 £21723.4%Win-back campaign, discount offer, short surveyWin-back campaign, discount offer, छोटा survey召回活动、折扣优惠、简短问卷
3VIP ChampionsVIP ChampionsVIP 冠军客户~21 orders/year, £224 per order, £4,729 total~21 orders/साल, £224 प्रति order, कुल £4,729每年约 21 单,每单 £224,总计 £4,72917.9%Loyalty programme, early access, premium supportLoyalty programme, early access, premium support会员计划、新品抢先购、专属客服
1Core RegularsCore Regulars核心常客~9 orders/year, £113 per order, £1,034 total~9 orders/साल, £113 प्रति order, कुल £1,034每年约 9 单,每单 £113,总计 £1,03437.1%Upsell / cross-sell, new-category emailsUpsell / cross-sell, नई category वाले emails追加销售 / 交叉销售、新品类推荐邮件
0Frequent Bargain HuntersFrequent Bargain Hunters高频薄利客~15 orders/year, only £36 per order~15 orders/साल, सिर्फ़ £36 प्रति order每年约 15 单,每单仅 £3621.7%Bundle offers, free delivery above a minimum basketBundle offers, एक तय basket से ऊपर free delivery组合优惠、满额免运费
📌
What Happens Next (an illustrative outcome)आगे क्या होता है (एक उदाहरण के तौर पर)接下来会怎样(示意性结果)

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 测试来衡量效果。


SectionSection第 12 节

📋 Case Study 2 — Image Compression with K-Means📋 Case Study 2 — K-Means से Image Compression📋 案例二 — 用 K-Means 压缩图像

Shrinking a Photo by Using Fewer Coloursकम रंगों से Photo को छोटा करना用更少的颜色缩小照片
A full-colour photo stores each pixel as three numbers — Red, Green, Blue — each from 0 to 255. That allows 16.7 million different colours (256³), and each pixel needs 24 bits.

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.
एक full-colour photo हर pixel को तीन numbers में रखती है — Red, Green, Blue — हर एक 0 से 255. इससे 1.67 करोड़ अलग रंग (256³) बन सकते हैं, और हर pixel को 24 bits चाहिए।

पर ज़्यादातर 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× कमी.
一张全彩照片把每个像素存成三个数 —— 红、绿、蓝 —— 每个取值 0 到 255。这样可以表示 1670 万种颜色(256³),每个像素需要 24 位。

但大多数照片实际用到的颜色少得多。日落照片里是各种橙色和蓝色;森林照片里是各种绿色。如果不存每个像素的精确颜色, 而是只存 K 种代表色(就是质心!),再给每个像素存一个“最近颜色”的编号呢?

这就是 K-Means 图像压缩。每个像素都是三维颜色空间(R, G, B)中的一个点。K = 64 时,每个像素只需 log₂(64) = 6 位,而不是 24 位 —— 颜色数据缩小 4 倍。
LIVELIVE互动Compress a Picture with K ColoursK रंगों से तस्वीर Compress करें用 K 种颜色压缩图片

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)调色板(即质心)

Bits per pixelहर pixel के bits每像素位数
—
Average colour errorऔसत रंग error平均颜色误差
—

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}")
OUTPUT
Image shape: 427×640 pixels, 3 colour channels Total unique colours (theoretical): 16,777,216 Total unique colours (actual): 96,615 Pixel matrix shape: (273280, 3)

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)")
OUTPUT
Original unique colours: 96,615 Compressed unique colours: 64 Original storage (raw): 819,840 bytes Compressed storage: 205,152 bytes Compression ratio: 4.0× Average colour error: 4.5 (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}")
OUTPUT
K= 4 | Bits/pixel: 2 | Size: 68,320 bytes | Ratio: 12.0× | Avg error: 17.4 K= 8 | Bits/pixel: 3 | Size: 102,480 bytes | Ratio: 8.0× | Avg error: 11.1 K= 16 | Bits/pixel: 4 | Size: 136,640 bytes | Ratio: 6.0× | Avg error: 8.0 K= 32 | Bits/pixel: 5 | Size: 170,800 bytes | Ratio: 4.8× | Avg error: 5.9 K= 64 | Bits/pixel: 6 | Size: 204,960 bytes | Ratio: 4.0× | Avg error: 4.5 K= 128 | Bits/pixel: 7 | Size: 239,120 bytes | Ratio: 3.4× | Avg error: 3.5
K (Colours)K (रंग)K(颜色数)Compression RatioCompression Ratio压缩比Avg error (0–255)औसत error (0–255)平均误差(0–255)Visual Qualityदिखने में Quality视觉质量Use Caseकहाँ इस्तेमाल适用场景
412×17.4Posterised — a few flat coloursPosterised — कुछ सपाट रंग海报化 —— 只剩几块平涂色Icons, flat-colour logosIcons, सपाट रंग वाले logos图标、纯色 logo
166×8.0Visible banding, shapes clearBanding दिखती है, आकार साफ़有明显色带,形状清楚Thumbnails, previewsThumbnails, previews缩略图、预览
644×4.5Near-photographic, slight banding in smooth areasलगभग photo जैसी, smooth हिस्सों में थोड़ी banding接近照片,平滑区域有轻微色带Web images, email assetsWeb images, email assets网页图片、邮件素材
1283.4×3.5Excellent — hard to tell apart from the originalबेहतरीन — original से अलग पहचानना मुश्किल极好 —— 很难和原图区分High-quality displayHigh-quality display高质量展示
💡
The Core Lesson of This Case Studyइस Case Study का मुख्य सबक本案例的核心启示

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。


SectionSection第 13 节

K-Means Limitations — What No One Tells BeginnersK-Means की सीमाएँ — जो कोई शुरुआती लोगों को नहीं बताताK-Means 的局限 — 没人告诉初学者的事

🔴
Assumes Round Clustersगोल Clusters मानता है假设簇是圆形的
Hard geometric assumptionसख़्त geometric मान्यता强几何假设
K-Means draws Voronoi borders — straight lines halfway between centroids. It cannot find clusters shaped like rings, crescents or spirals. Each border is a straight line (a hyperplane in higher dimensions).
K-Means Voronoi सीमाएँ बनाता है — centroids के ठीक बीच में सीधी lines. यह rings, अर्धचंद्र या spirals जैसे clusters नहीं खोज सकता। हर सीमा एक सीधी line है (ज़्यादा dimensions में hyperplane)।
K-Means 画的是 Voronoi 边界 —— 质心之间正中的直线。它找不到圆环、月牙或螺旋形的簇。每条边界都是直线(高维中是超平面)。
Fix: DBSCAN, Spectral Clustering, GMMउपाय: DBSCAN, Spectral Clustering, GMM对策:DBSCAN、谱聚类、GMM
🔴
Sensitive to OutliersOutliers से प्रभावित对离群点敏感
The mean is not robustMean मज़बूत नहीं均值不稳健
The centroid is the mean of its cluster, so a few extreme points can pull it far from the real centre. A handful of luxury purchases can drag the "mid-tier customer" centroid a long way.
Centroid अपने cluster का mean है, इसलिए कुछ extreme points उसे असली केंद्र से दूर खींच सकते हैं। कुछ luxury ख़रीदारियाँ "mid-tier customer" centroid को काफ़ी दूर खींच सकती हैं।
质心是簇的均值,所以少数极端点就能把它拉离真正的中心。几笔奢侈品消费就能把“中端客户”质心拖出很远。
Fix: K-Medoids (PAM), remove or cap outliers firstउपाय: K-Medoids (PAM), पहले outliers हटाएँ या cap करें对策:K-Medoids(PAM),或先删除 / 截断离群点
🔴
You Must Choose KK आपको चुनना होगा必须事先指定 K
No automatic KK अपने-आप नहीं无法自动确定 K
The algorithm cannot discover K by itself, and it always returns K clusters — even when the data has no real groups. A poor K gives meaningless clusters. Always run elbow + silhouette analysis.
Algorithm खुद K नहीं खोज सकता, और हमेशा K clusters लौटाता है — तब भी जब data में असली groups न हों। ग़लत K से बेमतलब clusters मिलते हैं। हमेशा elbow + silhouette analysis चलाएँ।
算法自己无法发现 K,而且总会返回 K 个簇 —— 即使数据里根本没有真正的分组。K 选得不好,簇就毫无意义。务必做肘部法 + 轮廓系数分析。
Fix: DBSCAN (finds the count itself), hierarchical clusteringउपाय: DBSCAN (गिनती खुद खोजता है), hierarchical clustering对策:DBSCAN(自动确定簇数)、层次聚类
🔴
Prefers Clusters of Similar Spreadएक जैसे फैलाव वाले Clusters पसंद偏好分散程度相近的簇
Equal-variance assumptionEqual-variance मान्यता等方差假设
Every border sits halfway between two centroids, so K-Means implicitly assumes every cluster has a similar spread. A big, wide cluster next to a small, tight one gets cut in the wrong place (try "Very different sizes" in the Section 07 simulator).
हर सीमा दो centroids के ठीक बीच में होती है, इसलिए K-Means चुपचाप मानता है कि हर cluster का फैलाव एक जैसा है। छोटे कसे cluster के पास बड़ा फैला cluster ग़लत जगह से कटता है (Section 07 के simulator में "बहुत अलग आकार" आज़माएँ)।
每条边界都在两个质心的正中间,所以 K-Means 默认每个簇的分散程度相近。一个又大又散的簇挨着一个又小又紧的簇时,会在错误的位置被切开(试试第 07 节模拟器中的“大小差异很大”)。
Fix: Gaussian Mixture Models (GMM)उपाय: Gaussian Mixture Models (GMM)对策:高斯混合模型(GMM)
🔴
Curse of DimensionalityCurse of Dimensionality维度灾难
Distances become similarदूरियाँ एक जैसी हो जाती हैं距离变得差不多
With very many features (hundreds), Euclidean distances concentrate: every point looks almost equally far from every centroid. Clustering quality usually drops as the number of features grows, especially when many features are noise.
बहुत ज़्यादा features (सैकड़ों) होने पर Euclidean distances सिमट जाती हैं: हर point हर centroid से लगभग बराबर दूर लगता है। Features बढ़ने पर clustering की quality आमतौर पर गिरती है, ख़ासकर जब कई features noise हों।
特征非常多(几百个)时,欧氏距离会趋于集中:每个点看起来到每个质心都差不多远。随着特征增多,聚类质量通常会下降,尤其当许多特征只是噪声时。
Fix: PCA → K-Means; t-SNE / UMAP only for plotsउपाय: PCA → K-Means; t-SNE / UMAP सिर्फ़ plots के लिए对策:PCA → K-Means;t-SNE / UMAP 只用于可视化
🔴
Categorical DataCategorical Data类别型数据
A mean of categories is undefinedCategories का mean नहीं होता类别没有均值
You cannot compute the mean of "London / Paris / Tokyo". K-Means only works on numbers. One-hot columns can be used, but the means and distances become hard to interpret.
"London / Paris / Tokyo" का mean नहीं निकाला जा सकता। K-Means सिर्फ़ numbers पर काम करता है। One-hot columns इस्तेमाल हो सकते हैं, पर तब means और distances समझना मुश्किल हो जाता है।
你无法计算“伦敦 / 巴黎 / 东京”的均值。K-Means 只能处理数值。可以用 one-hot 编码,但均值和距离会变得难以解释。
Fix: K-Modes (categorical), K-Prototypes (mixed)उपाय: K-Modes (categorical), K-Prototypes (mixed)对策:K-Modes(类别型)、K-Prototypes(混合型)

SectionSection第 14 节

K-Means vs Other Clustering AlgorithmsK-Means vs दूसरे Clustering AlgorithmsK-Means 与其他聚类算法对比

Propertyगुण特性K-MeansDBSCANHierarchicalHierarchical层次聚类GMM
Needs K up frontपहले से K चाहिए需要事先指定 KYesहाँ是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相互重叠的分组
🏆
The Practitioner's RulePractitioner का नियम实践者法则

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 图上明显不是圆形的形状。


SectionSection第 15 节

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 则用小的随机样本(小批量)来更新质心。 每次更新都非常便宜,而且数据可以分块到达,所以即使数据装不进内存也能用。代价是:质心的精度略低一些。

LIVELIVE互动Race: Standard vs Mini-Batch K-Meansदौड़: Standard vs Mini-Batch K-Means比赛:标准 K-Means vs Mini-Batch

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.")
OUTPUT
Standard K-Means : 3.71s WCSS=89,693,124 Mini-Batch : 4.59s WCSS=92,698,660 partial_fit : 1.00s WCSS=92,698,502 Mini-Batch WCSS is 3.4% worse than standard K-Means.
⚖️
The Honest Resultईमानदार नतीजा真实的结论

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) 数据源源不断地到来(流式数据),这时你更新模型而不是重新训练。做选择之前,一定要在你自己的数据和硬件上给两者计时。


SectionSection第 16 节

Golden RulesGolden Rules黄金法则

🌲 K-Means — Non-Negotiable RulesK-Means — ज़रूरी नियमK-Means — 必须遵守的规则
1
Always scale your features first. K-Means uses Euclidean distance, so features on very different scales will control the distance and make the clusters meaningless. Apply StandardScaler before K-Means — unless all features are already in the same units (like pixel values). Take the log of skewed money columns first.
हमेशा पहले features scale करें। K-Means Euclidean distance इस्तेमाल करता है, इसलिए बहुत अलग scales वाले features distance पर कब्ज़ा कर लेंगे और clusters बेमतलब हो जाएँगे। K-Means से पहले StandardScaler लगाएँ — जब तक सभी features पहले से एक ही unit में न हों (जैसे pixel values)। टेढ़े पैसे वाले columns का पहले log लें।
永远先缩放特征。K-Means 使用欧氏距离,尺度差异很大的特征会主导距离,让聚类失去意义。运行 K-Means 前使用 StandardScaler —— 除非所有特征本来就是同一单位(比如像素值)。偏斜的金额列先取对数。
2
Never just guess K. Run the elbow method and silhouette analysis — they take minutes. When they disagree, the silhouette is the more objective tie-breaker. Then use domain knowledge to make the final call.
K का कभी सिर्फ़ अंदाज़ा न लगाएँ। Elbow method और silhouette analysis दोनों चलाएँ — इनमें कुछ minute लगते हैं। जब दोनों असहमत हों, silhouette ज़्यादा objective फ़ैसला देता है। फिर domain knowledge से आख़िरी फ़ैसला करें।
永远不要凭感觉选 K。同时做肘部法和轮廓系数分析 —— 只需几分钟。两者不一致时,轮廓系数是更客观的裁判。最后再结合领域知识做决定。
3
Use 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).
ज़रूरी models के लिए init='k-means++' (sklearn default) और n_init=10 इस्तेमाल करें। एक ही run के साथ init='random' से बचें — नतीजा क़िस्मत पर बहुत निर्भर करता है (Section 05 का simulator देखें)।
重要模型请使用 init='k-means++'(sklearn 默认值)和 n_init=10。避免只跑一次的 init='random' —— 结果太依赖运气(见第 05 节模拟器)。
4
Remove or cap extreme outliers before clustering. One customer with £10,000,000 of spend among customers spending £200–£2,000 can take over a whole centroid. Check with IQR or z-scores and handle outliers before fitting.
Clustering से पहले extreme outliers हटाएँ या cap करें। £200–£2,000 ख़र्च करने वालों के बीच £10,000,000 ख़र्च करने वाला एक customer पूरे centroid पर कब्ज़ा कर सकता है। Fit करने से पहले IQR या z-scores से जाँचें और outliers संभालें।
聚类前删除或截断极端离群点。在消费 £200–£2,000 的顾客中,一位消费 £10,000,000 的顾客就能独占一个质心。训练前用 IQR 或 z 分数检查并处理离群点。
5
Profile your clusters after fitting — do not just report labels. Compute the mean of each original (unscaled) feature per cluster, count the members, and give each cluster a business name. A cluster you cannot describe in plain words is not useful.
Fit के बाद clusters का profile बनाएँ — सिर्फ़ labels न बताएँ। हर cluster के लिए हर original (बिना scale) feature का mean निकालें, members गिनें, और हर cluster को business नाम दें। जिस cluster को आप आसान शब्दों में समझा न सकें, वह काम का नहीं।
训练后一定要给簇画像 —— 不要只报告标签。计算每个簇在各原始(未缩放)特征上的均值,统计成员数,并给每个簇起个业务名称。无法用大白话描述的簇没有用。
6
Consider 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).
जब data memory में न समाए या लगातार आता रहे, तब MiniBatchKMeans पर विचार करें। टुकड़ों पर partial_fit इस्तेमाल करें। जो data memory में समा जाए, उस पर पहले दोनों का समय मापें — standard K-Means अक्सर काफ़ी तेज़ होता है और कम WCSS देता है (Section 15)।
当数据装不进内存或持续到来时,考虑使用 MiniBatchKMeans。对数据块使用 partial_fit。对于内存装得下的数据,先给两种方法计时 —— 标准 K-Means 往往已经够快,而且 WCSS 更低(第 15 节)。
7
Set 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.
सभी experiments में random_state set करें। K-Means random शुरुआत करता है। तय seed के बिना हर run में नतीजे बदलते हैं, जिससे debugging, तुलना और reproducibility असंभव हो जाती है — ख़ासकर production pipelines में।
所有实验都要设置 random_state。K-Means 是随机初始化的。不固定随机种子,每次运行结果都不同,调试、比较和复现都无从谈起 —— 在生产流水线中尤其要命。