Reformulations
This commit is contained in:
parent
8b26c0bf17
commit
f4bdbe2c7f
@ -2,7 +2,8 @@
|
||||
|
||||
## Installation de l'environnement de base
|
||||
|
||||
Après avoir cloné le dépôt :
|
||||
Après avoir cloné le dépôt, on commence par préparer un environnement Python isolé pour ne pas polluer le système global et pouvoir supprimer facilement tout ce qui concerne ce projet.
|
||||
L’idée est de regrouper au même endroit le moteur [`Python`](https://www.python.org/), les bibliothèques scientifiques et le client pour la base de données [`InfluxDB`](https://www.influxdata.com/), qui stocke nos séries temporelles.
|
||||
|
||||
```shell
|
||||
python3 -m venv .venv
|
||||
@ -12,11 +13,11 @@ pip install -r requirements.txt
|
||||
python -c "import pandas, influxdb_client, sklearn; print('OK')"
|
||||
```
|
||||
|
||||
- On installe l'environnement virtuel de python
|
||||
- On entre dans cet environnement
|
||||
- On met à jour le gestionnaire de paquets pip
|
||||
- On installe les dépendances définies dans `requirements.txt`
|
||||
- On vérifie que les dépendances sont correctement installées
|
||||
- `python3 -m venv .venv` crée un environnement virtuel Python local dans le dossier `.venv`, ce qui permet d’isoler les paquets de ce projet du reste du système (voir par exemple la documentation sur les environnements virtuels [`venv`](https://docs.python.org/fr/3/library/venv.html)).
|
||||
- `source .venv/bin/activate` active cet environnement dans le shell courant ; tant qu’il est actif, la commande `python` pointera vers l’interpréteur de `.venv` et non vers celui du système.
|
||||
- `python -m pip install --upgrade pip` met à jour [`pip`](https://pip.pypa.io/), le gestionnaire de paquets de Python, afin d’éviter les bugs ou limitations des versions trop anciennes.
|
||||
- `pip install -r requirements.txt` installe toutes les dépendances nécessaires au projet (notamment [`pandas`](https://pandas.pydata.org/), le client Python pour InfluxDB et [`scikit-learn`](https://scikit-learn.org/stable/) pour les modèles prédictifs) en suivant la liste déclarée dans `requirements.txt`.
|
||||
- `python -c "import pandas, influxdb_client, sklearn; print('OK')"` vérifie que les principales bibliothèques s’importent correctement ; si la commande affiche `OK`, l’environnement de base est prêt à être utilisé.
|
||||
|
||||
## Configuration
|
||||
|
||||
@ -24,23 +25,26 @@ python -c "import pandas, influxdb_client, sklearn; print('OK')"
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
On copie le fichier de configuration d'exemple, puis on l'ouvre pour l'adapter à notre cas.
|
||||
On copie le fichier de configuration d'exemple, puis on l'ouvre pour l'adapter à notre cas. Ce fichier `.env` sera lu automatiquement par les scripts via [`python-dotenv`](https://github.com/theskumar/python-dotenv) (voir `meteo/config.py`), ce qui évite d’exporter les variables à la main à chaque session.
|
||||
|
||||
- `INFLUXDB_URL` : URL de l'api du serveur InfluxDB2 (cela inclue probablement le port 8086)
|
||||
- `INFLUXDB_TOKEN` : le jeton d'authentification à créer dans votre compte InfluxDB2
|
||||
- `INFLUXDB_ORG` : l'organisation à laquelle le token est rattaché
|
||||
- `INFLUXDB_BUCKET` : le nom du bucket dans lequel les données sont stockées
|
||||
- `STATION_LATITUDE` : latitude GPS de la station météo
|
||||
- `STATION_LONGITUDE` : longitude GPS de la station météo
|
||||
- `STATION_ELEVATION` : altitude de la station météo
|
||||
- `INFLUXDB_URL` : URL de l'API du serveur InfluxDB 2.x (incluant généralement le port 8086), par exemple `http://localhost:8086` ou l’adresse de votre serveur ; c’est le point d’entrée HTTP/HTTPS vers votre base de données de séries temporelles (voir aussi l’introduction aux [bases de données de séries temporelles](https://fr.wikipedia.org/wiki/Base_de_donn%C3%A9es_de_s%C3%A9ries_temporelles)).
|
||||
- `INFLUXDB_TOKEN` : jeton d'authentification généré dans l’interface d’[`InfluxDB 2.x`](https://docs.influxdata.com/influxdb/v2/), associé à un jeu de permissions (lecture/écriture) ; sans ce token, le client Python ne peut pas interroger le serveur.
|
||||
- `INFLUXDB_ORG` : nom de l'organisation InfluxDB à laquelle le token est rattaché ; InfluxDB 2.x organise les ressources (utilisateurs, buckets, tokens) par organisation, il faut donc préciser celle que l’on souhaite utiliser.
|
||||
- `INFLUXDB_BUCKET` : nom du bucket (espace logique de stockage avec sa politique de rétention) dans lequel les données sont enregistrées ; c’est ce bucket que les scripts interrogeront pour récupérer les mesures de la station.
|
||||
- `STATION_LATITUDE` : latitude GPS de la station météo (en degrés décimaux), utilisée plus loin pour les calculs d’élévation solaire et pour enrichir les données avec des métadonnées astronomiques.
|
||||
- `STATION_LONGITUDE` : longitude GPS de la station météo (en degrés décimaux), nécessaire pour les mêmes raisons que la latitude.
|
||||
- `STATION_ELEVATION` : altitude de la station météo (en mètres au-dessus du niveau de la mer) ; cette information affine légèrement certains calculs physiques, mais reste optionnelle si l’altitude est mal connue.
|
||||
|
||||
## Tests de l'environnement de travail
|
||||
|
||||
Avant d’attaquer des analyses plus lourdes, on vérifie que la connexion au serveur InfluxDB fonctionne bien et que la configuration est cohérente.
|
||||
Les scripts de test qui suivent n’écrivent rien dans la base : ils se contentent d’effectuer quelques requêtes simples pour valider l’accès.
|
||||
|
||||
```shell
|
||||
python "docs/01 - Installation, configuration et tests/scripts/test_influx_connection.py"
|
||||
```
|
||||
|
||||
```output
|
||||
```text
|
||||
Configuration InfluxDB chargée :
|
||||
URL : http://10.0.3.2:8086
|
||||
Org : Dern
|
||||
@ -57,13 +61,15 @@ Exemple de point :
|
||||
value : humidity
|
||||
```
|
||||
|
||||
Si vous obtenez un résultat similaire (URL affichée, ping OK, requête de test qui retourne quelques enregistrements), c’est que le serveur InfluxDB est joignable, que le token est valide et que le bucket indiqué existe bien.
|
||||
|
||||
Ensuite, on peut demander à InfluxDB de nous détailler ce qu'il stocke :
|
||||
|
||||
```shell
|
||||
python "docs/01 - Installation, configuration et tests/scripts/test_influx_schema.py"
|
||||
```
|
||||
|
||||
```output
|
||||
```text
|
||||
Bucket InfluxDB : weather
|
||||
|
||||
Measurements disponibles :
|
||||
@ -115,13 +121,16 @@ Champs pour measurement « °C » :
|
||||
- value (type: unknown)
|
||||
```
|
||||
|
||||
Ce deuxième script interroge le schéma du bucket : il liste les _measurements_ (grandeurs physiques comme `%`, `°C`, `km/h`, etc.), ainsi que les champs associés à chacun.
|
||||
Dans InfluxDB, un _measurement_ correspond en gros à un type de mesure (par exemple une unité), et les _fields_ contiennent les valeurs numériques que l’on exploitera plus tard ; les metadata (comme `entity_id`) sont stockées sous forme de _tags_ (voir la documentation sur le [modèle de données InfluxDB](https://docs.influxdata.com/influxdb/v2/reference/key-concepts/data-elements/)).
|
||||
|
||||
Mais pour obtenir les données dont on a besoin, il faut aussi connaitre les entités manipulées par Influx :
|
||||
|
||||
```shell
|
||||
python "docs/01 - Installation, configuration et tests/scripts/test_influx_entities.py"
|
||||
```
|
||||
|
||||
```output
|
||||
```text
|
||||
Bucket InfluxDB : weather
|
||||
|
||||
Measurement « % »
|
||||
@ -202,6 +211,9 @@ Measurement « °C »
|
||||
- station_meteo_bresser_exterieur_temperature
|
||||
```
|
||||
|
||||
Ces informations combinées se retrouvent dans le fichier `meteo/station_config.py` et dans `meteo/variables.py`.
|
||||
Ce dernier script fait le lien avec la source des données : il dresse la liste des clés de tags et des `entity_id` possibles pour chaque _measurement_.
|
||||
Ces identifiants correspondent aux entités exposées par votre système domotique (par exemple [`Home Assistant`](https://www.home-assistant.io/)), et permettent de distinguer clairement l’humidité extérieure, la pression, la vitesse du vent, etc.
|
||||
|
||||
Ces informations combinées se retrouvent dans le fichier `meteo/station_config.py` et dans `meteo/variables.py` : c’est là que l’on fixe, une fois pour toutes, quelles entités InfluxDB seront considérées comme « température extérieure », « pluie », « vent », et sous quels noms elles seront manipulées dans la suite de l’étude.
|
||||
|
||||
On aurait pu se passer de ces scripts pour déterminer la structure des données stockées dans Influx, mais ils évitent de se reposer sur des intuitions : ici, on demande à Influx de nous donner les informations dont on va avoir besoin au lieu de les deviner.
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# Préparation des données
|
||||
|
||||
Cette étape regroupe l'export initial depuis InfluxDB ainsi que les scripts d'ajustement nécessaires pour obtenir un dataset minuté propre.
|
||||
Cette étape regroupe l'export initial depuis InfluxDB ainsi que les scripts d'ajustement nécessaires pour obtenir un dataset minuté propre, c’est‑à‑dire une [série temporelle](https://fr.wikipedia.org/wiki/S%C3%A9rie_temporelle) où chaque minute possède une observation complète pour toutes les variables utiles.
|
||||
L’objectif est de passer d’un format brut, pensé pour la domotique temps réel, à un format tabulaire lisible par les bibliothèques d’analyse comme `pandas`.
|
||||
|
||||
## Export des données
|
||||
|
||||
@ -8,10 +9,13 @@ Cette étape regroupe l'export initial depuis InfluxDB ainsi que les scripts d'a
|
||||
python "docs/02 - Préparation des données/scripts/export_station_data.py"
|
||||
```
|
||||
|
||||
Ce script se connecte au serveur InfluxDB configuré au chapitre précédent, interroge les mesures de la station sur une fenêtre récente (par défaut les sept derniers jours) et les exporte dans un fichier CSV `data/weather_raw_7d.csv`.
|
||||
On quitte ainsi la base de données de séries temporelles pour un format beaucoup plus simple à manipuler avec `pandas`, tout en conservant l’horodatage précis.
|
||||
|
||||
La sortie est assez longue, et inclut un certain nombre d'avertissements qui peuvent être ignorés.
|
||||
L'important est que le script se termine sur :
|
||||
|
||||
```output
|
||||
```text
|
||||
✔ Export terminé : /Users/richard/Documents/donnees_meteo/data/weather_raw_7d.csv
|
||||
```
|
||||
|
||||
@ -25,18 +29,24 @@ Vérifiez que le fichier est bien créé et qu'il contient des données.
|
||||
python "docs/02 - Préparation des données/scripts/export_station_data_full.py"
|
||||
```
|
||||
|
||||
Au lieu de télécharger les données des 7 derniers jours, l'ensemble des données stockées sur le serveur pour ce bucket seront téléchargées, ce qui, selon la granularité et l'ancienneté des données peut prendre un certain temps et occuper un espace disque conséquent.
|
||||
Mon fichier complet contient plus d'un million d'enregistrements et pèse 70Mo.
|
||||
Au lieu de télécharger les données des sept derniers jours, l'ensemble des données stockées sur le serveur pour ce _bucket_ seront téléchargées, ce qui, selon la granularité et l'ancienneté des données, peut prendre un certain temps et occuper un espace disque conséquent.
|
||||
Mon fichier complet contient plus d'un million d'enregistrements et pèse 70 Mo.
|
||||
|
||||
En pratique, il est souvent plus confortable de développer et tester les scripts suivants sur quelques jours de données (fichier `weather_raw_7d.csv`), puis de relancer le pipeline complet sur l’historique complet une fois les étapes stabilisées.
|
||||
Les deux scripts s’appuient sur l’API HTTP d’[InfluxDB 2.x](https://docs.influxdata.com/influxdb/v2/) et son langage de requête Flux (voir la documentation dédiée à [Flux](https://docs.influxdata.com/flux/v0.x/)).
|
||||
|
||||
## Ajustements
|
||||
|
||||
Le CSV exporté reste très proche du format de stockage utilisé par la domotique : chaque capteur envoie une mesure à des instants légèrement différents, et InfluxDB stocke donc plusieurs lignes par seconde, chacune ne contenant qu’une seule variable renseignée.
|
||||
Pour l’analyse statistique, on cherche au contraire à obtenir une table où chaque horodatage regroupe toutes les variables de la station sur une grille temporelle régulière.
|
||||
|
||||
Le fichier peut être rapidement inspecté avec la commande `head` :
|
||||
|
||||
```shell
|
||||
head data/weather_raw_full.csv
|
||||
```
|
||||
|
||||
```output
|
||||
```text
|
||||
time,temperature,humidity,pressure,illuminance,wind_speed,wind_direction,rain_rate
|
||||
2025-03-10 09:35:23.156646+00:00,,,996.95,,,,
|
||||
2025-03-10 09:35:23.158538+00:00,10.6,,,,,,
|
||||
@ -49,7 +59,8 @@ time,temperature,humidity,pressure,illuminance,wind_speed,wind_direction,rain_ra
|
||||
2025-03-10 09:36:22.640356+00:00,,,,,,306.0,
|
||||
```
|
||||
|
||||
On peut voir que HomeAssistant écrit une nouvelle entrée pour chaque capteur, alors qu'on aurait pu s'attendre à une ligne unique pour l'ensemble des capteurs.
|
||||
On peut voir que [Home Assistant](https://www.home-assistant.io/) écrit une nouvelle entrée pour chaque capteur, alors qu'on aurait pu s'attendre à une ligne unique pour l'ensemble des capteurs.
|
||||
C’est un format très pratique pour la collecte temps réel, mais moins confortable pour l’analyse : il faut d’abord tout remettre en forme.
|
||||
|
||||
Le script suivant s'occupe de regrouper les données de capteurs dont l'enregistrement est proche :
|
||||
|
||||
@ -57,7 +68,7 @@ Le script suivant s'occupe de regrouper les données de capteurs dont l'enregist
|
||||
python "docs/02 - Préparation des données/scripts/format_raw_csv.py"
|
||||
```
|
||||
|
||||
```output
|
||||
```text
|
||||
Fichier brut chargé : data/weather_raw_full.csv
|
||||
Lignes : 1570931, colonnes : ['temperature', 'humidity', 'pressure', 'illuminance', 'wind_speed', 'wind_direction', 'rain_rate']
|
||||
Type d'index : <class 'pandas.core.indexes.datetimes.DatetimeIndex'>
|
||||
@ -66,12 +77,15 @@ Après combinaison (1s) : 630171 lignes
|
||||
```
|
||||
|
||||
Un nouveau document CSV intermédiaire est donc créé.
|
||||
On voit que l’on passe d’environ 1,57 million de lignes à 630 000 lignes « combinées » : le script regroupe les mesures de tous les capteurs tombant dans la même seconde, en utilisant l’horodatage comme clé.
|
||||
L’index de type `DatetimeIndex` indiqué dans la sortie est l’axe temporel standard de `pandas` (voir la documentation de [`pandas.DatetimeIndex`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DatetimeIndex.html)).
|
||||
Cette étape correspond à une première forme de rééchantillonnage temporel, classique lorsqu’on prépare une série pour l’analyse.
|
||||
|
||||
```shell
|
||||
head data/weather_formatted_1s.csv
|
||||
```
|
||||
|
||||
```output
|
||||
```text
|
||||
time,temperature,humidity,pressure,illuminance,wind_speed,wind_direction,rain_rate
|
||||
2025-03-10 09:35:23+00:00,10.6,83.0,996.95,,7.4,256.0,0.0
|
||||
2025-03-10 09:35:41+00:00,,,,20551.2,,,
|
||||
@ -84,7 +98,8 @@ time,temperature,humidity,pressure,illuminance,wind_speed,wind_direction,rain_ra
|
||||
2025-03-10 09:40:22+00:00,,,,19720.8,10.0,209.0,
|
||||
```
|
||||
|
||||
Il reste des cellules vides : en effet, HA n'enregistre pas la valeur d'un capteur si elle n'a pas changé depuis la dernière fois.
|
||||
Il reste des cellules vides : en effet, Home Assistant n'enregistre pas la valeur d'un capteur si elle n'a pas changé depuis la dernière fois.
|
||||
On se retrouve donc avec une série temporelle à pas régulier (1 s), mais encore parsemée de trous.
|
||||
|
||||
On fait donc :
|
||||
|
||||
@ -92,20 +107,22 @@ On fait donc :
|
||||
python "docs/02 - Préparation des données/scripts/fill_formatted_1s.py"
|
||||
```
|
||||
|
||||
```output
|
||||
```text
|
||||
Fichier 1s formaté chargé : data/weather_formatted_1s.csv
|
||||
Lignes : 630171, colonnes : ['temperature', 'humidity', 'pressure', 'illuminance', 'wind_speed', 'wind_direction', 'rain_rate']
|
||||
Après propagation des dernières valeurs connues : 630171 lignes
|
||||
✔ Fichier 1s 'complet' écrit dans : /Users/richard/Documents/donnees_meteo/data/weather_filled_1s.csv
|
||||
```
|
||||
|
||||
Cette seconde passe applique un remplissage par propagation de la dernière valeur connue (_forward fill_ ou `ffill` dans `pandas`) : tant qu’un capteur ne publie pas de nouvelle mesure, on considère que la précédente reste valable. C’est une hypothèse raisonnable pour des variables relativement lisses comme la température ou la pression, moins pour des phénomènes très brusques ; l’objectif ici est surtout d’obtenir un _dataset_ sans [valeurs manquantes](https://fr.wikipedia.org/wiki/Donn%C3%A9es_manquantes), ce qui simplifie grandement les analyses et les modèles dans les chapitres suivants.
|
||||
|
||||
## Enrichissements (saisons et position du soleil)
|
||||
|
||||
Une fois les données nettoyées, on peut les enrichir avec des métadonnées météorologiques simples :
|
||||
Une fois les données nettoyées, on peut les enrichir avec des métadonnées météorologiques simples, qui aideront ensuite à interpréter les graphiques et à construire des modèles plus pertinents :
|
||||
|
||||
- regrouper les points par minute,
|
||||
- ajouter la saison correspondant à chaque observation (en fonction de l'hémisphère),
|
||||
- calculer la hauteur du soleil si la latitude/longitude de la station sont configurées.
|
||||
- regrouper les points par minute, pour lisser légèrement le bruit tout en restant réactif ; ce pas de 60 secondes est un bon compromis entre fidélité au signal brut et taille raisonnable du _dataset_ ;
|
||||
- ajouter la saison correspondant à chaque observation (en fonction de l'hémisphère), ce qui permet de comparer facilement les comportements printemps/été/automne/hiver et de relier nos courbes aux notions classiques de [saisons](https://fr.wikipedia.org/wiki/Saison) en météorologie ;
|
||||
- calculer la hauteur du soleil si la latitude/longitude de la station sont configurées, afin de disposer d’une estimation de l’élévation solaire au‑dessus de l’horizon (jour/nuit, midi solaire, etc.) en s’appuyant sur la bibliothèque d’astronomie [`astral`](https://astral.readthedocs.io/).
|
||||
|
||||
Ces opérations sont réalisées par :
|
||||
|
||||
@ -113,26 +130,34 @@ Ces opérations sont réalisées par :
|
||||
python "docs/02 - Préparation des données/scripts/make_minutely_dataset.py"
|
||||
```
|
||||
|
||||
Le script produit `data/weather_minutely.csv`. Pensez à définir `STATION_LATITUDE`, `STATION_LONGITUDE` et `STATION_ELEVATION` dans votre `.env` pour permettre le calcul de la position du soleil ; sinon, seule la colonne `season` sera ajoutée.
|
||||
Le script produit `data/weather_minutely.csv`. Chaque ligne de ce fichier correspond à une minute, avec toutes les variables météo alignées (température, humidité, pression, vent, pluie, etc.) et, si les coordonnées de la station sont connues, des colonnes supplémentaires comme la saison et l’élévation du soleil.
|
||||
|
||||
> Pensez à définir `STATION_LATITUDE`, `STATION_LONGITUDE` et `STATION_ELEVATION` dans votre `.env` pour permettre le calcul de la position du soleil ; sinon, seule la colonne `season` sera ajoutée.
|
||||
|
||||
Ce fichier minuté est le jeu de données de référence utilisé dans la majorité des chapitres suivants.
|
||||
|
||||
## Pipeline simplifié
|
||||
|
||||
Un script tout simple permet de faire automatiquement tout ce qu'on vient de voir.
|
||||
Un script tout simple permet de faire automatiquement tout ce qu'on vient de voir, dans le bon ordre, sans avoir à lancer chaque étape à la main.
|
||||
Il supprime **tous** les fichiers CSV existants : il faudra donc relancer la génération des images dans les étapes suivantes pour qu'elles intègrent les nouvelles données.
|
||||
|
||||
```shell
|
||||
python -m scripts.refresh_data_pipeline
|
||||
```
|
||||
|
||||
Ce module Python orchestre l’export depuis InfluxDB, la mise en forme à 1 seconde, le remplissage des valeurs manquantes puis la construction du dataset minuté.
|
||||
Le fait de repartir de zéro à chaque exécution garantit que `weather_minutely.csv` reflète bien l’état actuel de la base, au prix d’un temps de calcul un peu plus long.
|
||||
|
||||
## Vérification des données
|
||||
|
||||
On peut s'assurer que plus aucune information n'est manquante :
|
||||
Avant d’explorer les graphiques ou de lancer des modèles, on vérifie que le dataset minuté est cohérent : pas de valeurs manquantes, des ordres de grandeur plausibles, et une grille temporelle effectivement régulière.
|
||||
On peut d’abord s'assurer que plus aucune information n'est manquante :
|
||||
|
||||
```shell
|
||||
python "docs/02 - Préparation des données/scripts/check_missing_values.py"
|
||||
```
|
||||
|
||||
```output
|
||||
```text
|
||||
Dataset chargé : data/weather_minutely.csv
|
||||
Lignes : 321881
|
||||
Colonnes : ['temperature', 'humidity', 'pressure', 'illuminance', 'wind_speed', 'wind_direction', 'rain_rate']
|
||||
@ -156,13 +181,15 @@ Valeurs manquantes par colonne :
|
||||
✔ Aucune valeur manquante dans le dataset minuté.
|
||||
```
|
||||
|
||||
Ce premier contrôle confirme que toutes les lignes de `weather_minutely.csv` sont complètes : aucune cellule n’est manquante, ce qui évitera bien des subtilités dans les analyses ultérieures.
|
||||
|
||||
Le script suivant nous permet de vérifier rapidement si des problèmes majeurs peuvent être découverts :
|
||||
|
||||
```shell
|
||||
python "docs/02 - Préparation des données/scripts/describe_minutely_dataset.py"
|
||||
```
|
||||
|
||||
```output
|
||||
```text
|
||||
Dataset minuté chargé : data/weather_minutely.csv
|
||||
Lignes : 321881
|
||||
Colonnes : ['temperature', 'humidity', 'pressure', 'illuminance', 'wind_speed', 'wind_direction', 'rain_rate'] Période : 2025-03-10 09:35:00+00:00 → 2025-11-17 00:41:00+00:00
|
||||
@ -216,13 +243,17 @@ Name: count, dtype: int64
|
||||
Nombre d'intervalles ≠ 60s : 17589
|
||||
```
|
||||
|
||||
Ces écarts peuvent être identifiés avec le script suivant :
|
||||
Ce deuxième script fournit un aperçu statistique classique (fonction `describe()` de `pandas`) et quelques min/max datés pour chaque variable : on y vérifie que les valeurs restent plausibles (par exemple pas de température à +80 °C ni de vent négatif) et que les extrêmes correspondent à des dates réalistes.
|
||||
La section sur les différences d’intervalle permet déjà de repérer que certains pas ne sont pas strictement de 60 secondes, ce qui est courant sur des données issues de capteurs, mais qu’il faut garder en tête pour la suite.
|
||||
Ce type de contrôle s’inscrit dans une démarche d’[analyse exploratoire de données](https://fr.wikipedia.org/wiki/Analyse_exploratoire_de_donn%C3%A9es).
|
||||
|
||||
Ces écarts peuvent être identifiés plus finement avec le script suivant :
|
||||
|
||||
```shell
|
||||
python "docs/02 - Préparation des données/scripts/list_time_gaps.py"
|
||||
```
|
||||
|
||||
```
|
||||
```text
|
||||
Dataset minuté chargé : data/weather_minutely.csv
|
||||
Lignes : 321881
|
||||
|
||||
@ -243,8 +274,9 @@ Top 10 des gaps les plus longs :
|
||||
- De 2025-06-21 17:25:00+00:00 à 2025-06-21 18:10:00+00:00 (durée: 0 days 00:45:00, manquants: 44, de 2025-06-21 17:26:00+00:00 à 2025-06-21 18:09:00+00:00)
|
||||
```
|
||||
|
||||
Ces trous dans les données peuvent correspondre à des pannes de connexion entre la station et mon réseau, un redémarrage de mon serveur (physique ou logiciel), au redémarrage de la box ou du point d'accès sans-fil, etc.
|
||||
Ils peuvent aussi correspondre aux modifications opérées dans les scripts précédents.
|
||||
Ce troisième script ne corrige rien : il se contente de lister précisément les intervalles dans lesquels des minutes manquent dans la série, ainsi que leur durée.
|
||||
Ces trous dans les données peuvent correspondre à des pannes de connexion entre la station et mon réseau, un redémarrage de mon serveur (physique ou logiciel), au redémarrage de la box ou du point d'accès sans‑fil, etc.
|
||||
Mais ils peuvent également correspondre aux modifications opérées dans les scripts précédents !
|
||||
|
||||
Ces scripts sont intéressants parce qu'ils mettent en évidence des facteurs indirects, contribuant à la qualité des données soumise.
|
||||
On peut prendre toutes les précautions, on peut avoir l'intuition d'avoir tout géré, et se rassurer parce qu'on utilise des outils fiables, mais il existera toujours des manques dans les données.
|
||||
|
||||
@ -1,13 +1,22 @@
|
||||
# Premiers graphiques
|
||||
|
||||
On peut désormais tracer nos premiers graphiques simples et bruts.
|
||||
S'ils ne sont pas très instructifs par rapport à ce que nous fournissent Home Assistant et InfluxDB, ils nous permettent au moins de nous assurer que tout fonctionne, et que les données semblent cohérentes.
|
||||
Les fichiers CSV correspondant à chaque figure sont conservés dans `data/` dans ce dossier.
|
||||
On peut désormais tracer nos premiers graphiques simples et bruts à partir du dataset minuté construit au chapitre précédent.
|
||||
S'ils ne sont pas encore très instructifs par rapport à ce que nous fournissent déjà Home Assistant et InfluxDB, ils nous permettent au moins de nous assurer que tout fonctionne, que les données semblent cohérentes, et que la chaîne « export → préparation → visualisation » tient la route.
|
||||
Les scripts de ce chapitre s’appuient sur [`pandas`](https://pandas.pydata.org/) et sur la bibliothèque de visualisation [`Matplotlib`](https://matplotlib.org/) (via le module `meteo.plots`) pour produire des graphiques standards : séries temporelles, _heatmaps_, calendriers.
|
||||
Les fichiers CSV correspondant à chaque figure sont conservés dans le sous-dossier `data/` de ce chapitre, ce qui permet de réutiliser directement les séries pré-agrégées si besoin.
|
||||
|
||||
```shell
|
||||
python "docs/03 - Premiers graphiques/scripts/plot_basic_variables.py"
|
||||
```
|
||||
|
||||
Ce script lit `data/weather_minutely.csv`, sélectionne éventuellement une fenêtre temporelle (par exemple les derniers jours si l’on utilise l’option `--days`) puis choisit une fréquence d’agrégation adaptée pour ne pas saturer le graphique en points.
|
||||
Pour chaque variable (température, pression, humidité, pluie, vent, illuminance, élévation du soleil), il applique un style par défaut : courbe continue pour les variables lisses, diagramme en barres pour la pluie, nuage de points pour la direction du vent, etc.
|
||||
L’idée est d’obtenir une première vue d’ensemble de la [série temporelle](https://fr.wikipedia.org/wiki/S%C3%A9rie_temporelle) de chaque variable, sans prise de tête :
|
||||
|
||||
- vérifier le cycle quotidien de la température et de l’élévation solaire ;
|
||||
- repérer les paliers ou dérives de capteurs (pression trop plate, humidité coincée, etc.) ;
|
||||
- confirmer que les unités, ranges et horodatages sont plausibles.
|
||||
|
||||

|
||||
|
||||

|
||||
@ -30,6 +39,14 @@ python "docs/03 - Premiers graphiques/scripts/plot_basic_variables.py"
|
||||
python "docs/03 - Premiers graphiques/scripts/plot_calendar_overview.py"
|
||||
```
|
||||
|
||||
Le second script propose une vue complémentaire sous forme de _calendrier thermique_ (une [carte de chaleur](https://fr.wikipedia.org/wiki/Carte_de_chaleur) disposée en jours et mois).
|
||||
À partir du même dataset minuté, il calcule des moyennes quotidiennes (température, humidité, pression, illuminance, vent) ou des cumuls quotidiens (pluie), puis remplit une matrice « mois x jours » pour l’année la plus récente disponible.
|
||||
Ces vues servent surtout à :
|
||||
|
||||
- repérer rapidement les saisons, épisodes pluvieux ou périodes de vent soutenu ;
|
||||
- détecter des trous dans la série (jours entièrement manquants) ;
|
||||
- avoir un aperçu global de l’année sans zoomer/dézoomer en permanence sur une longue série temporelle.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
@ -1,11 +1,22 @@
|
||||
# Corrélations binaires
|
||||
|
||||
L’objectif de ce chapitre est d’explorer les relations entre variables deux à deux : d’abord visuellement (superposition de séries temporelles, comme ci-dessous, et [nuages de points](https://fr.wikipedia.org/wiki/Nuage_de_points), comme dans le chapitre suivant), puis numériquement via des coefficients de [corrélation](<https://fr.wikipedia.org/wiki/Corr%C3%A9lation_(statistiques)>).
|
||||
On reste volontairement dans un cadre simple : une variable « primaire » et une variable « associée », à la fois dans le temps et dans les matrices de corrélation.
|
||||
|
||||
## Superpositions simples
|
||||
|
||||
```shell
|
||||
python "docs/04 - Corrélations binaires/scripts/plot_pairwise_time_series.py"
|
||||
```
|
||||
|
||||
Ce script parcourt toutes les paires de variables disponibles et produit, pour chacune, un graphique superposant les deux séries sur le même axe temporel (ou sur deux axes verticaux si nécessaire).
|
||||
Les données sont ré-échantillonnées pour limiter le nombre de points et lisser légèrement le bruit, en utilisant les mêmes mécanismes que dans le chapitre 3.
|
||||
Ces superpositions servent surtout à repérer des co‑évolutions évidentes (par exemple humidité qui baisse quand la température monte) ou, au contraire, des paires qui semblent indépendantes à l’œil nu.
|
||||
|
||||
### Température
|
||||
|
||||
Toutes les figures de cette section ont pour variable « primaire » la température ; l’autre variable change d’un graphique à l’autre.
|
||||
|
||||

|
||||
|
||||

|
||||
@ -20,6 +31,10 @@ python "docs/04 - Corrélations binaires/scripts/plot_pairwise_time_series.py"
|
||||
|
||||

|
||||
|
||||
### Humidité relative
|
||||
|
||||
Ici, on fixe l’humidité comme variable principale et on observe comment elle évolue en parallèle des autres variables.
|
||||
|
||||

|
||||
|
||||

|
||||
@ -32,6 +47,10 @@ python "docs/04 - Corrélations binaires/scripts/plot_pairwise_time_series.py"
|
||||
|
||||

|
||||
|
||||
### Pression
|
||||
|
||||
Dans ces vues, on suit la pression atmosphérique et on la compare aux autres champs mesurés.
|
||||
|
||||

|
||||
|
||||

|
||||
@ -42,18 +61,30 @@ python "docs/04 - Corrélations binaires/scripts/plot_pairwise_time_series.py"
|
||||
|
||||

|
||||
|
||||
### Pluviométrie
|
||||
|
||||
On regarde ici comment les épisodes de pluie (taux de précipitation) se positionnent par rapport au vent et à la hauteur du soleil.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### Luminance
|
||||
|
||||
Ces superpositions éclairent les liens entre lumière, vent et position du soleil.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### Vent (vitesse / direction)
|
||||
|
||||
Enfin, on se concentre sur le vent : d’abord sa vitesse en lien avec l’élévation solaire, puis la direction comparée à cette même référence.
|
||||
|
||||

|
||||
|
||||

|
||||
@ -62,8 +93,12 @@ python "docs/04 - Corrélations binaires/scripts/plot_pairwise_time_series.py"
|
||||
|
||||
## Matrices de corrélation (instantané, signé)
|
||||
|
||||
Le calcul des coefficients de Pearson et de Spearman peut nous donner une indication numérique des corrélations entre les différentes variables.
|
||||
Cette information peut nous aiguiller sur des relations spécifiques (ou au contraire, nous induire en erreur...).
|
||||
Le calcul des coefficients de Pearson et de Spearman peut nous donner une indication numérique de la force et du signe des corrélations entre les différentes variables.
|
||||
On passe ainsi du visuel (superpositions, nuages de points) à un résumé compact des co‑variations, même si cela ne capture que des dépendances linéaires ou monotones simples.
|
||||
On utilise ici :
|
||||
|
||||
- le coefficient de corrélation linéaire de Pearson (voir [corrélation linéaire](https://fr.wikipedia.org/wiki/Corr%C3%A9lation_lin%C3%A9aire)) pour mesurer à quel point deux variables varient ensemble de manière approximativement linéaire ;
|
||||
- le coefficient de Spearman (voir [corrélation de Spearman](https://fr.wikipedia.org/wiki/Corr%C3%A9lation_de_Spearman)) pour capturer des relations monotones (croissantes ou décroissantes), même si elles ne sont pas parfaitement linéaires.
|
||||
|
||||
```shell
|
||||
python "docs/04 - Corrélations binaires/scripts/plot_correlation_heatmap.py" --transform=identity --upper-only
|
||||
@ -73,5 +108,5 @@ python "docs/04 - Corrélations binaires/scripts/plot_correlation_heatmap.py" --
|
||||
|
||||

|
||||
|
||||
Le signe et l'intensité des coefficients montrent à quel point deux variables bougent ensemble au même instant (co-mouvement linéaire pour Pearson, monotone pour Spearman).
|
||||
Le signe et l'intensité des coefficients montrent à quel point deux variables bougent ensemble au même instant (co‑mouvement linéaire pour Pearson, monotone pour Spearman).
|
||||
Cette matrice sert donc surtout de carte globale : repérer rapidement les couples très corrélés ou indiquer un lien physique évident, mettre en alerte des variables à forte corrélation qui pourraient masquer d'autres effets (saisonnalité, cycle jour/nuit), et choisir quelles paires méritent qu'on teste des décalages temporels ou des relations non linéaires dans la suite.
|
||||
|
||||
@ -381,22 +381,22 @@ Les régimes diurnes/nocturnes modulent [la direction](https://en.wikipedia.org/
|
||||
|
||||
Conclusion : le pattern jour/nuit est plausible ; sans mesure régionale, on ne peut isoler précisément le mécanisme.
|
||||
|
||||
## Données manquantes
|
||||
## Synthèse des données manquantes
|
||||
|
||||
| Relation | Variable | Comment se la procurer |
|
||||
| -------- | -------- | ---------------------- |
|
||||
| Température ↔ Humidité relative | Eau précipitable intégrée (PWV) | Reanalyses ERA5/AROME via [API Copernicus CDS](https://cds.climate.copernicus.eu/api-how-to), radiosondages proches, station GNSS locale pour PWV. |
|
||||
| Température ↔ Luminance / Humidité ↔ Luminance / Élévation solaire ↔ Humidité | Couverture/épaisseur nuageuse | Meteosat via [EUMETSAT Data Store](https://data.eumetsat.int/), METAR/TAF via [NOAA ADDS API](https://aviationweather.gov/data/api/), reanalyses fraction nuageuse via CDS API, caméra ciel locale. |
|
||||
| Température ↔ Luminance / Élévation solaire ↔ Température | Humidité du sol | Capteur sol, reanalyses ERA5-Land via [CDS](https://cds.climate.copernicus.eu), SAFRAN Météo-France ([données publiques](https://donneespubliques.meteofrance.fr/) ou [data.gouv.fr](https://www.data.gouv.fr/)), API AROME WCS si accessible. |
|
||||
| Température ↔ Luminance | Albédo du sol | [Corine](https://land.copernicus.eu/pan-european/corine-land-cover) ou [OSM](https://www.openstreetmap.org/) en open data ; NDVI Sentinel/Landsat (ex. [Sentinel Hub](https://www.sentinel-hub.com/)) pour dériver l’albédo. |
|
||||
| Vent (vitesse/direction) ↔ Température/Pluie | Champ de pression régional / gradient horizontal | ERA5 via CDS, GFS via [NOAA NOMADS](https://nomads.ncep.noaa.gov/), cartes synoptiques publiques, stations baro proches ([data.gouv.fr](https://www.data.gouv.fr/)). |
|
||||
| Humidité ↔ Pluie / Pluie ↔ Élévation solaire | Profils verticaux (T/HR/vent) | Radiosondages [NOAA IGRA](https://www.ncei.noaa.gov/products/weather-balloon/integrated-global-radiosonde-archive), reanalyses horaires ERA5/AROME via CDS, profils AROME HD (API Météo-France si éligible). |
|
||||
| Humidité ↔ Pluie / Pluie ↔ Élévation solaire | Indices de stabilité (CAPE/CIN) | Calculés depuis ERA5/AROME via CDS ou sondes ; outils [MetPy](https://unidata.github.io/MetPy/latest/) ou [wgrib2](https://www.cpc.ncep.noaa.gov/products/wesley/wgrib2/). |
|
||||
| Direction ↔ Humidité / Pluie | Trajectoires des masses d’air (back-trajectoires) | [HYSPLIT NOAA READY](https://www.ready.noaa.gov/HYSPLIT.php), services NOAA en ligne, scripts [PySPLIT](https://pysplit.readthedocs.io/). |
|
||||
| Luminance ↔ Élévation solaire | Opacité atmosphérique / aérosols | [AERONET API](https://aeronet.gsfc.nasa.gov/new_web/API/index.html), [CAMS](https://ads.atmosphere.copernicus.eu/), PM locaux via [OpenAQ](https://openaq.org/), MODIS AOD via [NASA LAADS](https://ladsweb.modaps.eosdis.nasa.gov/). |
|
||||
| Luminance ↔ Vent / Température | Flux radiatif net (SW/LW) | Pyranomètre/pyrgéomètre locaux, reanalyses de surface ERA5 via CDS, stations agricoles/météo proches en open data si disponibles. |
|
||||
| Vent ↔ Température/Pluie | Rugosité / traînée de surface | Corine/OSM, LIDAR [IGN RGE Alti](https://geoservices.ign.fr/rgealti), survey terrain pour estimer z0. |
|
||||
| Toutes relations | Données hivernales complètes | Continuer la collecte jusqu’à fin d’hiver ; combler avec reanalyses ERA5 via CDS API pour les périodes manquantes. |
|
||||
| Relation | Variable | Comment se la procurer |
|
||||
| ----------------------------------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Température ↔ Humidité relative | Eau précipitable intégrée (PWV) | Réanalyses ERA5/AROME via [API Copernicus CDS](https://cds.climate.copernicus.eu/api-how-to), radiosondages Météo-France (accessibles via [donneespubliques.meteofrance.fr](https://donneespubliques.meteofrance.fr/) ou intégrés dans [NOAA IGRA](https://www.ncei.noaa.gov/products/weather-balloon/integrated-global-radiosonde-archive)), réseau GNSS permanent (ex. [RGP de l’IGN](https://geodesie.ign.fr/index.php?page=rgp)) ou station GNSS locale pour le PWV. |
|
||||
| Température ↔ Luminance / Humidité ↔ Luminance / Élévation solaire ↔ Humidité | Couverture/épaisseur nuageuse | Imagerie Meteosat via [EUMETSAT Data Store](https://data.eumetsat.int/) ou produits dérivés de Météo-France, bulletins METAR/SYNOP (nébulosité) via [donneespubliques.meteofrance.fr](https://donneespubliques.meteofrance.fr/) ou [data.gouv.fr](https://www.data.gouv.fr/), fraction nuageuse des réanalyses ERA5/AROME via CDS API, caméra ciel locale. |
|
||||
| Température ↔ Luminance / Élévation solaire ↔ Température | Humidité du sol | Capteur sol in situ, réanalyses ERA5-Land via [CDS](https://cds.climate.copernicus.eu), analyse SAFRAN Météo-France ([données publiques](https://donneespubliques.meteofrance.fr/) ou [data.gouv.fr](https://www.data.gouv.fr/)), champs AROME/ARPEGE de surface si accessibles (API ou jeux climatologiques). |
|
||||
| Température ↔ Luminance | Albédo du sol | Cartes d’occupation du sol [Corine](https://land.copernicus.eu/pan-european/corine-land-cover) ou [OSM](https://www.openstreetmap.org/) en open data ; NDVI Sentinel/Landsat (ex. [Sentinel Hub](https://www.sentinel-hub.com/)) pour dériver l’albédo, complété au besoin par les produits d’albédo Copernicus. |
|
||||
| Vent (vitesse/direction) ↔ Température/Pluie | Champ de pression régional / gradient horizontal | Réanalyses ERA5 via CDS, champs de pression AROME/ARPEGE Météo-France (données publiques ou produits dérivés), GFS via [NOAA NOMADS](https://nomads.ncep.noaa.gov/), cartes synoptiques publiques, stations baro proches (réseau Météo-France ou stations amateurs sur [data.gouv.fr](https://www.data.gouv.fr/)). |
|
||||
| Humidité ↔ Pluie / Pluie ↔ Élévation solaire | Profils verticaux (T/HR/vent) | Radiosondages Météo-France (Trappes, Nîmes, etc.) via [donneespubliques.meteofrance.fr](https://donneespubliques.meteofrance.fr/) ou archives [NOAA IGRA](https://www.ncei.noaa.gov/products/weather-balloon/integrated-global-radiosonde-archive), réanalyses horaires ERA5/AROME via CDS, profils AROME HD si accessibles. |
|
||||
| Humidité ↔ Pluie / Pluie ↔ Élévation solaire | Indices de stabilité (CAPE/CIN) | Calculés depuis ERA5/AROME via CDS ou à partir de radiosondages ; outils [MetPy](https://unidata.github.io/MetPy/latest/) ou [wgrib2](https://www.cpc.ncep.noaa.gov/products/wesley/wgrib2/), certains produits dérivés disponibles dans les jeux climatologiques Météo-France ou via services universitaires français. |
|
||||
| Direction ↔ Humidité / Pluie | Trajectoires des masses d’air (back-trajectoires) | [HYSPLIT NOAA READY](https://www.ready.noaa.gov/HYSPLIT.php) (forçage GFS ou réanalyses globales), scripts [PySPLIT](https://pysplit.readthedocs.io/), et, pour la France, champs de vent issus d’AROME/ARPEGE (Météo-France ou CDS) pour forcer des trajectoires régionales plus fines. |
|
||||
| Luminance ↔ Élévation solaire | Opacité atmosphérique / aérosols | Réseau photomètres [AERONET API](https://aeronet.gsfc.nasa.gov/new_web/API/index.html) (plusieurs sites en France), produits [CAMS](https://ads.atmosphere.copernicus.eu/) sur les aérosols, mesures de particules fines via [OpenAQ](https://openaq.org/) et réseaux de qualité de l’air français, MODIS AOD via [NASA LAADS](https://ladsweb.modaps.eosdis.nasa.gov/). |
|
||||
| Luminance ↔ Vent / Température | Flux radiatif net (SW/LW) | Pyranomètre/pyrgéomètre locaux, réanalyses de surface ERA5 via CDS, bilans radiatifs de surface dans les produits Météo-France (SAFRAN/AROME Surface) si disponibles, stations agricoles ou réseaux météo/agro français en open data. |
|
||||
| Vent ↔ Température/Pluie | Rugosité / traînée de surface | Cartes d’occupation du sol Corine/OSM, modèles numériques de terrain et LIDAR [IGN RGE Alti](https://geoservices.ign.fr/rgealti), inventaires locaux (haies, forêts, bâtiments) pour estimer la rugosité z0 autour de la station. |
|
||||
| Toutes relations | Données hivernales complètes | Continuer la collecte jusqu’à fin d’hiver ; compléter les manques avec les réanalyses ERA5/ERA5-Land via CDS API et, si besoin, les produits climatologiques de Météo-France pour les périodes plus anciennes. |
|
||||
|
||||
## Conclusion
|
||||
|
||||
|
||||
@ -2,42 +2,57 @@
|
||||
|
||||
## Hexbin colorés
|
||||
|
||||
Les nuages de points tri-variés saturent vite : on regroupe ici les points sur une grille hexagonale et on colore chaque case par une statistique de la 3ᵉ variable (max/médiane/moyenne selon les besoins). Cela limite le bruit des outliers et met en évidence les régimes dominants plutôt que les valeurs isolées. Les scénarios sont décrits dans `meteo/correlation_presets.py` et exécutés via un helper générique (`meteo.plots.hexbin`) pour rester réutilisables ailleurs dans le dépôt.
|
||||
Les nuages de points tri-variés saturent vite : on regroupe ici les points sur une grille hexagonale et on colore chaque case par une statistique de la 3ᵉ variable (max/médiane/moyenne selon les besoins).
|
||||
Cela limite le bruit des valeurs extrêmes et met en évidence les régimes dominants plutôt que les valeurs isolées.
|
||||
Les scénarios sont décrits dans `meteo/correlation_presets.py` et exécutés via un helper générique (`meteo.plots.hexbin`) pour rester réutilisables ailleurs dans le dépôt.
|
||||
|
||||
```shell
|
||||
python "docs/07 - Corrélations multiples/scripts/plot_hexbin_explorations.py"
|
||||
```
|
||||
|
||||
### Température vs humidité — couleur = pluie (max)
|
||||
### Température, humidité et pluie
|
||||
|
||||
Plafond d'humidité quasi systématique sous 5–10 °C, et même quand la température remonte, la pluie ne survient que dans une bande 8–16 °C où l'humidité reste >90 %. L'agrégat `max` met en valeur les épisodes pluvieux rares.
|
||||
Sur ce graphique, l’axe horizontal montre la température, l’axe vertical l’humidité, et la couleur indique la pluie maximale observée dans chaque case.
|
||||
On voit un plafond d'humidité quasi systématique sous 5–10 °C, et même quand la température remonte, la pluie ne survient que dans une bande 8–16 °C où l'humidité reste >90 %.
|
||||
L'agrégat `max` met en valeur les épisodes pluvieux rares, qui ressortent comme des taches plus sombres dans ce « nuage » autrement très dense.
|
||||
|
||||

|
||||
|
||||
### Température vs élévation solaire — couleur = humidité (médiane)
|
||||
### Soleil, température et humidité
|
||||
|
||||
La courbe en cloche suit le soleil : températures les plus hautes autour de 60° d'élévation, tandis que l'humidité médiane dégringole dès que le soleil est positif puis remonte au crépuscule, ce qui matérialise l'assèchement diurne.
|
||||
Ici, on place l’élévation solaire en abscisse, la température en ordonnée, et on colore chaque hexagone par l’humidité médiane.
|
||||
La courbe en cloche suit le soleil : températures les plus hautes autour de 60° d'élévation, tandis que l'humidité médiane dégringole dès que le soleil est positif puis remonte au crépuscule.
|
||||
On visualise ainsi, en un seul coup d’œil, l’assèchement diurne classique : plus le soleil monte, plus l’air se réchauffe et plus l’humidité relative chute.
|
||||
|
||||

|
||||
|
||||
### Pression vs pluie — couleur = vent (médiane)
|
||||
### Pression, pluie et vent
|
||||
|
||||
La matrice est clairsemée (pluie rare), mais les cases actives se concentrent sous ~1015 hPa avec des médianes de vent plus élevées, signe que les épisodes pluvieux et venteux coïncident surtout avec des pressions modestes.
|
||||
Dans cette vue, la pression est en abscisse, le taux de pluie en ordonnée, et la couleur représente la vitesse médiane du vent.
|
||||
La matrice est clairsemée (la pluie est rare), mais les cases actives se concentrent sous ~1015 hPa avec des médianes de vent plus élevées.
|
||||
On retrouve un schéma familier : les épisodes pluvieux un peu ventés se produisent surtout sous des pressions modestes, tandis que les hautes pressions restent largement calmes et sèches.
|
||||
|
||||

|
||||
|
||||
### Humidité vs illuminance — couleur = température (moyenne)
|
||||
### Lumière, humidité et température
|
||||
|
||||
Deux régimes se détachent : nuits très humides et fraîches (illuminance proche de zéro), journées sèches et plus chaudes. La température moyenne colorée rend visibles les transitions plus fraîches sous ciel couvert.
|
||||
On regarde ici l’illuminance (lumière reçue) en abscisse, l’humidité en ordonnée, avec la température moyenne en couleur.
|
||||
Deux régimes se détachent très nettement : nuits très humides et fraîches (illuminance proche de zéro), journées plus sèches et plus chaudes.
|
||||
Entre les deux, la carte montre des zones dans lesquelles la température reste modérée malgré un peu de lumière, typiques des journées couvertes où l’on ne « ressent » pas vraiment la montée du soleil.
|
||||
|
||||

|
||||
|
||||
### Élévation solaire vs illuminance — couleur = pluie (max)
|
||||
### Soleil, lumière et pluie
|
||||
|
||||
Le nuage suit la diagonale « géométrie du soleil → lumière attendue », avec des cases assombries (illuminance faible malgré un soleil haut) où la pluie maximale ressort : on visualise directement l'impact d'un ciel très chargé sur l'apport lumineux.
|
||||
Dans cette dernière combinaison, l’élévation solaire est en abscisse, l’illuminance en ordonnée, et la couleur code la pluie maximale.
|
||||
Le nuage suit la diagonale « géométrie du soleil → lumière attendue » : plus le soleil monte, plus la case devrait être lumineuse.
|
||||
Les hexagones assombris (illuminance faible malgré un soleil haut) ressortent immédiatement : ce sont les situations dans lesquelles un ciel très chargé bloque la lumière, et où la pluie maximale apparaît.
|
||||
C’est une façon très visuelle de voir que « soleil haut » ne signifie pas forcément « journée lumineuse ».
|
||||
|
||||

|
||||
|
||||
## Conclusion
|
||||
|
||||
Ces hexbins confirment les mécanismes physiques attendus : le rayonnement solaire chauffe et assèche, l’humidité suit la capacité de l’air en vapeur, la pluie survient surtout sous pression plus basse et lumière écrasée par les nuages. Mais notre jeu s’arrête en novembre : il manque la saison froide, donc les régimes hivernaux (neige, pluies froides, journées très courtes, plafond d’humidité quasi permanent) restent invisibles. Toute généralisation doit tenir compte de cette lacune saisonnière ; il faudrait compléter la série ou intégrer des données externes (nébulosité, contexte synoptique) pour confirmer ces motifs en hiver.
|
||||
Ces hexbins confirment les mécanismes physiques attendus : le rayonnement solaire chauffe et assèche, l’humidité suit la capacité de l’air en vapeur, la pluie survient surtout sous pression plus basse et lumière écrasée par les nuages.
|
||||
Mais notre jeu s’arrête en novembre : il manque la saison froide, donc les régimes hivernaux (neige, pluies froides, journées très courtes, plafond d’humidité quasi permanent) restent invisibles.
|
||||
Toute généralisation doit tenir compte de cette lacune saisonnière ; il faudra attendre de pouvoir compléter la série ou intégrer des données externes (nébulosité, contexte synoptique) pour confirmer ces motifs en hiver.
|
||||
|
||||
@ -1,40 +1,70 @@
|
||||
# Cadre prédictif local
|
||||
|
||||
Objectif : poser les bases d’un modèle sur-mesure qui prédit, au pas local de la station, la température, la pluie et le vent à plusieurs horizons (T+10 min, +60 min, +6 h, +24 h).
|
||||
On garde une approche expérimentale : on cherche à comprendre ce qui fonctionne ou échoue, non pas à atteindre une performance commerciale.
|
||||
Il ne s'agit pas ici de venir concurrencer Météo France, mais de jouer avec nos données et avec l'IA.
|
||||
Dans ce chapitre, on quitte le terrain purement descriptif pour tenter quelque chose de plus ambitieux : faire parler la station météo comme un petit modèle de prévision maison.
|
||||
L’idée est de construire un cadre simple, mais honnête, qui prédise au pas local la température, la pluie et le vent à plusieurs horizons (T+10 min, +60 min, +6 h, +24 h).
|
||||
On garde une approche expérimentale : on cherche à comprendre ce qui fonctionne, ce qui casse, et pourquoi, et non pas à rivaliser avec les services de prévision nationaux.
|
||||
Il s’agit avant tout de jouer avec nos données et avec l’IA, en gardant les pieds sur terre.
|
||||
|
||||
## Cibles et horizons
|
||||
|
||||
- Température (continue) ; Vitesse du vent (continue) ; Précipitations binaires (pluie ou neige oui/non). Éventuellement : événements extrêmes (forte chaleur/froid, risque d’orage) vus comme des seuils.
|
||||
- Horizons évalués : T+10, T+60, T+360 (~6 h), T+1440 (~24 h) minutes pour voir quand notre modèle montrera ses faiblesses.
|
||||
Concrètement, on veut prédire trois types de grandeurs.
|
||||
|
||||
D’abord des valeurs continues comme la température et la vitesse du vent, pour lesquelles on attend des erreurs exprimées en °C ou en km/h.
|
||||
Ensuite une variable binaire « pluie oui/non », qui condense les précipitations en un simple événement : y a‑t‑il eu pluie (ou neige fondue) sur le pas considéré, oui ou non ?
|
||||
On pourrait prolonger ce cadre vers des événements extrêmes (forte chaleur, coup de froid, rafales, risque d’orage) en posant des seuils, mais on reste ici sur ces cibles de base.
|
||||
|
||||
Ces cibles sont évaluées à plusieurs horizons pour voir à partir de quand la prévision décroche : T+10 minutes pour le très court terme, T+60 minutes pour l’heure qui vient, T+360 minutes (~6 h) pour la demi‑journée et T+1440 minutes (~24 h) pour l’échéance journalière.
|
||||
On ne s’attend pas à ce que le modèle soit bon partout ; justement, comparer les horizons permettra de voir où il commence à perdre pied.
|
||||
|
||||
## Métriques
|
||||
|
||||
- Température / vent : _MAE_ (_Mean Absolute Error_) = moyenne des écarts en valeur absolue, facile à lire en °C ou km/h ; _RMSE_ (_Root Mean Squared Error_) pénalise davantage les grosses erreurs pour mieux voir les limites du modèle lorsque des écarts importants apparaissent.
|
||||
- Précipitations binaires : précision (part des annonces de pluie qui étaient justes), rappel (part des pluies réellement captées), _F1_ (compromis précision/rappel), _Brier score_ (qualité des probabilités, plus il est bas mieux c’est) et _calibration_ des probabilités (est-ce qu’un 30 % de pluie signifie vraiment ~30 % des cas).
|
||||
- Événements extrêmes : même logique précision/rappel sur dépassement de seuils (chaleur/froid/rafale), avec suivi des fausses alertes pour rester prudent.
|
||||
Pour juger ces prévisions, on a besoin d’une grille de lecture commune.
|
||||
Sur la température et le vent, on utilise deux erreurs classiques : la _MAE_ (_Mean Absolute Error_), qui est en gros la moyenne des écarts en valeur absolue, et la _RMSE_ (_Root Mean Squared Error_), qui pénalise davantage les grosses erreurs (voir par exemple l’article sur l’[erreur quadratique moyenne](https://fr.wikipedia.org/wiki/Erreur_quadratique_moyenne)).
|
||||
|
||||
La MAE se lit directement en unités physiques (°C, km/h) et donne une intuition simple : « en moyenne, je me trompe de 0,7 °C ».
|
||||
La RMSE, elle, sert surtout à mettre en avant les scénarios dans lesquels le modèle déraille.
|
||||
|
||||
Pour la pluie binaire, on revient aux métriques de classification : précision (proportion des annonces de pluie qui étaient correctes), rappel (part des pluies réellement captées), [_F1_](https://fr.wikipedia.org/wiki/F-mesure) (compromis entre précision et rappel), et [_Brier score_](https://en.wikipedia.org/wiki/Brier_score) (qualité des probabilités, plus il est bas mieux c’est).
|
||||
On s’intéresse aussi à la calibration : lorsqu’on annonce 30 % de pluie, est‑ce qu’il pleut effectivement dans ~30 % des cas ?
|
||||
Un modèle mal calibré « sur‑réagit » ou se montre trop timide, même si son F1 est correct.
|
||||
|
||||
Pour des événements extrêmes éventuels (rafale, forte chaleur, etc.), on resterait sur la même logique précision/rappel, mais avec un focus particulier sur les fausses alertes : il vaut mieux ne pas déclencher une alerte dès que le modèle a un doute, surtout si l’utilisateur est un simple particulier.
|
||||
|
||||
## Limites à garder en tête
|
||||
|
||||
- Pas d’hiver complet dans le jeu actuel (mars→novembre) : les régimes froids et la neige sont absents.
|
||||
- Aucune info synoptique (pression régionale, nébulosité, vent en altitude) : le modèle reste “aveugle” au contexte large.
|
||||
- Pluie rare (~4 % des pas), donc classes déséquilibrées pour la partie pluie/orage.
|
||||
- Pas brut à 10 minutes : bon pour réactivité courte, mais bruité ; on testera aussi des features lissées.
|
||||
Avant de lancer des modèles, il faut aussi être clair sur **ce qu’ils ne pourront pas faire**.
|
||||
|
||||
Notre jeu de données ne couvre que mars à novembre : toute la saison froide manque, avec la neige, les pluies froides et les régimes hivernaux typiques.
|
||||
|
||||
La station ne voit que son environnement immédiat : elle n’a aucune information sur la situation synoptique (pression régionale, nébulosité large, vent en altitude), ce qui la laisse quasiment aveugle au contexte qui pilote la météo à grande échelle.
|
||||
|
||||
La pluie est rare (~4 % des pas de temps), ce qui crée un fort déséquilibre de classes pour la partie pluie/orage.
|
||||
|
||||
Enfin, le pas brut de 10 minutes est pratique pour la réactivité, mais assez bruité : il faudra tester des variables un peu lissées pour ne pas nourrir les modèles avec du « bruit blanc ».
|
||||
|
||||
Ces contraintes ne rendent pas l’exercice inutile ; elles fixent simplement la barre de ce que l’on peut raisonnablement espérer.
|
||||
Tout gain devra se lire à l’aune de ces limites.
|
||||
|
||||
## Données et découpes
|
||||
|
||||
- Source principale : `data/weather_minutely.csv` (pas 10 min), enrichissable au fil du temps. On peut réutiliser les CSV dérivés des chapitres précédents (matrices de lags/corrélations du chapitre 5, notamment) pour guider les lags utiles ou vérifier la cohérence.
|
||||
- Découpe temporelle sans fuite : partie _train_ (début→~70 %), partie validation (~15 % suivant), partie test finale (~15 % le plus récent). Variante : _time-series split_ “en rouleau”, où l’on répète ce découpage plusieurs fois ; on appelle _fold_ chaque paire (train, validation) ainsi construite.
|
||||
- Normalisation/standardisation : on calcule les paramètres (par exemple moyenne et écart-type) uniquement sur la partie _train_, puis on applique ces mêmes paramètres à la validation et au test. Cela évite d’introduire, par mégarde, des informations issues du futur dans les étapes de préparation des données.
|
||||
Le terrain de jeu reste le même : `data/weather_minutely.csv`, le dataset minuté du chapitre 2, mis à jour au fil du temps.
|
||||
On peut y rattacher les CSV dérivés des chapitres précédents (matrices de lags et de corrélations décalées du chapitre 5, notamment) pour guider les choix de variables et vérifier que les signaux utilisés restent cohérents.
|
||||
|
||||
## Variables dérivées de base (simples et explicables)
|
||||
Pour évaluer un modèle, on découpe cette série temporelle en trois morceaux successifs : une partie _train_ qui couvre environ les 70 % premiers points, une partie validation (~15 % suivant) qui sert à choisir les hyperparamètres sans toucher au test, et enfin une partie test (~15 % les plus récents) qui joue le rôle de futur inconnu.
|
||||
|
||||
Tout est gardé dans l’ordre chronologique pour éviter d’utiliser des informations à rebours.
|
||||
Une variante plus robuste consiste à utiliser un _time-series split_ « en rouleau » : on répète plusieurs fois ce découpage en faisant glisser la fenêtre d’apprentissage/validation dans le temps, chaque couple (_train_, validation) formant alors un _fold_.
|
||||
|
||||
La normalisation (ou standardisation) se fait, elle aussi, de façon prudente : on calcule les paramètres (par exemple moyenne et écart‑type) uniquement sur la partie _train_, puis on applique ces mêmes paramètres à la validation et au test.
|
||||
Cela évite de « voir le futur » lors de la préparation des données, ce qui fausserait immédiatement l’évaluation.
|
||||
|
||||
## Variables dérivées de base
|
||||
|
||||
- Temps (_sin_/_cos_) : l’heure et le jour de l’année sont périodiques ; représenter l’heure avec _sin_/_cos_ évite un faux saut entre 23h et 0h ou entre 31 déc et 1er jan. On encode ainsi heure/minute sur 24 h et jour de l’année sur 365 j.
|
||||
- Lags courts : valeurs à T-10, -20, -30 min pour chaque variable cible ; deltas (T0 − T-10) pour décrire la tendance récente (la “pente”) : est‑ce que la température, le vent ou la pression augmentent ou diminuent, et à quelle vitesse. Les lags analysés au chapitre 5 serviront d’inspiration.
|
||||
- Moyennes glissantes : moyenne ou médiane sur 30–60 min pour lisser le bruit ; cumul de pluie sur 30–60 min pour connaître l’état “humide” récent.
|
||||
- Composantes vent : (u, v) = (speed _ *sin*(direction), speed _ _cos_(direction)) pour représenter la direction sans discontinuité 0/360°.
|
||||
- Drapeaux d’événements : pluie*en_cours (rain_rate > 0), vent_fort (seuil), chaleur/froid (seuils). Peuvent servir de \_features* et de cibles dérivées.
|
||||
- Composantes vent : on projette la vitesse et la direction du vent en deux composantes cartésiennes `(u, v)` avec `u = speed * sin(direction)` et `v = speed * cos(direction)`. Cela permet de représenter la direction sans discontinuité artificielle entre 0° et 360° (un vent de 359° reste ainsi très proche d’un vent de 1°).
|
||||
- Drapeaux d’événements : créer des variables booléennes comme `pluie_en_cours` (quand `rain_rate > 0`), `vent_fort` (au‑delà d’un certain seuil) ou `chaleur`/`froid` (au‑delà/en‑deçà de seuils de température). Ces indicateurs peuvent servir de _features_ supplémentaires pour les modèles, mais aussi de cibles dérivées lorsque l’on s’intéresse à des événements plutôt qu’à des valeurs exactes.
|
||||
|
||||
## Références simples (points de comparaison)
|
||||
|
||||
@ -45,8 +75,8 @@ Il ne s'agit pas ici de venir concurrencer Météo France, mais de jouer avec no
|
||||
|
||||
## Modèles à introduire dans les chapitres suivants
|
||||
|
||||
- Modèles linéaires avec régularisation (_Ridge_/_Lasso_) pour températures/vents : même formule que la régression linéaire classique, mais avec un terme supplémentaire qui limite l’ampleur des coefficients pour réduire le sur‑apprentissage (_Ridge_ pénalise surtout les coefficients trop grands, _Lasso_ peut en forcer certains à zéro).
|
||||
- Régression logistique pour la pluie : produit une probabilité de pluie plutôt qu’un oui/non brut, ce qui permet ensuite de choisir un seuil de décision adapté à l’usage (plutôt prudent ou plutôt conservateur).
|
||||
- Si besoin de courbes plus flexibles : arbres peu profonds, _random forest_ ou _boosting_ légers pour capturer des relations non linéaires sans rendre le modèle complètement opaque.
|
||||
- Modèles linéaires avec régularisation ([_Ridge_](https://en.wikipedia.org/wiki/Ridge_regression)/[_Lasso_](<https://en.wikipedia.org/wiki/Lasso_(statistics)>)) pour températures/vents : même formule que la régression linéaire classique, mais avec un terme supplémentaire qui limite l’ampleur des coefficients pour réduire le sur‑apprentissage (_Ridge_ pénalise surtout les coefficients trop grands, _Lasso_ peut en forcer certains à zéro).
|
||||
- [Régression logistique](https://fr.wikipedia.org/wiki/R%C3%A9gression_logistique) pour la pluie : produit une probabilité de pluie plutôt qu’un oui/non brut, ce qui permet ensuite de choisir un seuil de décision adapté à l’usage (plutôt prudent ou plutôt conservateur).
|
||||
- Si besoin de courbes plus flexibles : arbres peu profonds, [_random forest_](https://fr.wikipedia.org/wiki/For%C3%AAt_al%C3%A9atoire) ou [_gradient boosting_](https://fr.wikipedia.org/wiki/Gradient_boosting) légers pour capturer des relations non linéaires sans rendre le modèle complètement opaque .
|
||||
- Évaluation multi-horizons avec _time-series split_, courbes d’erreur en fonction de l’horizon pour voir à partir de quand le modèle décroche.
|
||||
- Pipeline d’inférence local (_pipeline_ de prédiction) : charger le dernier point, générer les variables dérivées, prédire T+10/+60/+360/+1440, journaliser l’erreur au fil du temps pour suivre la qualité du modèle.
|
||||
|
||||
@ -1,11 +1,32 @@
|
||||
# Premiers modèles prédictifs
|
||||
|
||||
Objectif : passer de la description à la prédiction sur nos données locales, en restant simple et lisible. On compare quelques approches de base sur les horizons T+10, T+60, T+360 (~6 h) et T+1440 (~24 h) pour température, vent et pluie, sans présupposer que ça va marcher à tous les coups.
|
||||
Objectif : passer de la description à la prédiction sur nos données locales, en restant simple et lisible.
|
||||
L’idée est de prendre le cadre posé au chapitre 8 et de le peupler avec des modèles très basiques, pour voir ce qu’ils valent réellement sur les horizons T+10, T+60, T+360 (~6 h) et T+1440 (~24 h) pour la température, le vent et la pluie, sans présupposer que “plus complexe” signifie forcément “meilleur”.
|
||||
|
||||
## Point de départ : données, features et métriques
|
||||
|
||||
On travaille toujours à partir de `data/weather_minutely.csv` (pas 10 minutes), enrichi des variables dérivées vues au chapitre 8 : temps encodé en sin/cos, lags courts (T‑10/‑20/‑30), deltas, moyennes et cumuls glissants sur 30–60 minutes, composantes `(u, v)` du vent, drapeaux d’événements (pluie en cours, vent fort, chaleur/froid).
|
||||
|
||||
Cette table est découpée en trois blocs chronologiques : une partie _train_ (~70 % du début de la série) pour l’apprentissage, une partie validation (~15 % suivante) pour régler les hyperparamètres, et une partie test (~15 % la plus récente) pour juger les modèles sur un futur qui n’a pas servi à l’entraînement.
|
||||
On peut, en variante, utiliser un _time‑series split_ “en rouleau” comme décrit au chapitre 8, mais les figures de ce chapitre s’appuient sur une découpe simple.
|
||||
|
||||
Côté métriques, on reste sur les repères déjà introduits : MAE/RMSE pour température et vent, et pour la pluie binaire, le trio précision–rappel–[_F1_](https://fr.wikipedia.org/wiki/F-mesure) complété par le [_Brier score_](https://en.wikipedia.org/wiki/Brier_score) et la calibration des probabilités.
|
||||
Les modèles ne seront jugés intéressants que s’ils apportent un gain clair par rapport à des références naïves.
|
||||
|
||||
## Étape 1 — Baselines de référence
|
||||
|
||||
```shell
|
||||
python "docs/09 - Premiers modèles prédictifs/scripts/run_baselines.py"
|
||||
```
|
||||
|
||||
Ce premier script ne fait qu’une chose : mesurer la performance de quelques stratégies “bêtes mais honnêtes” qui serviront ensuite de ligne de base.
|
||||
Il lit le dataset minuté, applique le découpage temporel, puis entraîne et évalue :
|
||||
|
||||
- des baselines de persistance (prédire que la prochaine valeur est identique à la dernière observée) ;
|
||||
- des climatologies horaires (moyennes/quantiles par heure locale, éventuellement par saison) ;
|
||||
- des moyennes mobiles à court terme ;
|
||||
- un classifieur “toujours sec” pour la pluie, qui illustre à quel point la rareté des précipitations peut tromper les métriques.
|
||||
|
||||
Le script génère :
|
||||
|
||||
- deux CSV de résultats dans `docs/09 - Premiers modèles prédictifs/data/` :
|
||||
@ -15,11 +36,30 @@ Le script génère :
|
||||
- `baselines_mae_validation.png` (MAE vs horizon pour température et vent)
|
||||
- `baselines_rain_validation.png` (F1 et Brier vs horizon pour la pluie)
|
||||
|
||||
Ces deux graphiques résument ce que ces baselines savent faire, horizon par horizon.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Sur la figure MAE, la persistance reste imbattable jusqu’à +6 h sur la température, avec une erreur moyenne sous le degré ; à +24 h, elle se dégrade (MAE ≈1,5 °C), mais reste nettement devant la climatologie horaire, qui plafonne autour de 4–6 °C.
|
||||
|
||||
Pour le vent, la moyenne mobile sur 60 minutes devance légèrement la persistance dès +10 min, mais l’écart reste modeste et la MAE grimpe doucement avec l’horizon (≈2 km/h à +24 h).
|
||||
Le message est clair : sur un pas de 10 minutes, les baselines “bricolées” font déjà un travail honorable, et le gain potentiel d’un modèle plus riche sera nécessairement limité.
|
||||
|
||||
Sur la figure pluie, la persistance profite à plein de la rareté des événements : annoncer “sec” presque tout le temps donne un F1 très élevé aux petits horizons, même si le Brier score se dégrade en s’éloignant.
|
||||
La climatologie horaire, sans contexte, ne voit pratiquement jamais la pluie.
|
||||
Toute tentative de modèle devra donc battre la persistance sur F1/Brier, surtout à +60 et +360 minutes où le score chute déjà : la barre n’est pas très haute en absolu, mais elle l’est par rapport à la quantité d’information disponible dans une simple série locale.
|
||||
|
||||
Ces baselines fixent donc une référence indispensable : si un modèle plus sophistiqué n’apporte pas de gain visible par rapport à elles, il ne sert à rien en pratique.
|
||||
|
||||
## Étape 2 — Premiers modèles supervisés
|
||||
|
||||
```shell
|
||||
python "docs/09 - Premiers modèles prédictifs/scripts/run_first_models.py"
|
||||
```
|
||||
|
||||
Ce second script :
|
||||
Une fois les références en place, on passe à des modèles un peu plus élaborés. Ce second script :
|
||||
|
||||
- construit les variables dérivées (sin/cos temporels, lags, deltas, moyennes glissantes, vent u/v, drapeaux) à partir du CSV brut ;
|
||||
- découpe en _train_/_validation_/_test_ (70/15/15 %) ;
|
||||
@ -28,66 +68,28 @@ Ce second script :
|
||||
- exporte `models_regression.csv` et `models_rain.csv` dans `docs/09 - Premiers modèles prédictifs/data/` ;
|
||||
- produit `models_mae_validation.png` (MAE vs horizon pour température et vent) dans `docs/09 - Premiers modèles prédictifs/figures/`.
|
||||
|
||||
## Données et préparation
|
||||

|
||||
|
||||
- Jeu principal : `data/weather_minutely.csv` (pas 10 min), mis à jour au fil du temps. On peut réutiliser les CSV dérivés (matrices de lags/corrélations du chapitre 5) pour choisir des lags pertinents et vérifier la cohérence.
|
||||
- Variables dérivées reprises du chapitre 8 : temps en _sin_/_cos_, lags courts (T-10/-20/-30), deltas (variation récente), moyennes/cumul sur 30–60 min, composantes (u, v) du vent, drapeaux d’événements (pluie en cours, vent fort, chaleur/froid).
|
||||
- Normalisation : on calcule moyenne/écart-type sur la partie _train_ uniquement, puis on applique ces paramètres aux parties _validation_ et _test_ pour ne pas utiliser d’informations futures.
|
||||
Cette figure concentre la lecture sur température et vent, en MAE vs horizon.
|
||||
|
||||
## Découpage et validation
|
||||
Côté température, Ridge/Lasso battent légèrement la persistance sur tous les horizons sauf à +10 min (MAE ≈0,14 à +60 min vs 0,15 pour la persistance ; ≈1,48 à +1440 vs 1,55).
|
||||
Injecter les variables corrélées (humidité, illuminance, pression…) donne un petit gain par rapport à la version “lags génériques”, mais la marge reste modeste.
|
||||
|
||||
- Découpe sans fuite : _train_ (début→~70 %), _validation_ (~15 % suivant), _test_ (~15 % le plus récent), tout en ordre chronologique.
|
||||
- Variante robuste : _time-series split_ “en rouleau”, où l’on répète plusieurs découpes successives ; chaque paire (_train_, _validation_) est un _fold_. Cela aide à voir si un modèle reste stable dans le temps.
|
||||
Pour le vent, la logique est la même : un léger mieux que la persistance (≈0,87 à +10 min vs 0,99 ; ≈1,67 à +1440 vs 1,74), sans révolution.
|
||||
Les corrélations étant globalement faibles, l’apport des autres variables reste limité sur ce pas de 10 minutes.
|
||||
|
||||
## Références de comparaison (_baselines_)
|
||||
Pour la pluie, la régression logistique ne parvient pas encore à dépasser la persistance : F1 ≈0,91 à +10 min contre 0,94 pour la persistance, puis chute rapide à +60 min et au‑delà.
|
||||
La probabilité produite est pourtant correctement calibrée (Brier ≈0,011 à +10 min), mais cela ne suffit pas à compenser l’avantage d’un modèle qui “reste sec” la plupart du temps.
|
||||
Il faudra enrichir les variables d’entrée ou changer de famille de modèles pour espérer dépasser cette baseline très difficile à battre sur une série aussi déséquilibrée.
|
||||
|
||||
- Persistance : prédire que la prochaine valeur est identique à la dernière observée (par horizon).
|
||||
- Climatologie horaire : moyenne ou quantiles par heure locale (et éventuellement par saison) pour température/vent ; fréquence de pluie par heure pour la pluie.
|
||||
- Moyenne mobile : prolonger la moyenne des 30–60 dernières minutes.
|
||||
- Pluie rare : classifieur “toujours sec” comme seuil minimal ; si un modèle ne fait pas mieux, il ne sert à rien.
|
||||
En résumé, ces premiers modèles linéaires apportent un petit gain sur température/vent, mais échouent encore à battre la persistance pour la pluie.
|
||||
Ils fixent un second niveau de référence : toute complexité supplémentaire devra se justifier par un gain clair, surtout sur les horizons intermédiaires (+60/+360 min) où les baselines commencent à se dégrader.
|
||||
|
||||
## Modèles simples à essayer
|
||||
## Conclusion
|
||||
|
||||
- Régressions linéaires avec régularisation (_Ridge_/_Lasso_) pour température et vent : même principe que la régression linéaire, avec un terme qui limite l’ampleur des coefficients (_Ridge_) ou peut en annuler certains (_Lasso_) pour éviter le sur-apprentissage.
|
||||
- Régression logistique pour la pluie : fournit une probabilité de pluie plutôt qu’un oui/non, ce qui permet d’ajuster le seuil selon l’usage (prudence ou non).
|
||||
- Si besoin de non-linéarités : petits arbres de décision, _random forest_ ou _boosting_ légers pour capturer des relations plus courbes tout en restant interprétables.
|
||||
Contre l’intuition, c’est au très court terme que nos modèles simples se heurtent à un mur pour la pluie : la persistance reste devant à +10 min, et l’écart se creuse déjà à +60 min.
|
||||
|
||||
## Lecture des résultats
|
||||
Pour la température et le vent, les gains existent mais restent modestes, même à +10 min, alors qu’on pouvait espérer que ces prévisions soient “faciles”.
|
||||
Les horizons longs se dégradent comme prévu, mais le vrai défi est donc d’améliorer les prédictions proches sans sur-complexifier.
|
||||
|
||||
- Température / vent : _MAE_ et _RMSE_ (définis au chapitre 8) pour juger l’erreur moyenne et la sensibilité aux grosses erreurs.
|
||||
- Pluie : précision, rappel, _F1_, _Brier score_ et calibration des probabilités pour voir si les annonces de pluie sont réalistes et bien calibrées.
|
||||
- Multi-horizons : tracer l’erreur en fonction de l’horizon pour identifier à partir de quand la prévision décroche. On s’attend à ce que +24 h soit difficile sans contexte synoptique, et on documentera ces limites.
|
||||
|
||||
## Déroulé proposé
|
||||
|
||||
1. Construire les variables dérivées et sauvegarder un jeu prêt pour l’apprentissage (en suivant le découpage temporel).
|
||||
2. Évaluer les références (_baselines_) sur chaque horizon.
|
||||
3. Entraîner les modèles simples (linéaires régularisés, logistique, éventuellement arbres légers) et comparer aux références.
|
||||
4. Consolider l’évaluation multi-horizons (_time-series split_), conserver les résultats pour les chapitres suivants (affinements et pipeline d’inférence local).
|
||||
|
||||
## Synthèse visuelle des baselines (validation)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### Ce que montrent ces baselines
|
||||
|
||||
- Température : la persistance reste imbattable jusqu’à +6 h avec une MAE < 1 °C ; au-delà (+24 h), l’erreur grimpe (≈1,5 °C) mais reste meilleure que la climatologie horaire qui plafonne autour de 4–6 °C. On part donc avec un avantage net sur le très court terme, mais l’horizon journalier sera plus difficile.
|
||||
- Vent : la moyenne mobile 60 min devance légèrement la persistance dès +10 min, mais l’écart reste faible et l’erreur croît avec l’horizon (MAE ≈2 km/h à +24 h). Le gain potentiel d’un modèle plus riche sera modeste si l’on reste sur ce pas de 10 min.
|
||||
- Pluie (binaire) : la persistance affiche des F1 élevés aux petits horizons parce que la pluie est rare et que “rester sec” gagne souvent ; le Brier augmente avec l’horizon, signe que la confiance se dégrade. La climatologie horaire est nulle : sans contexte, elle ne voit pas la pluie. Toute tentative de modèle devra donc battre la persistance sur F1/Brier, surtout à +60/+360 min où le score chute déjà.
|
||||
- Conclusion provisoire : les baselines définissent une barre à franchir — forte sur le très court terme (température/vent), beaucoup plus basse pour la pluie (où la rareté favorise la persistance). Les modèles devront prouver un gain net sur ces repères, en particulier sur les horizons intermédiaires (+60/+360 min) où la prévisibilité commence à décrocher.
|
||||
|
||||
## Premiers modèles (Ridge/Lasso/logistique)
|
||||
|
||||

|
||||
|
||||
- Température : Ridge/Lasso battent légèrement la persistance sur tous les horizons sauf à +10 min (MAE ≈0,14 à +60 min vs 0,15 pour la persistance ; ≈1,48 à +1440 vs 1,55). Injecter les variables corrélées (humiditié, illumination, pression…) donne un petit gain par rapport à la version “lags génériques”, mais la marge reste modeste.
|
||||
- Vent : même logique, un léger mieux que la persistance (≈0,87 à +10 min vs 0,99 ; ≈1,67 à +1440 vs 1,74). Les corrélations étant faibles, l’apport des autres variables reste limité.
|
||||
- Pluie : la régression logistique reste derrière la persistance (F1 ≈0,91 à +10 min contre 0,94 pour la persistance ; chute rapide à +60 et au-delà). La probabilité est calibrée (Brier ≈0,011 à +10 min), mais ne compense pas l’avantage de “rester sec”. Il faudra enrichir les features ou changer de modèle pour espérer dépasser la baseline.
|
||||
|
||||
En résumé, les modèles linéaires apportent un petit gain sur température/vent et échouent encore à battre la persistance pour la pluie. C’est une base de référence ; les prochains essais devront justifier leur complexité par un gain clair, surtout sur les horizons où les baselines se dégradent (+60/+360 min).
|
||||
|
||||
## Conclusion provisoire du chapitre
|
||||
|
||||
Contre l’intuition, c’est au très court terme que nos modèles simples se heurtent à un mur pour la pluie : la persistance reste devant à +10 min, et l’écart se creuse déjà à +60 min. Pour la température et le vent, les gains existent mais restent modestes, même à +10 min, alors qu’on pouvait espérer les “faciles”. Les horizons longs se dégradent comme prévu, mais le vrai défi est donc d’améliorer les prédictions proches sans sur-complexifier. Prochaine étape : tester des modèles plus flexibles (arbres/boosting) et enrichir les features, tout en vérifiant que le gain sur les petits horizons justifie l’effort.
|
||||
Prochaine étape : tester des modèles plus flexibles (arbres/boosting) et enrichir les features, tout en vérifiant que le gain sur les petits horizons justifie l’effort.
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
# Modèles non linéaires (arbres, forêts, gradient boosting)
|
||||
|
||||
Objectif : tester des modèles plus flexibles que les régressions linéaires/logistiques, en restant raisonnables côté ressources. On utilise des forêts aléatoires (_random forest_) et du _gradient boosting_ sur les mêmes horizons (T+10, T+60, T+360, T+1440) pour température, vent et pluie.
|
||||
Objectif : tester des modèles plus flexibles que les régressions linéaires/logistiques, en restant raisonnables côté ressources. On utilise des forêts aléatoires (_random forest_, voir [forêt aléatoire](https://fr.wikipedia.org/wiki/For%C3%AAt_al%C3%A9atoire)) et du _gradient boosting_ (voir [gradient boosting](https://fr.wikipedia.org/wiki/Gradient_boosting)) sur les mêmes horizons (T+10, T+60, T+360, T+1440) pour température, vent et pluie, afin de voir si cette complexité supplémentaire paie réellement sur nos données locales.
|
||||
|
||||
```shell
|
||||
python "docs/10 - Modèles non linéaires/scripts/run_tree_models.py"
|
||||
```
|
||||
|
||||
Le script :
|
||||
Ce script réutilise le même jeu de données minutées que les chapitres précédents et applique un pipeline très proche, en changeant simplement la famille de modèles. Le déroulé est le suivant :
|
||||
|
||||
- lit `data/weather_minutely.csv` et construit les variables dérivées (sin/cos, lags/deltas/moyennes, vent u/v, drapeaux) ;
|
||||
- s’appuie sur la matrice de corrélation décalée (chapitre 5) pour prioriser les variables/lags avec |r| ≥ 0,2, tout en conservant les cibles ;
|
||||
@ -28,9 +28,10 @@ Le script :
|
||||
- Vent : gains modestes, MAE ~0,94 à +10 min (GB) et ~1,19 à +60 min, sans dépassement clair des modèles linéaires précédents.
|
||||
- Pluie : F1 ≈0,85 (forêt) et 0,67 (GB) à +10 min, mais toujours en dessous de la persistance (~0,94) ; le Brier reste modéré (~0,02–0,03). Aux horizons +60/+360/+1440, les scores retombent rapidement.
|
||||
|
||||
## Conclusion provisoire
|
||||
## Conclusion
|
||||
|
||||
Ces modèles non linéaires apportent de la flexibilité mais, avec un apprentissage allégé pour tenir le temps de calcul, ils ne battent pas les baselines ni les modèles linéaires sur les horizons courts. Pour progresser, il faudra soit élargir l’échantillon d’apprentissage (temps de calcul plus long), soit régler finement les hyperparamètres, soit enrichir les features (ou combiner les deux).
|
||||
Ces modèles non linéaires apportent de la flexibilité mais, avec un apprentissage allégé pour tenir le temps de calcul, ils ne battent pas les baselines ni les modèles linéaires sur les horizons courts.
|
||||
Pour progresser, il faudra soit élargir l’échantillon d’apprentissage (temps de calcul plus long), soit régler finement les hyperparamètres, soit enrichir les features (ou combiner les deux).
|
||||
|
||||
À ce stade, les modèles non-linéaires "naïfs" que l'on a implémenté ici travaillent pendant plusieurs minutes et ne sont pas capables de faire mieux que les modèles vus précédemment.
|
||||
Je doute donc qu'il soit pertinent de creuser le sujet, mais cela a aiguisé ma curiosité pour des modèles existants, pré-entraînés, tels que Chronos, d'Amazon.
|
||||
Je doute donc qu'il soit pertinent de creuser bien davantage cette piste dans le cadre local actuel, mais cela a aiguisé ma curiosité pour des modèles existants, pré-entraînés, tels que Chronos d'Amazon, que l’on testera au chapitre suivant.
|
||||
|
||||
@ -1,23 +1,43 @@
|
||||
# Modèle Chronos-2 (foundation model HF)
|
||||
|
||||
Objectif : tester un modèle de prévision généraliste récent (**Chronos-2**, Amazon) en zéro-shot sur notre station. On resample la température à l’heure, on coupe les dernières 96 h pour évaluer la prévision, et on compare le forecast à l’observé.
|
||||
Dans les chapitres précédents, on a testé des modèles “fabriqués maison” (linéaires, arbres, forêts, boosting) sur nos données locales.
|
||||
Ici, on bascule dans un autre monde : celui des modèles de prévision pré‑entraînés sur de vastes jeux de séries temporelles.
|
||||
|
||||
**Chronos‑2**, développé par Amazon et distribué notamment via [Hugging Face](https://huggingface.co/amazon/chronos-t5-small) et le dépôt [chronos‑forecasting](https://github.com/amazon-science/chronos-forecasting), est un modèle de type “foundation” capable de produire des prévisions probabilistes sur des séries très variées.
|
||||
|
||||
L’objectif est de le tester en zéro‑shot sur notre station : lui fournir uniquement l’historique local (sans ré‑entraînement), lui demander une prévision et voir comment il se comporte face aux observations et aux modèles précédents.
|
||||
|
||||
## Première passe : choix de la taille du modèle (horizon 96 h)
|
||||
|
||||
On commence par un exercice simple : prédire les 96 dernières heures de température à partir des 336 heures précédentes, en faisant en resampling de la série à l’heure.
|
||||
On coupe donc les 96 h finales, on fournit à Chronos le contexte horaire, et on compare sa prévision aux observations.
|
||||
|
||||
```shell
|
||||
python "docs/11 - Modèle Chronos/scripts/run_chronos.py"
|
||||
```
|
||||
|
||||
### Résultats comparés
|
||||
Ce script s’appuie sur quelques variables d’environnement pour contrôler le comportement du modèle :
|
||||
|
||||
Nous avons utilisé les variables d’environnement suivantes : `CHRONOS_CONTEXT` (336 h), `CHRONOS_HORIZON` (96 h), `CHRONOS_RESAMPLE` (`1h`), `CHRONOS_SAMPLES` (20).
|
||||
- `CHRONOS_CONTEXT` : longueur du contexte temporel fourni au modèle (ici 336 h, soit 14 jours) ;
|
||||
- `CHRONOS_HORIZON` : horizon de prévision demandé (96 h) ;
|
||||
- `CHRONOS_RESAMPLE` : pas temporel utilisé (`1h`) ;
|
||||
- `CHRONOS_SAMPLES` : nombre d’échantillons générés pour lisser la prévision (20).
|
||||
|
||||

|
||||
|
||||
Sur la même fenêtre de validation locale, nous avons testé trois tailles (`CHRONOS_MODEL`) : `chronos-t5-mini`, `chronos-t5-small` et `chronos-t5-base`. Le modèle **small** semble le plus précis (MAE ≈ 3,68 °C, RMSE ≈ 4,53 °C), les versions mini et base étant derrière (MAE ≈ 4,18–4,24 °C, RMSE ≈ 5,3–5,6 °C). Autrement dit, monter en taille n’a pas amélioré la prévision à 96 h sur ces données locales ; la version `small` offre le meilleur compromis précision/poids.
|
||||
Sur cette même fenêtre de validation locale, on teste trois tailles de modèle (`CHRONOS_MODEL`) : `chronos-t5-mini`, `chronos-t5-small` et `chronos-t5-base`. Le script de comparaison :
|
||||
|
||||
```shell
|
||||
python "docs/11 - Modèle Chronos/scripts/compare_chronos.py"
|
||||
```
|
||||
|
||||
produit la figure suivante, qui résume la performance par taille.
|
||||
|
||||

|
||||
|
||||
Le modèle **small** ressort comme le meilleur compromis : MAE ≈ 3,68 °C, RMSE ≈ 4,53 °C, alors que les versions mini et base sont derrière (MAE ≈ 4,18–4,24 °C, RMSE ≈ 5,3–5,6 °C) sur cette fenêtre.
|
||||
Autrement dit, “monter en taille” n’améliore pas la prévision à 96 h sur nos données ; Chronos‑small fait ici légèrement mieux que ses voisins, pour un coût de calcul encore raisonnable.
|
||||
|
||||
On peut ensuite inspecter, pour chaque taille, la trajectoire temporelle prédit vs observé :
|
||||
|
||||
#### chronos-t5-mini
|
||||
|
||||

|
||||
@ -26,26 +46,40 @@ python "docs/11 - Modèle Chronos/scripts/compare_chronos.py"
|
||||
|
||||

|
||||
|
||||
Le modèle suit un peu mieux la courbe de référence que les autres, mais une forte amplitude existe.
|
||||
Le modèle small suit un peu mieux la courbe de référence que les autres, même si l’amplitude reste importante à 96 h.
|
||||
|
||||
#### chronos-t5-base
|
||||
|
||||

|
||||
|
||||
### Lecture et portée
|
||||
Au terme de cette première passe, on retient donc `chronos-t5-small` comme taille “par défaut” pour la suite des expériences.
|
||||
|
||||
Pour coller à nos horizons cibles, `run_chronos_multi.py` évalue Chronos-small sur 1 h, 6 h et 24 h pour la température, le vent et la pluie (horaire uniquement ; l’horizon 10 minutes n’est pas couvert par Chronos qui est pré-entraîné en pas horaire). Les figures `chronos_multi_temperature.png`, `chronos_multi_wind_speed.png` et `chronos_multi_rain_rate.png` illustrent où le modèle est le plus fiable : à 1 h, la température reste sous ~1,3 °C de MAE et le vent sous ~0,6 km/h ; à 6 h, l’erreur grimpe modérément (≈2 °C temp., ≈3 km/h vent) ; à 24 h, elle dépasse 4–6 (°C/ km/h). Sur la pluie, le F1 reste nul à 1 h/6 h et ne monte qu’à ~0,15 à 24 h, signe que le modèle “foundation” horaire ne capture pas bien les occurrences locales rares.
|
||||
## Évaluation multi-horizons locale (1 h, 6 h, 24 h)
|
||||
|
||||
Pour comparer plus finement à notre cadre prédictif local, on évalue ensuite Chronos‑small sur des horizons plus courts, en restant au pas horaire (Chronos n’est pas pré‑entraîné au pas 10 minutes).
|
||||
Le script suivant demande au modèle de prévoir la température, le vent et la pluie à 1 h, 6 h et 24 h :
|
||||
|
||||
```shell
|
||||
python "docs/11 - Modèle Chronos/scripts/run_chronos_multi.py"
|
||||
```
|
||||
|
||||
Les trois figures suivantes montrent la performance par horizon :
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
On y voit que :
|
||||
|
||||
- à 1 h, la température reste sous ~1,3 °C de MAE et le vent sous ~0,6 km/h ;
|
||||
- à 6 h, l’erreur grimpe modérément (≈2 °C pour la température, ≈3 km/h pour le vent) ;
|
||||
- à 24 h, elle dépasse 4–6 unités (°C / km/h) ;
|
||||
- sur la pluie, le F1 reste nul à 1 h/6 h et ne monte qu’à ~0,15 à 24 h, signe que ce modèle “foundation” horaire ne capture pas bien les occurrences locales rares.
|
||||
|
||||
Pour avoir une vue plus synthétique, on combine les erreurs sur plusieurs figures :
|
||||
|
||||
```shell
|
||||
python "docs/11 - Modèle Chronos/scripts/plot_chronos_errors_combined.py"
|
||||
```
|
||||
@ -54,7 +88,7 @@ python "docs/11 - Modèle Chronos/scripts/plot_chronos_errors_combined.py"
|
||||
|
||||

|
||||
|
||||
Les figures individuelles permettent de voir la trajectoire prédite vs observée (dans la section précédente) et l’erreur par horizon (ci-dessous).
|
||||
Enfin, un script dédié permet de comparer directement, pour plusieurs tailles de Chronos, l’erreur absolue en fonction de l’horizon :
|
||||
|
||||
```shell
|
||||
python "docs/11 - Modèle Chronos/scripts/run_chronos_multi_errors.py"
|
||||
@ -62,9 +96,17 @@ python "docs/11 - Modèle Chronos/scripts/run_chronos_multi_errors.py"
|
||||
|
||||

|
||||
|
||||
Au final, Chronos-small fournit un signal exploitable sur la température et un peu sur le vent pour des horizons courts à intermédiaires, mais reste faible sur la pluie et se dégrade nettement au-delà de 24 h. Une calibration locale, davantage de contexte ou une cible adaptée (pluie binaire calibrée) seraient nécessaires pour en faire un outil de prévision robuste sur toutes les variables.
|
||||
Au final, dans cette configuration zéro‑shot, Chronos‑small fournit un signal exploitable sur la température (surtout à 1–6 h) et un peu sur le vent, mais reste faible sur la pluie et se dégrade nettement au‑delà de 24 h.
|
||||
Pour en faire un outil de prévision robuste sur toutes les variables, il faudrait envisager une calibration locale, davantage de contexte ou des cibles adaptées (par exemple une pluie binaire mieux calibrée).
|
||||
|
||||
### Réglages prudents (contexte 288 h, horizon limité à 64 h, 100 échantillons)
|
||||
## Réglages plus prudents (contexte 288 h, horizon limité à 64 h, 100 échantillons)
|
||||
|
||||
Une troisième série d’essais cherche à voir si un Chronos‑small “raisonnablement bridé” se comporte mieux qu’une version trop ambitieuse.
|
||||
L’idée : moins de contexte, un horizon maximum plus court, mais davantage d’échantillons pour lisser la prévision :
|
||||
|
||||
```shell
|
||||
python "docs/11 - Modèle Chronos/scripts/run_chronos_tuned.py"
|
||||
```
|
||||
|
||||

|
||||
|
||||
@ -72,9 +114,18 @@ Au final, Chronos-small fournit un signal exploitable sur la température et un
|
||||
|
||||

|
||||
|
||||
Avec `run_chronos_tuned.py`, on réduit le contexte (288 h) et l’horizon maximum (64 h) tout en augmentant les échantillons (100). Sur la même fenêtre locale, la température s’améliore nettement : MAE ~0,75 °C à 1 h, ~1,27 °C à 6 h, ~3,40 °C à 24 h (vs 1,33/2,02/4,84 auparavant). Le vent progresse surtout à 24 h (≈2,39 contre ~6,38 auparavant), même si le 1 h est moins bon que la première passe. La pluie reste instable : le F1 peut atteindre 0,22–0,28 à 24–48 h mais les scores courts sont peu fiables. Limiter l’horizon à 64 h, raccourcir le contexte et lisser par davantage d’échantillons améliorent donc la température et le vent, mais ne suffisent pas à rendre la pluie prédictible.
|
||||
Avec ces réglages (contexte 288 h, horizon limité à 64 h, 100 échantillons), la température s’améliore nettement sur la même fenêtre locale : MAE ~0,75 °C à 1 h, ~1,27 °C à 6 h, ~3,40 °C à 24 h (contre ~1,33/2,02/4,84 auparavant).
|
||||
|
||||
### Dernier essai en conditions réelles : prévision sur les 6 dernières heures
|
||||
Le vent progresse surtout à 24 h (≈2,39 km/h contre ~6,38 km/h initialement), même si l’horizon 1 h est un peu moins bon.
|
||||
La pluie reste instable : le F1 peut atteindre 0,22–0,28 à 24–48 h, mais les scores à court terme demeurent peu fiables.
|
||||
|
||||
En pratique, raccourcir le contexte, limiter l’horizon et augmenter le nombre d’échantillons améliore donc nettement la température et le vent, mais ne suffit pas à rendre la pluie réellement prédictible à partir de cette seule station.
|
||||
|
||||
## Dernier essai quasi “en conditions réelles” : prévision sur les 6 dernières heures
|
||||
|
||||
Pour terminer, on simule une situation d’usage : prévoir les 6 prochaines heures à partir de l’historique immédiatement disponible, sans les connaître à l’avance.
|
||||
|
||||
On masque donc les 6 dernières heures de la série, on fournit à Chronos‑small 288 h de contexte, et on lui demande la prévision correspondante :
|
||||
|
||||
```shell
|
||||
python "docs/11 - Modèle Chronos/scripts/run_chronos_holdout6.py"
|
||||
@ -82,4 +133,8 @@ python "docs/11 - Modèle Chronos/scripts/run_chronos_holdout6.py"
|
||||
|
||||

|
||||
|
||||
On a masqué les 6 dernières heures de la série et demandé à Chronos-small (contexte 288 h, 50 échantillons) de prévoir température, vent (vitesse + direction), humidité et pression, puis comparé aux valeurs réelles. Moyennes des erreurs absolues sur ces 6 pas : température ~0,84 °C, vent ~1,2 km/h, direction ~3,9°, pression ~5,3 hPa, humidité ~24 %. Les erreurs restent très contenues sur température/vent et la direction est raisonnable (quelques degrés) ; la pression dérive (5 hPa) et l’humidité est clairement décalée. Ce test confirme que Chronos peut fournir des tendances crédibles à très court terme (<6 h) sur température et vent, mais pas sur l’humidité (et on a vu plus haut que la pluie reste peu fiable).
|
||||
Sur ces 6 pas, les moyennes des erreurs absolues sont les suivantes : température ~0,84 °C, vent ~1,2 km/h, direction ~3,9°, pression ~5,3 hPa, humidité ~24 %.
|
||||
|
||||
Les erreurs restent très contenues sur température et vent, la direction est raisonnable (quelques degrés de décalage) ; la pression dérive (≈5 hPa) et l’humidité est clairement décalée.
|
||||
|
||||
Ce test, modeste, mais concret, confirme que Chronos peut fournir des tendances crédibles à très court terme (<6 h) sur la température et le vent dans ce cadre zéro‑shot, mais qu’il reste peu fiable sur l’humidité et la pluie, où l’on a vu plus haut que les occurrences locales rares sont difficiles à capter pour un modèle généraliste.
|
||||
|
||||
BIN
docs/12 - Conclusion/figures/weekday_profiles.png
Normal file
BIN
docs/12 - Conclusion/figures/weekday_profiles.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
@ -48,3 +48,14 @@ Une simple série locale, aussi bien nettoyée soit‑elle, ne suffit pas à dé
|
||||
Ce projet n’aboutit pas à un modèle de prévision local prêt à l’emploi, mais il remplit une autre fonction : celle d’un carnet d’exploration.
|
||||
On y voit comment des données réelles, avec leurs trous et leurs biais, peuvent être préparées, visualisées, confrontées à la physique, puis poussées jusqu’à leurs limites prédictives.
|
||||
Si un lecteur a envie de reprendre ce travail, d’ajouter des sources externes, de tester d’autres modèles ou simplement de tracer de nouveaux graphiques, tant mieux : la station continue d’enregistrer, et l’histoire ne s’arrête pas ici.
|
||||
|
||||
Pour finir sur une note plus légère, un petit script de curiosité :
|
||||
|
||||
```shell
|
||||
python "docs/12 - Conclusion/scripts/plot_weekday_profiles.py"
|
||||
```
|
||||
|
||||
calcule les moyennes de température, d’humidité et de luminance pour chaque jour de la semaine et produit le graphique ci‑dessous.
|
||||
Dans mon jeu de données, c’est le samedi qui ressort comme le jour « le plus agréable » : en moyenne un peu plus chaud, un peu plus lumineux, et moins humide que ses voisins… ce qui tombe plutôt bien pour organiser les activités du week‑end.
|
||||
|
||||

|
||||
|
||||
79
docs/12 - Conclusion/scripts/plot_weekday_profiles.py
Normal file
79
docs/12 - Conclusion/scripts/plot_weekday_profiles.py
Normal file
@ -0,0 +1,79 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
import pandas as pd
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[3]
|
||||
if str(PROJECT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from meteo.dataset import load_raw_csv
|
||||
from meteo.variables import VARIABLES_BY_KEY, Variable
|
||||
from meteo.plots import plot_weekday_profiles
|
||||
|
||||
|
||||
CSV_PATH = PROJECT_ROOT / "data" / "weather_minutely.csv"
|
||||
DOC_DIR = Path(__file__).resolve().parent.parent
|
||||
OUTPUT_PATH = DOC_DIR / "figures" / "weekday_profiles.png"
|
||||
|
||||
# On se concentre sur le ressenti "agréable" : température, humidité, lumière.
|
||||
VARIABLE_KEYS = ["temperature", "humidity", "illuminance"]
|
||||
|
||||
|
||||
def compute_weekday_means(df: pd.DataFrame, variables: list[Variable]) -> pd.DataFrame:
|
||||
"""
|
||||
Calcule, pour chaque jour de semaine (0=lundi,…,6=dimanche),
|
||||
la moyenne des variables fournies.
|
||||
"""
|
||||
if df.empty:
|
||||
return pd.DataFrame(index=range(7))
|
||||
|
||||
weekday_index = df.index.dayofweek
|
||||
columns = [var.column for var in variables]
|
||||
weekday_means = df.groupby(weekday_index)[columns].mean()
|
||||
# S'assure que toutes les valeurs 0–6 sont présentes, même si certaines manquent.
|
||||
weekday_means = weekday_means.reindex(range(7))
|
||||
weekday_means.index.name = "weekday"
|
||||
return weekday_means
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if not CSV_PATH.exists():
|
||||
print(f"⚠ Fichier introuvable : {CSV_PATH}")
|
||||
return
|
||||
|
||||
df = load_raw_csv(CSV_PATH)
|
||||
print(f"Dataset minuté chargé : {CSV_PATH}")
|
||||
print(f" Lignes : {len(df)}")
|
||||
print(f" Colonnes : {list(df.columns)}")
|
||||
print()
|
||||
|
||||
variables = [VARIABLES_BY_KEY[key] for key in VARIABLE_KEYS]
|
||||
weekday_means = compute_weekday_means(df, variables)
|
||||
|
||||
output_path = plot_weekday_profiles(
|
||||
weekday_df=weekday_means,
|
||||
variables=variables,
|
||||
output_path=OUTPUT_PATH,
|
||||
title="Moyennes par jour de semaine",
|
||||
)
|
||||
|
||||
print(f"✔ Profils hebdomadaires exportés : {output_path}")
|
||||
|
||||
weekday_labels_long = ["lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche"]
|
||||
for var in variables:
|
||||
series = weekday_means[var.column]
|
||||
if series.isna().all():
|
||||
continue
|
||||
best_idx = int(series.idxmax())
|
||||
best_label = weekday_labels_long[best_idx]
|
||||
best_value = series.max()
|
||||
unit = f" {var.unit}" if var.unit else ""
|
||||
print(f" → {var.label} maximale en moyenne le {best_label} (≈{best_value:.2f}{unit})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user