5 Chargement et sauvegarde de données

Pour explorer des données et/ou réaliser des analyses statistiques ou économétriques, il est important de savoir importer et exporter des données.

Avant toute chose, il convient d’évoquer la notion de répertoire courant (working directory). En informatique, le répertroire courant d’un processus désigne un répertoire du système de fichier associé à ce processus.

Lorsqu’on lance Jupyter, une arborescence nous est proposée, et nous navigons à l’interieur de celle-ci pour créer ou ouvrir un notebook. Le répertoire contenant le notebook est le répertoire courant. Lorsqu’on indiquera à Python d’importer des données (ou d’exporter des objets), l’origine (ou la destination) sera indiquée relativement au répertoire courant, à moins d’avoir recours à des chemins absolus (c’est-à-dire un chemin d’accès à partir de la racine /).

Si on lance un programme Python depuis un terminal, le répertoire courant est le répertoire dans lequel on se trouve dans le terminal au moment de lancer le programme.

Pour afficher dans Python le répertoire courant, on peut utiliser le code suivant :

import os
cwd = os.getcwd()
print(cwd)
## /Users/ewengallic/Dropbox/Universite_Aix_Marseille/Magistere_2_Programming_for_big_data/Cours/chapters/python/Python_pour_economistes

La fonction listdir() de la librairie os est très pratique : elle permet de lister tous les documents et répertoires contenus dans le répertoire couant, ou dans n’importe quel répertoire si le paramètre path renseigne le chemin (absolu ou relatif). Après avoir importé la fonction (from os import getcwd), on peut l’appeler : os.listdir().

5.1 Charger des données

En fonction du format d’enregistrement des données, les techniques d’importation de données diffèrent.

Le Chapitre 10 propose d’autres manières d’importer les données, avec la libraririe pandas.

5.1.1 Fichiers textes

Lorsque les données sont présentes dans un fichier texte (ASCII), Python propose d’utiliser la fonction open().

La syntaxe (simplifiée) de la fonction open() est la suivante :

open(file, mode='r', buffering=-1,
  encoding=None, errors=None, newline=None)

Voici à quoi correspondent les paramètres (il en existe d’autres) :

  • file : une chaîne de caractères indiquant le chemin et le nom du fichier à ouvrir ;
  • mode : spécifie la manière par laquelle le fichier est ouvert (c.f. juste après pour les valeurs possibles) ;
  • buffering : spécifie à l’aide d’un entier le comportement à adopter pour la mise en mémoire tampon (1 pour mettre en mémoire par ligne ; un entier \(>1\) pour indiquer la taille en octets des morceaux à charger en mémoire tampon) ;
  • encoding : spécifie l’encodage du fichier ;
  • errors : spécifie la manière de gérer les erreurs d’encodage et de décodage (e.g., strict retourne une erreur d’exception, ignore permet d’ignorer les erreurs, replace de les remplacer, backslashreplace de remplacer les données mal formées par des séquences d’échappement) ;
  • newline : contrôle la fin des lignes (\n, \r, etc.).
Table 5.1: Valeurs principales pour la manière d’ouvrir les fichiers.
Valeur Description
r Ouverture pour lire (défaut)
w Ouverture pour écrire
x Ouverture pour créer un document, échoue si le fichier existe déjà
a Ouverture pour écrire, en venant ajouter à la fin du fichier si celui-ci existe déjà
+ Ouverture pour mise à jour (lecture et écriture)
b À ajouter à un mode d’ouverture pour les fichiers binaires (rb ou wb)
t Mode texte (décodage automatique des octets en Unicode). Par défaut si non spécifié (s’ajoute au mode, comme b)

Il est important de bien penser à fermer le fichier une fois qu’on a terminé de l’utiliser. Pour ce faire, on utilise la méthode close().

Dans le dossier fichiers_exemples se trouve un fichier appelé fichier_texte.txt qui contient trois lignes de texte. Ouvrons ce fichier, et utilisons la méthode .read() pour afficher son contenu :

