skills/timeseries/store-profile-hierarchical-clustering/SKILL.md
Re-cluster retail stores by scale-normalized weekday/dayoff mean+std profiles using Ward agglomerative clustering, replacing vendor-supplied "type/cluster" labels that correlate with store size instead of demand shape
npx skillsauth add wenmin-wu/ds-skills timeseries-store-profile-hierarchical-clusteringInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Vendor-supplied store type and cluster labels (common in retail datasets like Favorita) usually encode store size, not demand shape. A store profile is the right grouping key when you plan to train per-group models or apply per-group post-processing: two small stores with identical weekday shapes should cluster together even if one sells twice as much. The recipe is three steps — normalize each row by its store's overall mean to kill scale, aggregate to a per-store weekday mean+std profile, then Ward-cluster the profiles.
import pandas as pd
from scipy.cluster.hierarchy import ward, dendrogram
from sklearn.cluster import AgglomerativeClustering
store_avg = sales.groupby('store_nbr')['transactions'].mean()
sales['normalized'] = sales['transactions'] / sales['store_nbr'].map(store_avg)
profile = (sales.groupby(['store_nbr', 'day_of_week'])['normalized']
.agg(['mean', 'std'])
.unstack(level='day_of_week')) # (n_stores, 14)
dendrogram(ward(profile.values)) # eyeball a cutoff k
labels = AgglomerativeClustering(n_clusters=6).fit_predict(profile.values)
stores['shape_cluster'] = labels
(store, day_of_week) and aggregate mean and std → unstack so each store is one feature row (7 × 2 = 14 cols)dayoff flag for 28-dim profiles that separate holiday behaviork at the biggest vertical gapAgglomerativeClustering(k) on the profile matrix and attach labels to the stores tableshape_cluster as a grouping key for per-cluster models or as a categorical feature in a global modeldata-ai
Scaled Pinball Loss (SPL) metric for evaluating quantile forecasts, normalized by mean absolute successive differences of training data
data-ai
Walk backward through a time series and multiplicatively rescale segments when jumps exceed a fraction of the running mean to correct data collection anomalies
testing
Transform forecasting target to next/current ratio minus one so that optimizing MAE or squared error implicitly minimizes SMAPE
tools
Convert point forecasts to prediction intervals by scaling with logit-transformed quantile ratios passed through a Normal CDF