5.3. TP analyse de données avec numpy#

Marc BUFFAT, dpt mécanique, Université Lyon 1

temp_terre.png

message à valider Pour indiquer que vous avez compris les consignes (la charte du cours) sur les IA Génératives, veuillez recopier le texte ci-dessus dans la variable acceptation dans la cellule suivante.

acceptation=""
## BEGIN SOLUTION
## END SOLUTION
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
# police des titres
plt.rc('font', family='serif', size='18')

from IPython.display import display, Markdown, clear_output
from validation.valide_markdown import test_markdown, test_code, test_algorithme
from validation.validation import info_etudiant

def printmd(string):
    display(Markdown(string))
# test si numero étudiant spécifier
try: NUMERO_ETUDIANT
except NameError: NUMERO_ETUDIANT = None 
if type(NUMERO_ETUDIANT) is not int :
    NOM, PRENOM, NUMERO_ETUDIANT = info_etudiant()
# parametres spécifiques
_uid_  = NUMERO_ETUDIANT
np.random.seed(_uid_)
printmd("**Etudiant** {} {}  id={}".format(NOM,PRENOM,NUMERO_ETUDIANT))
# parametres
_i1 = 5   + np.random.randint(10)
_i2 = 146 - np.random.randint(10)
_an = 2030 + np.random.randint(10)
# generation du fichier de donnees
cde="'1,{}d;{},$d'".format(_i1,_i2)
#print("cde:",cde)
!sed $cde ./data/land_global_temperature_anomaly.csv > ./data/anomalie_temperature.csv
printmd("**Estimation de la hausse des température en {}**".format(_an))

Etudiant Marc BUFFAT id=137764122

Estimation de la hausse des température en 2036

5.3.1. Objectifs#

Apprendre à lire des données dans un fichier, les analyser et les traiter pour en déduire des prédictions.

La démarche consiste en

  1. lecture des données

  2. analyse des données

  3. détermination d’une loi simple

  4. prédiction à partir de cette loi

  5. analyse des résultats

application

  • problème du réchauffement climatique.

5.3.2. Étape 1: lecture des données#

Dans le répertoire data, le fichier anomalie_temperature.csv contient des mesures annuelles du réchauffement climatique, i.e. l’écart de température annuelle du globe par rapport à une moyenne climatique. Dans la suite on appelle anomalie climatique cet écart.

En utilisant la commande unix/linux head mon_fichier, on affiche les 10 premières lignes du fichier ./data/anomalie_temperature.csv dans la cellule ci-dessous

Attention vous n’avez pas tous les mêmes données, donc ne vous contentez pas de comparer les résultats bruts, mais essayer de comprendre la méthode.

!head "./data/anomalie_temperature.csv"
1883,-0.28
1884,-0.24
1885,-0.45
1886,-0.18
1887,-0.52
1888,-0.33
1889,-0.03
1890,-0.34
1891,-0.40
1892,-0.24

5.3.2.1. lecture du fichier#

Pour charger les données à partir du fichier, nous utiliserons la fonction numpy.loadtxt(), qui nous permet de charger directement les données lues dans des tableaux NumPy en spécifiant comme paramètre le nom du fichier en tant que chaîne de caractères.

Les données sont séparées par des , et on veut enregistrer directement les données dans les deux tableaux annee et anomalie_temp. On va donc fournir des arguments à la fonction np.loadtxt pour l’utiliser (voir la documentation de loadtxt)

    annee, anomalie_temp = np.loadtxt("nom du fichier", delimiter=',', unpack=True)

Dans la cellule suivante,

  • importer la bibliothèque numpy.

  • écrire le code python pour lire les données dans les deux tableaux annee et anomalie_temp

  • vérifier le type et la taille des tableaux et afficher les 10 premières valeurs des tableaux pour comparer avec head

import numpy as np
annee = 0
anomalie_temp = 0
### BEGIN SOLUTION
### END SOLUTION

5.3.3. Étape 2: tracer des données#

  • Utiliser ensuite la fonction plot() pour tracer l’anomalie de température en fonction de l’année,

  • Ajouter un titre,

  • Ajouter des labels pour les axes.

