Unsupervised ML · Market Segmentation · Statistics Canada CFAF 2011–2017

Canadian Freight Corridor
Segmentation

Python · numpy · scikit-learnPCA · K-Means · Ward · GMM bootstrap validation6 interactive dashboards

Statistics Canada's Canadian Freight Analysis Framework records every commodity flow between provinces — 58,721 rows of shipments, tonnage, revenue and mode from 2011–2017. I engineered 13 corridor-level features, compressed them with PCA, and segmented 194 origin→destination corridors into five market archetypes with K-Means — then stress-tested the segmentation with bootstrap resampling, hierarchical and Gaussian-mixture cross-checks, permutation feature importance and a Mahalanobis anomaly audit. The result is a validated market map that feeds T-Baar's demand-model calibration, plus a live classifier you can steer yourself.

58,721
CFAF records (2011–17)
194
Corridors clustered
13
Engineered features
5
PCs → 90% variance
5
Corridor archetypes
0.90
Bootstrap ARI @ k=5
$379B
CAD freight revenue
// 01 — MARKET SEGMENTS

Five corridor archetypes

Each card is a cluster from the final k=5 model. Sizes, revenue shares and silhouettes are computed from the re-run pipeline; the top pills are each cluster's largest corridors by total revenue. Click a card to isolate that archetype in the explorer below.

// 02 — CORRIDOR EXPLORER

Every corridor, one map

Each dot is one of the 194 corridors, placed by t-SNE over the 5 retained principal components (or raw PC1×PC2 — toggle below). Size ∝ √revenue. Color by archetype, by anomaly score (Mahalanobis distance to own-cluster centroid), or by the corridor's 2011→2017 revenue-trend direction. Hover for details, click to pin a full profile.

// 03 — MODEL SELECTION & VALIDATION

Why k = 5, and how much to trust it

Choosing k is where most clustering projects hand-wave. Here five independent criteria are computed for k = 2…9 on the PCA-reduced matrix: inertia (elbow), mean silhouette, Calinski–Harabasz, a spherical-Gaussian BIC for K-Means, an EM-fitted diagonal GMM BIC, and the gap statistic against 40 uniform reference sets. Silhouette and CH plateau at k≈4–6 while the elbow flattens past 5 — but the decisive evidence is stability: reclustering 120 bootstrap resamples and comparing each to the full-sample partition (Adjusted Rand Index) shows k=5 is the most reproducible choice, ARI 0.90.

Inertia (elbow)
Bootstrap stability — ARI vs full-sample partition (120 resamples, 5–95% band)

Do other algorithms find the same structure?

A segmentation you can only get from one algorithm is fragile. Cutting a from-scratch Ward hierarchy at 5 clusters recovers the K-Means partition at ARI 0.75 — strong agreement given Ward's very different objective. A diagonal-covariance Gaussian mixture fitted by EM prefers similar mid-range k by BIC. And the re-run reproduces the originally archived labels at ARI 1.00 — the pipeline is fully deterministic and reproducible.

CheckMethodResultReading
Reproducibilityre-run, seed 42, n_init 100ARI 1.00 vs archiveddeterministic pipeline
Algorithm agreementWard linkage (Lance–Williams), cut k=5ARI 0.75same macro-structure
Model-based checkdiagonal GMM via EM, BIC over k=2–8favors k≈5–7no strong over-split signal
Sampling robustness120 bootstrap resamplesARI 0.90 [0.74, 1.00]k=5 = stability peak
Separabilitynearest-centroid classifier, 13-d scaled space100% training assignment recoveryclusters are convex & separable
// 04 — CLUSTER PROFILES & DRIVERS

What actually separates the segments

The heatmap shows each cluster's mean z-score on all 13 features — hover any cell for the cluster's raw median. Two importance measures agree on the drivers: one-way ANOVA F (between/within variance) and permutation importance (accuracy drop of the nearest-centroid classifier when a feature is shuffled, 30 reps). Mode split (rl_share/tf_share) and the cross_border flag dominate — geography and modal economics, not just size, define Canada's freight markets.

Cluster profile heatmap — mean z-scores (hover for raw medians)
Feature importance — ANOVA F (bars) & permutation Δacc (dots)
PCA — variance explained & top loadings
Silhouette profile — every corridor, sorted within cluster (mean 0.36)
// 05 — ANOMALY AUDIT

Corridors that don't fit the map

Segmentations get used blindly, so I audit the misfits. For each corridor I compute the Mahalanobis distance to its own cluster's centroid (diagonal covariance, PC space) — corridors far from every archetype are flagged rather than silently averaged in. The flags are sensible: territorial self-loops (YT→YT, NT→NT) with unusual rate structures, SK→UM waste exports, and BC→BC, which is trunk-like in volume but priced like a periphery corridor. In the T-Baar demand model these get corridor-specific overrides instead of archetype-level parameters.

