55147e94ab99c32da939f38c2e14b01ad2ef0258
[talweg.git] / reports / Experiments.gj
1 -----
2 # Résultats numériques
3
4 Cette partie montre les résultats obtenus avec des variantes de l'algorithme décrit à la
5 section 4, en utilisant le package présenté au chapitre précédent. Cet algorithme est
6 systématiquement comparé à deux approches naïves :
7
8 * la moyenne des lendemains des jours "similaires" dans tout le passé, c'est-à-dire
9 prédiction = moyenne de tous les mardis passés si le jour courant est un lundi.
10 * la persistence, reproduisant le jour courant ou allant chercher le lendemain de la
11 dernière journée "similaire" (même principe que ci-dessus ; argument "same\_day").
12
13 Concernant l'algorithme principal à voisins, deux variantes sont comparées dans cette
14 partie :
15
16 * avec simtype="mix" et raccordement "Neighbors" dans le cas "non local", i.e. on va
17 chercher des voisins n'importe où du moment qu'ils correspondent au premier élément d'un
18 couple de deux jours consécutifs sans valeurs manquantes.
19 * avec simtype="none" (moyenne simple) et raccordement=NULL (aucun ajustement après
20 moyenne des courbes) dans le cas "local" : voisins de même niveau de pollution et même
21 saison.
22
23 Pour chaque période retenue $-$ chauffage, épandage, semaine non polluée $-$ les erreurs
24 de prédiction sont d'abord affichées, puis quelques graphes de courbes réalisées/prévues
25 (sur le jour "en moyenne le plus facile" à gauche, et "en moyenne le plus difficile" à
26 droite). Ensuite plusieurs types de graphes apportant des précisions sur la nature et la
27 difficulté du problème viennent compléter ces premières courbes. Concernant les graphes
28 de filaments, la moitié droite du graphe correspond aux jours similaires au jour courant,
29 tandis que la moitié gauche affiche les jours précédents : ce sont donc les voisinages
30 tels qu'utilisés dans l'algorithme.
31 <%
32 list_titles = ['Pollution par chauffage','Pollution par épandage','Semaine non polluée']
33 list_indices = ['indices_ch', 'indices_ep', 'indices_np']
34 %>
35 -----r
36 library(talweg)
37
38 P = ${P} #première heure de prévision
39 H = ${H} #dernière heure de prévision
40
41 ts_data = read.csv(system.file("extdata","pm10_mesures_H_loc_report.csv",
42 package="talweg"))
43 exo_data = read.csv(system.file("extdata","meteo_extra_noNAs.csv",
44 package="talweg"))
45 # NOTE: 'GMT' because DST gaps are filled and multiple values merged in
46 # above dataset. Prediction from P+1 to P+H included.
47 data = getData(ts_data, exo_data)
48
49 indices_ch = seq(as.Date("2015-01-19"),as.Date("2015-01-25"),"days")
50 indices_ep = seq(as.Date("2015-03-16"),as.Date("2015-03-22"),"days")
51 indices_np = seq(as.Date("2015-04-27"),as.Date("2015-05-03"),"days")
52 % for i in range(3):
53 -----
54 ##<h2 style="color:blue;font-size:2em">${list_titles[i]}</h2>
55 ${"##"} ${list_titles[i]}
56 -----r
57 p1 = computeForecast(data, ${list_indices[i]}, "Neighbors", "Neighbors", predict_from=P,
58 horizon=H, simtype="mix", local=FALSE)
59 p2 = computeForecast(data, ${list_indices[i]}, "Neighbors", NULL, predict_from=P,
60 horizon=H, simtype="none", local=TRUE)
61 p3 = computeForecast(data, ${list_indices[i]}, "Average", "Zero", predict_from=P,
62 horizon=H)
63 p4 = computeForecast(data, ${list_indices[i]}, "Persistence", "Zero", predict_from=P,
64 horizon=H, same_day=${'TRUE' if loop.index < 2 else 'FALSE'})
65 -----r
66 e1 = computeError(data, p1, P, H)
67 e2 = computeError(data, p2, P, H)
68 e3 = computeError(data, p3, P, H)
69 e4 = computeError(data, p4, P, H)
70 options(repr.plot.width=9, repr.plot.height=7)
71 plotError(list(e1, e4, e3, e2), cols=c(1,2,colors()[258],4))
72
73 # noir: Neighbors non-local (p1), bleu: Neighbors local (p2),
74 # vert: moyenne (p3), rouge: persistence (p4)
75
76 sum_p23 = e2$abs$indices + e3$abs$indices
77 i_np = which.min(sum_p23) #indice de jour "facile"
78 i_p = which.max(sum_p23) #indice de jour "difficile"
79 -----
80 % if i == 0:
81 L'erreur absolue -- en haut à gauche -- reste modérée pour les meilleurs modèles
82 (variantes à voisins), ne dépassant 10 que deux jours. Les deux modèles naïfs ont des
83 erreurs similaires sauf sur la période "difficile" (jours 4 à 6), sur laquelle on gagne
84 donc à chercher des jours similaires pour effectuer la prévision.
85 Le MAPE reste en général inférieur à 35% pour les meilleurs méthodes.
86 % elif i == 1:
87 Le modèle à voisins avec contrainte de localité obtient ici les meilleurs résultats, son
88 erreur étant clairement en dessous des autres à partir du jour 4 (graphe en haut à
89 droite). Le MAPE jour après jour est du même ordre que précédemment pour cette méthode
90 (35%, graphe en bas à droite) sauf un jour sur lequel le MAPE explose.
91 % else:
92 Dans ce cas plus favorable les intensité des erreurs absolues ont clairement diminué :
93 elles sont souvent en dessous de 5. En revanche le MAPE moyen reste en général au-delà de
94 20%. Comme dans le cas de l'épandage on constate une croissance globale de la courbe
95 journalière d'erreur absolue moyenne (en haut à gauche) -- sauf pour la méthode à voisins
96 "locale" ; ceci peut être dû au fait que l'on ajuste le niveau du jour à prédire en le
97 recollant sur la dernière valeur observée (sauf pour "Neighbors local").
98 % endif
99 -----r
100 options(repr.plot.width=9, repr.plot.height=4)
101 par(mfrow=c(1,2))
102
103 plotPredReal(data, p1, i_np); title(paste("PredReal p1 day",i_np))
104 plotPredReal(data, p1, i_p); title(paste("PredReal p1 day",i_p))
105
106 plotPredReal(data, p2, i_np); title(paste("PredReal p2 day",i_np))
107 plotPredReal(data, p2, i_p); title(paste("PredReal p2 day",i_p))
108
109 # Bleu : prévue ; noir : réalisée (confondues jusqu'à predict_from-1)
110 -----
111 % if i == 0:
112 Le jour "facile à prévoir", à gauche, se décompose en deux modes : un léger vers 10h
113 (7+3), puis un beaucoup plus marqué vers 19h (7+12). Ces deux modes sont retrouvés par
114 les deux variantes de l'algorithme à voisins, bien que l'amplitude soit mal prédite.
115 Concernant le jour "difficile à prévoir" (à droite) il y a deux pics en tout début et
116 toute fin de journée (à 9h et 23h), qui ne sont pas du tout anticipés par les méthodes ;
117 la grande amplitude de ces pics explique alors l'intensité de l'erreur observée.
118 % elif i == 1:
119 Dans le cas d'un jour "facile" à prédire $-$ à gauche $-$ la forme est plutôt bien
120 retrouvée, ainsi que le niveau moyen pour la méthode sans contrainte de localité
121 (dans l'autre, l'algorithme a probablement écarté trop de voisins potentiels).
122 Concernant le jour "difficile" à droite, non seulement la forme n'est pas anticipée mais
123 surtout le niveau prédit est largement supérieur au niveau de pollution observé -- dans
124 une moindre mesure toutefois pour la variante "locale".
125 % else:
126 L'impression visuelle est plutôt mauvaise dans ce cas, mais les écart étant minimes les
127 erreurs au final ne sont pas très importantes. De plus deux des quatres graphes sont
128 satisfaisants (en haut à droite et en bas à gauche : forme + niveau acceptables.
129 % endif
130 -----r
131 par(mfrow=c(1,2))
132
133 f_np1 = computeFilaments(data, p1, i_np, plot=TRUE)
134 title(paste("Filaments p1 day",i_np))
135
136 f_p1 = computeFilaments(data, p1, i_p, plot=TRUE)
137 title(paste("Filaments p1 day",i_p))
138
139 f_np2 = computeFilaments(data, p2, i_np, plot=TRUE)
140 title(paste("Filaments p2 day",i_np))
141
142 f_p2 = computeFilaments(data, p2, i_p, plot=TRUE)
143 title(paste("Filaments p2 day",i_p))
144 -----
145 % if i == 0:
146 Les voisins du jour courant (période de 24h allant de 8h à 7h le lendemain) sont affichés
147 avec un trait d'autant plus sombre qu'ils sont proches. On constate dans le cas non
148 contraint (en haut) une grande variabilité des lendemains, très nette sur le graphe en
149 haut à droite. Ceci indique une faible corrélation entre la forme d'une courbe sur une
150 période de 24h et la forme sur les 24h suivantes ; **cette observation est la source des
151 difficultés rencontrées par l'algorithme sur ce jeu de données.**
152 % elif i == 1:
153 Les observations sont les mêmes qu'au paragraphe précédent : trop de variabilité des
154 voisins (et ce même le jour précédent).
155 % else:
156 Les graphes de filaments ont encore la même allure, avec une assez grande variabilité
157 observée. Cette observation est cependant trompeuse, comme l'indique plus bas le graphe
158 de variabilité relative.
159 % endif
160 -----r
161 par(mfrow=c(1,2))
162
163 plotFilamentsBox(data, f_np1, predict_from=P)
164 title(paste("FilBox p1 day",i_np))
165
166 plotFilamentsBox(data, f_p1, predict_from=P)
167 title(paste("FilBox p1 day",i_p))
168
169 # En pointillés la courbe du jour courant (à prédire) + précédent
170 -----
171 % if i == 0:
172 Sur cette boxplot fonctionnelle (voir la fonction fboxplot() du package R "rainbow") on
173 constate essentiellement deux choses : le lendemain d'un voisin "normal" peut se révéler
174 être une courbe atypique, fort éloignée de ce que l'on souhaite prédire (courbes bleue et
175 rouge à gauche) ; et, dans le cas d'une courbe à prédire atypique (à droite) la plupart
176 des voisins sont trop éloignés de la forme à prédire et forcent ainsi un aplatissement de
177 la prédiction.
178 % elif i == 1:
179 Concernant le jour "difficile" on constate la présence de voisins au lendemains
180 complètement atypiques avec un pic en début de journée (courbes en vert et rouge à
181 droite). Ajouté au fait que le jour à prévoir est lui-même "hors norme", cela montre
182 l'impossibilité de bien prévoir une courbe en utilisant l'algorithme à voisins.
183 % else:
184 On peut réappliquer les mêmes remarques qu'auparavant sur les boxplots fonctionnels :
185 voisins atypiques, courbe à prévoir elle-même légèrement "hors norme".
186 % endif
187 -----r
188 par(mfrow=c(1,2))
189
190 plotRelVar(data, f_np1, predict_from=P)
191 title(paste("StdDev p1 day",i_np))
192
193 plotRelVar(data, f_p1, predict_from=P)
194 title(paste("StdDev p1 day",i_p))
195
196 plotRelVar(data, f_np2, predict_from=P)
197 title(paste("StdDev p2 day",i_np))
198
199 plotRelVar(data, f_p2, predict_from=P)
200 title(paste("StdDev p2 day",i_p))
201
202 # Variabilité globale en rouge ; sur les voisins en noir
203 -----
204 % if i == 0:
205 Ces graphes viennent confirmer l'impression visuelle après observation des filaments. En
206 effet, la variabilité globale en rouge (écart-type heure par heure sur l'ensemble des
207 couples "hier/aujourd'hui" du passé) devrait rester nettement au-dessus de la
208 variabilité locale, calculée respectivement sur un voisinage d'une soixantaine de jours
209 (pour p1) et d'une dizaine de jours (pour p2). Or ce n'est pas du tout le cas sur la
210 moitié droite, sauf pour le jour "facile" avec l'algorithme "local".
211 % elif i == 1:
212 Comme précédemment les variabilités locales et globales sont trop proches dans les
213 parties droites des graphes pour le jour "difficile". L'allure des graphes est
214 raisonnable ppour l'autre jour, qui est d'ailleurs bien prédit.
215 % else:
216 Cette fois la situation idéale est observée : la variabilité globale est nettement
217 au-dessus de la variabilité locale. Bien que cela ne suffise pas à obtenir de bonnes
218 prédictions de forme, on constate au moins l'amélioration dans la prédiction du niveau.
219 % endif
220 -----r
221 plotSimils(p1, i_np)
222 title(paste("Weights p1 day",i_np))
223
224 plotSimils(p1, i_p)
225 title(paste("Weights p1 day",i_p))
226
227 # Poids < 1/N à gauche, >= 1/N à droite ; jour facile en haut, difficile en bas
228 -----
229 % if i == 0:
230 Les poids se concentrent près de 0 : c'est ce que l'on souhaite observer pour éviter
231 d'effectuer une simple moyenne.
232 % elif i == 1:
233 En comparaison avec le paragraphe précédent on retrouve le même (bon) comportement des
234 poids pour la version "non locale".
235 % else:
236 Concernant les poids en revanche, deux cas a priori mauvais se cumulent : ...
237 % endif
238 -----r
239 options(digits=2)
240
241 p1$getParams(i_np)$window
242 p1$getParams(i_p)$window
243
244 # Fenêtres sélectionnées dans ]0,7]
245 % endfor
246 -----
247 ${"##"} Bilan
248
249 Nos algorithmes à voisins donnent de meilleurs résultats que les approches naïves
250 (persistence, moyenne sur tout le jeu de données). Les erreurs restent cependant assez
251 élevées, notamment en terme de MAPE. Une possible poste d'amélioration consisterait à
252 aggréger les courbes spatialement (sur plusieurs stations situées dans la même
253 agglomération ou dans une même zone).