%matplotlib inline
import matplotlib.pyplot as plt
# police des titres
plt.rc('font', family='serif', size='18')
### BEGIN SOLUTION
### END SOLUTION

5.3.4. Etape 3: régression linéaire par moindres carrés#

Les données brutes étant très fluctuantes, on va lisser les données d’anomalie de température par une droite, pour en déduire l’évolution de la température terrestre. Nous utiliserons la régression linéaire par moindres carrés pour calculer la pente \(a_1\) et la constante \(a_0\)

\[ y = a_1 x + a_0 \]

avec pour expression des coefficients \(a_1\) et \(a_0\):

(5.11)#\[\begin{eqnarray} a_1 = \frac{\overline{x*y} - \bar{x}\bar{y}} {\overline{x*x}- \bar{x }^2} \quad, \quad a_0 = \bar {y} - a_1 \bar {x} \end{eqnarray}\]

La notation \(\bar{x}\) signifie la moyenne des valeurs de x. Dans notre cas, les données x sont dans le tableau annee, et les données y sont dans le tableau anomalie_temp. Pour calculer nos coefficients avec la formule ci-dessus, nous avons besoin des valeurs moyennes des données. Comme nous devons calculer la moyenne à la fois pour x ety, il est utile d’écrire une fonction Python personnalisée valeur_moyenne qui calcule la moyenne pour n’importe quel tableau, que l’on peut ensuite réutiliser.

5.3.4.1. Question 1: écriture de la fonction valeur_moyenne#

On veut définir une fonction valeur_moyenne qui calcule la valeur moyenne de n’importe quel tableau TAB passé en argument. On devra utiliser une boucle sur les valeurs du tableau et ne pas utiliser la méthode .mean() de numpy qui calcule la moyenne arithmétique d’un tableau.

Dans la première cellule ci-dessous

  • Écrire la fonction Python valeur_moyenne(TAB) (sans utiliser mean) qui calcule la moyenne du tableau TAB passé en argument et renvoie la valeur moyenne de ce tableau.

