Pandas est une bibliothèque d’analyse de données puissante et populaire en Python, largement utilisée par les data scientists et les data analysts pour manipuler et transformer des données. Cependant, un grand pouvoir implique de grandes responsabilités, et il est facile de tomber dans les pièges courants qui peuvent conduire à un code inefficace et à des performances lentes.
Dans cet article, nous allons explorer les 10 principales erreurs à éviter lors de l’utilisation de Pandas, afin de maximiser efficacité et performance de Pandas et tirer le meilleur parti de cette puissante bibliothèque. Que tu sois débutant ou utilisateur chevronné de Pandas, ces conseils t’aideront à écrire un meilleur code et à éviter les erreurs courantes qui peuvent te ralentir.
1. Noms de colonnes avec espaces
Les noms de colonnes contenant des espaces dans Pandas peuvent entraîner des problèmes lors de la manipulation des données ou de l’accès aux valeurs des colonnes. Lorsqu’un nom de colonne contient un espace, il doit être placé entre guillemets ou entre crochets chaque fois qu’il est référencé dans le code, ce qui peut s’avérer fastidieux et source d’erreurs. En outre, on ne pourra pas utiliser la fonction dot dans Pandas.
Voici un exemple de la façon dont un nom de colonne contenant un espace peut causer des problèmes dans Pandas. Par exemple, si on a un DataFrame dont le nom de colonne contient un espace, par exemple « Sales Amount », on ne peut pas référencer la colonne en utilisant la notation . (point / dot) habituelle, comme ceci :
df.Sales Amount
Cela entraînera une erreur de syntaxe, car l’espace dans le nom de la colonne est source de confusion pour l’analyseur syntaxique de Python.
Au lieu de cela, on doit faire référence au nom de la colonne en utilisant des crochets et des guillemets, comme ceci :
df['Sales Amount']
Cependant, cela peut être lourd et source d’erreurs, en particulier si on a beaucoup de noms de colonnes avec des espaces.
Un autre problème lié aux espaces dans les noms de colonnes c’est que certaines fonctions de pandas peuvent ne pas être en mesure de les gérer correctement. Par exemple, si on veut grouper par colonne avec un espace dans le nom, comme ceci :
df.groupby('Sales Amount')['Quantity'].sum()
On obtiendra une KeyError, car pandas ne peut pas reconnaître le nom de la colonne avec l’espace.
Pour éviter ces problèmes, il est préférable d’éviter complètement les espaces dans les noms de colonnes lorsqu’on travaille avec DataFrames pandas. À la place, on peut utiliser des underscores ( _ ) ou des Camel cases pour séparer les mots dans les noms de colonnes. Par exemple, « Sales_Amount » ou « salesAmount ».
2. Ne pas utiliser la méthode query pour le filtrage
La deuxième erreur à éviter est de ne pas utiliser la méthode query lors du filtrage des données. La méthode query() de pandas est un outil utile pour créer des sous-ensembles d’un DataFrame en fonction de conditions spécifiques. Elle nous permet de filtrer les lignes en fonction d’une expression booléenne que l’on fournit et peut être un moyen pratique de créer des sous-ensembles complexes sans avoir à enchaîner plusieurs conditions.
Voici un exemple d’utilisation de la méthode query() pour créer un sous-ensemble d’une base de données :
import pandas as pd df = pd.DataFrame({'name': ['Alice', 'Bob', 'Charlie', 'David'], 'age': [25, 30, 35, 40]}) # Sous-ensemble dont l'âge est supérieur à 30 ans subset = df.query('age > 30')
Dans cet exemple, la méthode query() est utilisée pour créer un sous-ensemble du DataFrame df dont la colonne age est supérieure à 30. Le sous-ensemble obtenu est stocké dans la variable subset.
On peut également utiliser la méthode query() pour créer des sous-ensembles basés sur plusieurs conditions :
# Sous-ensemble dont l'âge est compris entre 30 et 40 ans (inclus) subset = df.query('age >= 30 and age <= 40')
Dans cet exemple, la méthode query() est utilisée pour créer un sous-ensemble du DataFrame df dont la colonne age est comprise entre 30 et 40 inclus.
Bien que la méthode query() puisse être un outil puissant, il est important de garder à l’esprit qu’elle peut être plus lente que d’autres méthodes telles que l’indexation booléenne ou les indexeurs loc et iloc. De plus, il est important de faire attention au scope des variables et aux collisions de noms lors de l’utilisation de la méthode query(). Il est donc recommandé d’utiliser la méthode query() de manière judicieuse et d’envisager d’autres méthodes le cas échéant.
3. Ne pas utiliser le symbole @ lors de la rédaction de requêtes complexes
Lorsque tu utilises la méthode query() dans pandas, il est important de garder à l’esprit que l’utilisation d’une chaîne de caractères (string) pour l’expression de la requête n’est pas toujours l’approche la plus efficace ou la plus lisible, en particulier pour les requêtes complexes.
Une autre approche consiste à utiliser le symbole @ pour référencer des variables dans l’expression de la requête, ce qui nous permet d’écrire un code plus lisible et plus flexible.
Voici un exemple d’utilisation du symbole @ avec la méthode query() :
df = pd.read_csv('sales_data.csv') product_category = 'Electronics' start_date = '2022-01-01' end_date = '2022-03-01' min_sales_amount = 1000 min_quantity = 10 subset = df.query('product_category == @product_category and @start_date <= order_date <= @end_date and (sales_amount >= @min_sales_amount or quantity >= @min_quantity)')
Dans cet exemple, le symbole @ est utilisé pour référencer des variables dans l’expression de la requête, ce qui rend le code plus souple et plus lisible. Les variables product_category, start_date, end_date, min_sales_amount et min_quantity sont définies plus tôt dans le code et peuvent être facilement modifiées sans qu’il soit nécessaire de mettre à jour l’expression de la chaîne.
En utilisant le symbole @ pour référencer des variables, on peut écrire des requêtes plus concises et plus lisibles sans sacrifier les performances ou la lisibilité. Cette approche est particulièrement utile pour les requêtes complexes impliquant plusieurs variables ou conditions.
4. Itérer sur un DataFrame au lieu d’utiliser la vectorisation
La vectorisation est une technique puissante d’analyse de données qui consiste à effectuer des opérations sur des tableaux ou des colonnes entières de données en une seule fois, plutôt que d’utiliser des boucles pour itérer sur chaque élément individuel. L’utilisation de la vectorisation permet souvent d’obtenir un code beaucoup plus rapide et efficace, en particulier lorsque l’on travaille avec de grands ensembles de données.
Pour illustrer l’utilisation de la vectorisation au lieu de boucler sur un bloc de données, prenons un exemple simple. Supposons que nous ayons un DataFrame avec deux colonnes, x et y, et que nous voulions créer une nouvelle colonne z contenant le produit de x et y.
Voici un exemple de la manière dont nous pourrions procéder à l’aide d’une boucle :
df = pd.DataFrame({'x': [1, 2, 3], 'y': [4, 5, 6]}) for index, row in df.iterrows(): df.loc[index, 'z'] = row['x'] * row['y']
Ce code itère sur chaque ligne du DataFrame et calcule le produit de x et y pour cette ligne, puis stocke le résultat dans la nouvelle colonne z. Bien que ce code fonctionne, il peut être lent et inefficace, en particulier pour les grands blocs de données.
Au lieu de cela, nous pouvons utiliser la vectorisation pour effectuer ce calcul de manière beaucoup plus efficace. Voici un exemple :
df = pd.DataFrame({'x': [1, 2, 3], 'y': [4, 5, 6]}) df['z'] = df['x'] * df['y']
Dans ce code, nous utilisons simplement l’opérateur * pour multiplier les colonnes x et y, puis nous affectons le résultat à la nouvelle colonne z. Ce code effectue le calcul de manière beaucoup plus efficace que l’approche basée sur une boucle.
5. Traiter les slices d’un DataFrame comme un nouveau DataFrame
Lorsqu’on crée un nouveau DataFrame à partir d’une tranche (slice) d’un DataFrame existant dans pandas, il est important de noter que le nouveau DataFrame est en fait « une vue » des données d’origine, plutôt qu’une copie. Cela signifie que toute modification apportée au nouveau DataFrame sera également reflétée dans le DataFrame d’origine.
Pour éviter ce comportement et garantir que les modifications apportées au nouveau DataFrame n’affectent pas le DataFrame d’origine, on peut utiliser la méthode copy pour créer une copie du DataFrame. Voici un exemple :
# Créer un exemple de DataFrame data = {'name': ['Alice', 'Bob', 'Charlie', 'David', 'Emily'], 'age': [25, 32, 18, 47, 29], 'gender': ['F', 'M', 'M', 'M', 'F']} df = pd.DataFrame(data) # Créer une copie du DataFrame new_df = df.loc[df['age'] > 30, ['name', 'age']].copy() # Modifier le nouveau DataFrame new_df['age'] = new_df['age'] + 5 # Imprimer les deux DataFrames print(df) print(new_df)
Dans cet exemple, nous commençons par créer un exemple de DataFrame avec trois colonnes : name, age et gender. Nous sélectionnons ensuite une tranche du DataFrame à l’aide de l’indexeur .loc pour sélectionner uniquement les lignes où la colonne age est supérieure à 30, et uniquement les colonnes name et age. Nous utilisons ensuite la méthode copy pour créer un nouveau DataFrame qui est une copie de la tranche, plutôt qu’une vue des données d’origine.
Nous modifions ensuite la colonne age du nouveau DataFrame en ajoutant 5 à chaque valeur. Comme nous avons utilisé la méthode copie pour créer le nouveau DataFrame, cette modification n’affecte pas le DataFrame d’origine.
Enfin, nous imprimons les deux DataFrames pour confirmer que la modification ne s’applique qu’au nouveau DataFrame et non au DataFrame d’origine.
6. Ne pas utiliser des commandes en chaîne pour des transformations multiples
La sixième erreur à éviter est de créer plusieurs DataFrames intermédiaires lors de transformations multiples. Au lieu de cela, il est préférable d’écrire la transformation dans des commandes en chaîne où toutes les transformations sont appliquées une seule fois.
Dans pandas, on peut enchaîner plusieurs transformations dans une seule déclaration, ce qui peut être une manière plus concise et efficace d’appliquer plusieurs transformations à un DataFrame. Voici un exemple de transformation d’un DataFrame à l’aide de commandes en chaîne :
# Créer un exemple de DataFrame data = {'name': ['Alice', 'Bob', 'Charlie', 'David', 'Emily'], 'age': [25, 32, 18, 47, 29], 'gender': ['F', 'M', 'M', 'M', 'F']} df = pd.DataFrame(data) # Appliquer plusieurs transformations dans une seule déclaration new_df = (df .loc[df['age'] > 30, ['name', 'age']] .copy() .assign(age_plus_5=lambda x: x['age'] + 5)) # Imprimer le nouveau DataFrame print(new_df)
Dans cet exemple, nous commençons par créer un exemple de DataFrame avec trois colonnes : name, age et gender Nous enchaînons ensuite plusieurs transformations dans une seule instruction pour créer un nouveau DataFrame :
- Utiliser l’indexeur .loc pour sélectionner uniquement les lignes où la colonne age est supérieure à 30, et uniquement les colonnes name et age.
- Utiliser la méthode copy pour créer un nouveau DataFrame qui est une copie de la tranche, plutôt qu’une vue des données d’origine.
- Utiliser la méthode assign pour créer une nouvelle colonne dans le DataFrame appelée age_plus_5, qui est égale à la colonne age plus 5.
Enfin, nous imprimons le nouveau DataFrame pour confirmer que toutes les transformations ont été appliquées correctement.
7. Ne pas définir les types de colonnes correctement
La définition des dtypes de colonnes dans Pandas est une étape importante dans l’analyse et la manipulation des données. Les dtypes, ou types de données, sont la façon dont Pandas stocke et représente les données en mémoire. En spécifiant les dtypes pour chaque colonne, on peut contrôler l’utilisation de la mémoire de nos données et améliorer les performances de nos opérations Pandas.
Dans de nombreux cas, tu devras définir manuellement le Dtype d’une certaine colonne. Cela t’aidera à manipuler efficacement tes données.
Voici quelques raisons pour lesquelles il est important de définir les types de colonnes :
- Utilisation de la mémoire : En définissant les bons types de données, on peut réduire l’utilisation de la mémoire de notre DataFrame. Ceci est particulièrement important lorsqu’on travaille avec de grands ensembles de données, car cela peut nous aider à éviter de manquer de mémoire et de faire planter notre programme.
- Cohérence des données : La définition des types de colonnes peut contribuer à garantir la cohérence et l’exactitude de nos données. Par exemple, si une colonne ne doit contenir que des nombres entiers, la définition de son dtype à int empêchera la saisie de valeurs non entières dans cette colonne.
- Performance : Les opérations Pandas peuvent être beaucoup plus rapides lorsque les dtypes sont définis correctement. Par exemple, des opérations telles que le tri et le filtrage peuvent être optimisées lorsque Pandas connaît les types de données des colonnes sur lesquelles il opère.
8. Ne pas utiliser la fonction intégrée de traçage de Pandas
Pandas fournit de nombreuses fonctions de traçage (plot) intégrées qui peuvent être utilisées pour créer une grande variété de tracés, y compris des tracés linéaires, des diagrammes de dispersion, des diagrammes à barres, des histogrammes, etc.
L’erreur la plus fréquente est que de nombreuses personnes ne les utilisent pas de manière efficace et utilisent même d’autres fonctions de traçage.
Voici quelques exemples d’utilisation efficace des fonctions de tracé Pandas :
Diagramme linéaire
import pandas as pd import numpy as np import matplotlib.pyplot as plt # Créer un DataFrame avec des données aléatoires df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')) # Tracer un graphique linéaire de la colonne A df['A'].plot(kind='line', color='red', title='diagrammme linéaire') plt.xlabel('Index') plt.ylabel('Valeur') plt.show()
Ce code crée un DataFrame avec 100 lignes et 4 colonnes de données aléatoires, puis trace un graphique linéaire de la colonne A à l’aide de la méthode .plot. Le paramètre kind est défini sur line pour créer un graphique linéaire, et le paramètre color est défini sur red pour changer la couleur de la ligne. Le titre, l’étiquette x et l’étiquette y du graphique sont également définis à l’aide des fonctions standard de Matplotlib.
Diagramme de dispersion
# Créer un DataFrame avec des données aléatoires df = pd.DataFrame(np.random.randn(100, 2), columns=['X', 'Y']) # Tracer un diagramme de dispersion des colonnes X et Y df.plot(kind='scatter', x='X', y='Y', color='blue', title='Diagramme de dispersion') plt.xlabel('X') plt.ylabel('Y') plt.show()
Ce code crée un DataFrame avec 100 lignes et 2 colonnes de données aléatoires, puis trace un diagramme de dispersion des colonnes X et Y à l’aide de la méthode .plot. Le paramètre kind est défini sur scatter pour créer un diagramme de dispersion, et les paramètres x et y sont définis sur X et Y respectivement pour spécifier les colonnes à utiliser comme axe x et axe y du diagramme.
Diagramme en barres
# Créer un DataFrame avec des données aléatoires df = pd.DataFrame({'A': np.random.randint(1, 10, 5), 'B': np.random.randint(1, 10, 5)}) # Tracer un diagramme à barres des colonnes A et B df.plot(kind='bar', color=['blue', 'red'], title='Diagramme en barres') plt.xlabel('Index') plt.ylabel('Valeur') plt.show()
Ce code crée un DataFrame avec 5 lignes et 2 colonnes de données aléatoires, puis trace un diagramme à barres des colonnes A et B à l’aide de la méthode .plot. Le paramètre kind est défini sur bar pour créer un diagramme à barres, et le paramètre color est défini sur une liste de couleurs à utiliser pour les barres.
Histogramme
# Créer un DataFrame avec des données aléatoires df = pd.DataFrame(np.random.randn(1000, 1), columns=['A']) # Tracer un histogramme de la colonne A df['A'].plot(kind='hist', bins=20, color='green', title='Histogramme') plt.xlabel('Valeur') plt.show()
Ce code crée un DataFrame avec 1000 lignes et 1 colonne de données aléatoires, puis trace un histogramme de la colonne A à l’aide de la méthode .plot. Le paramètre kind est fixé à hist pour créer un histogramme, et le paramètre bins est fixé à 20 pour contrôler le nombre de bins (barres / bacs) dans l’histogramme.
9. Agréger manuellement au lieu d’utiliser .groupby()
L’agrégation est une opération courante dans l’analyse de données qui consiste à regrouper les données sur la base d’une ou plusieurs colonnes et à appliquer une fonction mathématique aux colonnes restantes afin d’obtenir des informations résumées sur les données. Pandas fournit une méthode .groupby() qui simplifie le processus d’agrégation, mais l’exécution manuelle de l’agrégation peut conduire à un code inefficace.
Voici quelques exemples d’agrégation manuelle de données dans Pandas et la manière dont elle peut être améliorée à l’aide de .groupby() :
Agrégation manuelle en parcourant en boucle chaque groupe
df = pd.read_csv('sales_data.csv') unique_regions = df['region'].unique() for region in unique_regions: region_sales = df[df['region'] == region]['sales'] total_sales = region_sales.sum() average_sales = region_sales.mean() max_sales = region_sales.max() min_sales = region_sales.min() print(f'{region}: Total Sales: {total_sales}, Average Sales: {average_sales}, Max Sales: {max_sales}, Min Sales: {min_sales}')
Ce code parcourt en boucle chaque région unique de l’ensemble de données, filtre les données pour cette région et calcule manuellement les ventes totales, moyennes, maximales et minimales pour cette région. Ce processus peut être simplifié en utilisant .groupby() :
df = pd.read_csv('sales_data.csv') region_stats = df.groupby('region')['sales'].agg(['sum', 'mean', 'max', 'min']) print(region_stats)
Ce code regroupe les données en fonction de la colonne region et calcule les ventes totales, moyennes, maximales et minimales pour chaque région à l’aide de la méthode .agg().
Agrégation manuelle par la création de plusieurs tableaux croisés dynamiques
df = pd.read_csv('sales_data.csv') region_sales = pd.pivot_table(df, index='region', values='sales', aggfunc=['sum', 'mean', 'max', 'min']) category_sales = pd.pivot_table(df, index='category', values='sales', aggfunc=['sum', 'mean', 'max', 'min']) product_sales = pd.pivot_table(df, index='product', values='sales', aggfunc=['sum', 'mean', 'max', 'min']) print(region_sales) print(category_sales) print(product_sales)
Ce code crée plusieurs tableaux croisés dynamiques pour calculer les ventes totales, moyennes, maximales et minimales pour chaque région, catégorie et produit. Cette opération peut être simplifiée en utilisant .groupby() :
df = pd.read_csv('sales_data.csv') sales_stats = df.groupby(['region', 'category', 'product'])['sales'].agg(['sum', 'mean', 'max', 'min']) print(sales_stats)
Ce code regroupe les données en fonction des colonnes region, category et product et calcule les ventes totales, moyennes, maximales et minimales pour chaque combinaison de ces colonnes à l’aide de la méthode .agg().
Dans l’ensemble, l’agrégation manuelle des données peut prendre du temps et être source d’erreurs, en particulier pour les grands ensembles de données. La méthode .groupby() simplifie le processus et offre un moyen plus efficace et plus fiable d’effectuer des opérations d’agrégation dans Pandas.
10. Enregistrerr de grands ensembles de données sous forme de fichiers CSV
Bien que l’enregistrement de grands ensembles de données sous forme de fichiers CSV soit une approche courante et simple, ce n’est pas toujours la meilleure option. En voici les raisons :
- Taille importante du fichier : Les fichiers CSV peuvent être très volumineux, en particulier lorsqu’il s’agit d’ensembles de données comportant de nombreuses colonnes et/ou lignes. Cela peut poser des problèmes de stockage et de traitement, surtout si nos ressources sont limitées.
- Types de données limités : Les fichiers CSV ne prennent en charge qu’une gamme limitée de types de données, tels que le texte, les nombres et les dates. Si notre ensemble de données comprend des types de données plus complexes, tels que des images ou des objets JSON, le format CSV n’est peut-être pas le meilleur à utiliser.
- Perte de métadonnées : Les fichiers CSV ne prennent pas en charge les métadonnées, telles que les types de données, les noms de colonnes ou les valeurs nulles. Cela peut poser des problèmes lors de l’importation ou de l’exportation des données et rendre difficile l’analyse de données.
- Problèmes de performance : La lecture et l’écriture de fichiers CSV volumineux peuvent être lentes et solliciter les ressources du système, en particulier lorsqu’il s’agit d’ensembles de données complexes.
- Pas de validation des données : Les fichiers CSV n’intègrent pas de validation des données ni de contrôle des erreurs, ce qui peut entraîner des incohérences et des erreurs dans les données.
Il existe des moyens plus efficaces que les fichiers CSV pour sauvegarder des cadres de données volumineux. Voici quelques-unes de ces options :
- Parquet : Parquet est un format de stockage en colonnes optimisé pour le traitement de données sur de grands ensembles de données. Il peut gérer des types de données complexes et prend en charge la compression, ce qui en fait un bon choix pour le stockage de grandes images de données.
- Feather : Feather est un format de fichier binaire léger conçu pour des opérations de lecture et d’écriture rapides. Il est compatible avec R et Python et peut être utilisé pour stocker des images de données de manière compacte et efficace.
- HDF5 : HDF5 est un format de fichier conçu pour stocker de grands ensembles de données numériques. Il fournit une structure hiérarchique qui peut être utilisée pour organiser les données et prend en charge la compression et le découpage, ce qui le rend adapté au stockage de grandes images de données.
- Apache Arrow : Apache Arrow est une plateforme de développement inter-langues pour le traitement des données en mémoire. Elle fournit un format normalisé de représentation des données qui peut être utilisé dans différents langages de programmation et prend en charge le partage de données sans copie, ce qui la rend efficace pour le stockage et le traitement d’images de données volumineuses.
Chacune de ces options a ses propres forces et faiblesses, de sorte que le choix de l’une d’entre elles dépend de ton cas d’utilisation et de tes exigences spécifiques.
Si tu as apprécié ces 10 erreurs principales à éviter, je te recommande également 14 fonctions Pandas que les Data Scientists utilisent 60 % du temps pour le Data Cleaning.