On dispose aujourd'hui d'énormément des données statistiques en libre accès. Il est même inscrit dans la loi française un droit au libre accès aux données publiques (loi n° 2016-1321 du 7 octobre 2016 pour une République numérique).
Devant la multitude de données disposibles, il est nécessaire de s'accorder sur un format de présentation commun. C'est le format CSV pour Comma-Separeted Values.
Il s'agit d'un format rudimentaire (et donc facile à manipuler). Les données sont organisées en ligne, une par entrée. Au sein de chaque ligne, les données sont séparées par des virgules.
Remarque : en France, la virgule est le séparateur des nombres décimaux. Les fichiers CSV français peuvent donc soit :
Il n'y a donc pas de règle générale, il faut traîter nos données au cas par cas...
Nous allons dans ce document voir comment manipuler des données au format CSV
Nous allons travailler avec des données géographiques provenant du site https://www.populationdata.net/monde/.
Deux fichiers nous intéressent :
Notez que les deux fichiers de présentent pas exactement les mêmes pays...
Commençons par lire les données.
Imaginons que l'on veuille lire un receuil de poèmes. Pour cela il faut :
Lire un fichier CSV focntionne la même façon. On doit :
On récupèrera à la fin de ces étapes un tableau contenant différentes entrées, chacune d'entre elle correspondant à une ligne du fichier initial.
En python :
def lire_CSV(adresse, separateur) :
"""
Lecture d'un fichier CSV indiqué par son adresse sur le disque. Le séparateur de données est fournit en argument
adresse est une chaîne de caractères correspondant à l'adresse du fichier sur le disque
separateur est une chaîne de caractères indiquant le séparateur de données dans une ligne (typiquement , ou ;)
Renvoie une liste de liste, chaque sous-liste correspondant aux données d'une ligne du fichier CSV.
Attention, les données de sortie sont au format chaîne des caractère
"""
tableau_valeurs = []
#Lecture de l'ensemble des lignes
with open(adresse) as fichier :
for ligne in fichier :
tableau_valeurs.append(ligne.split(separateur))
return tableau_valeurs
Lisons le premier fichier :
populations = lire_CSV("paysPopulation.csv", ";")
# On affiche les trois premières lignes pour information
print(populations[:4])
On a bien nos données. On peut remarquer que la densité se termine par \n
qui est le caractère de retour à la ligne.
Convertissons les données :
# On convertit les valeurs à partir de la ligne 1 car la ligne 0 contient les en-têtes
for ligne in populations[1:] :
ligne[0] = int(ligne[0]) # le rang est convertir en un entier
ligne[2] = int(ligne[2]) # la population est convertir en un entier
ligne[3] = float(ligne[3]) # la superficie est un flottant
ligne[4] = float(ligne[4]) # la densité est un flottant
print(populations[:4])
On peut noter au passage que python ignore le \n
en fin de ligne et le supprime.
On peut importer de même notre fichier d'espérance de vie :
esperances = lire_CSV("paysVie.csv", ";")
for ligne in esperances :
ligne[0] = int(ligne[0]) # le rang est convertir en un entier
ligne[3] = float(ligne[3]) # l'espérance de vie est un flottant'
print(esperances[:4])
On va maintenant chercher des données dans les tables.
Afin d'avoir un outil efficace, on souhaite pouvoir chercher les données répondant à des questions compliquées du type :
On va donc écrire une fonction qui prendra en argument le nom de la table ou chercher et une condition sur les lignes à vérifier :
def cherche_lignes(liste, condition) :
"""
Parcourt l'ensemble des lignes de la liste et renvoie celles vérifiant la condition données
liste est une liste de données
condition est une condition saisie au format texte et portant sur la variable ligne
Par exemple "ligne[1][0] == 'A'", pour les lignes dont la deuxième valeur débute par 'A'
"""
resultat = []
for ligne in liste :
if eval(condition) :
resultat.append(ligne)
return resultat
La réponse à notre question :
print( cherche_lignes(populations, "ligne[1][0] == 'F' and ligne[2] > 20e6"))
Il n'y a que la France !
Un autre exemple (facile) :
print( cherche_lignes(esperances, "ligne[3] > 83"))
Qu'a-t-on cherché ?
Un dernier exemple techinque :
print( cherche_lignes(populations, "ligne[1][0] in 'AEIOUY' and ligne[3] > 2_000_000"))
Qu'a-t-on cherché ?
Les pays de la table populations
sont classés dans l'ordre alphabétique. Comment les classer dans l'ordre croissants de leur populations ?
La fonction sorted
de python va nous aider. Cette fonction tri une liste et renvoie la liste triée.
Appliquons-la à populations
. On tri à partir de la ligne 1
car la 0
contient les en-têtes :
sorted(populations[1:])[:5]
Python a classé les pays dans l'ordre de l'indice ! C'est assez logique.
Il nous faut donc indiquer à python qu'il doit classer les éléments en ne regardant que les populations (l'élément d'indice 2) :
tri_populations = sorted(populations[1:], key= lambda ligne : ligne[2])
tri_populations[:5]
Et si l'on souhaite le tri par la superficie ?
tri_superficie = sorted(populations[1:], key= lambda ligne : ligne[3])
tri_superficie[:5]
Nous avons donc deux tableaux reprenant diverses informations pour les mêmes pays.
Il serait plus pratique d'avoir ces données dans le même tableau... Nous allons donc compléter le tableau populations
(celui qui contient le plus de pays) en ajoutant les informations manquantes de l'autre tableau (le continent et l'espérance de vie).
Tout d'abord, on ajoute les en-têtes :
populations[0].append('Continent')
populations[0].append('Espérance de vie (années)')
populations[0]
On parcourt ensuite toutes les lignes du premier tableau et pour chacune on cherche si un pays du second tableau a le même nom. Si oui on copie les valeurs, si non on écrit des valeurs d'erreur.
for ligne1 in populations[1:] :
# Par défaut on donne les valeurs d'erreur
ligne1.append('?')
ligne1.append(-1)
for ligne2 in esperances :
# On remplace les valeurs d'erreur par les bonnes si les noms des pays correspondent
if ligne1[1] == ligne2[1] :
ligne1[-2] = ligne2[2]
ligne1[-1] = ligne2[3]
# Le break permet de sortir de la boucle for => inutile de continuer à chercher si on a
# trouvé une correspondance
break
print(populations[:4])