PythonPlaza - Python & AI

Hierarchical Clustering: (unsupervised learning algorithm)


Hierarchical clustering is an unsupervised machine learning technique that groups related data points without requiring labeled data. It builds a hierarchy (tree-like structure) of clusters based on similarity or distance. First, more similar data points are grouped together. Gradually, clusters are formed. The result is shown as a dendrogram, or tree diagram.

Types of Hierarchical Clustering

Agglomerative (Bottom-Up) – Most common
-Each data point starts as its own cluster
Closest clusters are merged step by step

Divisive (Top-Down)
All data points start in one cluster
Clusters are split recursively









Let’s compute the distances,

A to B = 1
A to C= 1.414
B to C= 1
D to E= 1.414
D to F= 2
E to F= 1.414


Step 2 — First Merge (Closest Points)

Merge A and B (distance = 1)
Cluster 1: {A, B}
Other clusters: {C}, {D}, {E}, {F}
Because A and B have the smallest distance

Step 3 — Second Merge

Now compare clusters to points
Hierarchical clustering usually does not assign new coordinates to merged clusters.
To compute distance between {A,B} and C
Compute the centroid of A,B.
A(1,1) ----●---- B(2,1)
↑ Centroid (1.5,1)

Now, distance between {A,B} and C is:
Distance between (1.5,1) and (2,2) = 1.11
(using single linkage = minimum distance)
Distance between {A,B} and C = 1
Distance between D and E = 1.41
Merge {A,B} and C

Cluster 1: {A, B, C}
Clusters left: {D}, {E}, {F}
Left-side points form a tight cluster

Step 4 — Third Merge
Right-side points:
D–E ≈ 1.41
E–F ≈ 1.41
Merge D and E
Cluster 2: {D, E}
Remaining: {F}

Step 5 — Fourth Merge
Merge {D,E} with F
Cluster 2: {D, E, F}
Final Step — Merge the Two Big Clusters
Now only two clusters remain:
Cluster 1: {A, B, C}
Cluster 2: {D, E, F}
Distance between them is large, so they merge last.




Machine Learning • Worked Example

Hierarchical Clustering

A complete step-by-step example using 10 customers, 4 independent variables, Euclidean distance, single linkage, and K = 3 clusters.

10 Customers4 VariablesEuclidean DistanceSingle LinkageK = 3
1

Customer Data

Variables: annual income, annual spending, number of visits, and age.

CustomerIncomeSpendingVisitsAge
C110203040
C211212941
C312193139
C450607080
C551597179
C649616981
C790100110120
C89199111119
C989101109121
C109298112118
2

Euclidean Distance

For customers i and j:

d(i,j) = √[(X₁ᵢ−X₁ⱼ)² + (X₂ᵢ−X₂ⱼ)² + (X₃ᵢ−X₃ⱼ)² + (X₄ᵢ−X₄ⱼ)²]

Example: C1 and C2

d(C1,C2) = √[(10−11)²+(20−21)²+(30−29)²+(40−41)²]
= √(1+1+1+1) = 2

Example: C1 and C3

d(C1,C3) = √[(10−12)²+(20−19)²+(30−31)²+(40−39)²]
= √(4+1+1+1) = √7 ≈ 2.646
3

Distance Matrix

C1C2C3C4C5C6C7C8C9C10
C102.0002.64680.00080.02580.025160.000160.012160.012160.050
C22.00003.60679.01979.07079.019159.009159.035159.009159.085
C32.6463.606079.54279.50579.630159.521159.502159.565159.509
C480.00079.01979.54202.0002.00080.00080.02580.02580.100
C580.02579.07079.5052.00004.00080.02580.00080.10080.025
C680.02579.01979.6302.0004.000080.02580.10080.00080.225
C7160.000159.009159.52180.00080.02580.02502.0002.0004.000
C8160.012159.035159.50280.02580.00080.1002.00004.0002.000
C9160.012159.009159.56580.02580.10080.0002.0004.00006.000
C10160.050159.085159.50980.10080.02580.2254.0002.0006.0000
4

