Fichiers CSV et Excel

pandas est un module Python très riche qui facilite :

Le module pandas

Si ce n'est pas déjà fait, vous devez installer ce module dans un terminal (invite de commandes sous Windows) en tapant la commande suivante :

Windows :

pip.exe install pandas

macOS ou Linux :

pip3 install pandas

Le type DataFrame

Il s'agit d'une structure de données représentant un tableau bidimensionnel avec entête, en quelque sorte la représentation en mémoire d'un fichier CSV ou d'une feuille Excel.

Initialisation

import pandas as pd

df = pd.DataFrame(
    [
        [ 1, 'Atlanta Hawks',  'ATL', 'Southeast' ],
        [ 2, 'Boston Celtics', 'BOS', 'Atlantic' ],
        [ 3, 'Brooklyn Nets',  'BKN', 'Atlantic' ],
    ],
    columns = [ 'id', 'full_name', 'abbr', 'division' ])

print(df)

Le script Python ci-dessus produit le résultat suivant :

   id       full_name abbr   division
0   1   Atlanta Hawks  ATL  Southeast
1   2  Boston Celtics  BOS   Atlantic
2   3   Brooklyn Nets  BKN   Atlantic

les attributs columns et index permettent respectivement de récupérer les noms des colonnes et la liste des indices des lignes de l'objet DataFrame.

print('Colonnes : ')
print(df.columns)

print('\nIndices : ')
print(df.index)
Colonnes : 
Index(['id', 'full_name', 'abbr', 'division'], dtype='object')

Indices : 
RangeIndex(start=0, stop=3, step=1)

Extraction de valeurs

Comme pour les listes, l'opérateur [] permet d'extraire une ou plusieurs valeurs du tableau.

Par exemple, df['abbr'] correspond aux données de la colonne abbr de l'objet df. Et df['abbr'][0] retourne la valeur de la première ligne, c'est à dire 'ATL'.

Attention

Pour modifier la valeur d'une cellule, il faut privilégier la propriété loc qui prend en paramètre le numéro de la ligne dans la colonne sélectionnée.
df.loc[0, 'abbr'] = 'LAL'

Astuce

La propriété iloc accepte des indices négatifs afin de parcourir les lignes du DataFrame depuis la fin comme pour les listes.
df['abbr'].iloc[-1] = 'LAL' # modification de la dernière cellule

Parcours des lignes

Il est possible de parcourir l'ensemble des lignes d'un DataFrame en utilisant l'attribut index dans une boucle.

for i in df.index:
    print(df['full_name'][i])
Atlanta Hawks
Boston Celtics
Brooklyn Nets

Opérations sur les colonnes

pandas propose des fonctions permettant de calculer certaines quantités au sein d'une colonne.

Fonction Définition
df['col'].mean() Moyenne des valeurs de la colonne col
df['col'].std() Écart type des valeurs de la colonne col
df['col'].max() Valeur maximale de la colonne col
df['col'].idxmax() Indice (i.e. emplacement) de la valeur maximale de la colonne col
df['col'].min() Valeur minimale de la colonne col
df['col'].idxmin() Indice de la valeur minimale de la colonne col

Chargement de fichiers

pandas facilite aussi le chargement de fichiers afin d'initaliser un DataFrame avec un volume important de données.

Format CSV

import pandas as pd

# Initialisation du DataFrame df
# à partir des données du fichier CSV
df = pd.read_csv('data.csv', sep = ';')

# Enregistrement du DataFrame df au format CSV
df.to_csv('data_updated.csv', sep = ';', index = False)

Format Excel

Ce format, plus complexe, nécessite l'installation de trois modules supplémentaires pour le chargement et la sauvegarde.

Windows :

pip.exe install xlrd openpyxl

macOS ou Linux :

pip3 install xlrd openpyxl
import pandas as pd

# Initialisation du DataFrame df
# à partir des données du fichier Excel
df = pd.read_excel('data.xlsx')

# Enregistrement du DataFrame df au format Excel
df.to_excel('data_updated.xlsx', index = False)

Exercice

Le fichier measures_20191114_20191122.xls recense les concentrations de certains polluants atmosphériques mesurées par le capteur Flow.

Produisez l'affichage suivant concernant la présence de composés organiques volatiles (COV).

Concentration de COV :
----------------------

Densité moyenne  :  159.0 ppm
Écart type       :  49.0
Densité maximale :  479 ppm ( 2019-11-20 08:12:14 )
Correction
import pandas as pd

# Chargement des données Excel en mémoire
df = pd.read_excel('data/measures_20191114_20191122.xls', sheet_name = 'Feuille1')

