Comment regrouper efficacement une liste Python en fonction d'une fonction donnée

PythonBeginner
Pratiquer maintenant

Introduction

L'organisation et la manipulation de collections de données sont des tâches fondamentales en programmation Python. Une opération courante consiste à regrouper les éléments d'une liste en fonction de certains critères. Ce processus transforme vos données en catégories organisées, ce qui facilite leur analyse et leur utilisation.

Dans ce tutoriel, vous apprendrez comment regrouper efficacement les éléments d'une liste Python en utilisant diverses techniques. Nous commencerons par des approches de base et introduirons progressivement des fonctions intégrées plus puissantes à cette fin. À la fin de ce lab, vous aurez une compréhension pratique des différentes façons de regrouper les données de liste en Python.

Groupement de listes de base avec des dictionnaires

Commençons par comprendre ce que signifie le groupement de listes et comment implémenter une technique de groupement de base en utilisant des dictionnaires Python.

Qu'est-ce que le groupement de listes ?

Le groupement de listes est le processus d'organisation des éléments d'une liste en catégories basées sur une caractéristique ou une fonction spécifique. Par exemple, vous pourriez vouloir regrouper une liste de nombres selon qu'ils sont pairs ou impairs, ou regrouper une liste de mots par leur première lettre.

Utilisation de dictionnaires pour le groupement de base

La façon la plus simple de regrouper les éléments d'une liste en Python est d'utiliser un dictionnaire :

  • Les clés représentent les groupes
  • Les valeurs sont des listes contenant les éléments appartenant à chaque groupe

Créons un exemple simple où nous regroupons les nombres en fonction de leur parité.

Étape 1 : Créer un fichier Python

Tout d'abord, créons un nouveau fichier Python pour écrire notre code :

  1. Ouvrez le WebIDE et créez un nouveau fichier nommé group_numbers.py dans le répertoire /home/labex/project.

  2. Ajoutez le code suivant au fichier :

## Basic list grouping using dictionaries
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

## Initialize empty dictionary to store our groups
even_odd_groups = {"even": [], "odd": []}

## Group numbers based on whether they are even or odd
for num in numbers:
    if num % 2 == 0:
        even_odd_groups["even"].append(num)
    else:
        even_odd_groups["odd"].append(num)

## Print the resulting groups
print("Grouping numbers by even/odd:")
print(f"Even numbers: {even_odd_groups['even']}")
print(f"Odd numbers: {even_odd_groups['odd']}")
  1. Enregistrez le fichier.

Étape 2 : Exécuter le script Python

Exécutez le script pour voir les résultats :

  1. Ouvrez un terminal dans le WebIDE.

  2. Exécutez le script :

python3 /home/labex/project/group_numbers.py

Vous devriez voir une sortie similaire à :

Grouping numbers by even/odd:
Even numbers: [2, 4, 6, 8, 10]
Odd numbers: [1, 3, 5, 7, 9]

Étape 3 : Regrouper selon un critère plus complexe

Maintenant, modifions notre script pour regrouper les nombres en fonction de leur reste lorsqu'ils sont divisés par 3 :

  1. Ajoutez le code suivant à votre fichier group_numbers.py :
## Group numbers by remainder when divided by 3
remainder_groups = {0: [], 1: [], 2: []}

for num in numbers:
    remainder = num % 3
    remainder_groups[remainder].append(num)

print("\nGrouping numbers by remainder when divided by 3:")
for remainder, nums in remainder_groups.items():
    print(f"Numbers with remainder {remainder}: {nums}")
  1. Enregistrez le fichier.

  2. Exécutez à nouveau le script :

python3 /home/labex/project/group_numbers.py

Vous devriez maintenant voir une sortie supplémentaire :

Grouping numbers by remainder when divided by 3:
Numbers with remainder 0: [3, 6, 9]
Numbers with remainder 1: [1, 4, 7, 10]
Numbers with remainder 2: [2, 5, 8]

