Dans cette série d’articles, nous allons tenter de comparer la façon de travailler avec SQL et Pandas dans ce petit duel SQL vs Pandas (Partie 2). Pour cela, dans ce second épisode, nous allons agréger et regrouper des données à partir du même jeu de données bien connu.

Ceci est la deuxième partie de la série. Vous pouvez trouver la première partie ici : Travailler avec SQL et Pandas (1ère partie)

Introduction

La bibliothèque Pandas de Python et le langage de requêtes SQL sont deux outils populaires pour la manipulation de données et leurs fonctionnalités peuvent parfois se chevaucher.
Dans cet article, nous allons aborder l’agrégation et le regroupement de données. Nous utiliserons une fois de plus le dataset Titanic que l’on peut trouver sur Kaggle pour les exemples de cet article. Je vous encourage à le télécharger et à le suivre pour une meilleure compréhension. N’oubliez pas non plus de vous essayer aux problèmes pratiques à la fin de l’article.

Okay, c’est parti !

SQL vs Pandas : Fonctions d’agrégation

Supposons que nous souhaitions obtenir des statistiques sur les données, comme le prix maximum et minimum payé, l’âge moyen des passagers et le nombre de survivants.

SQL

Pour utiliser les fonctions d’agrégation en SQL, vous pouvez utiliser AVG(), COUNT(), MIN(), MAX() et SUM() en mettant entre parenthèses la colonne à laquelle vous souhaitez appliquer la fonction. Il faut savoir que ces fonctions d’agrégation ignorent les valeurs nulles. Voici à quoi cela ressemblerait pour le problème que nous avons mis en place.

SELECT MAX(fare), MIN(fare), AVG(age), SUM(survived)
FROM titanic

Rappelez-vous que la colonne survived est codée avec 1 pour ceux qui ont survécu et 0 pour ceux qui n’ont pas survécu. C’est pourquoi la fonction SUM() fonctionne pour nous donner le total de ceux qui ont survécu.

Pour ces fonctions d’agrégation, vous pouvez trouver utile d’utiliser ROUND() pour obtenir des résultats plus jolis. Si nous voulions arrondir le résultat de la moyenne de la colonne age à une décimale par exemple, cela ressemblerait à ceci : ROUND(AVG(age), 1).
Si nous voulions arrondir au nombre entier le plus proche, cela ressemblerait à ceci : ROUND(AVG(age)).

L’un des inconvénients de SQL est que les fonctions d’agrégation énumérées précédemment sont les seules fonctions standard. Il n’existe pas de moyens aussi simples et directs de calculer des choses comme la médiane ou l’écart type d’une colonne. Je pense que certaines versions spécifiques de SQL peuvent avoir plus d’options de fonctions d’agrégation, je vous recommande donc de faire quelques recherches sur la version que vous utilisez.

Pandas

Il existe plusieurs options dans Pandas pour les fonctions d’agrégation. Par défaut, Pandas ignore les valeurs nulles, mais il existe des paramètres permettant de les inclure si vous le souhaitez vraiment. Pour obtenir des fonctions d’agrégation spécifiques sur certaines colonnes, nous pouvons calculer chacune d’entre elles individuellement. Voici à quoi cela ressemblerait :

titanic.fare.agg(['max','min'])
titanic.age.mean()
titanic.survived.sum()

La méthode agg() nous permet ici d’entrer une liste. Puisque nous voulons trouver la valeur maximale et minimale de la colonne fare, nous pouvons combiner cela en une seule ligne de code en utilisant la méthode agg().

Comme mentionné dans l’exemple SQL, vous pouvez vouloir arrondir pour obtenir de meilleurs résultats. Vous pouvez continuer en utilisant la méthode round() pour cela. Le premier paramètre est le nombre de décimales, 0 étant la valeur par défaut. Par exemple, l’arrondi à une place après la décimale pour l’âge moyen serait titanic.age.mean().round(1).

La méthode describe(), qui renvoie un tableau récapitulatif des colonnes numériques, est un atout majeur de Pandas. Le code titanic.describe() renvoie le tableau ci-dessous :

SQL vs Pandas : describe

C’est plus d’informations que ce qui était techniquement demandé, mais cela reste très utile et ne nécessite qu’une ligne de code très simple. Pourquoi s’en priver ?
Vous pouvez également obtenir des informations sur les colonnes du type de données « objet » avec titanic.describe(include="O").
Voici ce qui serait retourné :

