Week 09 · Session 1

Clustering & Segmentation

Finding Hidden Groups in Unlabeled Data

Department of Computer Science

University of the Philippines Cebu

Lecture 17: K-Means & Hierarchical

The Power of Grouping

"The goal is to turn data into information, and information into insight."

— Carly Fiorina

Agenda

Lecture 17 Objectives

Supervised vs Unsupervised

Distinguish labeled from unlabeled learning paradigms.

K-Means

Apply the K-Means algorithm and choose optimal K.

Hierarchical

Build dendrograms and compare linkage methods.

Interpretation

Profile clusters and translate them into business actions.

Foundations

Two Paradigms of Machine Learning

In Weeks 7-8 we built supervised models (regression, trees) that learn from labeled outcomes. This week we remove the labels entirely.

Supervised Unsupervised
Labels Has target variable (y) No labels at all
Goal Predict an outcome Discover hidden structure
Methods Regression, Classification Clustering, Dim. Reduction
Question "What will happen?" "What patterns exist?"
Evaluation Accuracy, RMSE, AUC Silhouette, Inertia
Motivation

Why Clustering Matters in Industry

Clustering is the most widely deployed unsupervised learning technique. Every major tech company uses it daily.

Core Algorithm

K-Means Clustering

Partition n observations into K clusters by minimizing within-cluster variance.

Algorithm Steps

  1. Initialize K centroids randomly
  2. Assign each point to the nearest centroid
  3. Update centroids as cluster means
  4. Repeat steps 2-3 until convergence

Objective Function

Minimize Within-Cluster Sum of Squares (WCSS):
J = Σk Σi ∈ Ck ||xi − μk||²

+ + + Cluster 1 Cluster 2 Cluster 3 K-Means with K=3 + = Centroid
Critical Step

Always Scale Your Features First

K-Means uses Euclidean distance. Features with larger scales will dominate the distance calculation and distort the clusters.

Implementation

K-Means in Python

Key Parameters

  • n_clusters — number of clusters (K)
  • n_init — number of random initializations (default 10)
  • random_state — seed for reproducibility
TL;DR

Scale → Fit → Predict → Add labels to DataFrame

python
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
import pandas as pd

# 1. Prepare features
features = ['income', 'age', 'spending_score']
X = df[features]

# 2. Always scale first!
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 3. Fit K-Means
kmeans = KMeans(
    n_clusters=4,
    random_state=42,
    n_init=10
)
clusters = kmeans.fit_predict(X_scaled)

# 4. Add to dataframe
df['cluster'] = clusters
print(df['cluster'].value_counts())
Model Selection

Choosing K: Elbow Method

Plot inertia (WCSS) vs. K. The elbow is where adding clusters stops giving meaningful improvement.

How to Find the Elbow

  1. Compute inertia for K = 1 to 10+
  2. Find the sharpest bend — where the slope changes from steep to flat
  3. Validate with silhouette — elbow alone isn’t always conclusive

The elbow is subjective. Two analysts may disagree on the exact K. Always cross-check with silhouette score or domain knowledge.

python — elbow plot
inertias = [KMeans(k).fit(X_scaled).inertia_
            for k in range(1, 11)]
plt.plot(range(1, 11), inertias, 'bo-')
Elbow (K=3) Diminishing returns Number of Clusters (K) Inertia 1 3 5 7 10

Rule of thumb: Pick K at the elbow — adding more clusters gives diminishing returns.

Model Selection

Not Every Elbow is Obvious

In practice, the elbow can be sharp, gradual, or completely absent. Here’s how to handle each case.

✔ Clear Elbow

K=3 1 3 5 7

Pick K=3

Sharp bend — easy choice

⚠ Gradual Elbow

K=3–5? 1 3 5 7

K=3–5 all reasonable

Use silhouette to break the tie

❌ No Elbow

Nearly linear 1 3 5 7

No natural clusters?

Consider if clustering is appropriate

💡

