ADR 003 — k choisi par silhouette pure, sans tie-break heuristique¶
Status¶
Acté — Lot 2 (2026-06-02).
Context¶
KMeans exige de fixer k (nombre de clusters) avant de fitter. Les approches courantes :
- k codé en dur par connaissance métier (ex : "on sait qu'il y a 4 archetypes").
- Elbow method (inflexion de l'inertie).
- Silhouette (cohésion intra-cluster vs séparation inter-cluster, score ∈ [-1, 1]).
- Gap statistic, information criteria, etc.
Au design, on connaît 4 archetypes générés. Si on codait k=4 en dur, on tricherait :
le test "le système retrouve les archetypes" perdrait sa valeur d'inférence.
Au premier essai d'archetypes (cf. ADR 002), la silhouette piquait à k=2, qui n'est pas la valeur souhaitée. La tentation était d'ajouter une heuristique de tie-break : "si silhouette[k+1] ≥ 95 % de silhouette[best], préférer k+1".
Decision¶
Pas de tie-break heuristique. k est l'argmax pur de silhouette sur la bande
k ∈ [k_min, k_max] (défaut [2, 8]).
for k in range(k_min, k_max + 1):
score[k] = silhouette_score(X_scaled, KMeans(k).fit(X_scaled).labels_)
best_k = argmax(score) # ← rien d'autre
Si la silhouette pure ne donne pas le k attendu, le problème est dans le dataset
(pas assez de séparation par forme), pas dans l'algo. C'est ce qui a conduit à
ADR 002.
Consequences¶
Positives¶
- Honnêteté algorithmique : pas de "magie" cachée dans la sélection de k. Un
évaluateur peut auditer la silhouette retournée par
/clusterset vérifier quek == argmax(silhouette_by_k). - Reproductibilité : seed 42 + bande [2, 8] fixée → mêmes résultats partout (CLI, API, tests).
- Pédagogiquement défendable : si on travaille un jour avec des datasets réels, on
saura que la valeur de
kreflète la structure des données, pas un biais d'analyste.
Compromis¶
- Sensibilité au design du dataset. C'est l'apport principal d'ADR 002 : pour que la silhouette pure soit informative, le dataset doit avoir des centroïdes d'archetypes suffisamment orthogonaux.
- En production réelle (vrai dataset, pas synthétique), la silhouette peut être faible partout — le score retenu (0.309 ici) est correct mais pas spectaculaire en valeur absolue. C'est une métrique relative, lue ensemble avec la pureté terrain.
Limites assumées¶
- KMeans euclidien sur features standardisées privilégie des clusters sphériques de tailles comparables. Si la vraie structure était hiérarchique ou non convexe, on changerait d'algorithme (DBSCAN, Gaussian Mixture, hiérarchique) — c'est hors scope au niveau 1.
- Le test correspondant accepte
k ∈ [3, 5](pas strictement = 4) pour absorber la variance d'initialisation entre seeds. Documenté danstests/unit/test_clustering.py.