Single-Linkage Rule

The distance between two clusters is the minimum distance between any pair of observations across those clusters.

D(A,B) = min { d(i,j) : i ∈ A, j ∈ B }
5

Agglomerative Merging

Merge 1C1 + C2 → {C1,C2}Distance = 2.000 • 9 clusters
Merge 2C4 + C5 → {C4,C5}Distance = 2.000 • 8 clusters
Merge 3C7 + C8 → {C7,C8}Distance = 2.000 • 7 clusters
Merge 4{C4,C5} + C6min(2,4) = 2.000 • 6 clusters
Merge 5{C7,C8} + C9min(2,4) = 2.000 • 5 clusters
Merge 6{C7,C8,C9} + C10min(4,2,6) = 2.000 • 4 clusters
Merge 7 • K = 3{C1,C2} + C3min(2.646,3.606) = 2.646 • 3 clusters
Why stop? The hierarchy goes 10 → 9 → … → 4 → 3 → 2 → 1. We stop when exactly three clusters remain.
6

Final K = 3 Clusters

Cluster 1

Lower-value group

C1, C2, C3

Cluster 2

Middle-value group

C4, C5, C6

Cluster 3

Higher-value group

C7, C8, C9, C10
CustomerCluster
C11
C21
C31
C42
C52
C62
C73
C83
C93
C103
7

Dendrogram Concept

The branch height represents the distance at which clusters are merged.

Distance
  |
80+                         ┌──────── Cluster 1
  |                    ┌────┤
  |                    │    └────────
  |                    │
  |                    │       ┌──── Cluster 2
  |                    └───────┤
  |                            └────
  |
  |                              ┌── C7
  |                         ┌────┤
  |                         │    └── C8
  |                    ┌────┤
  |                    │    └──── C9
  |               ┌────┤
  |               │    └──── C10
  |
  |---- 2.646 ---- C1,C2,C3
  |---- 2.000 ---- C1,C2
  |---- 2.000 ---- C4,C5,C6
  |---- 2.000 ---- C7,C8,C9,C10
  +----------------------------------------
Key observation: there is a large jump from about 2.646 to about 79.019, supporting the three-cluster solution in this illustrative dataset.
8

Final Summary

Method: Hierarchical Agglomerative Clustering

Distance: Euclidean

Linkage: Single linkage

Observations: 10 customers

Variables: 4 independent variables

K: 3


Cluster 1: C1, C2, C3

Cluster 2: C4, C5, C6

Cluster 3: C7, C8, C9, C10

Note: For real data, standardization is usually appropriate when variables have substantially different scales. Different linkage methods can also produce different cluster structures.

USE CASE 1: Use Hierarchical Clustering for customer segmentation in Market Basket Analysis. Instead of finding which products are purchased together (like Apriori or FP-Growth), use Hierarchical Clustering to group customers based on their purchasing behavior. Once customers are clustered, you can create targeted promotions and personalized recommendations for each segment.


import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt


# ----------------------------------
# Step 1: Sample Market Basket Data
# ----------------------------------

data = pd.DataFrame({
    'Customer': ['C001','C002','C003','C004','C005','C006','C007','C008'],
    'Bread': [12,10,11,1,0,2,6,5],
    'Milk': [10,8,9,2,1,1,5,6],
    'Eggs': [8,7,6,1,2,0,4,5],
    'Beer': [0,1,0,10,12,9,4,5],
    'Chips': [1,0,1,8,10,7,3,4]
})


#Load data
#You can also download from
#https://www.pythonplaza.com/sample_customer_shopping.html
data= pd.read_csv("customer_shopping.csv")

print("Original Data")
print(data)



# ----------------------------------
# Step 2: Select Features
# ----------------------------------

X = data[['Bread', 'Milk', 'Eggs', 'Beer', 'Chips']]