Pro tip: When the elbow is ambiguous, run silhouette analysis for K=2 through 8 and pick the K with the highest average score. You can also try the Gap Statistic for a more rigorous approach.

Worked Example

GCash Customer Segmentation

GCash wants to segment 94M users by transaction frequency, average amount, and account age. How many segments?

Decision Process

  1. Scale features (StandardScaler)
  2. Run K-Means for K=2 to 8
  3. Elbow plot shows bend at K=4
  4. Silhouette confirms: K=4 → 0.58 (vs 0.51 for K=3, 0.49 for K=5)
  5. Decision: 4 segments
Elbow (K=4) Number of Clusters (K) Inertia (×10³) 2 3 4 5 6 7 8

Resulting Segments

# Profile Size
1Power Users (daily, high ₱)12%
2Regular (weekly, moderate ₱)38%
3Occasional (monthly, low ₱)35%
4Dormant (rare, very low ₱)15%
Model Selection

Choosing K: Silhouette Score

Measures how similar a point is to its own cluster vs. the nearest other cluster.

s(i) = (b(i) − a(i)) / max(a(i), b(i))

  • a(i) — mean intra-cluster distance
  • b(i) — mean nearest-cluster distance
  • Range: −1 to +1 (higher = better)
python
from sklearn.metrics import silhouette_score

scores = []
for k in range(2, 11):
    km = KMeans(n_clusters=k, random_state=42)
    labels = km.fit_predict(X_scaled)
    score = silhouette_score(X_scaled, labels)
    scores.append(score)
    print(f"K={k}: Silhouette = {score:.3f}")

# Pick K with highest silhouette score
best_k = range(2, 11)[scores.index(max(scores))]
print(f"\nBest K = {best_k}")

# Interpretation guide:
# > 0.7  Strong structure
# 0.5-0.7  Reasonable structure
# 0.25-0.5 Weak, may be artificial
# < 0.25  No substantial structure
Validation

Beyond Silhouette: More Cluster Validation Metrics

Silhouette Score is not the only option. Use multiple metrics together for a more robust evaluation of clustering quality.

Davies-Bouldin Index

Ratio of within-cluster scatter to between-cluster separation. Lower = better (0 is perfect).

  • Does not require distance matrix (fast)
  • Penalizes clusters with similar centroids
  • Sensitive to outliers

Calinski-Harabasz Index

Ratio of between-cluster variance to within-cluster variance. Higher = better (no upper bound).

  • Also called Variance Ratio Criterion
  • Very fast to compute
  • Favors convex, dense clusters
python — compare all three metrics
from sklearn.metrics import (silhouette_score,
    davies_bouldin_score, calinski_harabasz_score)

for k in range(2, 8):
    km = KMeans(n_clusters=k, random_state=42)
    labels = km.fit_predict(X_scaled)
    print(f"K={k}:  Silhouette={silhouette_score(X_scaled, labels):.3f}"
          f"  DB={davies_bouldin_score(X_scaled, labels):.3f}"
          f"  CH={calinski_harabasz_score(X_scaled, labels):.0f}")
Analysis

Profiling Your Clusters

Clusters are only useful when you can interpret and name them. Compute summary statistics per cluster.

Key Insight

Always ask: "How would I describe this group to a non-technical stakeholder?" If you can't name it, the clustering may not be meaningful.

python
# Cluster profiles
profile = df.groupby('cluster').agg({
    'income': 'mean',
    'age': 'mean',
    'spending_score': 'mean',
    'customer_id': 'count'
}).round(1)

profile.columns = [
    'Avg Income', 'Avg Age',
    'Avg Spending', 'Count'
]
print(profile)

# Name clusters based on patterns
cluster_names = {
    0: 'High-Value Loyalists',
    1: 'Budget-Conscious Shoppers',
    2: 'Young Big Spenders',
    3: 'Inactive Customers'
}
df['segment'] = df['cluster'].map(
    cluster_names
)
Visualization

2D Cluster Visualization with PCA

