Dans ce TP, on continue notre exploration de notions et techniques pour la science des données. On va notamment manipuler des fichiers de données beaucoup plus gros que précédemment et réaliser des tâches de régression.
Tous les TPs précédents doivent impérativement avoir été faits avant d'aborder celui-ci.
À l'issue de ce TP, vous m'envoyez par email un compte-rendu (format pdf) indiquant la réponse aux questions qui sont posées. Vous m'envoyez également un fichier python réalisant toutes les manipulations de ce TP : je dois pouvoir exécuter ce fichier en tapant python3 nom-de-votre-fichier.py et reproduire vos résultats. Cette exécution ne doit pas provoquer d'erreur de python. Remarque : un notebook ne convient pas.
Brad vit en altitude, dans les montagnes du Colorado (il y fait froid assez tôt dans l’automne et jusque tardivement au printemps). Il a aménagé une station de collecte des températures. Ainsi, quatre thermomètres électroniques mesurent la température dans son séjour, son bureau, son sous-sol et à l’extérieur de chez lui, toutes les 3 minutes. Ces thermomètres sont reliés à son ordinateur qui stocke chacune des mesures dans quatre fichiers, un fichier par thermomètre. On dispose de ces quatre fichiers qui contiennent plusieurs dizaines de milliers de mesures. Notre objectif est d’étudier les températures ainsi mesurées. On sait également que le thermostat de Brad est réglé à 21°C pendant la journée, à 16°C pendant la nuit.
Ces 4 fichiers de données sont disponibles à ces 4 urls :
Ces 4 fichiers ont le même format.
Dans votre navigateur, regardez l'un d'eux.
Vous constatez qu'il ne s'agit pas de fichiers csv et qu'ils n'ont pas d'en-tête avec le nom des attributs.
Dans ces 4 fichiers, les colonnes sont séparées par un espace. Dans l'ordre, les colonnes correspondent aux informations suivantes :
Les lignes de chacun de ces fichiers sont ordonnées chronologiquement.
Comme d'habitude, on va commencer par créer un tableau de données, les explorer à la main et visuellement, avant d'utiliser des méthodes analytiques.
On commence par lire chacun de ces fichiers en le stockant dans un tableau de données.
Pour lire ces fichiers qui ne sont pas au format csv, on utilisera la méthode read_table() de pandas. Regardez la documentation pour utiliser les bons arguments et lisez ces 4 fichiers dans 4 tableaux de données différents. Comme ces fichiers n'ont pas d'en-tête indiquant le nom des colonnes, donnez-leur un nom lors de la lecture. On trouve les mêmes 5 attributs indiquant la date et l'heure dans les 4 fichiers ; donnez-leur le même nom (ce qui vous simplifiera les choses un peu plus tard).
Comme la méthode read_table() est très générale (on peut lire des tas de formats différents), elle possède de très nombreux paramètre. On peut être un peu perdu face à tous ces paramètres. Aussi, pour vous aider, je vous indique les paramètres de read_table() à utiliser. D'une manière générale, pour trouver les bons paramètres il faut impérativement avoir regardé le contenu du fichier pour voir s'il y a un en-tête avec le nom des attributs, comment les valeurs des attributs sont séparées, ... Cette inspection faite, dans le cas présent :
À faire : faites tout ce qui vient d'être expliqué et vérifiez que la lecture des fichiers s'est bien passée.
On doit maintenant rassembler le contenu de ces 4 tableaux de données dans un seul. Cette fusion doit s'effectuer en fonction de l'instant de la mesure.
Le tableau de données fusionnés sera nommé brad.
Il faut utiliser la méthode merge_ordered() de pandas qui fusionne deux tableaux de données.
N'hésitez pas à regarder la documentation concernant cette méthode, la page décrivant merge_ordered () et une page qui explique la fusion de tableaux de données.
Comme les opérations de fusion sont assez compliquées à maîtriser et qu'il en existe de différentes sortes, je vous donne l'idée générale de ce qui doit être fait dans ce TP. La commande suivante :
pd.merge_ordered (df1, df2, on = liste_des_attributs_communs_sur_lesquels_on_fait_la_fusion, how = "outer")
fait la chose suivante :
À faire : construisez ce tableau de données brad.
Remarque : bien entendu, lorsqu'on réalise une telle opération de fusion, on vérifie que tout se passe bien. Puisque nous allons ensuite travailler uniquement sur le tableau de données brad, si celui-ci, pour une raison ou une autre, n'est pas construit correctement, tout ce que nous ferons par la suite sera faux.
Il faut donc impérativement passer quelques instants à s'assurer que brad a été correctement construit.
Pour vous aider, je vous indique ci-dessous les début et fin de brad correctement chargé :
>>> brad.head() an mois j h mn temp_b temp_l temp_lr temp_o 0 2003 7 25 16 4 24.0 NaN 29.8 27.5 1 2003 7 25 16 7 24.0 NaN 29.8 27.3 2 2003 7 25 16 10 24.0 NaN 29.8 27.3 3 2003 7 25 16 13 24.1 NaN 29.8 27.4 4 2003 7 25 16 16 24.1 NaN 29.8 27.8 >>> brad.tail() an mois j h mn temp_b temp_l temp_lr temp_o 169493 2004 7 16 15 16 21.7 22.9 22.8 16.8 169494 2004 7 16 15 19 21.7 22.9 22.8 16.9 169495 2004 7 16 15 22 21.7 22.9 22.8 16.8 169496 2004 7 16 15 25 21.7 22.9 22.8 16.8 169497 2004 7 16 15 28 21.7 22.9 22.8 16.4
Obtenez-vous le même résultat ? Est-ce que votre tableau de données semble correct ?
J'ai nommé les colonnes correspondant aux différentes températures temp_b pour le sous-sol (basement), temp_l pour la laboratoire (lab), temp_lr pour le salon (living-room) et temp_o pour l'extérieur (outside).
Notez bien les NaN : vous devez les avoir aussi pour ces lignes-là.
Question : qu'est ce que ces NaN ? Que font-ils là ? Quel est leur signification ?
Une fois la fusion correctement réalisée, on peut détruire les 4 tableaux de données (commande python del) et ne conserver que brad.
On peut commencer par quelques graphiques. Par exemple, représentons ces courbes de températures.
Un premier essai pourrait vous donner cela :
où on ne voit rien !
À faire : réalisez le graphique ci-dessous qui montre les 4 courbes de températures séparées les unes des autres. Notez bien les ordonnées de chaque courbe : c'est le même intervalle de valeurs (-25°, 25°), ceci pour pouvoir mieux les comparer visuellement. Vous devez obtenir exactement les mêmes figures.
C'est beaucoup mieux. Néanmoins, l'axe des abscisses est illisible. S'agissant de l'instant de mesure des températures, on préférerait y lire des dates, commme sur cette figure :
C'est ce que nous allons faire mais cela nécessite quelques explications concernant les dates. Nous y reviendrons un peu plus loin.
À faire : réaliser les 2 graphiques ci-dessous qui affichent les histogrammes des 4 températures. J'utilise le paramètre bins = 250 à gauche et bins = 1000 à droite. Remarquez les différences que cela entraîne sur le graphique. D'où viennent ces « trous » ?
Les dates sont des objets complexes : ce ne sont pas des nombres, mais on peut faire des opérations entre dates : on peut soustraire une date à une autre et obtenir une durée. De même, on peut ajouter une durée (positive ou négative) à une date et obtenir une autre date. Par ailleurs, il y a un ordre total sur les dates.
Concernant leur représentation, il en existe de multiples : par exemple, en français, on peut écrire 13/10/23, 13/10/2023, 13 octobre 2023, 13 oct. 2023, ... On peut trouver des dates écrites sous des formats très différents dans les jeux de données, et c'est la même chose pour les heures : 14h 27 mn, 14h 27 mn 29 s, 14:27:29, ...
Cette souplesse dans l'écriture nécessite des fonctions spécifiques permettant de les lire, les afficher et les manipuler.
On distingue deux cas : la date (et l'heure) est représentée par une chaîne de caractères qu'il faut correctement analyser ; la date (et l'heure) est représentée par un ensemble d'attributs, comme c'est le cas dans le jeu de données de Brad.
Dans les deux cas, on utilise la méthode to_datetime () de pandas.
La transformation des 5 attributs jour, mois, année, heure, minute en date se fait à l'aide de la méthode to_datetime() de pandas.
À faire : Regardez la documentation de cette méthode (regardez les exemples) et ajoutez un attribut date au tableau de données brad contenant la date et l'heure de chaque ligne.
Cela fait, l'attribut date contient un « tampon temporel » qui indique une date et une heure. Par exemple :
brad.date [0]
donne :
Timestamp('2003-07-25 16:04:00')
et on peut facilement accéder à chaque élément de ce tampon temporel :
>>> brad.date [0].day 25 >>> brad.date [0].month 7 >>> brad.date [0].year 2003 >>> brad.date [0].hour 16 >>> brad.date [0].minute 4 >>> brad.date [0].second 0
et à d'autres informations :
>>> brad.date [0].month_name () 'July' >>> brad.date [0].day_name () 'Friday' >>> brad.date [0].day_of_week 4 >>> brad.date [0].day_of_year 206 >>> brad.date [0].week 30 >>> brad.date [0].weekofyear 30 >>> brad.date [0].days_in_month 31
On peut alors facilement sélectionner des lignes correspondant à certains moments. Par exemple, la température du séjour pour toutes les lignes qui correspondent aux 23 du mois :
>>> brad [brad.date.dt.day == 23].temp_lr 13590 24.1 13591 24.1 13592 24.1 13593 24.0 13594 24.0 ... 158798 21.8 158799 21.8 158800 21.7 158801 21.7 158802 21.6
À faire : répondez aux questions suivantes :
Intuitivement, il doit y avoir des corrélations entre les températures relevées dans les différentes pièces chez Brad.
À faire : quelle corrélation vous attendez-vous à observer ?
À faire : faites des scatter plot entre les différents couples de températures. Quelles températures sont/semblent corrélées linéairement ? Cela correspond-il à vos attentes ?
La méthode corr () du paquetage pandas calcule le coefficient de corrélation linéaire.
À faire : calculer les coefficients de corrélation linéaire entre les différentes paires d'attributs. Ces valeurs confirment-elles votre intuition et vos constatations sur les graphiques ?
Vous devez trouver les coefficients suivants :
temp_b temp_l temp_lr temp_o temp_b 1.000000 0.801845 0.949450 0.623215 temp_l 0.801845 1.000000 0.790496 0.726466 temp_lr 0.949450 0.790496 1.000000 0.644963 temp_o 0.623215 0.726466 0.644963 1.000000
On souhaite modéliser la relation linéaire entre les températures. Pour cela, on va utiliser les modèles linéaires du paquetage sklearn documentés sur cette page et celle-ci.
Vous commencez par créer un objet régresseur linéaire par une commande comme reg = linear_model.LinearRegression().
Vous devez fournir un ensemble de couples (x, y) et sklearn calcule la droite de régression par la méthode fit () appliquée au régresseur (donc reg.fit (x, y)). Cette méthode prend en paramètre deux tableaux numpy. Pour cela, il faut transformer les attributs en tableaux bidimensionnels numpy et ensuite appeler la méthode fit () avec ces deux tableaux. Je reprends tranquillement pour la température dans le sous-sol et celle dans le salon :
À l'issue de l'appel de fit (), si tout s'est bien passé, l'objet reg contient deux attributs : coef_ est le coefficient directeur de la droite de régression, intercept_ est l'ordonnée à laquelle la droite de régression coupe l'axe des ordonnées.
Essayez de calculer les paramètres du modèle linéaire entre la température dans le salon et celle dans le sous-sol. Que se passe-t-il ? Pourquoi ?
Essayez de comprendre avant de lire la suite.
Comme l'indique la documentation, la méthode utilisée ne fonctionne pas en présence de données manquantes. La première question à se poser est : y en a-t-il beaucoup ou juste quelques-une ? S'il y en a quelques-unes, on peut calculer le modéle linéaire en retirant les individus correspondants à ces données manquantes et cela ne devrait pas avoir de sérieuses conséquences. S'il y en a beaucoup, c'est plus compliqué. Voyons dans quel cas on se trouve...
La méthode isna () du paquetage pandas indique les valeurs inconnues dans un vecteur sous la forme d'un vecteur de booléens. Le nombre de NAs peut ensuite être compté en sommant les booléens (car, comme vous le savez, une valeur False correspond à l'entier 0 et une valeur True correspond à l'entier 1).
À faire : les attributs correspondants aux 4 températures contiennent-ils des valeurs NA ? Si oui, combien ?
On voit que pour les températures dans le salon, dans le sous-sol et à l'extérieur, le nombre de valeurs manquantes est très réduit.
On va donc simplement ne pas tenir compte des individus avec des données manquantes et calculer les modèles linéaires.
Vous pouvez essayer de le faire sans lire la suite.
Une idée simple consiste à construire l'ensemble des indices des individus qui n'ont pas de valeur manquante. Pour cela, je vous donne quelques ingrédients :
Avec ces 3 méthodes, vous avez toutes les informations nécessaires pour construire un modèle linéaire en éliminant au préalable les valeurs manquantes.
À faire : calculer les coefficients des droites de régression linéaire entre les températures du salon, du sous-sol et à l'extérieur.
Puis, réaliser un graphique pour chacune des 3 combinaisons représentant les couples de températures et la droite de régression. Par exemple, pour les températures du sous-sol et du salon, vous devez obtenir quelque chose comme cela :
On ajoute une droite avec la méthode plt.axline () du paquetage matplotlib.
À faire : identifier les températures qui s'écartent significativement de la tendance indiquée par la droite de régression. Que pensez-vous de ces points ?
On a vu qu'il y a quelques valeurs manquantes dans les températures du sous-sol, du salon et à l'extérieur (et il en manque beaucoup pour le laboratoire, on laisse donc celui-ci de côté pour l'instant).
On peut imaginer au moins trois manières de donner une valeur :
À faire : imputer les valeurs manquantes pour ces 3 pièces.