Dans la deuxième cellule ci-dessous

  • Créer un tableau X contenant 11 nombres équi-répartis entre 1 et 3.

  • Calculer et affecter dans Xm la valeur moyenne du tableau X avec la fonction valeur_moyenne.

  • Faire afficher la valeur de Xm.

  • Mettre une phrase de commentaire (en utilisant le symbole #) pour dire si la valeur de Xm vous semble cohérente.

# fonction valeur_moyenne(TAB)
### BEGIN SOLUTION
### END SOLUTION
# utilisation de la fonction valeur_moyenne en l'appelant avec son argument 
X = None
Xm = 0
### BEGIN SOLUTION
### END SOLUTION
# ne pas modifier la cellule
### BEGIN HIDDEN TESTS
assert(np.isclose(valeur_moyenne(np.linspace(1,3,11)),2.0))
assert(test_code("TP_regression_lineaire.ipynb","cell-verif0","valeur_moyenne"))
### END HIDDEN TESTS
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[8], line 3
      1 # ne pas modifier la cellule
      2 ### BEGIN HIDDEN TESTS
----> 3 assert(np.isclose(valeur_moyenne(np.linspace(1,3,11)),2.0))
      4 assert(test_code("TP_regression_lineaire.ipynb","cell-verif0","valeur_moyenne"))

NameError: name 'valeur_moyenne' is not defined

5.3.4.2. question 2: utilisation de la fonction valeur_moyenne#

  • Calculer et affecter dans moyenne_annee la valeur moyenne du tableau annee avec la fonction valeur_moyenne.

  • Calculer et affecter dans moyenne_anomalie la valeur moyenne du tableau anomalie_temp avec la fonction valeur_moyenne.

moyenne_annee = 0
moyenne_anomalie = 0
### BEGIN SOLUTION
### END SOLUTION

5.3.4.3. question 3: écriture de la fonction Lissage()#

On cherche maintenant à écrire une fonction pour trouver la droite de régression par les moindres carrés \( Y = A0 + A1*X \). Les coefficients \( A1 \) et \( A0 \) sont donnés par les relations:

\[ A1 = \frac{ \overline{X*Y} - \bar{X}\bar{Y}}{\overline{X*X} - \bar{X}^2} \quad , \quad A0 = \bar{Y} - A1 * \bar{X} \]

. Indication 1 : Il faut d’abord calculer \( A1 \) puis d’utiliser cette valeur pour calculer \( A0\).

. Indication 2 : Pour calculer \(A1\), on se sert plusieurs fois de la fonction valeur_moyenne() pour déterminer \(\bar{X}\), \(\bar{Y}\), \(\overline{X*Y}\) et \(\overline{X*X}\), qui sont respectivement les valeurs moyennes des tableaux \(X\), \(Y\), \((X*Y)\) et \((X*X)\).

  • Ecrire une fonction python Lissage(X,Y) qui prend en arguments les tableaux X,Y, calcule et renvoie la valeur des 2 coefficients A0 et A1 dans cet ordre.

  • A l’aide de Lissage, calculer et affecter dans \(a_1\) et \(a_0\) les coefficients de la droite de régression linéaire pour les tableaux annee et anomalie_temp.

  • Afficher les valeurs de \(a_1\) et \(a_0\)

# fonction de Lissage Lissage(X,Y)
### BEGIN SOLUTION
### END SOLUTION

5.3.4.4. question 5: prédiction#

On va utiliser les données précédentes pour obtenir une prédiction prediction de la hausse des températures (si la tendance actuelle se confirme) dans l’année qui est donnée au bas de cette cellule.

A la question précédente, nous avons calculé les coefficients \(a_0\), \(a_1\) d’une fonction linéaire qui lisse les données. Nous pouvons maintenant calculer des valeurs d’anomalie de température \( f (t) \) avec $\( f(t) = a_0 + a_1 t\)$

Appelons reg le tableau obtenu en évaluant \( f (t) \) pour toutes les valeurs du tableau annee.

Dans la première cellule suivante

  • Calculer le tableau reg à partir des valeurs de \(a_0\), \(a_1\) et annee.

  • Affecter à an la valeur de l’année de prédiction qui vous a été attribuée.

  • Calculer la valeur de la hausse de température prédite dans la variable prediction à partir des valeurs de \(a_0\), \(a_1\) et an. On utilisera la fonction numpy np.round(val,2) qui arrondit une valeur val à 2 chiffres.

Dans la deuxième cellule suivante

  • Tracer les données d’origine anomalie_temp en fonction de annee (idem étape 2) avec un titre, des labels et des légendes

  • Tracer la régression linéaire correspondant à ces données

  • Rajouter sur la figure le point de prédiction.

Indication :

  • Pour agrandir la figure, on pourra utiliser l’instruction

          plt.figure(figsize=(12, 6))
    
  • Pour rajouter le point de prédiction, on pourra utiliser l’instruction

          plt.plot([an],[prediction],'*',markersize=15)
    

Dans la troisième cellule suivante (format markdown)

  • Commenter sur quelques lignes la figure et le résultat obtenu.

printmd("**Estimation** de la hausse des température en {}".format(_an))
# calcul de la prediction
prediction = 0
an = 0
reg = None
### BEGIN SOLUTION
### END SOLUTION
# tracer la figure avec les donnees, le lissage et le point de prédiction
### BEGIN SOLUTION
### END SOLUTION
# ne pas modifier la cellule
### BEGIN HIDDEN TESTS
assert(a1>0)
assert(np.abs(prediction*100 - np.round(prediction*100) < 1.0))
### END HIDDEN TESTS

5.3.5. Amélioration du modèle de prédiction#

Si vous regardez le graphique ci-dessus, vous remarquerez peut-être que vers 1970, la température commence à augmenter plus rapidement que la tendance précédente. Peut-être qu’une seule droite ne nous donne pas un bonne prédiction.

On propose de diviser les données en deux (avant et après 1970) et de faire une régression linéaire sur chaque partie. Nous avons besoin de créer deux sous-tableaux à partir des tableaux annee et anomalie_temp.

Pour ce faire, nous devons d’abord trouver la position dans notre tableau annee où se trouve l’année 1970. Heureusement, NumPy a une fonction pour cela appelée np.where() qui peut nous aider. Nous passons en argument une condition et np.where() nous indique où dans le tableau la condition est vrai (True). On rappelle que le test d’égalité en Python est noté ==. La fonction np.where() renvoie un tableau qui contient l’indice recherché. Pour trouver l’indice de l’année 1970, on utilisera donc l’instruction suivante pour sélectionner cet indice dans le tableau renvoyé par np.where:

i_1970 = np.where(annee==1970)[0][0]

Ensuite pour diviser les données, nous utilisons la notation de slicing avec : . N’oubliez pas qu’un deux-points entre deux indices indique une plage de valeurs d’un début à une fin. La règle est que [début:fin] inclut l’élément au début de l’index mais exclut celui à la fin de l’index.

Nous savons maintenant comment diviser nos données en deux partie, pour obtenir les deux droites de régression. Nous avons besoin de deux tranches des tableaux annee et anomalie_temp, que nous mettons dans de nouvelles variables. Puis, nous effectuons deux régressions linéaires à l’aide des fonctions NumPy apprises ci-dessus.

  • Déterminer l’indice de l’année 1970 et la mettre dans la variable i_1970.

  • Vérifier le résultat.

  • Calculer les 2 tranches des tableaux annee et anomalie_temp dans annee_1 , anomalie_temp_1 pour les années avant 1970 exclue et annee_2 , anomalie_temp_2 pour les années après 1970 inclue.

i_1970 = 0
annee_1 = 0
anomalie_temp_1 = 0
annee_2 = 0
anomalie_temp_2 = 0
### BEGIN SOLUTION
### END SOLUTION

5.3.5.1. Nouveau modèle#

en utilisant la fonction de Lissage sur les données précédentes, calculer les 2 courbes de lissage des données

  1. pour t < 1970

    \[ f1(t) = b0 + b1 * t \]
  2. sinon

    \[ f2(t) = c0 + c1 * t \]
  • Calculer et afficher les valeurs des coefficients \(b0\), \(b1\) et \(c0\) \(c1\)

  • En déduire une nouvelle estimation de la hausse des températures dans la variable prediction_2 avec une précision de 2 chiffres et comparer à la prédiction précédente.

  • Dans la cellule suivante, tracer sur une figure les données d’origine, les 2 régressions linéaires, ainsi que le point de prédiction en mettant des légendes, un titre et un label pour les axes.

  • Enfin dans la cellule Markdown en dessous de la courbe, commenter le résultat et donner votre analyse et conclusion sur quelques lignes.

# calcul de la prediction
prediction_2 = 0
### BEGIN SOLUTION
### END SOLUTION
# tracer du résultat avec les données, le lissage et le point de prédiction
### BEGIN SOLUTION
### END SOLUTION
# ne pas modifier la cellule
### BEGIN HIDDEN TESTS
# test validation du code de la cellule précédente
_X = annee_1
_Y = anomalie_temp_1
assert (np.abs(b1 - np.sum(_X*(_Y-np.ndarray.mean(_Y)))/np.sum(_X*(_X-np.ndarray.mean(_X)))) < 1.e-8)
assert (np.abs(_Y.mean() - b0 - b1*_X.mean())<1.e-8)
_X = annee_2
_Y = anomalie_temp_2
assert (np.abs(c1 - np.sum(_X*(_Y-np.ndarray.mean(_Y)))/np.sum(_X*(_X-np.ndarray.mean(_X)))) < 1.e-8)
assert (np.abs(_Y.mean() - c0 - c1*_X.mean())<1.e-8)
print("prédiction de la hausse de temperature: {} degré en {}".format(prediction_2,an))
assert (np.abs(prediction_2*100 - np.trunc(prediction_2*100))<1.)
### END HIDDEN TESTS

5.4. FIN du TP#

# version
from platform import python_version,uname,platform
print("Systeme       :",uname())
print("OS            :",platform())
print("version python:",python_version())
print("version numpy :",np.__version__)