path = "./fichiers_exemples/fichier_texte.txt"
# Ouverture en mode lecture (par défaut)
mon_fichier = open(path, mode = "r")
print(mon_fichier.read())
## Bonjour, je suis un fichier au format txt.
## Je contiens plusieurs lignes, l'idée étant de montrer comment fonctionne l'importation d'un tel fichier dans Python.
## Trois lignes devraient suffir.
mon_fichier.close()

Une pratique courante en Python est d’ouvrir un fichier dans un bloc with. La raison de ce choix est qu’un fichier ouvert dans un tel bloc est automatiquement refermé à la fin du bloc.

La syntaxe est la suivante :

# Ouverture en mode lecture (par défaut)
with open(path, "r") as mon_fichier:
  donnees = fonction_pour_recuperer_donnees_depuis_mon_fichier()

Par exemple, pour récupérer chaque ligne comme un élément d’une liste, on peut utiliser une boucle parcourant chaque ligne du fichier. À chaque itération, on récupère la ligne :

# Ouverture en mode lecture (par défaut)
with open(path, "r") as mon_fichier:
  donnees = [x for x in mon_fichier]
print(donnees)
## ['Bonjour, je suis un fichier au format txt.\n', "Je contiens plusieurs lignes, l'idée étant de montrer comment fonctionne l'importation d'un tel fichier dans Python.\n", 'Trois lignes devraient suffir.']

Note : à chaque itération, on peut appliquer la méthode strip(), qui retourne la chaîne de caractère de la ligne, en retirant les éventuels caractères blancs en début de chaîne :

# Ouverture en mode lecture (par défaut)
with open(path, "r") as mon_fichier:
  donnees = [x.strip() for x in mon_fichier]
print(donnees)
## ['Bonjour, je suis un fichier au format txt.', "Je contiens plusieurs lignes, l'idée étant de montrer comment fonctionne l'importation d'un tel fichier dans Python.", 'Trois lignes devraient suffir.']

On peut également utiliser la méthode readlines() pour importer les lignes dans une liste :

with open(path, "r") as mon_fichier:
    donnees = mon_fichier.readlines()
print(donnees)
## ['Bonjour, je suis un fichier au format txt.\n', "Je contiens plusieurs lignes, l'idée étant de montrer comment fonctionne l'importation d'un tel fichier dans Python.\n", 'Trois lignes devraient suffir.']

Il se peut parfois que l’encodage des caractères pose problème lors de l’importation. Dans ce cas, il peut être une bonne idée de changer la valeur du paramètre encoding de la fonction open(). Les encodages disponibles sont fonction de la locale. Les valeurs disponibles s’obtiennent à l’aide de la méthode suivante (code non exécuté dans ces notes) :

import locale
locale.locale_alias

5.1.1.1 Importation depuis internet

Pour importer un fichier texte depuis Internet, on peut utiliser des méthodes de la librairie urllib :

import urllib
from urllib.request import urlopen
url = "http://egallic.fr/Enseignement/Python/fichiers_exemples/fichier_texte.txt"
with urllib.request.urlopen(url) as mon_fichier:
   donnees = mon_fichier.read()
print(donnees)
## b"Bonjour, je suis un fichier au format txt.\nJe contiens plusieurs lignes, l'id\xc3\xa9e \xc3\xa9tant de montrer comment fonctionne l'importation d'un tel fichier dans Python.\nTrois lignes devraient suffir."

Comme on peut le constater, l’encodage des caractères pose souci ici. On peut appliquer la méthode decode() :

print(donnees.decode())
## Bonjour, je suis un fichier au format txt.
## Je contiens plusieurs lignes, l'idée étant de montrer comment fonctionne l'importation d'un tel fichier dans Python.
## Trois lignes devraient suffir.

5.1.2 Fichiers CSV

Les fichier CSV (comma separated value) sont très répandus. De nombreuses bases de données exportent leurs données en CSV (e.g., Banque Mondiale, FAO, Eurostat, etc.). Pour les importer dans Python, on peut uiliser le module csv.

À nouveau, on utilise la fonction open(), avec les paramètres décrits dans la Section 5.1.1. Ensuite, on fait appel à la méthode reader() du module csv :

