diff --git a/module3/exo3/exercice.ipynb b/module3/exo3/exercice.ipynb index 0bbbe371b01e359e381e43239412d77bf53fb1fb..cddb5e877f7de4d9b6c888a1310d6fbd18e38731 100644 --- a/module3/exo3/exercice.ipynb +++ b/module3/exo3/exercice.ipynb @@ -1,5 +1,867 @@ { - "cells": [], + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Sujet 1 - Concentration de CO2 dans l'atmosphère depuis 1958" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Récupération des données et analyse préliminaire" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Les données sur la concentration de CO2 dans l'atmosphère à l'observatoire de Mauna Loa sont disponibles sur le site web de l'[institut Scripps](https://scrippsco2.ucsd.edu/data/atmospheric_co2/primary_mlo_co2_record.html). La série de données s'étend de 1958 à nos jours. Les données considérées sont les relevés avec une granularité hebdomadaire. Elles sont disponibles à l'adresse suivante:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data_url = \"https://scrippsco2.ucsd.edu/assets/data/atmospheric/stations/in_situ_co2/weekly/weekly_in_situ_co2_mlo.csv\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pour nous protéger contre une éventuelle disparition ou modification du serveur de l'institut Scripps, nous faisons une copie locale de ce jeux de données que nous préservons avec notre analyse. Il est inutile et même risquée de télécharger les données à chaque exécution, car dans le cas d'une panne nous pourrions remplacer nos données par un fichier défectueux. Pour cette raison, nous téléchargeons les données seulement si la copie locale n'existe pas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data_file = \"CO2_Mauna_Loa_Hebdo.csv\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import urllib.request\n", + "if not os.path.exists(data_file):\n", + " urllib.request.urlretrieve(data_url, data_file)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Le jeu de données est téléchargé le 01/10/2020 à 17h44." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Un examen préliminaire des données permet d'en observer la structure.\n", + "\n", + "On note que les 44 premières lignes décrivent le contexte général. Ellent devront donc être supprimées lors de l'extraction des données.\n", + "\n", + "Les lignes 40 à 44 précisent que les unités de concentration de CO2 sont des micro-moles de CO2 par mole (ppm). Ces valeurs sont considérées à 12h00 le samedi de chaque semaine.\n", + "\n", + "On note également que les dates sont au format \"AAAA-MM-JJ\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Lignes = []\n", + "with open(data_file, \"r\", encoding='utf-8') as entree:\n", + " for ligne in entree:\n", + " Lignes.append(ligne)\n", + "for Cpt in range(60):\n", + " print(Cpt+1, Lignes[Cpt])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On charge les données à partir de la ligne 45 et on examine leur teneur." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "raw_data = pd.read_csv(data_file, skiprows=44, names=['Date', 'CO2'], parse_dates=[0], infer_datetime_format=True)\n", + "raw_data.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "raw_data.tail()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "date_début = raw_data.loc[raw_data.index.start, 'Date']\n", + "date_fin = raw_data.loc[raw_data.index.stop-1, 'Date']\n", + "print(f\"On remarque que les données couvrent la période allant du {date_début.strftime('%d/%m/%Y')} au {date_fin.strftime('%d/%m/%Y')}.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous pouvons vérifier si des données sont manquantes. Il semble que non (pas de valeur nulle)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "raw_data[raw_data.isnull().any(axis=1)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Manque-t-il des données (des semaines non enregistrées)? Pour cela, nous allons vérifier que l'écart entre deux dates consécutives est bien de 7 jours.\n", + "\n", + "On note que de nombreuses dates sont manquantes. Dans certains cas, ce sont plusieurs semaines qui sont manquantes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Calculer les écarts de dates entre deux index contigüs. Si l'écart n'est pas égal à 7 jours, afficher les deux lignes.\n", + "for cpt in range (raw_data.index.start, raw_data.index.stop-1):\n", + " début = raw_data.loc[raw_data.index.start:raw_data.index.stop, 'Date'][cpt]\n", + " fin = raw_data.loc[raw_data.index.start:raw_data.index.stop, 'Date'][cpt+1]\n", + " if str(fin-début) != '7 days 00:00:00':\n", + " print(cpt, ':', début, ' - ', cpt+1, ':', fin, ' - ', fin-début)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Si nous tentons d'analyser les données et surtout de modéliser leur tendance en les approchant par un polynôme, nous allons obtenir des résultats erronés. En effet, la variable d'entrée du polynôme pour obtenir une évaluation sera la colonne des indice des lignes du tableau. Comme les dates et les indices n'évoluent pas de manière conjointe, les résultats des prévisions en seront affectés.\n", + "\n", + "On se propose donc de créer un data frame avec toutes les semaines depuis le début des mesures, le 29/03/1958, jusqu'à la fin de l'année 2025. Les données déjà disponibles seront alors jointées dans ce data frame. Les nouvelles prévisions seront également ajoutées. Le modèle de prévision de la tendance de long terme pourra alors être ajusté." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Recontruction d'un jeu de données complété" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Création d'un data frame avec toutes les dates depuis le 29/03/1958 jusqu'à la fin de l'année 2025." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tab_date = pd.date_range(start='1958-03-29', end='2026-01-01', periods=None, freq='7D', normalize=False, name=None)\n", + "df = pd.DataFrame(tab_date, columns=['Date'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pour chaque date, le numéro de la semaine est calculé. Cette colonne est ajoutée au data frame." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tab_week = []\n", + "df_début = df.index.start\n", + "df_fin = df.index.stop\n", + "\n", + "for cpt in range(df_début, df_fin):\n", + " date = df.loc[df.index.start:df.index.stop, 'Date'][cpt]\n", + " tab_week.append(pd.Period(date, 'D').week)\n", + "\n", + "df = df.assign(Week = tab_week)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous allons intégrer les mesures dans ce data frame." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df = df.merge(raw_data, on='Date', how='outer')\n", + "df[4:16]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Observation du rendu des données disponibles" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous pouvons afficher les données. Nous observons une tendance globale de hausse et un phénomène qui semble périodique ou saisonnier." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.plot('Date', 'CO2')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Un graphique sur une période plus réduite permet de mieux observer le phénomène saisonnier.\n", + "\n", + "Il semble que le point bas du phénomène saisonnier se situe vers le mois d'octobre et son haut vers le mois de mai." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df[-500:-300].plot('Date', 'CO2')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On observe l'absence de données sur certaines périodes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df[200:350].plot('Date', 'CO2')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Elaboration d'un modèle prévisionnel de la tendance de long terme" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous nous proposons de tenter d'approcher cette courbe par un polynôme du second degré. L'ajustement du polynôme sera réalisé en minimisant la somme du carré des écarts. Cela devrait placer la courbe résultante comme la position moyenne du phénomène. On note un écart significatif entre la dynamique de la tendance de long terme et celle du phénomène saisonnier. Les deux parties du phénomène devraient donc pouvoir être correctement séparées. La tendance de long terme devrait pouvoir être approchée par un polynôme du second degré." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Toutefois, le data frame contient de nombreuses données manquantes ('NaN'). La présence de ces données manquantes pose problème à l'algorithme d'ajustement du polynôme. Il faut donc limiter l'ajustement à la période de mesure disponible (indice 0 à 3255, cf. ci-dessous). Pour les données manquantes à l'intérieur de cette période, nous utiliserons une interpolation linéaire qui ne devrait trop affecter le résultat final." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df[3250:3260]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On observe que les données manquantes à l'intérieur de la période de mesure sont maintenant renseignées." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_lt = df[0:3256]\n", + "df_lt = df_lt.interpolate()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_lt[4:16]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous nous proposons de tenter d'approcher cette courbe par un polynôme du second degré." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p = np.polyfit(df_lt.index, df_lt['CO2'], deg=2, full=False)\n", + "p" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Avec ces éléments, nous définissons une fonction qui pour un index donné, retourne une valeur de concentration en CO2 pour la tendance de long terme." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def taux_lt(x):\n", + " return np.polyval(p, x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous calculons maintenant le taux prévisionnel de long terme pour l'ensemble des index du data frame. Enfin, nous associons ces données au data frame \"df\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "prév_lt = []\n", + "for cpt in range(df_début, df_fin):\n", + " prév_lt.append(taux_lt(cpt))\n", + "\n", + "df = df.assign(Prév_LT = prév_lt)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.tail()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous pouvons tracer quelques graphiques pour observer la tendance de long terme qui a été évaluée. La tendance évaluée semble correctement coller au phénomène." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.plot('Date', ['CO2', 'Prév_LT'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df[-500:-300].plot('Date', ['CO2', 'Prév_LT'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Observation du phénomène saisonnier" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pour séparer le phénomène saisonnier de la tendance de long terme, nous calculons la différence entre les mesures de CO2 et la tendance de long terme précédemment évaluée." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df = df.assign(Saisonnier = df['CO2'] - df['Prév_LT'])\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Quelques graphiques pour observer le phénomène saisonnier. Le calcul de la moyenne sur la partie saisonnière devrait être proche de 0, si tout va bien. Ce qui semble être le cas.\n", + "\n", + "On notera toutefois une sorte de pseudo période avec ce qui semble être des pics vers 1960, 1990 et 2020." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df['Saisonnier'].mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.plot('Date', ['Saisonnier'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df[-500:-300].plot('Date', ['Saisonnier'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Evaluation du phénomène saisonnier moyen depuis 1958" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous avons observé que le phénomène saisonnier atteint un pic minimum vers le premier octobre et un point haut vers le mois de mai. Nous avons également observé que de nombreuses semaines de relevés sont manquantes.\n", + "\n", + "Une manière d'aborder le phénomène sans trop se préoccuper ni de son phasage dans l'année ni des données manquantes, serait de calculer la valeur moyenne de la partie saisonnière en fonction de la position de la semaine dans l'année. Cela permettrait d'utiliser au mieux les données disponibles. Une moyenne sur de nombreuses annèes de devrait pas être sensiblement affecter par l'absence de quelques données.\n", + "\n", + "Cela permettrait de raffiner les prévisions ultérieures." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Pour cela, on construit un tableau qui va permettre, pour chaque numéro de semaine de l'année, de cumuler la part saisonnière du taux de CO2 ainsi que le nombre de valeurs considérées. Il suffira ensuite de calculer la valeur moyenne observée pour chacune des semaines." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Parcourir le tableau.\n", + "# Pour chaque date, calculer la position de la semaine dans l'année.\n", + "# Ajouter la valeur du CO2_Saisonnier dans le tableau de résultats et incrémenter le nombre de valeurs\n", + "# disponibles pour ce numéro de semaine.\n", + "\n", + "année = [] # Créer le tableau de résultats.\n", + "for i in range (0, 55):\n", + " # La première information est le numéro de semaine,\n", + " # le second, le cumul de taux, le troisième le nombre de valeurs cumulées.\n", + " # Le quatrième contient la moyenne calculée.\n", + " année.append([i, 0.0, 0, 0.0])\n", + " \n", + "for cpt in range(df.index.min(), df.index.max()):\n", + " # Récupérer les informations.\n", + " sem = df.at[cpt, 'Week']\n", + " taux_w = df.at[cpt, 'Saisonnier']\n", + " if pd.isna(taux_w):\n", + " pass\n", + " else:\n", + " année[sem][1] = année[sem][1] + df.at[cpt, 'Saisonnier']\n", + " année[sem][2] = année[sem][2] + 1\n", + "\n", + "for i in range (0, 55): # Calculer la moyenne pour chaque semaine.\n", + " if année[i][2] != 0:\n", + " année[i][3] = année[i][1] / année[i][2] " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On affiche le tableau résultant afin de vérifier que toutes les semaines ont été correctement traitées et que le nombre des données est suffisant pour que la moyenne ait un sens (de même que l'approche proposée)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sem = pd.DataFrame(année[1:54], columns=['Num_semaine', 'Cumul', 'Nbre_valeurs', 'Moyenne_semaine'])\n", + "sem" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous pouvons donc éventuellement envisager de compléter les données manquantes dans les mesures en utilisant ce tableau." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On peut afficher la courbe résultante sur le cycle annuel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sem.plot('Num_semaine', 'Moyenne_semaine')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Elaboration d'un modèle prévisionnel du cycle annuel" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous allons tenter d'approcher le cycle annuel moyen par un polynôme de degré 7. Le résultat semble correct après quelques essais effectués avec des polynômes de degré inférieur." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "p = np.polyfit(sem['Num_semaine'], sem['Moyenne_semaine'], deg=7, full=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def taux_semaine(x):\n", + " return np.polyval(p, x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Calculer une année de prévision saisonnière." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "prév_sem = []\n", + "for cpt in range(sem.index.start+1, sem.index.stop+1):\n", + " prév_sem.append(taux_semaine(cpt))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Afficher le plot. Le phénomène saisonnier moyen est affiché avec le modèle de prévision proposé. Le résultat semble correct." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sem = sem.assign(Prév_Sem = prév_sem)\n", + "sem.plot('Num_semaine', ['Moyenne_semaine', 'Prév_Sem'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous disposons donc d'un modèle de prévision du phénomène saisonnier." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Comparaison entre les mesures et les prévisions du modèle" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous calculons pour chaque date du data frame \"df\", la part saisonnière du taux de CO2 en fonction du numéro de semaine, en utilisant le data frame \"sem\". Puis nous ajoutons la colonne correspondante au data frame \"df\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "prév_sem = []\n", + "for cpt in range(df.index.min(), df.index.max()+1):\n", + " w = df.at[cpt, 'Week']\n", + " prév_sem.append(sem.at[w-1, 'Moyenne_semaine'])\n", + "df = df.assign(Prév_Sem = prév_sem)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous pouvons maintenant calculer la somme des contributions saisonnière et long terme et ajouter la colonne correspondante au data frame \"df\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df = df.assign(Prév_total = df['Prév_LT'] + df['Prév_Sem'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous pouvons maintenant afficher quelques graphiques pour comparer un peu les données mesurées avec les données issues de la prévision." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df.plot('Date', ['CO2', 'Prév_total'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df[-500:-300].plot('Date', ['CO2', 'Prév_total'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous calculons l'écart entre les mesures et les prévisions lorsque cela a un sens (hors valeurs 'NaN')." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Tab_écart_prév = []\n", + "for cpt in range(df.index.min(), df.index.max()):\n", + " # Récupérer les informations.\n", + " Ecart_prév = df.at[cpt, 'CO2'] - df.at[cpt, 'Prév_total']\n", + " if pd.isna(Ecart_prév):\n", + " pass\n", + " else:\n", + " Tab_écart_prév.append(Ecart_prév)\n", + "df_écart_prév = pd.DataFrame(Tab_écart_prév)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous affichons un histogramme afin d'évaluer l'ampleur des erreurs. L'hitogramme ne semble pas être tout à fait une gaussienne. On note cependant que la majorité des erreurs sont proches de 0. La gamme des écarts de prévision vont de -3ppm à +2ppm environ. Les erreurs les plus importantes sont en faible nombre. Pour une valeur de taux de CO2 qui est autour de 300ppm au moins, ces erreurs ne représentent que 1% environ." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_écart_prév.hist()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prévisions pour l'année 2025" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nous pouvons maintenant établir notre prévision pour l'année 2025. Commençons par afficher le graphique correspondant." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df[-52:].plot('Date', ['Prév_LT', 'Prév_total'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On observe un taux moyen annuel (lié à la tendance long terme, choisie au début du mois de juillet), de l'ordre de 425.5ppm. Avec un minimum annuel de 421ppm et un maximum de l'ordre de 428ppm." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Recherchons les valeurs numériques plus précisément." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "moy2025 = round(df[-52:]['Prév_total'].mean(), 2)\n", + "min2025 = round(df[-52:]['Prév_total'].min(), 2)\n", + "max2025 = round(df[-52:]['Prév_total'].max(), 2)\n", + "print(f\"Le taux moyen de CO2 prévu pour l'année 2025 est de {moy2025}ppm, avec un minimum de {min2025}ppm et un maximum de {max2025}ppm.\" )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], "metadata": { "kernelspec": { "display_name": "Python 3", @@ -16,10 +878,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.3" + "version": "3.6.4" } }, "nbformat": 4, "nbformat_minor": 2 } -