# Recherche de l'indice de la valeur maximale dans la colonne VOC
maxVOCindex = df['VOC (ppb)'].idxmax()

# Affichage de la date et de la concentration
print('\n\nConcentration de COV :')
print('-----------------------\n')
print('Densité moyenne  : ', round(df['VOC (ppb)'].mean()), 'ppm')
print('Écart type       : ', round(df['VOC (ppb)'].std()))
print('Densité maximale : ', df['VOC (ppb)'][maxVOCindex], 'ppm (', df['date (UTC)'][maxVOCindex], ')')

L'archive NBA2018-2019.zip contient les fichiers suivants :

teams.xlsx
liste des équipes NBA
ATL.xlsx, BKN.xlsx, BOS.xlsx, ...
liste des matchs (à domicile ou à l'extérieur) de l'équipe

Exercice

À partir du fichier teams.xlsx, affichez la liste des équipes de la division Pacific.

Correction
import pandas as pd

# Chargement des données Excel en mémoire
df = pd.read_excel('data/NBA2018-2019/teams.xlsx', sheet_name = 'teams')

# Afficher le nom des équipes de la division Pacific

# Parcours de l'ensemble des lignes du DataFrame df
for i in df.index:
    # Pour chaque ligne, tester la valeur de la colonne 'division'
    # pour savoir si on doit afficher ou pas le nom de l'équipe 'full_name'
    if df['division'][i] == 'Pacific':
        print(df['full_name'][i])

Exercice

À partir du fichier ATL.xlsx, calculez le nombre de victoires à domicile et à l'extérieur de l'équipe des Atlanta Hawks.

Correction
import pandas as pd

# Chargement des données Excel en mémoire
df = pd.read_excel('data/NBA2018-2019/ATL.xlsx', sheet_name='games')

# Initialisation des variables 
home_wins = 0
visitor_wins = 0

# Parcours de l'ensemble des lignes du DataFrame df
for i in df.index:
    # Match à domicile ?
    if df['home_team'][i] == 'ATL':
        # Victoire à domicile ?
        if df['home_team_score'][i] > df['visitor_team_score'][i]:
            home_wins += 1
    else:
        # Victoire à l'extérieur ?
        if df['visitor_team_score'][i] > df['home_team_score'][i]:
            visitor_wins += 1

print('home wins :', home_wins)
print('visitor wins :', visitor_wins)

Traitement par lots

L'intérêt d'un script réside dans sa capacité à automatiser une tâche sur un grand nombre de données, par exemple sur plusieurs fichiers. Le module glob permet de filtrer les noms de fichiers à l'aide d'une expression rationnelle.

import glob

# Affiche les noms de fichiers situés dans le sous-répertoire
# data ayant pour extension .txt
for filename in glob.glob('data/*.txt'):
  print(filename)

# Affiche les noms de fichiers csv situés dans le sous-répertoire
# data commençant par measure et suivis de 2 caractères
for filename in glob.glob('data/measure??.csv'):
  print(filename)

Exercice

Créez un fichier teams_stats.xlsx à partir du fichier teams.xlsx en y ajoutant 3 colonnes :

home_wins
Nombre de victoires à domicile
visitor_wins
Nombre de victoires à l'extérieur
win_percentage
Pourcentage de victoires
Correction
import pandas as pd

# Chargement des équipes en mémoire
df_teams = pd.read_excel('data/NBA2018-2019/teams.xlsx', sheet_name = 'teams')

for filename in glob.glob('data/NBA2018-2019/???.xlsx'):
    # Extraction des trois lettres avant l'extension .xlsx
    abbr = filename[-8:-5]
    
    # Chargement des matchs en mémoire
    df = pd.read_excel(filename, sheet_name = 'games')

    # Parcours de l'ensemble des lignes du DataFrame df
    home_wins    = 0
    visitor_wins = 0

    for i in df.index:
        if df['home_team'][i] == abbr:
            if df['home_team_score'][i]>df['visitor_team_score'][i]:
                home_wins += 1
        else:
            if df['visitor_team_score'][i]>df['home_team_score'][i]:
                visitor_wins += 1
        
    df_teams.loc[df_teams['abbreviation'] == abbr, 'home_wins']      = home_wins
    df_teams.loc[df_teams['abbreviation'] == abbr, 'visitor_wins']   = visitor_wins
    df_teams.loc[df_teams['abbreviation'] == abbr, 'win_percentage'] = 100 * (home_wins + visitor_wins)/ len(list(df.index))
                
# Enregistre le DataFrame df au format Excel
df_teams.to_excel('data/NBA2018-2019/teams_stats.xlsx', sheet_name = 'stats', index = False)

####################################
#
# Autre solution
#
####################################

import pandas as pd

teams = pd.read_excel('data/NBA2018-2019/teams.xlsx')

for filename in glob.glob('data/NBA2018-2019/???.xlsx'):
  df = pd.read_excel(filename)
  
  abbr = filename[-8:-5]
  
  home_wins = df[ (df['home_team'] == abbr) & (df['home_team_score'] > df['visitor_team_score']) ]
  visitor_wins = df[ (df['visitor_team'] == abbr) & (df['visitor_team_score'] > df['home_team_score']) ]
  
  teams.loc[ teams['abbreviation'] == abbr, 'home_wins'] = len(home_wins.index)
  teams.loc[ teams['abbreviation'] == abbr, 'visitor_wins'] = len(visitor_wins.index)
  teams.loc[ teams['abbreviation'] == abbr, 'win_percentage'] = round((len(home_wins.index) + len(visitor_wins.index))*100/len(df.index))

teams.to_excel('data/NBA2018-2019/teams_stats.xlsx', sheet_name='stats', index = False)

Tri et filtre

Enfin, le module pandas permet d'effectuer des opérations globales sur un objet DataFrame.

Tri

La méthode df.sort_values() permet de trier l'ensemble des lignes d'un objet DataFrame nommé df avec les paramètres suivants :

Paramètre Signification
by Nom de la colonne utilisée comme critère de tri
ascending Ordre du tri : True pour croissant et False pour décroissant
inplace True pour un tri sur place et False pour créer une copie du DataFrame
df_sorted = df.sort_values(by='division', ascending=True, inplace=False)

Exercice

Réalisez un palmarès de la saison NBA 2018-2019 en triant dans l'ordre décroissant des pourcentages de victoire le fichier teams_stats.xlsx.

Correction
import pandas as pd

# Chargement des équipes en mémoire
df_teams = pd.read_excel('data/NBA2018-2019/teams_stats.xlsx', sheet_name = 'stats')

# Recherche des max et min
maxPercentageIndex = df_teams['win_percentage'].idxmax()
minPercentageIndex = df_teams['win_percentage'].idxmin()

print('\n\nNBA 2018-2019 statistics :')
print('--------------------------\n')
print('Best team  : ', df_teams['full_name'][maxPercentageIndex])
print('Worst team : ', df_teams['full_name'][minPercentageIndex])

# Tri par ordre décroissant en fonction du pourcentage de victoires
df_teams.sort_values(by='win_percentage', ascending=False, inplace=True)

# Sauvegarde au format Excel
df_teams.to_excel('data/NBA2018-2019/teams_stats.xlsx', sheet_name = 'stats', index = False)

Filtre

La méthode df.filter() permet de filter le contenu de l'objet DataFrame nommé df en sélectionnant les colonnes à retenir

df_filtered = df.filter(['full_name', 'abbr'])

Ou en sélectionnant les indices des lignes à conserver avec la propriété df.iloc

df_filtered = df.iloc[1:3, :]

Enfin, il est aussi possible de filtrer le contenu d'un objet DataFrame en sélectionnant les lignes vérifiant un critère. Par exemple :

df_filtered = df[df['division'] == 'Atlantic']

Exercice

À partir du fichier teams_stats.xlsx, générez deux nouveaux fichiers Excel donnant les palmarès pour les conference East et West, en ne retenant que les colonnes abbreviation, city, division, full_name et win_percentage.

Correction
import pandas as pd

# Chargement des équipes en mémoire
df_teams = pd.read_excel('data/NBA2018-2019/teams_stats.xlsx', sheet_name = 'stats')

# Filtrage des lignes pour la conference East
df_teams_east = df_teams[df_teams['conference'] == 'East']
df_teams_short = df_teams_east.filter(['abbreviation', 'city', 'division', 'full_name', 'win_percentage'])

# Sauvegarde dans un fichier Excel
df_teams_short.to_excel('data/NBA2018-2019/teams_stats_east.xlsx', sheet_name = 'stats', index = False)

# Filtrage des lignes de la conference West
df_teams_west = df_teams[df_teams['conference'] == 'West']
df_teams_short = df_teams_west.filter(['abbreviation', 'city', 'division', 'full_name', 'win_percentage'])

# Sauvegarde dans un fichier Excel
df_teams_short.to_excel('data/NBA2018-2019/teams_stats_west.xlsx', sheet_name = 'stats', index = False)