Cours
Introduction
Importer des données est l’une des premières étapes indispensables de tout projet lié aux données. Savoir charger correctement les données est une compétence incontournable pour tout data scientist en devenir.
Les données existent sous de nombreuses formes. Vous devez non seulement savoir importer ces différents formats, mais aussi analyser et manipuler les données pour en tirer des enseignements utiles.
pandas est une bibliothèque Python open source, simple d’utilisation, performante, et idéale pour l’analyse de données sur divers formats.
Elle permet de lire de nombreux types de formats, comme CSV, JSON, Excel, Pickle, etc. Elle représente vos données sous forme tabulaire lignes/colonnes, ce qui les rend plus lisibles et présentables.
pandas représente les données sous forme de DataFrame et offre un large éventail de fonctionnalités pour l’analyse et la manipulation. Une fois que vous commencez à donner du sens aux données avec pandas, vous pouvez les utiliser pour analyser, prévoir, classifier, et bien plus encore !
pandas propose une API d’entrée/sortie avec des fonctions de haut niveau reader et writer. La fonction de lecture s’utilise via pandas.read_json(), qui retourne un objet pandas, et la fonction d’écriture via pandas.to_json(), une méthode d’objet.
Le DataFrame dispose d’un Reader et d’un Writer. Le Reader vous permet de lire différents formats de données, tandis que le Writer vous permet d’enregistrer les données dans un format précis.
Voici les formats pris en charge par DataFrame : si vos données sont dans l’un de ces formats, vous pouvez utiliser pandas pour les charger ou même les enregistrer dans un format particulier.
Dans le tutoriel d’aujourd’hui, vous allez travailler sur quelques-uns de ces formats, notamment JSON, HTML et Pickle.
Remarque : consultez ce tutoriel pour apprendre à lire des fichiers CSV avec pandas.
Charger des données JSON
JSON, pour JavaScript Object Notation, est un format texte d’échange et de sérialisation de données. JSON est facile à lire et à écrire. Il est basé sur un sous-ensemble du langage JavaScript, mais reprend des conventions de Python et de nombreux autres langages.
JSON est surtout utilisé pour stocker des données non structurées, ce qui n’est pas idéal pour les bases SQL. Il rend toutefois les données facilement lisibles par les machines.
JSON repose principalement sur deux structures :
-
Une collection de paires clé/valeur. En Python, une paire clé/valeur correspond à un
Dictionary. Unecléest un attribut unique, alors que les valeurs ne le sont pas. -
Une liste ordonnée de valeurs. Cette liste peut parfois être une liste de listes. En Python, les listes regroupent des valeurs (chaînes, entiers, etc.).
Voyons maintenant comment charger des données JSON de plusieurs façons.
Le premier jeu de données JSON provient de ce lien. Les données sont au format dictionnaire clé-valeur. On y trouve trois clés : integer, datetime et category.
- Commencez par importer la bibliothèque
pandas, puis passez l’URLàpd.read_json(), qui renverra un dataframe. Les colonnes correspondent aux clés et les lignes aux valeurs du JSON.
import pandas as pd
json = pd.read_json('https://raw.githubusercontent.com/chrisalbon/simulated_datasets/master/data.json')
Imprimons rapidement les dernières lignes du JSON lu à l’aide de la fonction .tail().
json.tail(6)
| integer | datetime | category | |
|---|---|---|---|
| 94 | 5 | 2015-01-01 00:01:34 | 0 |
| 95 | 9 | 2015-01-01 00:01:35 | 0 |
| 96 | 8 | 2015-01-01 00:01:36 | 0 |
| 97 | 6 | 2015-01-01 00:01:37 | 0 |
| 98 | 8 | 2015-01-01 00:01:38 | 0 |
| 99 | 1 | 2015-01-01 00:01:39 | 0 |
json.shape
(100, 3)
Comme on le voit ci-dessus, le dataset contient trois colonnes : integer, datetime et category. Il y a également 100 observations, comme le confirme la méthode .shape qui renvoie 100 x 3.
- Écrire un JSON
Exporter des données au format JSON est aussi simple que de les lire : une seule ligne de code. Au lieu de read_json(), utilisez to_json() avec un nom de fichier, et c’est tout !
json.to_json('dataframe.json')
- Analyser un JSON imbriqué sous forme de chaîne
Passons à un autre type de jeu de données JSON, un peu moins trivial : un JSON imbriqué. Dans une structure imbriquée, chaque clé peut contenir d’autres clés.
Voyons l’exemple suivant pour mieux comprendre.
nested_json = """{
"article": [
{
"id":"01",
"language": "JSON",
"edition": "first",
"author": "Allen"
},
{
"id":"02",
"language": "Python",
"edition": "second",
"author": "Aditya Sharma"
}
],
"blog":[
{
"name": "Datacamp",
"URL":"datacamp.com"
}
]
}"""
Dans ce dataset, vous remarquerez que article et blog sont deux clés primaires sous lesquelles se trouvent des valeurs. Ces valeurs possèdent elles-mêmes des paires clé-valeur.
Notez que l’exemple ci-dessus est encadré par des guillemets doubles et est donc une chaîne de caractères.
La lecture d’un JSON imbriqué peut se faire de plusieurs façons.
Commencez par utiliser la fonction json.loads pour lire une chaîne JSON en lui passant la variable de données en paramètre. Ensuite, utilisez json_normalize pour aplatir la structure imbriquée en un tableau.
Importez la fonction json_normalize depuis la bibliothèque pandas.io.json.
import json
from pandas.io.json import json_normalize
nested = json.loads(nested_json)
nested
{'article': [{'id': '01',
'language': 'JSON',
'edition': 'first',
'author': 'Allen'},
{'id': '02',
'language': 'Python',
'edition': 'second',
'author': 'Aditya Sharma'}],
'blog': [{'name': 'Datacamp', 'URL': 'datacamp.com'}]}
Ensuite, aplatissez le JSON avec normalize. Passez-lui pour l’instant l’ensemble des données et observez le résultat.
nested_full = json_normalize(nested)
nested_full
| article | blog | |
|---|---|---|
| 0 | [{'id': '01', 'language': 'JSON', 'edition': '... | [{'name': 'Datacamp', 'URL': 'datacamp.com'}] |
Parfait ! Comme vous le voyez, les clés primaires deviennent les colonnes du dataframe, tandis que leurs valeurs constituent les lignes.
Cependant, la sortie reste peu lisible. Voyons comment la scinder en plusieurs dataframes.
Repassez la sortie de json.loads à json_normalize, mais en spécifiant cette fois l’argument record_path.
blog = json_normalize(nested,record_path ='blog')
blog
| URL | name | |
|---|---|---|
| 0 | datacamp.com | Datacamp |
article = json_normalize(nested,record_path ='article')
article
| author | edition | id | language | |
|---|---|---|---|---|
| 0 | Allen | first | 01 | JSON |
| 1 | Aditya Sharma | second | 02 | Python |
Vous constatez que les clés primaires sont désormais réparties en deux dataframes. Leurs colonnes correspondent aux clés qui étaient imbriquées à l’intérieur sous forme de paires clé-valeur. Pratique, n’est-ce pas ?
Pour terminer sur le chargement de JSON, voyons rapidement comment lire un JSON en tant que fichier et non comme une chaîne.
- Lire un JSON depuis un fichier
nested_json = {
"article": [
{
"id":"01",
"language": "JSON",
"edition": "first",
"author": "Allen"
},
{
"id":"02",
"language": "Python",
"edition": "second",
"author": "Aditya Sharma"
}
],
"blog":[
{
"name": "Datacamp",
"URL":"datacamp.com"
}
]
}
Comme vous le voyez, il n’y a pas de guillemets doubles au début et à la fin des données : vous traitez donc ces données comme un fichier à lire.
Une seule ligne de code suffit. Voici comment faire !
json_file = pd.DataFrame.from_dict(json_normalize(nested_json))
json_file
| article | blog | |
|---|---|---|
| 0 | [{'id': '01', 'language': 'JSON', 'edition': '... | [{'name': 'Datacamp', 'URL': 'datacamp.com'}] |
Le résultat est similaire à la lecture d’un JSON sous forme de chaîne. La différence, c’est que vous utilisez pandas pour à la fois analyser et aplatir le JSON. Comme il s’agit d’un dictionnaire, vous utilisez .from_dict().
Charger des données HTML
HTML (HyperText Markup Language) est principalement utilisé pour créer des pages et applications web. Il décrit la structure d’une page de manière sémantique. Le navigateur reçoit un document HTML d’un serveur web et le rend sous forme de page multimédia.
Dans les applications web, HTML est utilisé avec les feuilles de style en cascade (CSS) et, côté serveur, avec des frameworks comme Flask, Django, etc.
HTML utilise des balises pour définir chaque bloc de code, par exemple <p></p> pour un paragraphe, <image></image> pour intégrer une image, etc. Ensemble, ces balises composent une page HTML.
Pour lire un fichier HTML, un dataframe pandas recherche une balise : la balise <td></td>, utilisée pour définir une table en HTML.
pandas utilise read_html() pour lire un document HTML.
Ainsi, lorsque vous passez une page HTML à pandas et souhaitez en obtenir un joli dataframe, assurez-vous que la page contient un tableau !
- À propos des données : vous allez utiliser un site de
cryptomonnaiescomme dataset HTML, listant différentes pièces et des informations pour chacune, telles que :- Le dernier prix (
Last price) - L’évolution du prix en pourcentage (
%) - Le volume sur 24 heures (
24 volume) - Le nombre total de pièces (
# Coins)
- Le dernier prix (
C’est parti !
Commencez par importer la bibliothèque requests, qui vous permettra d’envoyer une requête à l’URL dont vous souhaitez récupérer le contenu HTML.
import requests
url = 'https://www.worldcoinindex.com/'
crypto_url = requests.get(url)
crypto_url
<Response [200]>
Jusqu’ici, vous avez défini l’URL, envoyé une requête avec requests.get() et obtenu une réponse acknowledgement [200] OK, signe que la connexion au serveur web a réussi.
Pour lire le contenu de la page HTML, il suffit ensuite d’appeler crypto_url.text, qui renverra le code HTML de la page de cryptomonnaies.
N’hésitez pas à exécuter crypto_url.text pour voir la sortie.
Enfin, passez crypto_url.text à pd.read_html(). Cette fonction renverra une liste de dataframes, où chaque élément de la liste correspond à un tableau (dataframe) présent sur la page de cryptomonnaies.
crypto_data = pd.read_html(crypto_url.text)
Affichons la longueur et le type de l’objet retourné. Le type doit être une liste.
len(crypto_data), type(crypto_data)
(1, list)
Comme le montre la sortie, il n’y a qu’un seul tableau, et l’objet est bien une liste.
crypto_data = crypto_data[0]
Supprimons la première et la deuxième colonne, qui n’apportent pas d’informations utiles, tout en conservant toutes les lignes.
crypto_final = crypto_data.iloc[:,2:]
Il est temps d’afficher le dataframe de cryptomonnaies !
crypto_final.head()
| Name | Ticker | Last price | % | 24 high | 24 low | Price Charts 7d | 24 volume | # Coins | Market cap | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | bitcoin | BTC | $ 8,008.027 | +1.83% | $ 8,056.630 | $ 7,812.784 | NaN | $ 12.04B | 17.71M | $ 141.89B |
| 1 | ethereum | ETH | $ 251.72335 | +2.68% | $ 253.84721 | $ 242.95687 | NaN | $ 6.93B | 106.20M | $ 26.73B |
| 2 | litecoin | LTC | $ 98.633851 | +11.08% | $ 99.946324 | $ 88.618815 | NaN | $ 3.46B | 61.91M | $ 6.10B |
| 3 | bitcoincash | BCH | $ 411.94075 | +2.31% | $ 418.60850 | $ 394.18927 | NaN | $ 2.10B | 17.79M | $ 7.33B |
| 4 | eos | EOS | $ 6.4230717 | +6.05% | $ 6.4765695 | $ 6.0264079 | NaN | $ 2.06B | 1.01B | $ 6.50B |
Dans ce tableau, vous pouvez constater que Bitcoin présente la plus forte Market Cap.
Supprimer les NaN (Not a Number)
Certains champs ne contiennent pas de valeurs réelles. Supprimons-les rapidement.
Commençons par supprimer complètement la colonne Price Charts 7d, entièrement remplie de NaN et donc inutile.
del crypto_final['Price Charts 7d']
crypto_final.head()
| Name | Ticker | Last price | % | 24 high | 24 low | 24 volume | # Coins | Market cap | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | bitcoin | BTC | $ 8,008.027 | +1.83% | $ 8,056.630 | $ 7,812.784 | $ 12.04B | 17.71M | $ 141.89B |
| 1 | ethereum | ETH | $ 251.72335 | +2.68% | $ 253.84721 | $ 242.95687 | $ 6.93B | 106.20M | $ 26.73B |
| 2 | litecoin | LTC | $ 98.633851 | +11.08% | $ 99.946324 | $ 88.618815 | $ 3.46B | 61.91M | $ 6.10B |
| 3 | bitcoincash | BCH | $ 411.94075 | +2.31% | $ 418.60850 | $ 394.18927 | $ 2.10B | 17.79M | $ 7.33B |
| 4 | eos | EOS | $ 6.4230717 | +6.05% | $ 6.4765695 | $ 6.0264079 | $ 2.06B | 1.01B | $ 6.50B |
Supprimons maintenant les NaN.
crypto_final = crypto_final.dropna()
Visualiser les cryptos (Ticker) vs. hausse/baisse du prix (%)
Importons d’abord matplotlib pour tracer le graphique.
import matplotlib.pyplot as plt
%matplotlib inline
La colonne % est de type string. Vous devez la convertir en float : commencez par retirer le signe %, puis changez le type en flottant.
crypto_final['%'] = crypto_final['%'].apply(lambda x: x.strip('%'))
crypto_final['%'] = crypto_final['%'].astype('float')
Traçons maintenant les données.
plt.figure()
plt.figure(figsize=(16,10))
x = crypto_final.iloc[:20]['Ticker']
y = crypto_final.iloc[:20]['%']
plt.xticks(fontsize=12)
plt.yticks(fontsize=14)
plt.xlabel('Percentage Increase/Decrease in Price',fontsize=20)
plt.ylabel('Ticker',fontsize=20)
plt.plot(x,y,label='% Increase/Decrease in Price')
plt.legend(loc='lower left',prop={'size': 15})
<matplotlib.legend.Legend at 0x1298a9630>
<Figure size 432x288 with 0 Axes>
D’après le graphique, Litecoin (LTC) et Huobitoken (HT) affichent la plus forte hausse de prix, tandis que Maticnetwork (MATIC) et Waves enregistrent les plus fortes baisses.
Charger des données Pickle
Pickle est un format binaire de sérialisation spécifique à Python, non lisible par l’humain, contrairement à JSON. Il sert à sérialiser et désérialiser des objets Python. Il sérialise l’objet et le « picklise » pour l’enregistrer sur disque, en convertissant des objets comme DataFrame, liste, dictionnaire, etc., en un flux d’octets.
L’un des atouts de Pickle est sa capacité à stocker divers types Python.
Pickle est largement utilisé pour enregistrer des instances de modèles de machine learning entraînés. Comme JSON, Pickle propose des fonctions pratiques telles que pickle.load() pour charger un fichier Pickle, et pickle.dump() pour enregistrer un objet au format Pickle.
Autre avantage important : enregistrer un dataframe au format Pickle occupe moins d’espace disque et conserve le type des données lors du rechargement.
Allons-y : pickleons le dataframe de cryptomonnaies créé plus haut, puis rechargeons cet objet picklé avec pandas.
import pickle
Utilisez pickle.dump pour sauvegarder le dataframe en objet Pickle et définissez le protocol sur HIGHEST_PROTOCOL, rétrocompatible avec Python 2.
with open('crypto_final.pickle', 'wb') as sub_data:
pickle.dump(crypto_final, sub_data, protocol=pickle.HIGHEST_PROTOCOL)
Enfin, utilisez pandas et sa fonction read_pickle pour convertir l’objet pickle en dataframe.
crypto_final = pd.read_pickle('crypto_final.pickle')
crypto_final.head()
| Name | Ticker | Last price | % | 24 high | 24 low | 24 volume | # Coins | Market cap | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | bitcoin | BTC | $ 7,776.567 | +1.81% | $ 7,870.205 | $ 7,506.518 | $ 12.70B | 17.71M | $ 137.78B |
| 1 | ethereum | ETH | $ 241.81372 | -0.97% | $ 245.57293 | $ 232.62523 | $ 7.47B | 106.18M | $ 25.67B |
| 2 | litecoin | LTC | $ 88.062811 | +0.33% | $ 88.946501 | $ 85.248641 | $ 2.59B | 61.90M | $ 5.45B |
| 3 | bitcoincash | BCH | $ 388.76089 | +0.06% | $ 398.27697 | $ 370.29831 | $ 2.33B | 17.79M | $ 6.91B |
| 4 | eos | EOS | $ 5.9327948 | -0.41% | $ 6.0163442 | $ 5.7789154 | $ 1.99B | 1.01B | $ 6.00B |
Impressionnant, non ? C’était on ne peut plus simple. Et avec Pickle, vous n’avez pas à craindre les erreurs de conversion de types : la sérialisation pickle s’en charge pour vous !
Pour aller plus loin
Félicitations pour avoir terminé ce tutoriel.
Ce guide constitue un excellent point de départ pour charger différents formats de données en Python avec pandas.
Il existe encore bien d’autres formats pris en charge par pandas, comme Excel, SQL, HDF5, etc. Nous vous invitons à pratiquer en trouvant des jeux de données publics intéressants dans ces formats et en expérimentant.
Pour approfondir votre maîtrise des DataFrames avec pandas, suivez le cours interactif de DataCamp data manipulation with pandas. DataCamp propose aussi plusieurs tutoriels pandas utiles sur joining dataframes, implementing moving averages et using the apply method. Et si vous débutez totalement avec pandas, commencez par ce guide d’initiation à pandas.
Références :
N’hésitez pas à poser vos questions sur ce tutoriel dans les commentaires ci-dessous.