Une valeur qui ne peut pas être juste
Un rendement quotidien de +30 % sur une grande capitalisation est soit une OPA, soit une erreur de données comme un fractionnement oublié ou une virgule mal placée. Une valeur aberrante est assez éloignée des autres pour exiger une décision : la garder, la corriger ou la retirer. Ne la supprimez jamais simplement parce qu'elle gêne, car les vrais chocs sont précisément ce que les modèles de risque doivent voir. La première étape est toujours de les rendre visibles avec une règle explicite et reproductible.
La règle du z-score, et pourquoi elle peut échouer
La règle classique signale les valeurs situées à plus de 2 ou 3 écarts types de la moyenne : z = (x - mean) / std. Elle est simple et fonctionne sur des données propres. Mais la valeur aberrante gonfle elle-même la moyenne et surtout l'écart type, et elle se cache donc de la règle. Dans l'exemple ci-dessous, la journée à +30 % n'obtient qu'un z-score de 2,85 et, avec un seuil de 3, elle ne serait pas signalée. Plus l'erreur est extrême, plus elle se protège.
import pandas as pd
returns = pd.Series([0.004, -0.002, 0.001, 0.003, -0.004, 0.002, 0.30, -0.001, 0.0, 0.002])
z = (returns - returns.mean()) / returns.std()
print(z.round(2).tolist())
# [-0.28, -0.34, -0.31, -0.29, -0.36, -0.3, 2.85, -0.33, -0.32, -0.3]
print(returns.mean().round(4), returns.std().round(4)) # 0.0305 0.0947 one day moved the mean tenfold
print(returns.drop(6).std().round(4)) # 0.0026 the std without that dayRègles robustes : IQR et MAD
Les statistiques robustes sont à peine déplacées par les valeurs aberrantes qu'elles traquent. L'écart interquartile IQR = Q3 - Q1 mesure la dispersion de la moitié centrale des données, et les valeurs au-delà de Q1 - 1.5 * IQR ou Q3 + 1.5 * IQR sont hors des bornes d'une boîte à moustaches. Le MAD (écart absolu médian) remplace l'écart type par une médiane, et le z-score modifié 0.6745 * (x - median) / MAD se lit comme un z-score normal (3,5 est un seuil courant). Les deux repèrent sans peine la journée à +30 %.
# The fences of a box plot
q1, q3 = returns.quantile(0.25), returns.quantile(0.75)
spread = q3 - q1
lower, upper = q1 - 1.5 * spread, q3 + 1.5 * spread
print(round(lower, 4), round(upper, 4)) # -0.006 0.008
print(returns[(returns < lower) | (returns > upper)].to_dict()) # {6: 0.3}
# The modified z-score, built on the median
median = returns.median()
mad = (returns - median).abs().median()
modified_z = 0.6745 * (returns - median) / mad
print(modified_z.round(1).tolist()) # [0.8, -1.2, -0.2, 0.5, -1.9, 0.2, 100.7, -0.8, -0.5, 0.2]Winsorisation : plafonner plutôt que supprimer
Supprimer une ligne supprime aussi l'information de ses autres colonnes et casse l'espacement des dates. La winsorisation garde toutes les lignes et ramène les valeurs extrêmes à des quantiles choisis, par exemple ceux de 1 % et 99 % : tout ce qui est sous le quantile à 1 % devient ce quantile, tout ce qui est au-dessus de celui à 99 % devient celui-ci. Avec pandas, c'est clip(lower, upper) avec les bornes tirées de quantile. La forme de la série subsiste et les extrêmes perdent leur emprise sur les moyennes et les régressions.
low, high = returns.quantile(0.1), returns.quantile(0.9)
print(round(low, 4), round(high, 4)) # -0.0022 0.0336
clipped = returns.clip(lower=low, upper=high)
print(clipped.round(4).tolist())
# [0.004, -0.002, 0.001, 0.003, -0.0022, 0.002, 0.0336, -0.001, 0.0, 0.002]
# ^ raised ^ the 30% day pulled back to the 90% quantile# Flag with a rule, then look at what is flagged before deciding anything
mask = z.abs() > 2
print(returns[mask].to_dict()) # {6: 0.3} the +30% day
print(returns[~mask].std().round(4)) # 0.0026 the volatility of the remaining days- La règle du z-score
abs((x - mean) / std) > kest simple, mais les valeurs aberrantes gonflent la moyenne et l'écart type et peuvent se cacher. - Les règles robustes utilisent quantiles et médianes : bornes IQR (
Q1 - 1.5 IQR,Q3 + 1.5 IQR) et z-score modifié fondé sur le MAD. clip(lower, upper)avec des bornes en quantiles (winsorisation) garde les lignes ; ne supprimez jamais un choc sans savoir ce que c'est.
À suivre : les opérations sur titres, les fractionnements et dividendes qui rendent un ancien prix incomparable avec celui d'aujourd'hui.
Lab : ce qui est noté
- Repérer les rendements éloignés avec
zscore_outliers25 pts - Calculer les bornes de la boîte à moustaches avec
iqr_bounds25 pts - Repérer les valeurs aberrantes avec un score robuste grâce à
mad_outliers25 pts - Dompter les extrêmes avec
winsorize25 pts