Cette technique de base utilisant des dictionnaires fournit un moyen simple de regrouper les éléments d'une liste. Cependant, à mesure que vos besoins de groupement deviennent plus complexes, Python offre des méthodes plus puissantes et efficaces, que nous explorerons dans les prochaines étapes.

Utilisation de itertools.groupby() pour un groupement efficace

Maintenant que vous comprenez le concept de base du groupement, explorons une approche plus puissante en utilisant la fonction intégrée itertools.groupby(). Cette fonction est particulièrement utile lorsque vous travaillez avec des données triées.

Comprendre itertools.groupby()

La fonction groupby() du module itertools regroupe les éléments consécutifs d'un itérable en fonction d'une fonction clé. Elle renvoie un itérateur qui produit des paires de :

  • La valeur renvoyée par la fonction clé
  • Un itérateur produisant les éléments du groupe

Note importante : groupby() ne regroupe que les éléments consécutifs, donc les données d'entrée doivent généralement être triées en premier.

Implémentons un exemple pour voir comment cela fonctionne en pratique.

Étape 1 : Créer un nouveau fichier Python

  1. Créez un nouveau fichier nommé groupby_example.py dans le répertoire /home/labex/project.

  2. Ajoutez le code suivant pour importer le module nécessaire :

import itertools

## Sample data
words = ["apple", "banana", "avocado", "blueberry", "apricot", "blackberry"]

Étape 2 : Regrouper les mots par leur première lettre

Maintenant, utilisons itertools.groupby() pour regrouper les mots par leur première lettre :

  1. Ajoutez le code suivant à votre fichier groupby_example.py :
## First, we need to sort the list by the key we'll use for grouping
## In this case, the first letter of each word
words.sort(key=lambda x: x[0])
print("Sorted words:", words)

## Now group by first letter
grouped_words = {}
for first_letter, group in itertools.groupby(words, key=lambda x: x[0]):
    grouped_words[first_letter] = list(group)

## Print the resulting groups
print("\nGrouping words by first letter:")
for letter, words_group in grouped_words.items():
    print(f"Words starting with '{letter}': {words_group}")
  1. Enregistrez le fichier.

  2. Exécutez le script :

python3 /home/labex/project/groupby_example.py

Vous devriez voir une sortie similaire à :

Sorted words: ['apple', 'apricot', 'avocado', 'banana', 'blackberry', 'blueberry']

Grouping words by first letter:
Words starting with 'a': ['apple', 'apricot', 'avocado']
Words starting with 'b': ['banana', 'blackberry', 'blueberry']

Étape 3 : Comprendre l'importance du tri

Pour démontrer pourquoi le tri est crucial lors de l'utilisation de groupby(), ajoutons un autre exemple sans tri :

  1. Ajoutez le code suivant à votre fichier groupby_example.py :
## Sample data (unsorted)
unsorted_words = ["apple", "banana", "avocado", "blueberry", "apricot", "blackberry"]

print("\n--- Without sorting first ---")
print("Original words:", unsorted_words)

## Try to group without sorting
unsorted_grouped = {}
for first_letter, group in itertools.groupby(unsorted_words, key=lambda x: x[0]):
    unsorted_grouped[first_letter] = list(group)

print("\nGrouping without sorting:")
for letter, words_group in unsorted_grouped.items():
    print(f"Words starting with '{letter}': {words_group}")
  1. Enregistrez le fichier.

  2. Exécutez à nouveau le script :

python3 /home/labex/project/groupby_example.py

Dans la sortie, vous remarquerez que le groupement sans tri produit des résultats différents :

--- Without sorting first ---
Original words: ['apple', 'banana', 'avocado', 'blueberry', 'apricot', 'blackberry']

Grouping without sorting:
Words starting with 'a': ['apple']
Words starting with 'b': ['banana']
Words starting with 'a': ['avocado']
Words starting with 'b': ['blueberry']
Words starting with 'a': ['apricot']
Words starting with 'b': ['blackberry']