# ----------------------------------
# Step 3: Scale Features
# ----------------------------------

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)


# ----------------------------------
# Step 4: Dendrogram (optional but recommended)
# ----------------------------------


plt.figure(figsize=(8,5))
linked = linkage(X_scaled, method='ward')

dendrogram(linked,
           labels=data['Customer'].values)

plt.title("Dendrogram (Hierarchical Clustering)")
plt.xlabel("Customers")
plt.ylabel("Distance")
plt.show()


# ----------------------------------
# Step 5: Train Hierarchical Clustering Model
# ----------------------------------

hc = AgglomerativeClustering(
    n_clusters=3,
    linkage='ward'
)

data['Cluster'] = hc.fit_predict(X_scaled)

print("\nCluster Assignments")
print(data[['Customer', 'Cluster']])


# ----------------------------------
# Step 6: Cluster Profiles (mean of original data)
# ----------------------------------

print("\nCluster Profiles (Original Scale Means)")

cluster_profiles = data.groupby('Cluster')[['Bread','Milk','Eggs','Beer','Chips']].mean()

print(cluster_profiles.round(2))


# ----------------------------------
# Step 7: Test New Customer
# ----------------------------------

new_customer = pd.DataFrame({
    'Bread': [11],
    'Milk': [9],
    'Eggs': [7],
    'Beer': [1],
    'Chips': [1]
})

new_customer_scaled = scaler.transform(new_customer)

# NOTE: AgglomerativeClustering has no direct predict()
# So we assign manually using nearest cluster centroid

centroids = data.groupby('Cluster')[['Bread','Milk','Eggs','Beer','Chips']].mean()
centroids_scaled = scaler.transform(centroids)

import numpy as np

distances = np.linalg.norm(centroids_scaled - new_customer_scaled, axis=1)
predicted_cluster = np.argmin(distances)

print("\nNew Customer")
print(new_customer)
print(f"\nPredicted Cluster: {predicted_cluster}")


# ----------------------------------
# Step 8: Recommendation Logic
# ----------------------------------


if predicted_cluster == 0:
    print("Recommendation: Bread, Milk, Eggs promotions")
elif predicted_cluster == 1:
    print("Recommendation: Beer and Chips promotions")
else:
    print("Recommendation: Mixed basket offers")


USE CASE 2: Healthcare Patient Grouping using Hierarchical Clustering: Hospitals often need to group patients with similar characteristics to: Identify high-risk patients, Personalize treatment plans, Optimize resource allocation, Improve healthcare management



import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import AgglomerativeClustering
import numpy as np


# Load data
# download from:
# https://www.pythonplaza.com/healthcare_patient_dataset.html


df = pd.read_csv("patients_data.csv")

# Features used for clustering


X = df[['Age',
        'BMI',
        'Blood_Pressure',
        'Cholesterol',
        'Hospital_Visits']]


# Scale data


scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)


# Train Hierarchical Clustering model


hc = AgglomerativeClustering(n_clusters=3, linkage='ward')
df['Cluster'] = hc.fit_predict(X_scaled)


# New patient

new_patient = [[33, 28.0, 139, 210, 4]]

# Apply SAME scaling
new_patient_scaled = scaler.transform(new_patient)

# ---------------------------------------
# NOTE:
# Hierarchical clustering has NO .predict()
# So we assign cluster by nearest centroid
# ---------------------------------------


# Compute cluster centroids (in original scale)


centroids = df.groupby('Cluster')[['Age','BMI','Blood_Pressure','Cholesterol','Hospital_Visits']].mean()


# Scale centroids using same scaler

centroids_scaled = scaler.transform(centroids)

# Find nearest cluster


distances = np.linalg.norm(centroids_scaled - new_patient_scaled, axis=1)
cluster = np.argmin(distances)

print("Patient belongs to Cluster:", cluster)




About Us  | Contact Us | Sitemap  | Privacy Policy