On a les données de 2 stations: Besançon (relevés amateurs) et Besançon-Thyse (Météo France) séparées de 2 km et toutes les deux à plus de 10 km du point d’enregistrement. En plus, meteociel.fr permet aussi d’avoir accès aux données historique.
infoclimat <- read_rds("infoclimat.rds")
infoclimat_t <- read_rds("infoclimat_t.rds")
meteociel <- read_rds("meteociel.rds")
On s’intéresse à analyser la cohérence et la précision des relevés suivants: température, force du vent, direction du vent, précipitation. De plus, on inclut la pression et l’humidité qui peuvent être moins sensible à la localisation. On ignore donc la biométéo, les radiation, le point de rosée et la visibilité.
On va commencer par afficher les relevés sur une période de 3 jours au cœur de la période étudié (à partir du 1er septembre 2018) avec les données de la station amateur.
infoclimat %>%
gather(mesure, valeur, Température, pluie_heure, Humidité, vent_heure,
direction, Pression) %>%
filter(Heure > make_date(2018, 9, 1)) %>%
filter(Heure < make_date(2018, 9, 4)) %>%
ggplot(aes(x = Heure, y = valeur)) +
facet_wrap(~ mesure, scales = "free_y") +
geom_point(size = 1)
## Warning: Removed 360 rows containing missing values (geom_point).
On observe des phénomènes journaliers sur la direction des vents. D’autre part, la direction du vent prend une certaine valeur lorsque sa force est nulle. Finalement, la force des vents semble prendre des valeurs discrètes.
directions <- sort(unique(infoclimat$direction))
table(tail(directions, -1) - head(directions, -1))
##
## 1 2 3 4 5
## 329 5 1 2 1
speed <- sort(unique(infoclimat$vent_heure))
table(tail(speed, -1) - head(speed, -1))
##
## 1 2
## 7 11
La direction semble précise à un degré près, tandis que la force semble l’être à 1 ou 2 km/h.
On étudie la relation entre heure de la journée et direction du vent (lors qu’il est de force non-nulle) sur la période de l’étude (du 22/8 au 30/10).
infoclimat %>%
filter(vent_heure != 0) %>%
filter(Heure > make_date(2018, 8, 22)) %>%
filter(Heure < make_date(2018, 10, 31)) %>%
mutate(Heure_jour = hms::hms(hours = hour(Heure), minutes = minute(Heure))) %>%
ggplot(aes(x = Heure_jour, y = direction, color = Heure)) +
geom_point(size = 0.3) +
scale_y_continuous(breaks = (0:4) * 90) +
scale_x_time(breaks = hms::hms(hours = (0:4) * 6))
Si le vent vient parfois du sud-ouest/ouest entre 12h et 20h, il est principalement du nord-est durant la nuit.
On peut confirmer ces observations avec une rose des vents (entre 22h et 5h).
# compass rose
infoclimat %>%
filter(vent_heure != 0) %>%
filter(Heure > make_date(2018, 8, 22)) %>%
filter(Heure < make_date(2018, 10, 31)) %>%
filter(hour(Heure) < 5 | 22 < hour(Heure)) %>%
ggplot(aes(x = direction,
fill = cut_number(pmax(0, jitter(vent_heure)), 5))) +
geom_histogram(breaks = (0:16) * (360 / 16)) +
# geom_density(aes(y = stat(count)), position = "stack") +
# expand_limits(x = 0) +
scale_x_continuous(breaks = (0:3) * 90) +
scale_fill_viridis_d("Wind speed") +
coord_polar()
On constate une dominance très forte des vents du nord-est (toute vitesse confondue).
La dernière mesure d’intérêt est la pluie et il y a deux types de relevés pour la pluie. Commençons par trouver une période pluvieuse.
infoclimat %>%
mutate(day = date(Heure)) %>%
group_by(day) %>%
summarise(pluie = sum(pluie_heure, na.rm = TRUE)) %>%
arrange(desc(pluie)) %>%
head()
## # A tibble: 6 x 2
## day pluie
## <date> <dbl>
## 1 2018-09-06 10.6
## 2 2018-09-23 7.6
## 3 2018-10-30 7.2
## 4 2018-10-29 6.6
## 5 2018-08-13 6
## 6 2018-08-25 5.6
Le 6 septembre est le jour le plus pluvieux. Observons les deux relevé de pluie.
infoclimat %>%
gather(mesure, valeur, pluie_heure, pluie_inst) %>%
filter(Heure > make_date(2018, 9, 6)) %>%
filter(Heure < make_date(2018, 9, 7)) %>%
ggplot(aes(x = Heure, y = valeur)) +
facet_wrap(~ mesure, scales = "free_y", nrow = 2) +
geom_point()
## Warning: Removed 251 rows containing missing values (geom_point).
Les deux types de relevés pour la pluie semblent cohérents.
(pluie_data <- infoclimat %>%
mutate(Heure_heure = ceiling_date(Heure, "1 hour")) %>%
group_by(Heure_heure) %>%
summarise(pluie_heure = max(pluie_heure, na.rm = TRUE),
pluie_inst_agg = sum(pluie_inst, na.rm = TRUE) / 6) %>%
arrange(pluie_heure, desc(pluie_inst_agg)))
## # A tibble: 2,209 x 3
## Heure_heure pluie_heure pluie_inst_agg
## <dttm> <dbl> <dbl>
## 1 2018-08-25 21:00:00 -Inf 2.57
## 2 2018-08-09 02:00:00 -Inf 1.8
## 3 2018-08-09 16:00:00 -Inf 0.667
## 4 2018-08-09 13:00:00 -Inf 0.20
## 5 2018-08-01 09:00:00 -Inf 0
## 6 2018-08-01 10:00:00 -Inf 0
## 7 2018-08-01 11:00:00 -Inf 0
## 8 2018-08-01 12:00:00 -Inf 0
## 9 2018-08-01 13:00:00 -Inf 0
## 10 2018-08-01 14:00:00 -Inf 0
## # … with 2,199 more rows
pluie_data %>%
filter(is.finite(pluie_heure)) %>%
summarise(corr = cor(pluie_heure, pluie_inst_agg))
## # A tibble: 1 x 1
## corr
## <dbl>
## 1 0.838
pluie_data %>%
ggplot(aes(x = pluie_heure, y = pluie_inst_agg, color = Heure_heure)) +
geom_point() +
stat_smooth(method = "lm")
## Warning: Removed 71 rows containing non-finite values (stat_smooth).
Les deux types de relevés sont corrélés malgré quelques valeurs manquantes pour la pluie par heure. La qualité de la données pluviométriques est donc discutable mais on peut au moins espérer avoir une indication qualitative sur les jours pluvieux à défaut d’avoir des données quantitatives fiables.
Vérifions la cohérence entre l’humidité et la pluie:
infoclimat %>%
mutate(Heure_heure = ceiling_date(Heure, "1 hour")) %>%
group_by(Heure_heure) %>%
summarise(Humidité = max(Humidité, na.rm = TRUE),
pluie_heure = max(pluie_heure, na.rm = TRUE),
pluie_inst_agg = sum(pluie_inst, na.rm = TRUE) / 6) %>%
filter(pluie_heure > 0 | pluie_inst_agg > 0) %>%
ggplot(aes(x = Humidité)) +
stat_ecdf()
Les trois-quarts des journées pluvieuse présentent une humidité maximale supérieure à 90%.
On se focalise d’abord sur la même période de 3 jours.
infoclimat_t %>%
gather(mesure, valeur, Température, Pluie, Humidité, direction, Pression,
vent_heure) %>%
filter(Heure > make_date(2018, 9, 1)) %>%
filter(Heure < make_date(2018, 9, 4)) %>%
ggplot(aes(x = Heure, y = valeur)) +
facet_wrap(~ mesure, scales = "free_y") +
geom_rect(aes(xmin = coucher, ymin = -Inf, xmax = lever, ymax = Inf)) +
geom_point(size = 1)
On observe les mêmes phénomènes avec cependant aucune précipitation et des valeurs de forces de vent encore plus discrètes.
directions <- sort(unique(infoclimat_t$direction))
table(tail(directions, -1) - head(directions, -1))
##
## 10
## 36
speed <- sort(unique(infoclimat_t$vent_heure))
table(tail(speed, -1) - head(speed, -1))
##
## 2 3 4
## 2 2 3
La direction est précise à 10 degrés près, tandis que la force semble l’être à 2, voire 4 km/h.
On étudie à nouveau la relation entre heure de la journée et direction du vent.
infoclimat_t %>%
filter(vent_heure != 0) %>%
filter(Heure > make_date(2018, 8, 22)) %>%
filter(Heure < make_date(2018, 10, 31)) %>%
mutate(Heure_jour = hms::hms(hours = hour(Heure), minutes = minute(Heure))) %>%
ggplot(aes(x = Heure_jour, y = direction, color = Heure)) +
geom_jitter(size = 0.3) +
scale_y_continuous(breaks = (0:4) * 90) +
scale_x_time(breaks = hms::hms(hours = (0:4) * 6))
Les résultats sont similaires. On refait une rose des vents.
# compass rose
infoclimat_t %>%
filter(vent_heure != 0) %>%
filter(Heure > make_date(2018, 8, 22)) %>%
filter(Heure < make_date(2018, 10, 31)) %>%
filter(hour(Heure) < 5 | 22 < hour(Heure)) %>%
ggplot(aes(x = direction,
fill = cut_number(pmax(0, jitter(vent_heure)), 5))) +
geom_histogram(breaks = (0:16) * (360 / 16)) +
# geom_density(aes(y = stat(count)), position = "stack") +
# expand_limits(x = 0) +
scale_x_continuous(breaks = (0:3) * 90) +
scale_fill_viridis_d("Wind speed") +
coord_polar()
Même dominance avec des vents qui viennent un peu plus du nord, mais qui restent quand même orientés nord-est.
Vérifions à nouveau la cohérence entre l’humidité et la pluie:
infoclimat_t %>%
filter(Pluie > 0) %>%
ggplot(aes(x = Humidité)) +
stat_ecdf()
Les deux-tiers des journées pluvieuse présentent une humidité maximale supérieure à 90%.
Comparons que les données accessible sur meteociel.fr sont les mêmes.
meteociel %>%
left_join(infoclimat_t, by = c("Heurelocale" = "Heure")) %>%
mutate(Pression = Pression.x - Pression.y,
Température = Température.x - Température.y,
Humidité = Humidité.x - Humidité.y,
Pluie = Pluie - `Précip./h`,
Vent = Vent - vent_heure) %>%
select(Pression, Température, Humidité, Pluie, Vent) %>%
summary()
## Pression Température Humidité Pluie Vent
## Min. :0 Min. :0 Min. :0.00000 Min. :0 Min. :-2.0000
## 1st Qu.:0 1st Qu.:0 1st Qu.:0.00000 1st Qu.:0 1st Qu.:-1.0000
## Median :0 Median :0 Median :0.00000 Median :0 Median : 0.0000
## Mean :0 Mean :0 Mean :0.02273 Mean :0 Mean :-0.4214
## 3rd Qu.:0 3rd Qu.:0 3rd Qu.:0.00000 3rd Qu.:0 3rd Qu.: 0.0000
## Max. :0 Max. :0 Max. :1.00000 Max. :0 Max. : 2.0000
## NA's :2 NA's :2 NA's :2 NA's :7 NA's :2
meteociel %>%
left_join(infoclimat_t, by = c("Heurelocale" = "Heure")) %>%
filter(Vent != 0) %>%
ggplot(aes(x = direction.x, y = direction.y)) +
geom_jitter(size = 1)
## Warning: Removed 2 rows containing missing values (geom_point).
C’est correct, à quelques pourcents près.
Comparons la proximité entre les données des deux stations météorologiques de Besançon.
meteo <- infoclimat %>%
full_join(infoclimat_t, by = "Heure")
meteo %>%
mutate(Pression = Pression.x - Pression.y,
Température = Température.x - Température.y,
Humidité = Humidité.x - Humidité.y,
Pluie = ifelse(pluie_heure == 0 & Pluie == 0, NA, pluie_heure - Pluie),
Direction = ifelse(vent_heure.x == 0 & vent_heure.y == 0, NA,
pmin((direction.x - direction.y + 360) %% 360,
(direction.y - direction.x + 360) %% 360)),
Vent = ifelse(vent_heure.x == 0 & vent_heure.y == 0, NA,
vent_heure.x - vent_heure.y)) %>%
select(Pression, Température, Humidité, Pluie, Direction, Vent) %>%
summary()
## Pression Température Humidité Pluie
## Min. :-1.700 Min. :-3.800 Min. :-17.000 Min. :-6.400
## 1st Qu.:-0.875 1st Qu.:-0.500 1st Qu.: -3.000 1st Qu.:-0.350
## Median :-0.400 Median : 0.100 Median : 2.000 Median :-0.200
## Mean :-0.368 Mean : 0.335 Mean : 1.529 Mean :-0.306
## 3rd Qu.: 0.100 3rd Qu.: 1.000 3rd Qu.: 6.000 3rd Qu.: 0.000
## Max. : 1.400 Max. : 4.100 Max. : 17.000 Max. : 3.200
## NA's :11023 NA's :11023 NA's :11023 NA's :13038
## Direction Vent
## Min. : 0.00 Min. :-9.000
## 1st Qu.: 15.00 1st Qu.:-3.000
## Median : 30.00 Median :-1.000
## Mean : 38.31 Mean : 0.203
## 3rd Qu.: 52.00 3rd Qu.: 3.000
## Max. :178.00 Max. :14.000
## NA's :11353 NA's :11353
Les données les plus continues et qui sont susceptibles de peu dépendre de la localité sont la pression, la température et l’humidité. On observe effectivement une grande cohérence entre les pressions et des valeurs assez proches pour la température et l’humidité bien qu’il y ait des différences de quelques degrés pour la température et jusqu’à plus de 10 % de différence pour l’humidité.
meteo %>%
drop_na(Pression.x, Pression.y, Température.x, Température.y, Humidité.x,
Humidité.y) %>%
summarise(corr_pression = cor(Pression.x, Pression.y),
corr_temp = cor(Température.x, Température.y),
corr_humi = cor(Humidité.x, Humidité.y))
## # A tibble: 1 x 3
## corr_pression corr_temp corr_humi
## <dbl> <dbl> <dbl>
## 1 0.995 0.988 0.970
Les corrélations confirment ces similarités.
Étant un phénomène ponctuel, la pluie demandent à être analysée plus finement. Par ailleurs, même si pour la moitié des relevés, les forces du vent sont à 3 km/h l’un de l’autre et les directions à moins de 30 °, les valeurs restantes peuvent beaucoup différer.
Trouvons une période ou les données sur la pluie diffèrent le plus.
(pluie_coher <- meteo %>%
mutate(Heure_heure = ceiling_date(Heure, "1 hour")) %>%
group_by(Heure_heure) %>%
summarise(pluie_heure = max(0, pluie_heure, na.rm = TRUE),
pluie_inst_agg = sum(pluie_inst, na.rm = TRUE) / 6,
Pluie = max(0, Pluie, na.rm = TRUE)) %>%
mutate(day = date(Heure_heure)) %>%
group_by(day) %>%
summarise(pluie = sum(pluie_heure, na.rm = TRUE),
pluie_inst = sum(pluie_inst_agg, na.rm = TRUE),
pluie_t = sum(Pluie, na.rm = TRUE)) %>%
arrange(desc(abs(pluie - pluie_t))))
## # A tibble: 93 x 4
## day pluie pluie_inst pluie_t
## <date> <dbl> <dbl> <dbl>
## 1 2018-08-09 0 2.67 21.9
## 2 2018-09-06 10.6 13.6 23.6
## 3 2018-08-13 6 4.67 12.8
## 4 2018-08-23 4 3 9
## 5 2018-08-25 5.6 8.47 9.9
## 6 2018-09-21 5.6 6.53 8.9
## 7 2018-08-14 1.8 2.17 3.9
## 8 2018-09-23 7.6 17.9 9.6
## 9 2018-09-07 0.6 0 2.5
## 10 2018-10-30 7.2 2.6 5.8
## # … with 83 more rows
pluie_coher %>%
summarise(corr1 = cor(pluie, pluie_t), corr2 = cor(pluie_inst, pluie_t))
## # A tibble: 1 x 2
## corr1 corr2
## <dbl> <dbl>
## 1 0.777 0.761
pluie_coher %>%
gather(type, valeur, pluie, pluie_inst) %>%
ggplot(aes(x = pluie_t, y = valeur)) +
geom_point() +
facet_wrap(~ type) +
stat_smooth(method = "lm")
Le 9 août est le jour où les différences sont le plus marquées. Observons les données pluviométriques sur cette journée.
meteo %>%
gather(mesure, valeur, pluie_heure, pluie_inst, Pluie) %>%
filter(Heure > make_date(2018, 8, 9)) %>%
filter(Heure < make_date(2018, 8, 10)) %>%
ggplot(aes(x = Heure, y = valeur)) +
facet_wrap(~ mesure, scales = "free_y", nrow = 3) +
geom_point()
## Warning: Removed 358 rows containing missing values (geom_point).
La différence est essentiellement dû à des données manquantes. Cependant, les précipitations peuvent sensiblement varier en fonction de l’endroit, ce qui confirme l’utilité surtout qualitative de cette donnée (journée pluvieuse ou non) avec éventuellement une indication générale de la quantité des précipitations (beaucoup, moyenne, peu).
Pour le vent, la présence de deux variables complique l’analyse. Commençons par la force.
meteo %>%
filter(!is.na(vent_heure.x) & !is.na(vent_heure.y)) %>%
filter(vent_heure.x != 0 | vent_heure.y != 0) %>%
summarise(corr = cor(vent_heure.x, vent_heure.y))
## # A tibble: 1 x 1
## corr
## <dbl>
## 1 0.593
meteo %>%
filter(vent_heure.x != 0 | vent_heure.y != 0) %>%
ggplot(aes(x = vent_heure.x, y = vent_heure.y)) +
geom_jitter(size = 1) +
geom_abline(slope = 1)
## Warning: Removed 7955 rows containing missing values (geom_point).
La force du vent présente une forte variabilité et une faible corrélation entre les stations.
Étudions la direction observée.
meteo %>%
filter(vent_heure.x != 0 & vent_heure.y != 0) %>%
ggplot(aes(x = direction.x, y = direction.y, color = vent_heure.x)) +
geom_jitter(size = 1) +
geom_hline(yintercept = (0:8) * 360/8 + 360/16) +
geom_vline(xintercept = (0:8) * 360/8 + 360/16) +
geom_abline(slope = 1) +
scale_color_viridis_c()
On remarque quelques données proches de 360 ° assez alignées.
meteo %>%
filter(direction.x > 350) %>%
filter(200 < direction.y & direction.y < 300) %>%
select(direction.x, vent_heure.x, vent_heure.y) %>%
summary()
## direction.x vent_heure.x vent_heure.y
## Min. :360 Min. : 0.000 Min. : 4.000
## 1st Qu.:360 1st Qu.: 2.000 1st Qu.: 4.000
## Median :360 Median : 5.000 Median : 7.000
## Mean :360 Mean : 6.476 Mean : 6.524
## 3rd Qu.:360 3rd Qu.: 8.000 3rd Qu.: 7.000
## Max. :360 Max. :18.000 Max. :11.000
Cela ne ressemble pas à une erreur liée à des vents de faible amplitude. C’est peut-être des erreurs de mesures. Peu de données semblent impactées.
La pression semble extrêmement stable, suivi de la température et de l’humidité. Pour les précipitations, il faut sans doute agréger les données en quelques catégories sur une journée entière. Pour le vent, à la fois la direction et la force sont assez stables la moitié du temps, mais les différences peuvent cependant être importantes.
## R version 3.6.1 (2019-07-05)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.3 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/openblas/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so
##
## locale:
## [1] LC_CTYPE=fr_FR.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=fr_FR.UTF-8 LC_COLLATE=fr_FR.UTF-8
## [5] LC_MONETARY=fr_FR.UTF-8 LC_MESSAGES=fr_FR.UTF-8
## [7] LC_PAPER=fr_FR.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] tidyr_0.8.3 readr_1.3.1 lubridate_1.7.4 ggplot2_3.2.0
## [5] dplyr_0.8.3
##
## loaded via a namespace (and not attached):
## [1] Rcpp_1.0.1 pillar_1.4.2 compiler_3.6.1
## [4] tools_3.6.1 zeallot_0.1.0 digest_0.6.20
## [7] evaluate_0.14 tibble_2.1.3 gtable_0.3.0
## [10] viridisLite_0.3.0 pkgconfig_2.0.2 rlang_0.4.0
## [13] cli_1.1.0 yaml_2.2.0 xfun_0.8
## [16] withr_2.1.2 stringr_1.4.0 knitr_1.23
## [19] vctrs_0.2.0 hms_0.5.0 grid_3.6.1
## [22] tidyselect_0.2.5 glue_1.3.1 R6_2.4.0
## [25] fansi_0.4.0 rmarkdown_1.14 purrr_0.3.2
## [28] magrittr_1.5 scales_1.0.0 backports_1.1.4
## [31] htmltools_0.3.6 assertthat_0.2.1 colorspace_1.4-1
## [34] labeling_0.3 utf8_1.1.4 stringi_1.4.3
## [37] lazyeval_0.2.2 munsell_0.5.0 crayon_1.3.4