Clustering groups similar observations together without being told what the groups are. K-means is the most widely used clustering algorithm: you choose the number of clusters, k, and it places k centres so that each observation belongs to its nearest centre and the points in each cluster are as close to their centre as possible.
from sklearn.cluster import KMeans
X = [[1, 2], [2, 1], [9, 10], [10, 9]] # visits per week, hours per visit
model = KMeans(n_clusters=2, n_init=10, random_state=0).fit(X)
print(model.labels_) # cluster number for each memberThis lesson explains when clustering is the right tool, how k-means works, why feature scaling and the choice of k change the result, and how to judge whether clusters mean anything. The examples segment members of a community gym by how they use it. It's part of the ML track that begins with introduction to machine learning.
Unsupervised grouping
Clustering is unsupervised: there's no target column and no right answer to check against. You use it to explore structure, such as "are there distinct patterns in how members use the gym?", or to create segments for planning, such as timetables or targeted communications.
What counts as "similar" is entirely defined by the features you choose. Cluster members on visits per week and session length and you get usage patterns; add age and you get something different. Decide on features from the question you're asking, and exclude anything irrelevant or sensitive.
The algorithm returns cluster numbers, 0, 1, 2..., which carry no meaning by themselves. Cluster 0 isn't "the best" or "the first"; rerunning with different settings can swap the numbers. Meaning comes from describing each cluster afterwards, for example "frequent short visits" versus "occasional long sessions".
K-means objective
K-means alternates two steps until the assignments stop changing:
- Assign each point to its nearest centre.
- Update each centre to the mean of the points assigned to it.
It aims to minimise inertia: the sum of squared distances from each point to its centre. Because the starting centres are chosen randomly, different starts can end in different solutions; n_init=10 runs ten starts and keeps the best, and random_state makes the result repeatable.
model = KMeans(n_clusters=3, n_init=10, random_state=0).fit(X)
print(model.cluster_centers_) # one centre per cluster
print(model.inertia_) # total within-cluster squared distance
print(model.predict([[4, 1.5]])) # assign a new member to the nearest centreK-means works best when clusters are roughly round and of similar size. It struggles with elongated, nested or very unequal clusters, and every point is forced into some cluster, outliers included. Algorithms such as DBSCAN (density-based) and Gaussian mixtures handle other shapes when k-means doesn't fit.
Scaling and choices
Three choices change k-means results:
- Feature scale: k-means uses Euclidean distance, so a feature measured in minutes (0 to 120) outweighs one counted in visits (0 to 7). Standardise features first, inside a pipeline.
- The number of clusters, k: you must choose it.
- Initialisation: use
n_initgreater than 1 and fixrandom_state.
To compare values of k, look at two measures:
from sklearn.metrics import silhouette_score
for k in [2, 3, 4]:
km = KMeans(n_clusters=k, n_init=10, random_state=0).fit(X_scaled)
print(k, round(km.inertia_, 1), round(silhouette_score(X_scaled, km.labels_), 2))Inertia always falls as k grows, since more centres sit closer to the points, so look for an "elbow" where improvement levels off. The silhouette score (from −1 to 1) measures how much closer points are to their own cluster than to the next one; higher is better. Neither number alone decides k: a slightly lower-scoring solution that people can act on can be the more useful one.
Evaluation and meaning
Without labels, judge clusters by:
- Separation: silhouette score and how distinct the centres are.
- Stability: do similar clusters appear with different random starts or on a different sample of members?
- Interpretability: can you describe each cluster in plain language, in original units?
import pandas as pd
summary = members.assign(cluster=labels).groupby("cluster")[["visits", "minutes"]].mean()Describing clusters by their average visits and minutes, not by scaled values, makes them understandable to the people who will use them.
Treat clusters as descriptions of patterns in data, not as judgements about people. "Members in cluster 2 rarely visit" may reflect shift work or childcare, not lack of motivation. Using clusters to deny services or make assumptions about individuals is a misuse; use them to ask better questions and to design offers people can choose.
Independent practice and a worked check
Task: explore gym visit clusters with scaled features, several cluster counts and a careful interpretation of their limits.
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
members = [[1, 90], [1, 80], [2, 85], [5, 30], [6, 35], [5, 25],
[3, 60], [4, 55], [3, 65], [6, 30], [1, 95], [4, 60]]
for seed in [0, 1, 2]:
pipe = make_pipeline(StandardScaler(), KMeans(n_clusters=3, n_init=10, random_state=seed))
labels = pipe.fit_predict(members)
X = pipe[0].transform(members)
print(f"seed {seed}: sizes {sorted([list(labels).count(c) for c in set(labels)])}, "
f"silhouette {silhouette_score(X, labels):.2f}")If cluster sizes and silhouette scores agree across seeds, the grouping is stable. Write one sentence per cluster in original units and one sentence on limits, such as "based on 12 members over one month". For the worked check: do k-means cluster labels have inherent category meanings? No. Meaning comes from describing the clusters afterwards.
Reference and next practice
scikit-learn's clustering guide compares k-means with other algorithms, and silhouette analysis shows how to choose k. Continue with the Python examples library and practice problems. Practise with the Python exercises and Python quiz.
Clustering and K-Means Summary
- Unsupervised grouping: Clustering groups observations by selected feature relationships without known target labels.
- K-means objective: K-means assigns observations to centers and seeks small within cluster squared distances.
- Scaling and choices: Feature scale, cluster count and initialization affect the result.
- Evaluation and meaning: Use stability, separation and domain interpretation to assess useful grouping.
Clustering and K-Means Examples
Each example shows the code, the output it produces and what each part does.
Clustering and K-Means in a small program
from sklearn.cluster import KMeans
X = [[1, 2], [2, 1], [9, 10], [10, 9]]
model = KMeans(n_clusters=2, random_state=3, n_init=10).fit(X)
centers = sorted([tuple(round(float(v), 1) for v in center) for center in model.cluster_centers_])
print(centers)[(1.5, 1.5), (9.5, 9.5)]Line-by-line explanation
- Line 2Four members: two low-usage and two high-usage.
- Line 3K-means with two clusters, ten random starts and a fixed seed.
- Lines 4 to 5Sorting the rounded centres gives a stable display: each centre is the mean of its two members.
Scaling, choosing k and describing clusters
- k = 3 shows the inertia elbow (6.3 to 1.2, then only 0.9) and the highest silhouette score, matching three clear patterns: occasional long sessions, regular hour-long visits and frequent short visits.
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.preprocessing import StandardScaler
# visits per week, minutes per visit
members = [[1, 90], [1, 80], [2, 85], [5, 30], [6, 35], [5, 25],
[3, 60], [4, 55], [3, 65], [6, 30], [1, 95], [4, 60]]
X = StandardScaler().fit_transform(members)
for k in [2, 3, 4]:
km = KMeans(n_clusters=k, n_init=10, random_state=0).fit(X)
print(f"k={k} inertia {km.inertia_:5.1f} silhouette {silhouette_score(X, km.labels_):.2f}")
km = KMeans(n_clusters=3, n_init=10, random_state=0).fit(X)
for cluster in sorted(set(km.labels_)):
rows = [m for m, label in zip(members, km.labels_) if label == cluster]
visits = sum(r[0] for r in rows) / len(rows)
minutes = sum(r[1] for r in rows) / len(rows)
print(f"{len(rows)} members: {visits:.1f} visits/week, {minutes:.0f} min/visit")k=2 inertia 6.3 silhouette 0.53
k=3 inertia 1.2 silhouette 0.69
k=4 inertia 0.9 silhouette 0.67
4 members: 3.5 visits/week, 60 min/visit
4 members: 5.5 visits/week, 30 min/visit
4 members: 1.2 visits/week, 88 min/visitLine-by-line explanation
- Line 8Standardising stops minutes, with their larger numbers, from dominating the distance.
- Lines 10 to 12Inertia falls as k grows; the silhouette score helps judge whether extra clusters are genuinely distinct.
- Lines 15 to 19Each cluster is described by its average in original units, which is what makes it interpretable.
Common Clustering and K-Means Mistakes
Clustering unscaled features
KMeans(n_clusters=3).fit(members) # minutes (25-95) swamp visits (1-6)from sklearn.pipeline import make_pipeline
make_pipeline(StandardScaler(), KMeans(n_clusters=3, n_init=10, random_state=0)).fit(members)Treating cluster numbers as meaningful labels
print("Cluster 0 are our best members") # numbers are arbitrary and can swapfor c in sorted(set(labels)):
print(c, summary.loc[c].round(1).to_dict()) # describe, then nameClustering and K-Means in Real Projects
Clustering in practice
Retailers segment customers by purchase patterns to plan stock and promotions, city planners group neighbourhoods by transport use, and scientists cluster gene-expression profiles or galaxy measurements. Clustering also compresses data, for example reducing an image to k colours, and helps find anomalies, which sit far from every centre.
Good practice is consistent across fields: choose features from the question, scale them, compare several k values and random starts, describe clusters in original units, check stability, and present results as patterns to investigate rather than fixed categories.
Clustering and K-Means FAQ
How do I choose the number of clusters in k-means?
Fit several values of k and compare inertia (look for an elbow where improvement flattens) and silhouette scores (higher is better), then check which solution gives clusters you can describe and use. There's rarely one mathematically correct k.
Do I need to scale data before k-means?
Usually, yes. K-means uses distances, so features with larger numeric ranges dominate. Standardise features unless they already share the same units and scale.
Why does k-means give different results each run?
Its starting centres are random, and different starts can converge to different solutions. Set n_init to run several starts and keep the best, and fix random_state for reproducible results.
What is the difference between clustering and classification?
Classification is supervised: it learns from examples with known labels to predict labels for new data. Clustering is unsupervised: it finds groups in unlabelled data, and people decide what those groups mean.
When should I not use k-means?
When clusters are elongated, nested or very different in size or density, when there are many outliers, or when features are categorical. Consider DBSCAN, Gaussian mixture models or hierarchical clustering instead.
Clustering and K-Means Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Do K-means cluster labels have inherent category meanings?
Which review concern is valid for clustering and k-means?
Clustering and K-Means Quiz
2 questions to check what you learned.
Do K-means cluster labels have inherent category meanings?
- Yes
- No
- Python ignores the distinction
Which statement correctly describes scaling and choices?
- Feature scale, cluster count and initialization affect the result.
- Only the example output matters, not the rule
- Every operation has the same behavior