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