Remarquez comment nous avons plusieurs groupes avec la même clé. Cela se produit parce que groupby() ne regroupe que les éléments consécutifs. Lorsque les données ne sont pas triées, les éléments avec la même clé mais apparaissant à des positions différentes dans la liste seront placés dans des groupes séparés.

La fonction itertools.groupby() est très efficace et fait partie de la bibliothèque standard, ce qui en fait un outil puissant pour de nombreuses tâches de groupement. Cependant, rappelez-vous qu'elle fonctionne mieux avec des données triées.

Groupement avec collections.defaultdict

Un autre outil puissant pour le groupement en Python est la classe defaultdict du module collections. Cette approche offre une manière plus propre et plus efficace de regrouper les données par rapport à l'utilisation de dictionnaires réguliers.

Comprendre defaultdict

Un defaultdict est une sous-classe de dictionnaire qui initialise automatiquement la première valeur pour une clé manquante. Cela élimine le besoin de vérifier si une clé existe avant d'ajouter un élément à un dictionnaire. À des fins de groupement, cela signifie que nous pouvons éviter d'écrire du code conditionnel pour initialiser des listes vides pour de nouveaux groupes.

Voyons comment defaultdict simplifie le processus de groupement.

Étape 1 : Créer un nouveau fichier Python

  1. Créez un nouveau fichier nommé defaultdict_grouping.py dans le répertoire /home/labex/project.

  2. Ajoutez le code suivant pour importer le module nécessaire et créer des exemples de données :

from collections import defaultdict

## Sample data - a list of people with their ages
people = [
    {"name": "Alice", "age": 25, "city": "New York"},
    {"name": "Bob", "age": 30, "city": "Boston"},
    {"name": "Charlie", "age": 35, "city": "Chicago"},
    {"name": "David", "age": 25, "city": "Denver"},
    {"name": "Eve", "age": 30, "city": "Boston"},
    {"name": "Frank", "age": 35, "city": "Chicago"},
    {"name": "Grace", "age": 25, "city": "New York"}
]

Étape 2 : Regrouper les personnes par âge

Maintenant, utilisons defaultdict pour regrouper les personnes par leur âge :

  1. Ajoutez le code suivant à votre fichier defaultdict_grouping.py :
## Group people by age using defaultdict
age_groups = defaultdict(list)

for person in people:
    age_groups[person["age"]].append(person["name"])

## Print the resulting groups
print("Grouping people by age:")
for age, names in age_groups.items():
    print(f"Age {age}: {names}")
  1. Enregistrez le fichier.

  2. Exécutez le script :

python3 /home/labex/project/defaultdict_grouping.py

Vous devriez voir une sortie similaire à :

Grouping people by age:
Age 25: ['Alice', 'David', 'Grace']
Age 30: ['Bob', 'Eve']
Age 35: ['Charlie', 'Frank']

Étape 3 : Comparaison avec l'approche du dictionnaire régulier

Pour comprendre l'avantage d'utiliser defaultdict, comparons-le à l'approche du dictionnaire régulier :

  1. Ajoutez le code suivant à votre fichier defaultdict_grouping.py :
print("\n--- Comparison with regular dictionary ---")

## Using a regular dictionary (the conventional way)
regular_dict_groups = {}

for person in people:
    age = person["age"]
    name = person["name"]

    ## Need to check if the key exists
    if age not in regular_dict_groups:
        regular_dict_groups[age] = []

    regular_dict_groups[age].append(name)

print("\nRegular dictionary approach:")
for age, names in regular_dict_groups.items():
    print(f"Age {age}: {names}")
  1. Enregistrez le fichier.

  2. Exécutez à nouveau le script :

python3 /home/labex/project/defaultdict_grouping.py

Vous remarquerez que les deux approches produisent le même résultat, mais l'approche defaultdict est plus propre et nécessite moins de code.

Étape 4 : Regrouper par plusieurs critères

Maintenant, étendons notre exemple pour regrouper les personnes à la fois par ville et par âge :

  1. Ajoutez le code suivant à votre fichier defaultdict_grouping.py :