SQL vs Pandas : describe(include=0

Pandas dispose de beaucoup plus de fonctions d’agrégation que SQL, comme la médiane (median()), l’écart type (std()) et la variance (var()). La méthode agg() offre également une plus grande flexibilité en vous permettant d’agréger sur la base d’une fonction personnalisée si vous le souhaitez.

SQL vs Pandas : Group By

Disons que nous voulons trouver des données agrégées pour les hommes et les femmes de chaque classe. Trouvons le nombre, l’âge moyen et le nombre de survivants parmi les hommes et les femmes de chaque classe.

SQL

En SQL, la clause GROUP BY est utilisée à cette fin.
Voici à quoi cela ressemblerait :

SELECT sex, pclass, COUNT(*), SUM(survived), AVG(age)
FROM titanic
GROUP BY sex, pclass

Dans cet exemple, étant donné que nous retournons des colonnes qui ne sont pas des valeurs agrégées (sex, pclass), le code ne fonctionnera pas sans la clause GROUP BY car SQL ne sait pas comment traiter ces colonnes sans elle. Dans le cas d’un regroupement par sexe et classe, les colonnes agrégées seront calculées individuellement pour chaque combinaison de sexe et de classe (femmes en première classe, hommes en première classe, femmes en deuxième classe, etc.).

Pandas

Avec la bibliothèque Pandas, nous disposons de la méthode groupby() pour obtenir les résultats que nous souhaitons. De la même manière que précédemment, nous pouvons exécuter du code pour obtenir chaque élément individuel que nous voulons ou nous pouvons exécuter du code qui contient plus d’informations que ce dont nous avons besoin.
Voici à quoi cela ressemblerait d’obtenir les informations par morceaux :

titanic.groupby(['sex', 'pclass']).survived.agg(['count', 'sum'])
titanic.groupby(['sex', 'pclass']).age.mean()

Nous pourrions également générer un tableau avec les informations que nous voulons, mais il contient plus d’informations que celles demandées.
Voici à quoi cela ressemblerait :

new_df = titanic.groupby(['sex', 'pclass'])[['survived', 'age']]
new_df.agg(['count', 'sum', 'mean'])

Dans cet exemple, j’ai créé une nouvelle variable pour diviser la cellule de code afin qu’elle soit plus facile à consulter, mais vous pourriez faire tout cela en une seule ligne. Nous appliquons d’abord le groupby, puis nous découpons les colonnes dont nous avons besoin, et enfin nous appliquons les fonctions d’agrégation à ces colonnes.
Voici un aperçu du tableau résultant :

SQL vs Pandas : groupby

Dans certains cas, ces informations supplémentaires peuvent constituer un bonus intéressant, dans d’autres cas, elles ne peuvent que créer davantage de confusion. Par exemple, les comptes des colonnes survived et age sont différents. C’est parce qu’il y a des valeurs nulles dans la colonne age, donc les comptes de la colonne survived sont les vrais comptes qui nous intéressent car il n’y a pas de valeurs nulles. Mais cela peut entraîner une confusion inutile. D’autre part, la moyenne dans la colonne survived nous indique le pourcentage de ceux qui ont survécu dans chacun des groupes, ce qui est une information intéressante qui ajoute de la valeur dans une analyse.

Pratique : Énoncé du problème

  1. Trouvez le prix moyen du billet et le nombre de passagers regroupés par port d’embarquement et classe.
  2. Trouvez l’âge minimum, maximum et moyen des passagers regroupés par classe et par survie.
  3. Trouvez le prix moyen du billet, l’âge minimum et l’âge maximum des passagers regroupés par survie.
SQL vs Pandas : Pratique

Réponse aux 3 questions

Avez-vous essayé de résoudre chaque problème avant de jeter un coup d’œil à la réponse ? N’oubliez pas que vos réponses seront probablement un peu différentes des miennes, car il y a souvent plusieurs façons de résoudre le problème.

Question 1

Trouvez le prix moyen du billet et le nombre de passagers regroupés par port d’embarquement et classe.

SQL

SELECT embarked, pclass, COUNT(*), AVG(fare)
FROM titanic
GROUP BY embarked, pclass

Pandas

titanic.groupby(['embarked', 'pclass']).fare.mean()
titanic.groupby(['embarked', 'pclass']).embarked.count()

Question 2

Trouvez l’âge minimum, maximum et moyen des passagers regroupés par classe et par survie.

SQL

SELECT pclass, survived, MIN(age), MAX(age), AVG(age)
FROM titanic
GROUP BY pclass, survived

Pandas

titanic.groupby(['pclass','survived']).age.agg(['min','max','mean'])

Question 3

Trouvez le prix moyen du billet, l’âge minimum et l’âge maximum des passagers regroupés par survie.

SQL

SELECT survived, AVG(fare), MIN(age), MAX(age)
FROM titanic
GROUP BY survived

Pandas

titanic.groupby('survived').age.agg(['min', 'max'])
titanic.groupby('survived').fare.mean()

Conclusion

J’espère que vous avez apprécié cette discussion sur les fonctions agrégées et le regroupement. Je souhaite que ces articles soient suffisamment courts pour être facilement assimilés, c’est pourquoi j’ai décidé de m’arrêter ici.

N’hésitez pas à partager et/ou commenter si vous avez une question sur le code ou une recommandation pour la prochaine partie.

Pour aller plus loin, vous pouvez suivre la formation Pandas et la formation SQL.

SQL vs Pandas (2ème partie)

A lire également

  • Je viens de lire certains de vos articles, ils sont très utiles, très bien expliqués, et très clairs, félicitations et bon travail !
    J’ai hâte d’en lire d’autres.

    Shïtõ 3 ⛩ 🌪