Chapter 4 · Section 4 practice
Choosing K and Checking the Result
Work from question 1 to 10. Edit your Python box, click Run Code, review the result, then click Submit attempt. Reference answers unlock after all ten attempts are submitted. This records completion, not correctness. Each box runs independently. Progress is saved in this browser.
1. Read feature shape
Warm-up. Print X.shape.
Write your answer, then run it.
2. Fit a candidate K
Warm-up. Fit K=3 and print inertia.
Write your answer, then run it.
3. Count a candidate’s groups
Warm-up. Fit K=3 and print membership counts.
Write your answer, then run it.
4. Compare WCSS at two K values
Build your skills. Print WCSS for K=3 and K=5.
Write your answer, then run it.
5. Create elbow values
Build your skills. Print WCSS for K=1,2,3,4.
Write your answer, then run it.
6. Calculate a silhouette
Build your skills. Fit K=5 and print the mean silhouette score.
Write your answer, then run it.
7. Compare seeds
Build your skills. Print K=5 inertia with seeds 42 and 7.
Write your answer, then run it.
8. Inspect a small group
Challenge. Fit K=6 and print the smallest cluster size.
Write your answer, then run it.
9. Compare scaling choices
Challenge. Print K=5 inertia on raw and standardised features, then explain why the two numbers cannot rank scaling choices.
Write your answer, then run it.
10. Avoid a trivial K decision
Challenge. Fit K=1 and K equal to the number of distinct feature rows; print their WCSS. Explain why minimum WCSS alone is insufficient.
Write your answer, then run it.
Reference answers are locked until all 10 attempts are submitted.
1. Read feature shape
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
mall = pd.read_csv(
"https://busanalytics-book.pages.dev/data/chapter4-mall-classroom.csv",
index_col="CustomerID")
features = ["Annual_Income", "Spending_Score"]
scaler = StandardScaler()
X = scaler.fit_transform(mall[features])
print(X.shape)Expected output
(200, 2)Two selected features define the standardised clustering space.
2. Fit a candidate K
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
mall = pd.read_csv(
"https://busanalytics-book.pages.dev/data/chapter4-mall-classroom.csv",
index_col="CustomerID")
features = ["Annual_Income", "Spending_Score"]
scaler = StandardScaler()
X = scaler.fit_transform(mall[features])
km = KMeans(n_clusters=3, random_state=42, n_init=10).fit(X)
print(round(km.inertia_, 3))Expected output
143.145WCSS describes this fitted solution and feature space.
3. Count a candidate's groups
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
mall = pd.read_csv(
"https://busanalytics-book.pages.dev/data/chapter4-mall-classroom.csv",
index_col="CustomerID")
features = ["Annual_Income", "Spending_Score"]
scaler = StandardScaler()
X = scaler.fit_transform(mall[features])
labels = KMeans(n_clusters=3, random_state=42, n_init=10).fit_predict(X)
print(pd.Series(labels).value_counts().sort_index())Expected output
0 51
1 42
2 107
Name: count, dtype: int64Inspect whether every proposed group is operationally meaningful.
4. Compare WCSS at two K values
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
mall = pd.read_csv(
"https://busanalytics-book.pages.dev/data/chapter4-mall-classroom.csv",
index_col="CustomerID")
features = ["Annual_Income", "Spending_Score"]
scaler = StandardScaler()
X = scaler.fit_transform(mall[features])
a = KMeans(n_clusters=3, random_state=42, n_init=10).fit(X)
b = KMeans(n_clusters=5, random_state=42, n_init=10).fit(X)
print(round(a.inertia_, 3), round(b.inertia_, 3))Expected output
143.145 37.976Lower WCSS with more groups does not by itself choose the business solution.
5. Create elbow values
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
mall = pd.read_csv(
"https://busanalytics-book.pages.dev/data/chapter4-mall-classroom.csv",
index_col="CustomerID")
features = ["Annual_Income", "Spending_Score"]
scaler = StandardScaler()
X = scaler.fit_transform(mall[features])
values = [
KMeans(n_clusters=k, random_state=42, n_init=10).fit(X).inertia_
for k in range(1, 5)
]
print([round(v, 2) for v in values])Expected output
[400.0, 237.0, 143.15, 74.92]The comprehension repeats fits across candidate K values.
6. Calculate a silhouette
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
mall = pd.read_csv(
"https://busanalytics-book.pages.dev/data/chapter4-mall-classroom.csv",
index_col="CustomerID")
features = ["Annual_Income", "Spending_Score"]
scaler = StandardScaler()
X = scaler.fit_transform(mall[features])
from sklearn.metrics import silhouette_score
labels = KMeans(n_clusters=5, random_state=42, n_init=10).fit_predict(X)
print(round(silhouette_score(X, labels), 3))Expected output
0.611This measures separation in the same standardised feature space.
7. Compare seeds
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
mall = pd.read_csv(
"https://busanalytics-book.pages.dev/data/chapter4-mall-classroom.csv",
index_col="CustomerID")
features = ["Annual_Income", "Spending_Score"]
scaler = StandardScaler()
X = scaler.fit_transform(mall[features])
a = KMeans(n_clusters=5, random_state=42, n_init=10).fit(X)
b = KMeans(n_clusters=5, random_state=7, n_init=10).fit(X)
print(round(a.inertia_, 3), round(b.inertia_, 3))Expected output
37.976 37.976Similar objectives do not guarantee identical numeric label IDs.
8. Inspect a small group
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
mall = pd.read_csv(
"https://busanalytics-book.pages.dev/data/chapter4-mall-classroom.csv",
index_col="CustomerID")
features = ["Annual_Income", "Spending_Score"]
scaler = StandardScaler()
X = scaler.fit_transform(mall[features])
labels = KMeans(n_clusters=6, random_state=42, n_init=10).fit_predict(X)
print(int(pd.Series(labels).value_counts().min()))Expected output
17A small group may be meaningful, unstable, or outlier-driven; investigate.
9. Compare scaling choices
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
mall = pd.read_csv(
"https://busanalytics-book.pages.dev/data/chapter4-mall-classroom.csv",
index_col="CustomerID")
features = ["Annual_Income", "Spending_Score"]
scaler = StandardScaler()
X = scaler.fit_transform(mall[features])
raw = KMeans(n_clusters=5, random_state=42, n_init=10).fit(mall[features])
scaled = KMeans(n_clusters=5, random_state=42, n_init=10).fit(X)
print(round(raw.inertia_, 3), round(scaled.inertia_, 3))
print("The objectives use different units and feature weights.")Expected output
28311.014 37.976
The objectives use different units and feature weights.A smaller rescaled objective is not proof of a better segmentation.
10. Avoid a trivial K decision
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
mall = pd.read_csv(
"https://busanalytics-book.pages.dev/data/chapter4-mall-classroom.csv",
index_col="CustomerID")
features = ["Annual_Income", "Spending_Score"]
scaler = StandardScaler()
X = scaler.fit_transform(mall[features])
one = KMeans(n_clusters=1, random_state=42, n_init=10).fit(X)
distinct = len(np.unique(X, axis=0))
all_rows = KMeans(n_clusters=distinct, random_state=42, n_init=1).fit(X)
print(round(one.inertia_, 3), round(all_rows.inertia_, 3))
print(
"One group per distinct record can make WCSS zero without creating a useful segmentation."
)Expected output
400.0 0.0
One group per distinct record can make WCSS zero without creating a useful segmentation.The objective alone favours excessive subdivision; business usefulness must enter the decision.