import csv
with open('./fichiers_exemples/fichier_csv.csv') as mon_fichier:
  mon_fichier_reader = csv.reader(mon_fichier, delimiter=',', quotechar='"')
  donnees = [x for x in mon_fichier_reader]

print(donnees)
## [['nom', 'prénom', 'équipe'], ['Irving', ' "Kyrie"', ' "Celtics"'], ['James', ' "Lebron"', ' "Lakers"', ''], ['Curry', ' "Stephen"', ' "Golden State Warriors"']]

La méthode reader() peut prendre plusieurs paramètres, décrits dans le Tableau 5.2.

Table 5.2: Paramètres de la fonction reader()
Paramètre Description
csvfile L’objet ouvert avec open()
dialect Paramètre spécifiant le ‘dialect’ du fichier CSV (e.g., excel, excel-tab, unix)
delimiter Le caractère délimitant les champs (i.e., les valeurs des variables)
quotechar Caractère utilisé pour entourer les champs contenant des caractères spéciaux
escapechar Caractère d’échappement
doublequote Contrôle comment les quotechar apparaissent à l’intérieur d’un champ : quand True, le caractère est doublé, ; quand False, le caractère d’échappement est utilisé en préfixe au quotechar
lineterminator Chaîne de caractères utilisée pour terminer une ligne
skipinitialspace Quand True, le caractère blanc situé juste après le caractère de séparation des champs est ignoré
strict Quand True, retourne une erreur d’exception en cas de mauvais input de CSV

On peut aussi importer un fichier CSV en tant que dictionnaire, à l’aide de la méthode csv.DictReader() du module CSV :

import csv
chemin = "./fichiers_exemples/fichier_csv.csv"
with open(chemin) as mon_fichier:
    mon_fichier_csv = csv.DictReader(mon_fichier)
    donnees = [ligne for ligne in mon_fichier_csv]
print(donnees)
## [OrderedDict([('nom', 'Irving'), ('prénom', ' "Kyrie"'), ('équipe', ' "Celtics"')]), OrderedDict([('nom', 'James'), ('prénom', ' "Lebron"'), ('équipe', ' "Lakers"'), (None, [''])]), OrderedDict([('nom', 'Curry'), ('prénom', ' "Stephen"'), ('équipe', ' "Golden State Warriors"')])]

5.1.2.1 Importation depuis internet

Comme pour les fichiers txt, on peut charger un fichier CSV hébergé sur Internet :

import csv
import urllib.request
import codecs

url = "http://egallic.fr/Enseignement/Python/fichiers_exemples/fichier_csv.csv"
with urllib.request.urlopen(url) as mon_fichier:
    mon_fochier_csv = csv.reader(codecs.iterdecode(mon_fichier, 'utf-8'))
    donnees = [ligne for ligne in mon_fochier_csv]
print(donnees)
## [['nom', 'prénom', 'équipe'], ['Irving', ' "Kyrie"', ' "Celtics"'], ['James', ' "Lebron"', ' "Lakers"', ''], ['Curry', ' "Stephen"', ' "Golden State Warriors"']]

5.1.3 Fichier JSON

Pour importer des fichiers au format JSON (JavaScript Object Notation), qui sont très utilisés dès lors qu’on communique avec une API, on peut utiliser la librairie json, et sa méthode load() :

import json
lien = './fichiers_exemples/tweets.json'

with open(lien) as mon_fichier_json:
    data = json.load(mon_fichier_json)

Ensuite, on peut afficher le contenu importé à l’aide de la fonction pprint() :

from pprint import pprint
pprint(data)
## {'created_at': 'Wed Sep 26 07:38:05 +0000 2018',
##  'id': 11,
##  'loc': [{'long': 5.3698}, {'lat': 43.2965}],
##  'text': 'Un tweet !',
##  'user_mentions': [{'id': 111, 'screen_name': 'nom_twittos1'},
##                    {'id': 112, 'screen_name': 'nom_twittos2'}]}

5.1.3.1 Importation depuis Internet

Encore une fois, il est possible d’importer des fichiers JSON depuis Internet :