When features exceed 2 dimensions, use PCA (Principal Component Analysis) to project clusters onto a 2D plane for plotting.

Why PCA?

  • Reduces high-dimensional data to 2 components
  • Preserves maximum variance
  • Shows cluster separation visually
  • Explained variance ratio tells how much info is retained
python
from sklearn.decomposition import PCA

# Reduce to 2D
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)

# Plot
plt.figure(figsize=(10, 7))
scatter = plt.scatter(
    X_pca[:, 0], X_pca[:, 1],
    c=df['cluster'], cmap='viridis',
    alpha=0.6, s=50
)

# Plot centroids
centers_pca = pca.transform(
    kmeans.cluster_centers_
)
plt.scatter(
    centers_pca[:, 0], centers_pca[:, 1],
    marker='X', s=200, c='red',
    edgecolors='black', linewidths=1.5,
    label='Centroids'
)
plt.xlabel(f'PC1 ({pca.explained_variance_ratio_[0]:.1%})')
plt.ylabel(f'PC2 ({pca.explained_variance_ratio_[1]:.1%})')
plt.legend()
Limitations

When K-Means Fails

K-Means is fast and intuitive but makes strong assumptions that don't always hold.

Spherical Only

Assumes circular/spherical clusters. Fails on elongated or irregular shapes.

Random Init

Mitigated by k-means++ (sklearn default) and n_init=10, but still possible.

Must Specify K

You must choose K before fitting. No automatic detection.

Outlier Sensitive

Outliers pull centroids, distorting cluster boundaries.

Equal Variance

Assumes clusters have similar size and density.

Alternative Algorithm

Hierarchical Clustering

Builds a tree of clusters without needing to specify K upfront. Agglomerative (bottom-up) is the most common approach.

Agglomerative Steps

  1. Start with each point as its own cluster
  2. Find the two closest clusters
  3. Merge them into one
  4. Repeat until only one cluster remains
Advantage

The dendrogram lets you visually choose K after fitting by cutting at a chosen height.

Dendrogram (cut at height = 4 → K=3)

A B C D E F Cut here 0 2 3 7 Height Cluster 1 Cluster 2 Cluster 3
Hierarchical Clustering

Linkage Methods: How to Measure Cluster Distance

The linkage criterion determines how the "distance" between two clusters is computed during merging.

Method Distance Computed As Best For Sensitivity
Single Minimum distance between any two points Chain-like / elongated clusters Very sensitive to noise
Complete Maximum distance between any two points Compact, spherical clusters Moderate
Average Mean pairwise distance between all points Balanced general-purpose Moderate
Ward Minimizes total within-cluster variance Similar-size clusters (most popular) Low (most robust)
Implementation

Hierarchical Clustering in Python

Two Libraries

  • sklearn — AgglomerativeClustering for predictions
  • scipy — linkage + dendrogram for visualization
Tip

Use truncate_mode='level' to show only the top merges when you have many samples.

python
from sklearn.cluster import (
    AgglomerativeClustering
)
from scipy.cluster.hierarchy import (
    dendrogram, linkage
)

# 1. Dendrogram (visual exploration)
Z = linkage(X_scaled, method='ward')

plt.figure(figsize=(12, 6))
dendrogram(Z, truncate_mode='level', p=5)
plt.xlabel('Sample Index')
plt.ylabel('Distance')
plt.title('Ward Linkage Dendrogram')

# 2. Fit with chosen K
hc = AgglomerativeClustering(
    n_clusters=4,
    linkage='ward'
)
df['hc_cluster'] = hc.fit_predict(X_scaled)
Philippine Case Study

GCash Customer Segmentation

With 94+ million users, GCash uses clustering to segment customers by transaction behavior and tailor financial products.

RFM Features

  • Recency — days since last transaction
  • Frequency — number of transactions
  • Monetary — total amount transacted
python — GCash-style segmentation
# Build RFM features from transactions
from datetime import datetime
today = datetime.now()

