Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

estimation des performances sur le passé #92

Open
FanchMorvan opened this issue Aug 28, 2023 · 8 comments
Open

estimation des performances sur le passé #92

FanchMorvan opened this issue Aug 28, 2023 · 8 comments

Comments

@FanchMorvan
Copy link

Pour le choix du modèle d'étalonnage-calage, avoir des indicateurs statistiques est intéressant, mais je me dis qu'il est aussi intéressant d'avoir une estimation des performances des modèles sur le passé.

J'ai donc écris une fonction qui donne l'output suivant :

image

On regarde, pour les années précédentes N, la différence entre :

  • ce qu'aurait donné l'étalonnage-calage, en supposant le compte connu jusqu'à l'année N-1,
  • et le compte final.

Il ne serait pas inintéressant d'intégrer un tel tableau dans reView à mon avis (un sous-onglet de plus dans l'onglet Presets de reView ?). Ou alors on peut juste ajouter une ligne de plus dans le sous-onglet summary-table avec le "résultat final" (la moyenne sur les 5 dernière années des carrés des erreurs de prévision), même si il y a nécessairement une perte d'information. C'est certainement assez proche de ce que donnerai une distance restreinte aux 5 dernières années, qui pourrait être une autre alternative encore plus simple mais aussi encore un peu moins informative.

Qu'est-ce que vous en pensez ? Suivant ce que l'on envisage de faire ce sera plus ou moins de travail. Je dois dire que je ne penses pas que j'aurai beaucoup de temps à consacrer à cela, mais je ne suis pas tout seul dans la division des comptes trimestriels ! Même si avec le changement de base on risque d'être nombreux à être bien occupé.

@arnaud-feldmann
Copy link
Member

arnaud-feldmann commented Aug 28, 2023

Salut et merci pour ta contribution :)

En fait, si je comprends bien ta proposition, il y a en fait deux suggestions assez indépendantes :

  1. Rajouter une simulation out-of-sample
  2. Rajouter un onglet dans reView où on voit en tableaux (plutôt qu'en graphiques, car les graphiques sont déjà là et sont bel et bien déjà des simulations in-sample) de simulations sur les presets.

D'abord le 2
Je vais d'abord répondre au 2 : je pense que c'est à vous de décider ensemble de ce que vous trouvez pertinent et général pour la pratique des étalonnages calages, donc pas de problèmes, vous êtes bien mieux placés que moi. Après, le graphique est déjà une simulation in_sample.
Mais feel free, modifiez l'application shiny comme vous le souhaitez. Cela est d'autant plus permis que je ne pense pas que des éventuels utilisateurs attendent de la rétrocompatibilité dans une app shiny. Tout le monde sait bien que c'est un outil de dataviz susceptible de bouger. Donc faites à ce qui vous semble le plus utile, informatif, et pratique !

Sur le 1
A titre personnel, je n'aime pas vraiment les simulations out-of-sample "sans adaptation" sur les étalonnages. Dans l'usage des CT, l'out of sample a un défaut énorme qui est de ne pas déconner violemment partout quand le modèle bugge sur les périodes récentes : il détecte insuffisamment les changements complets de relations indicateur-compte. On utilisait avant le out of sample, et des erreurs toutes bêtes sont passées sous le manteau à cause de ça. Dans le out of sample sans adaptation, la dernière observation compte 1 fois, l'avant dernière 2 fois, l'avant avant dernière 3 fois, etc. et la première n fois (dans le calcul des coefficients) y compris avec des étalonnages non convergés qui n'ont pas trop de sens.
De plus, l'existence d'une distance out-of-sample toute cuite possède un ascendant psychologique sur la distance in-sample. Tout le monde en rejoignant les comptes trims pense que c'est mieux, et c'est naturel car on n'aime pas mélanger échantillon d'entrainement et de validation. Et plus personne ne regarde le in-sample, alors que c'est elle qui correspond à effectivement à la distance des observations à la droite que l'on applique à l'instant t (pas celle qu'on aurait appliquée en 1998 en appliquant le même modèle avec 3 observations). Pour moi, à partir du moment où une droite a convergé, elle ne bouge plus trop, et donc le mélange validation/entrainement n'est que très modéré : puisque la droite n'est pas censée trop bouger d'une période à l'autre, une simulation in-sample ne me semble pas tant être une estimation des performances au présent qu'une estimation des performances dans le passé, en prenant compte de ce qu'on sait de la droite au présent.