## Grouping by city and then by age
city_age_groups = defaultdict(lambda: defaultdict(list))

for person in people:
    city = person["city"]
    age = person["age"]
    name = person["name"]

    city_age_groups[city][age].append(name)

print("\nGrouping people by city and then by age:")
for city, age_groups in city_age_groups.items():
    print(f"\nCity: {city}")
    for age, names in age_groups.items():
        print(f"  Age {age}: {names}")
  1. Enregistrez le fichier.

  2. Exécutez à nouveau le script :

python3 /home/labex/project/defaultdict_grouping.py

Vous devriez voir une sortie supplémentaire similaire à :

Grouping people by city and then by age:

City: New York
  Age 25: ['Alice', 'Grace']

City: Boston
  Age 30: ['Bob', 'Eve']

City: Chicago
  Age 35: ['Charlie', 'Frank']

City: Denver
  Age 25: ['David']

Cette approche defaultdict imbriquée permet des hiérarchies de groupement plus complexes avec un minimum de code. Le defaultdict est particulièrement utile lorsque vous ne connaissez pas toutes les clés de groupe à l'avance, car il crée de nouveaux groupes automatiquement si nécessaire.

Application pratique : Analyse de données avec des techniques de groupement

Maintenant que vous comprenez plusieurs méthodes pour regrouper des données, appliquons ces techniques pour résoudre un problème du monde réel : l'analyse d'un ensemble de données de dossiers d'étudiants. Nous utiliserons différentes méthodes de groupement pour extraire des informations utiles des données.

Configuration de l'exemple d'ensemble de données

Tout d'abord, créons notre ensemble de données de dossiers d'étudiants :

  1. Créez un nouveau fichier nommé student_analysis.py dans le répertoire /home/labex/project.

  2. Ajoutez le code suivant pour configurer les données d'exemple :

import itertools
from collections import defaultdict

## Sample student data
students = [
    {"id": 1, "name": "Emma", "grade": "A", "subject": "Math", "score": 95},
    {"id": 2, "name": "Noah", "grade": "B", "subject": "Math", "score": 82},
    {"id": 3, "name": "Olivia", "grade": "A", "subject": "Science", "score": 90},
    {"id": 4, "name": "Liam", "grade": "C", "subject": "Math", "score": 75},
    {"id": 5, "name": "Ava", "grade": "B", "subject": "Science", "score": 88},
    {"id": 6, "name": "William", "grade": "A", "subject": "History", "score": 96},
    {"id": 7, "name": "Sophia", "grade": "B", "subject": "History", "score": 85},
    {"id": 8, "name": "James", "grade": "C", "subject": "Science", "score": 72},
    {"id": 9, "name": "Isabella", "grade": "A", "subject": "Math", "score": 91},
    {"id": 10, "name": "Benjamin", "grade": "B", "subject": "History", "score": 84}
]

print("Student Records:")
for student in students:
    print(f"ID: {student['id']}, Name: {student['name']}, Subject: {student['subject']}, Grade: {student['grade']}, Score: {student['score']}")
  1. Enregistrez le fichier.

Utilisation de defaultdict pour regrouper les étudiants par matière

Analysons quels étudiants suivent chaque matière :

  1. Ajoutez le code suivant à votre fichier student_analysis.py :
print("\n--- Students Grouped by Subject ---")

## Group students by subject using defaultdict
subject_groups = defaultdict(list)

for student in students:
    subject_groups[student["subject"]].append(student["name"])

## Print students by subject
for subject, names in subject_groups.items():
    print(f"{subject}: {names}")
  1. Enregistrez le fichier.

Calcul des scores moyens par matière

Calculons le score moyen pour chaque matière :

  1. Ajoutez le code suivant à votre fichier student_analysis.py :
print("\n--- Average Scores by Subject ---")

## Calculate average scores for each subject
subject_scores = defaultdict(list)

for student in students:
    subject_scores[student["subject"]].append(student["score"])