#CorridorArchetypeMahalanobisSilhouetteRevenueDominant commodityWhy it's odd
// 06 — PROVINCE FLOW MATRIX

Where the money moves

Total 2011–17 freight revenue for every origin (rows) → destination (columns) pair, log-scaled. The bright diagonal is intra-provincial trucking; the off-diagonal hot cells — ON↔QC, AB↔BC, and the US column — are exactly the corridors the Cross-Border Arteries and Domestic Trunk archetypes capture. Hover any cell.

// 07 — LIVE CLASSIFIER

Build a corridor, watch it get classified

This is the fitted model running in your browser — the same scaler (log1p → z-score → ±4σ clip) and the same 5 centroids in 13-d feature space. Load a real corridor as a starting point, then drag the sliders: the nearest-centroid assignment, softmax confidence and distance profile update live. Try loading ON→QC and dragging rail share up — you can watch a trunk route migrate into Rail-Heavy Bulk.

// 08 — METHODOLOGY

Pipeline walkthrough

01

Clean & aggregate 58,721 CFAF records

Parse comma-formatted numerics, drop incomplete rows, build the corridor key OrigProv→DestProv, and drop "other international" pseudo-corridors (single-commodity data artifacts). 194 corridors survive.

02

Engineer 13 corridor-level features

Volume (shipments, revenue, value, tonne-km), economics (revenue per tonne-km, value/kg, revenue per shipment), structure (median distance, shipment weight), mix (Shannon commodity entropy H = −Σ pᵢ log₂ pᵢ, truck/rail/air shares), a cross-border flag, and a per-corridor OLS revenue-trend slope over the 7 years.

03

Transform: log1p → z-score → ±4σ clip

Five heavy-tailed volume features get log1p; all features are standardized, then clipped at 4σ so a single mega-corridor (ON→ON) can't dominate distance computations without discarding it.

04

PCA via SVD — 13 → 5 dimensions

Five components retain 90.0% of variance. PC1 loads on scale (volume/revenue), PC2 on modal split, PC3 on cross-border reach — the loading heatmap in §04 shows the full rotation.

05

Cluster: K-Means++, n_init=100, k selected by 6 criteria

Elbow, silhouette, Calinski–Harabasz, K-Means BIC, GMM BIC and the gap statistic — then k=5 confirmed as the bootstrap-stability peak (ARI 0.90 over 120 resamples).

06

Validate & audit

Ward-linkage cross-check (ARI 0.75), permutation feature importance, per-corridor silhouettes, and a Mahalanobis anomaly audit that flags 8 corridors for model-level overrides.

The two equations doing the work

K-Means objective:   argminC Σₖ Σx∈Cₖ ‖x − μₖ‖²   (Lloyd iterations from k-means++ seeds)
Gap statistic:   Gap(k) = E*[log Wₖ(uniform ref)] − log Wₖ(data),  B = 40 reference draws
for k in range(2, 10):
    km  = KMeans(n_clusters=k, n_init=30, random_state=42).fit(X_pca)
    sil = silhouette_score(X_pca, km.labels_)          # peak/plateau at k≈5
    ari = np.mean([adjusted_rand(km.labels_[idx],      # bootstrap stability
                   KMeans(k).fit_predict(X_pca[idx]))
                   for idx in bootstrap_indices(B=120)])
// 09 — KEY FINDINGS

Implications for logistics platform design

1
69 trunk corridors carry half the economy. Domestic Trunk Routes generate 49.7% of the $379B — dense, diverse, truck-led flows where a matching platform's liquidity compounds fastest. This is where T-Baar's demand model concentrates its calibration mass.
2
17 Cross-Border Arteries punch 4× their weight. 8.8% of corridors, 35.2% of revenue, the longest hauls and the strongest growth trends — but customs frictions make them structurally different. They need a separate pricing regime, not a scaled-up domestic one.
3
Mode, not size, is the sharpest divider. Rail share is the top-ranked feature on both importance measures. The 20 Rail-Heavy Bulk corridors (2.5σ above mean rail share) are effectively a different industry — bulk contracts, few shippers — and are excluded from truck-matching demand estimates.
4
The long tail is thin but not noise. 88 Periphery + Remote corridors sum to ~2% of revenue. Their archetype parameters stabilize what would otherwise be 194 corridor-level estimates from sparse data — the whole point of segmenting before modeling.
5
Eight corridors get manual overrides. The anomaly audit (§05) flags territorial self-loops and single-commodity export corridors whose economics no archetype represents; averaging them in would bias archetype-level rates by up to 1.4×.