import urllib
from urllib.request import urlopen
url = "http://egallic.fr/Enseignement/Python/fichiers_exemples/tweets.json"
with urllib.request.urlopen(url) as mon_fichier:
   donnees = json.load(mon_fichier)
pprint(donnees)
## {'created_at': 'Wed Sep 26 07:38:05 +0000 2018',
##  'id': 11,
##  'loc': [{'long': 5.3698}, {'lat': 43.2965}],
##  'text': 'Un tweet !',
##  'user_mentions': [{'id': 111, 'screen_name': 'nom_twittos1'},
##                    {'id': 112, 'screen_name': 'nom_twittos2'}]}

5.1.4 Fichiers Excel

Les fichiers Excel (xls ou xlsx) sont aussi très largement répandus en économie. Le lecteur est prié de se référer à la Section 10.17.2 pour une méthode d’importation des données Excel avec la librairie pandas.

5.2 Exporter des données

Il n’est pas rare de devoir exporter ses données, ne serait-ce que pour les partager. À nouveau, la fonction open() est mise à contribution, en jouant avec la valeur du paramètre mode (c.f. Tableau 5.1).

5.2.1 Fichiers textes

Admettons que nous ayons besoin d’exporter des lignes de texte dans un fichier. Avant de donner un exemple avec la fonction open(), regardons deux fonctions importantes pour convertir les contenus de certains objets en texte.

La première, str(), retourne une version en chaînes de caractères d’un objet. Nous l’avons déjà appliquée à des nombres que l’on désirait concaténer en Section 2.1.4.

x = ["pomme", 1, 3]
str(x)

Le résultat de cette instruction retourne la liste sous la forme d’une chaîne de caractères : "['pomme', 1, 3]".

La seconde fonction qu’il semble important d’aborder est repr(). Cette fonction retourne une chaîne contenant une représentation imprimable à l’écran d’un objet. De plus, cette chaîne peut être lue par l’interprète.

y = "Fromage, tu veux du fromage ?\n"
repr(y)

Le résultat donne : "'Fromage, tu veux du fromage ?\\n'".

Admettons que nous souhaitons exporter deux lignes :

  • la première, un texte qui indique un titre (“Caractéristiques de Kyrie Irving”) ;
  • la seconde, un dictionnaire contenant des informations sur Kyrie Irving (c.f. ci-dessous).

Définissions ce dictionnaire :

z = { "nom": "Kyrie",
  "prenom": "John",
  "naissance": 1992,
  "equipes": ["Cleveland", "Boston"]}

Une des syntaxes pour exporter les données au format txt est :

# Ouverture en mode lecture (par défaut)
chemin = "chemin/vers/fichier.txt"
with open(chemin, "w") as mon_fichier:
  fonction_pour_exporter()

On créé une variable indiquant le chemin vers le fichier. On ouvre ensuite le fichier en mode écriture en précisant le paramètre mode = "w". Puis, il reste à écrire nos lignes dans le fichier.

chemin = "./fichiers_exemples/Irving.txt"
with open(chemin, mode = "w") as mon_fichier:
  mon_fichier.write("Caractéristiques de Kyrie Irving\n")
  mon_fichier.writelines(repr(z))

Si le fichier est déjà existant, en ayant utilisé mode="w", l’ancien fichier sera écrasé par le nouveau. Si on souhaite ajouter des lignes au fichier existant, on utilisera mode="a" par exemple :

with open(chemin, mode = "a") as mon_fichier:
  mon_fichier.writelines("\nUne autre ligne\n")

Si on souhaite être prévenu si le fichier est déjà existant, et faire échouer l’écriture si tel est le cas, on peut utiliser mode="x" :

with open(chemin, mode = "x") as mon_fichier:
  mon_fichier.writelines("Une nouvelle ligne qui ne sera pas ajoutée\n")
## FileExistsError: [Errno 17] File exists: './fichiers_exemples/Irving.txt'
## 
## Detailed traceback: 
##   File "<string>", line 1, in <module>

5.2.2 Fichiers CSV