rfm = transactions.groupby('user_id').agg({
    'txn_date': lambda x: (today - x.max()).days,
    'txn_id': 'count',
    'amount': 'sum'
}).rename(columns={
    'txn_date': 'recency',
    'txn_id': 'frequency',
    'amount': 'monetary'
})

# Scale and cluster
scaler = StandardScaler()
rfm_scaled = scaler.fit_transform(rfm)

kmeans = KMeans(n_clusters=4, random_state=42)
rfm['segment'] = kmeans.fit_predict(rfm_scaled)

# Profile
rfm.groupby('segment').mean().round(1)
Philippine Case Study

Interpreting Customer Segments

After clustering, profile each segment and assign actionable marketing strategies.

Segment Recency Frequency Monetary Strategy
Champions Low (recent) High High Reward loyalty, early access to GCredit
Potential Low Medium Medium Upsell GInvest, push GCash Mastercard
At Risk High (lapsed) Low Medium Win-back campaign, cashback offers
Lost Very High Low Low Exit survey, final reactivation attempt
Activity

In-Class Exercise: Retail Segmentation

Tasks

  1. Load the provided retail transaction dataset
  2. Create RFM features from raw transactions
  3. Scale features with StandardScaler
  4. Run elbow + silhouette analysis to find optimal K
  5. Fit K-Means and profile each cluster
  6. Name your segments and propose strategies

Deliverables

  • Elbow plot and silhouette plot
  • PCA scatter plot colored by cluster
  • Summary table of cluster profiles
  • 1-paragraph marketing recommendation per segment
Time: 30 minutes · Mode: Pairs
Lecture 17 Summary

Key Takeaways

1. Clustering finds natural groups in data without labels.

2. Always scale features before running K-Means.

3. Use elbow + silhouette together to choose K.

4. Hierarchical clustering shows the full merge tree via dendrograms.

Week 09 · Session 2

Advanced Clustering & Customer Analytics

DBSCAN, Market Basket Analysis, and RFM Segmentation

Department of Computer Science

University of the Philippines Cebu

Lecture 18: Beyond K-Means

Agenda

Lecture 18 Objectives

DBSCAN

Apply density-based clustering for arbitrary shapes and outlier detection.

Anomaly Detection

Use clustering and Isolation Forest to flag unusual observations.

Market Basket

Find product associations with Apriori (support, confidence, lift).

RFM Analysis

Score and segment customers by Recency, Frequency, Monetary value.

Density-Based Clustering

DBSCAN

Density-Based Spatial Clustering of Applications with Noise. Groups dense regions and labels sparse points as noise.

Two Parameters

  • eps (ε) — radius of neighborhood
  • min_samples — minimum points to form a dense region

Key Advantages

  • No need to specify K
  • Finds arbitrarily shaped clusters
  • Automatically identifies outliers

Point Classification in DBSCAN

Core Point (≥min_samples in ε) Border Point (near a core point) Noise Point (outlier) ε
Implementation

DBSCAN in Python

Important

DBSCAN labels noise points as −1. Always check how many noise points you get — too many means ε is too small.

Choosing Parameters

  • eps too small → everything is noise
  • eps too large → everything is one cluster
  • min_samples ≈ 2 × n_features (rule of thumb)
python
from sklearn.cluster import DBSCAN

# Fit DBSCAN
dbscan = DBSCAN(eps=0.5, min_samples=5)
labels = dbscan.fit_predict(X_scaled)

# Analyze results
n_clusters = len(set(labels)) - (
    1 if -1 in labels else 0
)
n_noise = list(labels).count(-1)

print(f"Clusters found: {n_clusters}")
print(f"Noise points:   {n_noise}")
print(f"Noise ratio:    {n_noise/len(labels):.1%}")

# K-distance plot to find optimal eps
from sklearn.neighbors import NearestNeighbors

nn = NearestNeighbors(n_neighbors=5)
nn.fit(X_scaled)
distances, _ = nn.kneighbors(X_scaled)
distances = np.sort(distances[:, -1])