## Calculate and print averages
for subject, scores in subject_scores.items():
    average = sum(scores) / len(scores)
    print(f"{subject} Average: {average:.2f}")
  1. Enregistrez le fichier.

Utilisation de itertools.groupby() pour analyser les notes

Utilisons maintenant itertools.groupby() pour analyser la répartition des notes :

  1. Ajoutez le code suivant à votre fichier student_analysis.py :
print("\n--- Grade Distribution (using itertools.groupby) ---")

## Sort students by grade first
sorted_students = sorted(students, key=lambda x: x["grade"])

## Group and count students by grade
grade_counts = {}
for grade, group in itertools.groupby(sorted_students, key=lambda x: x["grade"]):
    grade_counts[grade] = len(list(group))

## Print grade distribution
for grade, count in grade_counts.items():
    print(f"Grade {grade}: {count} students")
  1. Enregistrez le fichier.

Combinaison de techniques : Analyse avancée

Enfin, effectuons une analyse plus complexe en combinant nos techniques de groupement :

  1. Ajoutez le code suivant à votre fichier student_analysis.py :
print("\n--- Advanced Analysis: Grade Distribution by Subject ---")

## Group by subject and grade
subject_grade_counts = defaultdict(lambda: defaultdict(int))

for student in students:
    subject = student["subject"]
    grade = student["grade"]
    subject_grade_counts[subject][grade] += 1

## Print detailed grade distribution by subject
for subject, grades in subject_grade_counts.items():
    print(f"\n{subject}:")
    for grade, count in grades.items():
        print(f"  Grade {grade}: {count} students")
  1. Enregistrez le fichier.

  2. Exécutez le script complet :

python3 /home/labex/project/student_analysis.py

Vous devriez voir une analyse complète des données des étudiants, comprenant :

  • Les dossiers des étudiants
  • Les étudiants regroupés par matière
  • Les scores moyens par matière
  • La répartition globale des notes
  • La répartition des notes par matière

Cet exemple démontre comment différentes techniques de groupement peuvent être combinées pour effectuer une analyse de données complexe avec un code relativement simple. Chaque approche a ses forces :

  • defaultdict est excellent pour un groupement simple sans avoir à vérifier l'existence de la clé
  • itertools.groupby() est efficace pour travailler avec des données triées
  • La combinaison de techniques permet un groupement à plusieurs niveaux et une analyse complexe

La sélection de la bonne technique de groupement dépend de vos besoins spécifiques et de la structure de vos données.

Résumé

Dans ce tutoriel, vous avez appris plusieurs méthodes efficaces pour regrouper des listes en Python :

  1. Groupement de base avec des dictionnaires : Vous avez commencé par une approche fondamentale utilisant des dictionnaires réguliers pour créer des groupes basés sur des critères spécifiques.

  2. itertools.groupby() : Vous avez exploré cette fonction intégrée qui regroupe efficacement les éléments consécutifs dans des données triées, en comprenant ses avantages et ses limites.

  3. collections.defaultdict : Vous avez utilisé cette sous-classe de dictionnaire pratique qui gère automatiquement les clés manquantes, rendant votre code de groupement plus propre et plus concis.

  4. Analyse pratique des données : Vous avez appliqué ces techniques pour analyser un ensemble de données, en voyant comment elles peuvent être utilisées individuellement et en combinaison pour extraire des informations significatives.

Chacune de ces méthodes a ses forces et ses cas d'utilisation idéaux :

  • Utilisez des dictionnaires de base pour un groupement simple lorsque la clarté est plus importante que la concision
  • Utilisez itertools.groupby() lorsque vos données sont triées ou peuvent être triées par la clé de groupement
  • Utilisez defaultdict lorsque vous souhaitez un code propre et concis et que vous ne connaissez pas toutes les clés de groupe à l'avance
  • Combinez les techniques pour un groupement et une analyse complexes à plusieurs niveaux

En maîtrisant ces techniques de groupement, vous avez ajouté des outils puissants à votre boîte à outils de programmation Python qui vous aideront à organiser, analyser et manipuler les données plus efficacement.