Ta proposition de limiter la distance out-of-sample aux 5 dernières années est intéressante, et limite les défauts manifestes du out-of-sample.
Mais ce n'est au fond plus très loin d'un in-sample sur ces 5 années. A priori, si on est sur les dernières années, la droite a de toutes manières à peu près convergé, et doit se comporter à peu près de manière stable sur les 5 dernières années. Et si elle ne le fait pas, ce n'est je pense pas une information à corriger par une séparation validation/entrainement au moyen d'un out of sample, mais au contraire une information capitale à mettre en avant : quelque chose est problématique. On veut que ce soit pris en compte, on veut que cela fasse exploser le coût partout, on ne veut pas corriger ce changement de droite dans le calcul du coût. Donc, à mon avis, le in-sample est très bien (en plus d'être simple).

A mon avis, si on voulait un vrai truc qui perd les biais du out of sample tout en valant le prix de la complexification, il faudrait un calcul pour lequel :

  • la stricte séparation échantillon validation/entrainement ne s'effectue pas aux dépends du poids des nouvelles observations, qui doit rester au moins égal à celui des anciennes dans le coût général.
  • la mesure doit être suffisamment meilleure par rapport au in_sample pour légitimer une complexification

Le premier point est peut-être atteignable avec une solution intermédiaire, en se débrouillant pour faire une validation croisée leave one out, c'est à dire estimer le point en fonction de chaque modèle en n'enlevant que ce point (et pas les points qui viennent après).
Pour ce faire, il me semble qu'il faudrait :

  • modifier praislm pour que les modèles puissent être estimés avec des trous. Par exemple dans le cas mcqg niveau on a on a u(n+2) = rho*u(n+1) + Ɛ(n+2) = rho^2*u(n) + Ɛ(n+2)+ rho * Ɛ(n+1) donc u(n+2)-rho^2*u(n) = N(0,sqrt(1+rho^2)* ecart_type(Ɛ)) . On peut peut-être réussir à estimer avec un trou en remplaçant ponctuellement rho par rho² et epsilon par un truc du genre sqrt(1+rho^2) * epsilon (*)
  • rajouter une possibilité de prédiction par interpolation
  • comparer cette prédiction par interpolation à la vraie valeur interpolée.

Mais du coup, ça complique beaucoup l'affaire pour un gain qui n'est sans doute pas énorme. Leave one out ne doit pas être très loin d'un simple in-sample dès lors que la droite a convergé. Peut-être un peu débiaisé mais beaucoup plus boîte noire. A titre personnel, je préfère les choses simples et biaisées que débiaisées et non-maitrisables.

Et un petit message de fin

Mais tout cela n'est que mon avis, et le package vous appartient : faites-ce que vous voulez, vous avez les droits GitHub :D C'est vous qui êtes à la prod, donc plus susceptibles de savoir ce qui est pertinent. Si vous ajoutez une out-of-sample sans adaptation, je vous conseille par contre vraiment de rappeler en doc visible que l'out-of-sample a des gros défauts, pour ne pas retomber dans les mêmes travers que quand on les utilisait avec un peu trop de confiance.

(*) : ou utiliser les outliers qui existent déjà ?

@FanchMorvan
Copy link
Author

Merci beaucoup pour ta réponse très complète !

Je suis assez convaincu par tes arguments. Je n'avais pas pensé au fait que l'on sur-pondère un peu les observations anciennes avec cette méthode, même si le fait que le score est basé sur les performances des modèles sur les années récentes compense peut-être en partie cela (il y a toujours un déséquilibre au sein de ces 5 dernières années, mais elles doivent toutes être surreprésentées dans la mesure par rapport aux autres années).

Mais surtout c'est vrai que si l'on a suffisamment d'années, le out-of-sample doit être très proche d'une distance in-sample si on se restreint aux dernières années, mais plus coûteux et biaisé.

Je penses malgré tout qu'avoir un indicateur des performances du modèle sur le passé proche serait utile, c'est ce que l'on essaye (ou en tout cas que j'essaye) de regarder à l'aide des graphiques quand deux modèles ont des performances proches, mais ce n'est pas toujours facile de trancher simplement avec des graphiques... Du coup regarder la distance in-sample obtenue sur les 5 dernières années pourrait être un indicateur intéressant à mon avis. Ou ajouter un tableau, ce serait plus complet mais moins immédiat à interpréter. On pourra en discuter entre nous je suppose !

@arnaud-feldmann
Copy link
Member

De rien ! Bonnes discussions et bon code !

@arnaud-feldmann
Copy link
Member

arnaud-feldmann commented Aug 30, 2023