plt.plot(distances)
plt.ylabel('5-NN Distance')
plt.title('K-Distance Plot')
# Look for the "elbow" = optimal eps
Comparison

DBSCAN vs K-Means: When to Use Which?

Aspect K-Means DBSCAN
Cluster shape Spherical / convex only Any arbitrary shape
Number of clusters Must specify K Discovered automatically
Outlier handling Forces into nearest cluster Labels as noise (−1)
Cluster density Assumes uniform Handles varying density
Scalability Fast (O(nKt)) Slower (O(n log n) with index)
Reproducibility Varies by initialization Nearly deterministic*
Best for Customer segmentation, compression Anomaly detection, spatial data
*Border points reachable from multiple clusters may vary by processing order.
Application

Anomaly Detection with Clustering

Use clustering to identify observations that don't belong to any group — potential fraud, errors, or rare events.

Two Approaches

  1. DBSCAN noise points: Points labeled −1 are anomalies
  2. Distance from centroid: Points far from their K-Means centroid are suspicious
python
# Method 1: DBSCAN noise detection
dbscan = DBSCAN(eps=0.5, min_samples=10)
labels = dbscan.fit_predict(X_scaled)
anomalies_db = df[labels == -1]
print(f"DBSCAN anomalies: {len(anomalies_db)}")

# Method 2: Centroid distance threshold
kmeans = KMeans(n_clusters=5, random_state=42)
kmeans.fit(X_scaled)
distances = kmeans.transform(X_scaled).min(axis=1)

# Flag top 5% as anomalies
threshold = np.percentile(distances, 95)
anomalies_km = df[distances > threshold]
print(f"K-Means anomalies: {len(anomalies_km)}")

# Method 3: Isolation Forest
from sklearn.ensemble import IsolationForest
iso = IsolationForest(contamination=0.05)
pred = iso.fit_predict(X_scaled)
anomalies_if = df[pred == -1]  # -1 = anomaly
Association Mining

Market Basket Analysis

Goal: Discover products that are frequently purchased together. Powers product recommendations, store layouts, and promotional bundles.

Real-World Applications

  • "Customers who bought X also bought Y"
  • Optimize shelf placement in grocery stores
  • Design cross-selling promotions
  • Bundle pricing strategies

Example Transaction Data

TXN Items Purchased
1 Rice, Eggs, Milk
2 Rice, Eggs
3 Bread, Butter, Coffee
4 Rice, Milk, Coffee
5 Eggs, Milk, Bread

Which items are often bought together?

Association Rules

Three Key Metrics: Support, Confidence, Lift

Implementation

Apriori Algorithm in Python

How Apriori Works

  1. Find all itemsets with support ≥ min_support
  2. Generate candidate itemsets of increasing size
  3. Prune candidates below threshold
  4. Extract rules with confidence ≥ min_threshold
Install

pip install mlxtend — provides Apriori and association rule functions.

python
from mlxtend.frequent_patterns import (
    apriori, association_rules
)
from mlxtend.preprocessing import (
    TransactionEncoder
)

# 1. Encode transactions
transactions = [
    ['rice', 'eggs', 'milk'],
    ['rice', 'eggs'],
    ['bread', 'butter', 'coffee'],
    ['rice', 'milk', 'coffee'],
    ['eggs', 'milk', 'bread'],
]

te = TransactionEncoder()
te_arr = te.fit_transform(transactions)
basket = pd.DataFrame(te_arr, columns=te.columns_)

# 2. Find frequent itemsets
freq = apriori(basket, min_support=0.3,
               use_colnames=True)

# 3. Generate rules (mlxtend >= 0.23)
rules = association_rules(
    freq, num_itemsets=len(basket),
    metric='lift', min_threshold=1.0
)
print(rules[['antecedents', 'consequents',
             'support', 'confidence', 'lift']])
Philippine Case Study

Sari-Sari Store Basket Analysis

The Philippines has over 1 million sari-sari stores. Basket analysis helps small retailers optimize their limited shelf space and bundling strategies.

Illustrative Rules (Hypothetical Data)

  • Instant noodles → Eggs (Lift: 2.3)
  • Rice → Cooking oil (Lift: 1.9)
  • Coffee sachets → Bread (Lift: 2.1)
  • Shampoo sachets → Soap (Lift: 1.7)
Business Insight

Place eggs next to instant noodles, and bundle coffee + bread for "breakfast packs."

python — sari-sari analysis
# Load sari-sari store transactions
baskets = pd.read_csv('ph_sarisari_txns.csv')

# One-hot encode
encoded = baskets.groupby(
    ['txn_id', 'product']
)['qty'].sum().unstack().fillna(0)
encoded = (encoded > 0).astype(int)

# Find associations
freq = apriori(encoded, min_support=0.02,
               use_colnames=True)
rules = association_rules(
    freq, num_itemsets=len(encoded),
    metric='lift', min_threshold=1.5
)

# Top actionable rules
top = rules[
    (rules['confidence'] > 0.5) &
    (rules['lift'] > 2)
].sort_values('lift', ascending=False)
print(top.head(10))
Customer Analytics

RFM Analysis: The Gold Standard for Customer Segmentation

RFM segments customers by three behavioral dimensions, each answering a critical business question.

Implementation

RFM Scoring in Python

Quintile Scoring (1–5)

Divide each metric into 5 equal groups. Score 5 = best. For Recency, lower days = higher score (inverted).

Example

RFM Score "555" = Champion (recent, frequent, high-value).
RFM Score "111" = Lost customer.

python
from datetime import timedelta

# 1. Calculate RFM
snapshot = df['order_date'].max() + timedelta(1)

rfm = df.groupby('customer_id').agg({
    'order_date': lambda x: (snapshot - x.max()).days,
    'order_id': 'nunique',
    'amount': 'sum'
}).rename(columns={
    'order_date': 'recency',
    'order_id': 'frequency',
    'amount': 'monetary'
})

# 2. Quintile scores (1-5)
rfm['R'] = pd.qcut(
    rfm['recency'], 5, labels=[5,4,3,2,1]
)
rfm['F'] = pd.qcut(
    rfm['frequency'].rank(method='first'),
    5, labels=[1,2,3,4,5]
)
rfm['M'] = pd.qcut(
    rfm['monetary'], 5, labels=[1,2,3,4,5]
)

# 3. Combined score
rfm['RFM'] = (rfm['R'].astype(str) +
               rfm['F'].astype(str) +
               rfm['M'].astype(str))
Customer Analytics

RFM Segment Definitions & Actions

Segment R F M Description Marketing Action
Champions 5 5 5 Best customers, recent & frequent Loyalty rewards, referral program
Loyal 3-5 4-5 3-5 Consistent, reliable buyers Upsell, premium access
Potential 4-5 1-3 1-3 Recent but low engagement Onboarding, education
At Risk 1-2 3-5 3-5 Were loyal, now lapsing Win-back campaign, discounts
Hibernating 1-2 1-2 2-3 Long inactive, moderate value Reactivation offer
Lost 1 1 1 Inactive, low value Exit survey, deprioritize
Advanced Technique

Clustering + RFM: Best of Both

Instead of manually defining segments with quintile thresholds, let K-Means discover natural groupings in the RFM space.

Why Combine?

Manual RFM uses arbitrary thresholds. Clustering finds the actual boundaries in your data — often more meaningful and data-driven.

Pro Tip

Monetary values are often heavily right-skewed. Apply np.log1p() before scaling to prevent a few high-spenders from dominating the clusters.

python
# Use K-Means on RFM features
rfm_features = rfm[['recency', 'frequency',
                     'monetary']].copy()

# Log-transform skewed monetary column
rfm_features['monetary'] = np.log1p(
    rfm_features['monetary'])

scaler = StandardScaler()
rfm_scaled = scaler.fit_transform(rfm_features)

# Find optimal K
from sklearn.metrics import silhouette_score
for k in range(2, 8):
    km = KMeans(n_clusters=k, random_state=42)
    labels = km.fit_predict(rfm_scaled)
    sil = silhouette_score(rfm_scaled, labels)
    print(f"K={k}: Silhouette={sil:.3f}")

# Fit best K (from silhouette loop above)
best_k = max(range(2, 8), key=lambda k:
    silhouette_score(rfm_scaled,
    KMeans(n_clusters=k, random_state=42)
    .fit_predict(rfm_scaled)))
best_km = KMeans(n_clusters=best_k, random_state=42)
rfm['cluster'] = best_km.fit_predict(rfm_scaled)

# Profile and name clusters
profile = rfm.groupby('cluster').agg({
    'recency': 'mean',
    'frequency': 'mean',
    'monetary': ['mean', 'count']
}).round(1)
print(profile)
Decision Guide

Which Clustering Algorithm Should I Use?

K-Means

  • You know (or can estimate) K
  • Clusters are roughly spherical
  • Large datasets (fast)
  • Customer segmentation
  • Image compression

Hierarchical

  • Want to explore different K values
  • Need a visual hierarchy (dendrogram)
  • Small-medium datasets (<10K)
  • Taxonomy / phylogenetics
  • Organizational structure

DBSCAN

  • Don't know K at all
  • Non-spherical / irregular clusters
  • Need outlier detection
  • Spatial / geographic data
  • Fraud / anomaly detection
Going Further

Beyond the Basics: GMM & HDBSCAN

K-Means, Hierarchical, and DBSCAN cover most use cases. But two modern algorithms solve specific pain points worth knowing.

Gaussian Mixture Models (GMM)

Soft clustering — each point gets a probability of belonging to each cluster, not a hard assignment.

  • Models clusters as Gaussian distributions
  • Handles elliptical (non-spherical) clusters
  • Use BIC/AIC to select number of components
  • sklearn.mixture.GaussianMixture
Best for: Overlapping clusters, uncertainty estimation, anomaly scoring via low probability.

HDBSCAN

Hierarchical DBSCAN — eliminates the need to tune the eps parameter manually.

  • Automatically finds clusters at varying densities
  • Only requires min_cluster_size
  • Provides cluster stability scores
  • pip install hdbscan (or sklearn 1.3+)
Best for: Real-world data with mixed-density clusters, when you don't want to tune eps.
Advice

Start with K-Means or DBSCAN. Move to GMM/HDBSCAN only when simpler methods fail to capture your data's structure. Simpler models are easier to explain to stakeholders.

Activity

In-Class Exercise: Complete Customer Analytics

Tasks

  1. Load the Philippine e-commerce dataset
  2. Calculate RFM metrics from raw transactions
  3. Cluster customers with K-Means (find best K)
  4. Compare with DBSCAN (identify anomalous customers)
  5. Run basket analysis on product purchases
  6. Create a 1-page segment recommendation report

Expected Outputs

  • Elbow + silhouette plots
  • PCA scatter plot by cluster
  • RFM cluster profile table
  • Top 5 association rules with interpretation
  • DBSCAN anomaly count and examples
  • Marketing recommendations per segment
Time: 35 minutes · Mode: Pairs
Lecture 18 Summary

Key Takeaways

1. DBSCAN finds arbitrary-shaped clusters and naturally identifies outliers as noise.

2. Anomaly detection uses distance from normal patterns (DBSCAN noise, centroid distance, Isolation Forest).

3. Market basket analysis reveals product co-occurrence patterns via support, confidence, and lift.

4. RFM + Clustering creates data-driven customer segments with clear marketing actions.

Coming Up

Lab 9: Customer Segmentation Project

A comprehensive end-to-end customer analytics exercise combining everything from this week.

Next Week: Time Series Analytics — Forecasting trends, seasonality, and building ARIMA models.