En tant qu’économiste, il est plus fréquent d’avoir à exporter les données au format CSV plutôt que texte, du fait de la structure en rectangle des données que l’on manipule. Comme pour l’importation de CSV (c.f. Section 5.1.2), on utilise le module csv. Pour écrire dans le fichier, on utilise la méthode writer(). Les paramètres de formatage de cette fonction sont les mêmes que ceux de la fonction reader() (c.f. Tableau 5.2).

Exemple de création d’un fichier CSV :

import csv
chemin = "./fichiers_exemples/fichier_export.csv"

with open(chemin, mode='w') as mon_fichier:
    mon_fichier_ecrire = csv.writer(mon_fichier, delimiter=',',
                                    quotechar='"',
                                    quoting=csv.QUOTE_MINIMAL)

    mon_fichier_ecrire.writerow(['Pays', 'Année', 'Trimestre', 'TC_PIB'])
    mon_fichier_ecrire.writerow(['France', '2017', 'Q4', 0.7])
    mon_fichier_ecrire.writerow(['France', '2018', 'Q1', 0.2])

Bien évidemment, la plupart du temps, nous n’écrivons pas à la main chaque entrée. Nous exportons les données contenues dans une structure. La Section 10.17.2 donne des exemples de ce type d’export, lorsque les données sont contenues dans des tableaux à deux dimension créés avec la librairie pandas.

5.2.3 Fichier JSON

Il peut être nécessaire de sauvegarder des données structurées au format JSON, par exemple lorsqu’on a fait appel à une API (e.g., l’API de Twitter) qui retourne des objets au format JSON.

Pour ce faire, nous allons utiliser la librairire json, et sa méthode dump(). Cette méthode permet de sérialiser un objet (par exemple une liste, comme ce que l’on obtient avec l’API Twitter interrogée avec la libraririe twitter-python) en JSON.

import json
x = [1, "pomme", ["pépins", "rouge"]]
y = { "nom": "Kyrie",
  "prenom": "John",
  "naissance": 1992,
  "equipes": ["Cleveland", "Boston"]}
x_json = json.dumps(x)
y_json = json.dumps(y)

print("x_json: ", x_json)
## x_json:  [1, "pomme", ["p\u00e9pins", "rouge"]]
print("y_json: ", y_json)
## y_json:  {"nom": "Kyrie", "prenom": "John", "naissance": 1992, "equipes": ["Cleveland", "Boston"]}

Comme on peut le constater, on rencontre quelques petite problèmes d’affichage des caractères accentués. On peut préciser, à l’aide du paramètre ensure_ascii évalué à False que l’on ne désire pas s’assurer que les caractères non-ascii soient échappés par des séquences de type \uXXXX.

x_json = json.dumps(x, ensure_ascii=False)
y_json = json.dumps(y, ensure_ascii=False)

print("x_json: ", x_json)
## x_json:  [1, "pomme", ["pépins", "rouge"]]
print("y_json: ", y_json)
## y_json:  {"nom": "Kyrie", "prenom": "John", "naissance": 1992, "equipes": ["Cleveland", "Boston"]}
chemin = "./fichiers_exemples/export_json.json"

with open(chemin, 'w') as f:
    json.dump(json.dumps(x, ensure_ascii=False), f)
    f.write('\n')
    json.dump(json.dumps(y, ensure_ascii=False), f)

Si on souhaite réimporter dans Python le contenu du fichier export_json.json :

chemin = "./fichiers_exemples/export_json.json"
with open(chemin, "r") as f:
    data = []
    for line in f:
        data.append(json.loads(line, encoding="utf-8"))

print(data)
## ['[1, "pomme", ["pépins", "rouge"]]', '{"nom": "Kyrie", "prenom": "John", "naissance": 1992, "equipes": ["Cleveland", "Boston"]}']

5.2.4 Exercice

  1. Créer une liste nommée a contenant des informations sur le taux de chômage en France au deuxième trimestre 2018. Cette liste doit contenir trois éléments :
    • l’année ;
    • le trimestre ;
    • la valeur du taux de chômage (\(9.1\%\)).
  2. Exporter au format CSV le contenu de la liste a, en le faisant précéder d’une ligne précisant les noms des champs. Utiliser le point virgule comme séparateur de champs.
  3. Importer le fichier créé dans la question précédente dans Python.