@FanchMorvan En y réflechissant, j'ai une idée de graphique issu d'out of sample qui pourrait être intéressant. Peut-être un graphique de convergence du coefficient inspiré des graphiques de descente de gradient ? On mettrait tracerait les coefficients normalisés (différents indicateurs, constante, rho) en ordonnées (plusieurs courbes), et l'année en abscisse.
Le coefficient de l'année n serait calculé uniquement avec ce qui est connu jusqu'à l'année n-1. Et le zéro représente les coefficients avec tout l'échantillon (vu que c'est normalisé).

Du coup, ça donne une idée graphique de la convergence de chaque modèle, et permet d'apprécier un éventuel point où les coefficients sauteraient. On peut donc apprécier si in_sample est représentatif.

Idées d'alternatives si on ne veut pas normaliser, pour voir l'évolution des vrais coefficients :

  • Un graphique où il n'y a que le coefficient de l'indicateur (lorsqu'il est unique) avec une droite horizontale en pointillés pour les coefficients de tout l'échantillon.
  • Pour les modèles avec constante, un graphique "abscisse=coefficient,ordonnée=constante,années=couleur et sens des flèches" (mais ça ne marche pas pour les modèles sans constantes)
  • Une sortie normale non-normalisée pour ceux qui le veulent (mais en graphique la constante va rendre invisible le coeff)

Comment ça pourrait s'articuler

  • On peut faire une fonction in_convergence présentée comme la convergence du modèle dans l'échantillon, qui sort une sortie à peu près comme les autres fonctions in_*, avec des colonnes pour chaque coefficient/rho et toutes les valeurs des coeffs out of sample pour chaque année. ça s'explique bien en doc je pense
  • un plot qui va là dessus et sort une des idées de graphiques ci-dessus.
  • Peut-être que l'argument type de la fonction in_convergence pourrait décider de la sortie et du plot renvoyé ? par exemple type pourrait être "normalized", "non-normalized-indicator-only", "non-normalized-indicator-constant", "non-normalized"

Qu'en penses-tu ?

@arnaud-feldmann
Copy link
Member

arnaud-feldmann commented Sep 6, 2023

Voilà, j'ai fait une branche où j'ai fait une première version (non relue, non peaufinée, et sans tests unitaires ni doc pour l'instant) de ce que j'ai proposé.

plot(in_convergence(twoStepsBenchmark(turnover,construction,include.differenciation = TRUE, include.rho = TRUE),type = "non-normalized-2d"))
image
En abscisse l'indicateur, en ordonnée la constante, et la croix rouge c'est les coefficients in sample

plot(in_convergence(twoStepsBenchmark(turnover,construction)))
image
(pour l'instant le truc par défaut est normalized)

plot(in_convergence(twoStepsBenchmark(turnover,construction), type ="non-normalized-indicators-only"))
image
indicator only enlève constante et outliers du graphique

plot(in_convergence(twoStepsBenchmark(turnover,construction,include.differenciation = TRUE, include.rho = TRUE),type = "normalized"))
image

plot(in_convergence(twoStepsBenchmark(turnover,construction,include.differenciation = TRUE, include.rho = TRUE),type = "non-normalized"))
image

Peut-être, pour la version normalisée, prendre 0 pour l'in-sample plutôt que la moyenne ?

En tout cas, ces graphiques montrent bien la convergence des indicateurs, sans être trop susceptibles aux débuts de série complètement pétés, où le modèle n'a pas convergé et fait n'importe quoi.

Je propose de mettre par défaut le graphique 2d (qui est le plus parlant) quand il est possible, cad quand on a une constante, et sinon le graphique indicators only. Ok ?

@arnaud-feldmann
Copy link
Member

arnaud-feldmann commented Sep 6, 2023

Dans la nouvelle version j'ai abandonné l'idée de normaliser (cela complique pour peu d'interprétabilité), et ça donne :

Le plot par défaut est indicators. Cela renvoie les indicateurs, donc l'indicateur dans le cas univarié. Dans la mesure où j'ai laissé la possibilté de sélectionner par nom, et que le nom par défaut est "hfserie", on a le même graphique avec "hfserie"
plot(in_convergence(twoStepsBenchmark(turnover,construction, include.differenciation = TRUE)))
plot(in_convergence(twoStepsBenchmark(turnover,construction, include.differenciation = TRUE),type = "indicators"))
plot(in_convergence(twoStepsBenchmark(turnover,construction, include.differenciation = TRUE),type="hfserie"))
image

On peut aussi sélectionner la constante séparément :
plot(in_convergence(twoStepsBenchmark(turnover,construction, include.differenciation = TRUE),type="constant"))
image

On peut faire un plot indicator-constant-2d (possible que sur l'univarié, et ça n'a d'intérêt que si la constante est libre) :
plot(in_convergence(twoStepsBenchmark(turnover,construction, include.differenciation = TRUE),type="indicator-constant-2d"))
image

On peut sinon sélectionner all (qui fera apparaître sur un même graphique les indics, la constante et les outliers donc pas forcément lisible)
plot(in_convergence(twoStepsBenchmark(turnover,construction, include.differenciation = TRUE),type="all"))
plot(in_convergence(twoStepsBenchmark(turnover,construction, include.differenciation = TRUE),type=c("constant","hfserie")))
image

Cela me semble plus simple : la normalisation n'était pas claire. Là on voit bien la convergence vers in_sample.
J'ai finalement opté pour ajouter l'année n+1 dans le graphique out-of-sample, cela me semble accentuer l'idée que les coefficients in-sample de l'année n ne sont rien de plus que les out of sample de l'année précédente.

@arnaud-feldmann
Copy link
Member

arnaud-feldmann commented Sep 6, 2023

En affichage sans plot, c'est de ce type là :
image
image

Et j'ai mis les distances de minkowski totales (entre les coefficients out et leur coefficient in), par cohérence avec les autres in_*, même si je ne pense pas que ça ait beaucoup de sens. Il faut mieux vérifier si le modèle finit par converger, donc les périodes récentes. J'enlève l'année n+1 qui correspond au in-sample n, dans la mesure où elle est égale par construction
image

@arnaud-feldmann
Copy link
Member

J'ai rajouté un onglet dans le modify de l'app Shiny
image

Je vous laisse checker si ça vous convient et faire éventuellement des petites adaptations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants