Comment traiter efficacement les fichiers CSV volumineux en Python

PythonBeginner
Pratiquer maintenant

Introduction

La manipulation de fichiers CSV volumineux est un défi courant pour les développeurs Python. Ce tutoriel vous guide à travers des techniques efficaces pour traiter ces fichiers de manière performante, en mettant l'accent sur l'optimisation des performances et l'utilisation de la mémoire. À la fin de ce lab, vous serez équipé des connaissances pratiques nécessaires pour aborder les tâches de traitement de fichiers CSV gourmandes en données en Python.

Que vous analysiez des données clients, traitiez des enregistrements financiers ou travailliez avec tout type de données structurées, les compétences acquises dans ce lab vous aideront à traiter efficacement de grands ensembles de données sans rencontrer de problèmes de mémoire.

Création et lecture d'un fichier CSV simple

CSV (Comma-Separated Values) est un format de fichier populaire utilisé pour stocker des données tabulaires. Dans cette étape, nous allons créer un fichier CSV simple et apprendre à le lire en utilisant le module csv intégré de Python.

Comprendre les fichiers CSV

Un fichier CSV stocke les données dans un format texte brut où :

  • Chaque ligne représente une ligne de données
  • Les valeurs de chaque ligne sont séparées par un délimiteur (généralement une virgule)
  • La première ligne contient souvent les en-têtes de colonnes

Commençons par créer un fichier CSV simple avec lequel travailler.

Création d'un fichier CSV

Tout d'abord, créons un répertoire dans lequel travailler, puis créons un fichier CSV simple :

  1. Ouvrez le terminal dans le WebIDE
  2. Créez un nouveau fichier Python nommé csv_basics.py dans l'éditeur

Maintenant, ajoutez le code suivant à csv_basics.py :

import csv

## Data to write to CSV
data = [
    ['Name', 'Age', 'City'],              ## Header row
    ['John Smith', '28', 'New York'],
    ['Sarah Johnson', '32', 'San Francisco'],
    ['Michael Brown', '45', 'Chicago'],
    ['Emily Davis', '36', 'Boston'],
    ['David Wilson', '52', 'Seattle']
]

## Writing data to a CSV file
with open('sample_data.csv', 'w', newline='') as file:
    writer = csv.writer(file)
    writer.writerows(data)

print("CSV file 'sample_data.csv' created successfully.")

Exécutez ce code en exécutant la commande suivante dans le terminal :

python3 csv_basics.py

Sortie attendue :

CSV file 'sample_data.csv' created successfully.

Cela créera un nouveau fichier CSV nommé sample_data.csv dans votre répertoire actuel. Vous pouvez afficher le contenu de ce fichier en exécutant :

cat sample_data.csv

Sortie attendue :

Name,Age,City
John Smith,28,New York
Sarah Johnson,32,San Francisco
Michael Brown,45,Chicago
Emily Davis,36,Boston
David Wilson,52,Seattle

Lecture d'un fichier CSV

Maintenant, lisons le fichier CSV que nous venons de créer. Créez un nouveau fichier nommé read_csv.py avec le code suivant :

import csv

## Reading a CSV file
with open('sample_data.csv', 'r') as file:
    reader = csv.reader(file)

    print("Contents of sample_data.csv:")
    print("--------------------------")

    for row in reader:
        print(row)

## Reading and accessing specific columns
print("\nReading specific columns:")
print("--------------------------")

with open('sample_data.csv', 'r') as file:
    reader = csv.reader(file)
    headers = next(reader)  ## Skip the header row

    for row in reader:
        name = row[0]
        age = row[1]
        city = row[2]
        print(f"Name: {name}, Age: {age}, City: {city}")

Exécutez ce code avec :

python3 read_csv.py

Sortie attendue :

Contents of sample_data.csv:
--------------------------
['Name', 'Age', 'City']
['John Smith', '28', 'New York']
['Sarah Johnson', '32', 'San Francisco']
['Michael Brown', '45', 'Chicago']
['Emily Davis', '36', 'Boston']
['David Wilson', '52', 'Seattle']

Reading specific columns:
--------------------------
Name: John Smith, Age: 28, City: New York
Name: Sarah Johnson, Age: 32, City: San Francisco
Name: Michael Brown, Age: 45, City: Chicago
Name: Emily Davis, Age: 36, City: Boston
Name: David Wilson, Age: 52, City: Seattle

Comprendre le module CSV

Le module csv de Python fournit deux classes principales :

  • csv.reader : Lit les fichiers CSV et renvoie chaque ligne sous forme de liste de chaînes de caractères
  • csv.writer : Écrit des données dans des fichiers CSV

Ce module gère toutes les complexités liées à la gestion de différents formats CSV, tels que l'échappement des caractères spéciaux et la gestion des guillemets.

Dans cette étape, vous avez appris à créer et à lire un fichier CSV simple. Dans l'étape suivante, nous explorerons des moyens plus efficaces de gérer des fichiers CSV plus volumineux.

Utilisation de DictReader pour un traitement CSV pratique

Dans l'étape précédente, nous avons travaillé avec les fonctions de base csv.reader et csv.writer. Maintenant, explorons une manière plus pratique de traiter les fichiers CSV en utilisant la classe csv.DictReader, ce qui est particulièrement utile lorsque l'on travaille avec des données qui ont des en-têtes de colonnes.

Qu'est-ce que DictReader ?

csv.DictReader lit les fichiers CSV et renvoie chaque ligne sous forme de dictionnaire où :

  • Les clés sont tirées des en-têtes de colonnes (première ligne du fichier CSV par défaut)
  • Les valeurs sont les données correspondantes de chaque ligne

Cette approche rend votre code plus lisible et moins sujet aux erreurs, car vous pouvez référencer les colonnes par nom au lieu de par index.

Créer un fichier de test plus grand

Tout d'abord, créons un fichier CSV légèrement plus grand pour démontrer les avantages de DictReader. Créez un nouveau fichier nommé create_users_data.py avec le code suivant :

import csv
import random

## Generate some sample user data
def generate_users(count):
    users = [['id', 'name', 'email', 'age', 'country']]  ## Header row

    domains = ['gmail.com', 'yahoo.com', 'outlook.com', 'example.com']
    countries = ['USA', 'Canada', 'UK', 'Australia', 'Germany', 'France', 'Japan', 'Brazil']
    first_names = ['John', 'Jane', 'Michael', 'Emily', 'David', 'Sarah', 'Robert', 'Lisa']
    last_names = ['Smith', 'Johnson', 'Brown', 'Davis', 'Wilson', 'Miller', 'Jones', 'Taylor']

    for i in range(1, count + 1):
        first_name = random.choice(first_names)
        last_name = random.choice(last_names)
        name = f"{first_name} {last_name}"
        email = f"{first_name.lower()}.{last_name.lower()}@{random.choice(domains)}"
        age = random.randint(18, 65)
        country = random.choice(countries)

        users.append([str(i), name, email, str(age), country])

    return users

## Create a CSV file with 100 users
users_data = generate_users(100)

## Write data to CSV file
with open('users_data.csv', 'w', newline='') as file:
    writer = csv.writer(file)
    writer.writerows(users_data)

print(f"Created 'users_data.csv' with 100 user records")

Exécutez le script pour créer le fichier :

python3 create_users_data.py

Sortie attendue :

Created 'users_data.csv' with 100 user records

Examinons les premières lignes de ce nouveau fichier :

head -n 5 users_data.csv

Vous devriez voir la ligne d'en-tête suivie de 4 lignes de données :

id,name,email,age,country
1,John Smith,john.smith@gmail.com,25,USA
2,Emily Brown,emily.brown@yahoo.com,32,Canada
3,David Jones,david.jones@outlook.com,45,UK
4,Sarah Wilson,sarah.wilson@example.com,28,Australia

Utilisation de DictReader pour traiter le fichier CSV

Maintenant, créons un script pour traiter ce fichier en utilisant DictReader. Créez un nouveau fichier nommé dict_reader_example.py avec le code suivant :

import csv

## Read the CSV file using DictReader
with open('users_data.csv', 'r') as file:
    csv_reader = csv.DictReader(file)

    ## Print the field names (column headers)
    print(f"Column headers: {csv_reader.fieldnames}")
    print("\nFirst 5 records:")
    print("-----------------")

    ## Print the first 5 records
    for i, row in enumerate(csv_reader):
        if i < 5:
            ## Access fields by name
            print(f"User {row['id']}: {row['name']}, {row['age']} years old, from {row['country']}")
            print(f"  Email: {row['email']}")
        else:
            break

## Using DictReader for data analysis
with open('users_data.csv', 'r') as file:
    csv_reader = csv.DictReader(file)

    ## Calculate average age
    total_age = 0
    user_count = 0

    ## Count users by country
    countries = {}

    for row in csv_reader:
        user_count += 1
        total_age += int(row['age'])

        ## Count users by country
        country = row['country']
        if country in countries:
            countries[country] += 1
        else:
            countries[country] = 1

    avg_age = total_age / user_count if user_count > 0 else 0

    print("\nData Analysis:")
    print("--------------")
    print(f"Total users: {user_count}")
    print(f"Average age: {avg_age:.2f} years")
    print("\nUsers by country:")

    for country, count in sorted(countries.items(), key=lambda x: x[1], reverse=True):
        print(f"  {country}: {count} users")

Exécutez ce script :

python3 dict_reader_example.py

Sortie attendue (vos valeurs exactes peuvent varier car les données sont générées aléatoirement) :

Column headers: ['id', 'name', 'email', 'age', 'country']

First 5 records:
-----------------
User 1: John Smith, 25 years old, from USA
  Email: john.smith@gmail.com
User 2: Emily Brown, 32 years old, from Canada
  Email: emily.brown@yahoo.com
User 3: David Jones, 45 years old, from UK
  Email: david.jones@outlook.com
User 4: Sarah Wilson, 28 years old, from Australia
  Email: sarah.wilson@example.com
User 5: Michael Taylor, 37 years old, from Germany
  Email: michael.taylor@example.com

Data Analysis:
--------------
Total users: 100
Average age: 41.35 years

Users by country:
  USA: 16 users
  Canada: 14 users
  Japan: 13 users
  UK: 12 users
  Germany: 12 users
  Australia: 12 users
  France: 11 users
  Brazil: 10 users

Avantages de l'utilisation de DictReader

Comme vous pouvez le constater, l'utilisation de DictReader offre plusieurs avantages :

  1. Code lisible : Vous pouvez accéder aux champs par nom au lieu de mémoriser les positions d'index
  2. Auto-documenté : Le code montre clairement à quel champ vous accédez
  3. Flexibilité : Si l'ordre des colonnes change dans le fichier CSV, votre code fonctionne toujours tant que les noms des colonnes restent les mêmes

Cette approche est particulièrement utile lorsque vous travaillez avec des données réelles qui comportent de nombreuses colonnes ou lorsque l'ordre des colonnes peut changer au fil du temps.

Dans l'étape suivante, nous explorerons des techniques efficaces pour traiter des fichiers CSV plus volumineux sans tout charger en mémoire à la fois.

Traitement efficace des fichiers CSV volumineux

Dans des scénarios réels, vous devrez peut-être traiter des fichiers CSV de plusieurs gigaoctets. Le chargement de ces fichiers entièrement en mémoire peut entraîner le plantage de votre application ou un ralentissement important. Dans cette étape, nous allons explorer des techniques pour traiter efficacement les fichiers CSV volumineux.

Le défi de la mémoire avec les fichiers volumineux

Lorsque vous travaillez avec des fichiers CSV, il existe trois approches courantes, chacune ayant des exigences de mémoire différentes :

  1. Chargement de l'intégralité du fichier en mémoire - Simple mais utilise le plus de mémoire
  2. Streaming du fichier ligne par ligne - Utilise un minimum de mémoire mais peut être plus lent pour les opérations complexes
  3. Chunking (traitement par blocs) - Un entre-deux qui traite le fichier par blocs gérables

Explorons chacune de ces approches avec des exemples pratiques.

Création d'un fichier d'exemple plus grand

Tout d'abord, créons un fichier d'exemple plus grand pour démontrer ces techniques. Créez un nouveau fichier nommé create_large_csv.py :

import csv
import random
from datetime import datetime, timedelta

def create_large_csv(filename, num_rows):
    ## Define column headers
    headers = ['transaction_id', 'date', 'customer_id', 'product_id', 'amount', 'status']

    ## Create a file with the specified number of rows
    with open(filename, 'w', newline='') as file:
        writer = csv.writer(file)
        writer.writerow(headers)

        ## Generate random data
        start_date = datetime(2022, 1, 1)
        status_options = ['completed', 'pending', 'failed', 'refunded']

        for i in range(1, num_rows + 1):
            ## Generate random values
            transaction_id = f"TXN-{i:08d}"
            days_offset = random.randint(0, 365)
            date = (start_date + timedelta(days=days_offset)).strftime('%Y-%m-%d')
            customer_id = f"CUST-{random.randint(1001, 9999)}"
            product_id = f"PROD-{random.randint(101, 999)}"
            amount = round(random.uniform(10.0, 500.0), 2)
            status = random.choice(status_options)

            ## Write row to CSV
            writer.writerow([transaction_id, date, customer_id, product_id, amount, status])

            ## Print progress indicator for every 10,000 rows
            if i % 10000 == 0:
                print(f"Generated {i} rows...")

## Create a CSV file with 50,000 rows (about 5-10 MB)
create_large_csv('transactions.csv', 50000)
print("Large CSV file 'transactions.csv' has been created.")

Exécutez ce script pour créer le fichier :

python3 create_large_csv.py

Sortie attendue :

Generated 10000 rows...
Generated 20000 rows...
Generated 30000 rows...
Generated 40000 rows...
Generated 50000 rows...
Large CSV file 'transactions.csv' has been created.

Vous pouvez vérifier la taille du fichier avec :

ls -lh transactions.csv

Sortie attendue (la taille peut varier légèrement) :

-rw-r--r-- 1 labex labex 3.8M Apr 15 12:30 transactions.csv

Approche 1 : Traitement ligne par ligne (Streaming)

L'approche la plus économe en mémoire consiste à traiter un fichier CSV ligne par ligne. Créez un fichier nommé streaming_example.py :

import csv
import time

def process_csv_streaming(filename):
    print(f"Processing {filename} using streaming (line by line)...")
    start_time = time.time()

    ## Track some statistics
    row_count = 0
    total_amount = 0
    status_counts = {'completed': 0, 'pending': 0, 'failed': 0, 'refunded': 0}

    ## Process the file line by line
    with open(filename, 'r') as file:
        reader = csv.DictReader(file)

        for row in reader:
            ## Increment row counter
            row_count += 1

            ## Process row data
            amount = float(row['amount'])
            status = row['status']

            ## Update statistics
            total_amount += amount
            status_counts[status] += 1

    ## Calculate and display results
    end_time = time.time()
    processing_time = end_time - start_time

    print(f"\nResults:")
    print(f"Processed {row_count:,} rows in {processing_time:.2f} seconds")
    print(f"Total transaction amount: ${total_amount:,.2f}")
    print(f"Average transaction amount: ${total_amount/row_count:.2f}")
    print("\nTransaction status breakdown:")
    for status, count in status_counts.items():
        percentage = (count / row_count) * 100
        print(f"  {status}: {count:,} ({percentage:.1f}%)")

## Process the file
process_csv_streaming('transactions.csv')

Exécutez ce script :

python3 streaming_example.py

Sortie attendue (vos chiffres exacts peuvent varier) :

Processing transactions.csv using streaming (line by line)...

Results:
Processed 50,000 rows in 0.17 seconds
Total transaction amount: $12,739,853.35
Average transaction amount: $254.80

Transaction status breakdown:
  completed: 12,432 (24.9%)
  pending: 12,598 (25.2%)
  failed: 12,414 (24.8%)
  refunded: 12,556 (25.1%)

Approche 2 : Traitement par blocs (Chunked Processing)

Pour des opérations plus complexes ou lorsque vous devez traiter les données par lots, vous pouvez utiliser une approche par blocs. Créez un fichier nommé chunked_example.py :

import csv
import time

def process_csv_chunked(filename, chunk_size=10000):
    print(f"Processing {filename} using chunks of {chunk_size} rows...")
    start_time = time.time()

    ## Track some statistics
    row_count = 0
    total_amount = 0
    status_counts = {'completed': 0, 'pending': 0, 'failed': 0, 'refunded': 0}

    ## Process the file in chunks
    with open(filename, 'r') as file:
        reader = csv.DictReader(file)

        chunk = []
        for row in reader:
            ## Add row to current chunk
            chunk.append(row)

            ## When chunk reaches desired size, process it
            if len(chunk) >= chunk_size:
                ## Process the chunk
                for row_data in chunk:
                    ## Update statistics
                    row_count += 1
                    amount = float(row_data['amount'])
                    status = row_data['status']

                    total_amount += amount
                    status_counts[status] += 1

                print(f"Processed chunk of {len(chunk)} rows... ({row_count:,} total)")
                ## Clear the chunk for next batch
                chunk = []

        ## Process any remaining rows in the last chunk
        if chunk:
            for row_data in chunk:
                row_count += 1
                amount = float(row_data['amount'])
                status = row_data['status']

                total_amount += amount
                status_counts[status] += 1

            print(f"Processed final chunk of {len(chunk)} rows... ({row_count:,} total)")

    ## Calculate and display results
    end_time = time.time()
    processing_time = end_time - start_time

    print(f"\nResults:")
    print(f"Processed {row_count:,} rows in {processing_time:.2f} seconds")
    print(f"Total transaction amount: ${total_amount:,.2f}")
    print(f"Average transaction amount: ${total_amount/row_count:.2f}")
    print("\nTransaction status breakdown:")
    for status, count in status_counts.items():
        percentage = (count / row_count) * 100
        print(f"  {status}: {count:,} ({percentage:.1f}%)")

## Process the file with chunks of 10,000 rows
process_csv_chunked('transactions.csv', chunk_size=10000)

Exécutez ce script :

python3 chunked_example.py

Sortie attendue :

Processing transactions.csv using chunks of 10000 rows...
Processed chunk of 10000 rows... (10,000 total)
Processed chunk of 10000 rows... (20,000 total)
Processed chunk of 10000 rows... (30,000 total)
Processed chunk of 10000 rows... (40,000 total)
Processed chunk of 10000 rows... (50,000 total)

Results:
Processed 50,000 rows in 0.20 seconds
Total transaction amount: $12,739,853.35
Average transaction amount: $254.80

Transaction status breakdown:
  completed: 12,432 (24.9%)
  pending: 12,598 (25.2%)
  failed: 12,414 (24.8%)
  refunded: 12,556 (25.1%)

Comparaison de l'utilisation de la mémoire

Les principales différences entre ces approches sont les suivantes :

  1. Streaming (ligne par ligne) :

    • Utilise un minimum de mémoire quelle que soit la taille du fichier
    • Idéal pour les très grands fichiers
    • Opérations simples sur chaque ligne
  2. Traitement par blocs :

    • Utilise plus de mémoire que le streaming, mais reste efficace
    • Bon pour les opérations qui doivent traiter les lignes par lots
    • Fournit des mises à jour de progression pendant le traitement
    • Peut être combiné avec le traitement en parallèle (multiprocessing)

Dans la plupart des cas pratiques, l'approche de streaming est recommandée, sauf si vous avez spécifiquement besoin de capacités de traitement par lots. Elle offre la meilleure efficacité mémoire tout en maintenant de bonnes performances.

Dans l'étape suivante, nous explorerons l'utilisation de bibliothèques tierces comme pandas pour des capacités de traitement CSV encore plus puissantes.

Utilisation de Pandas pour le traitement CSV avancé

Bien que le module csv intégré de Python soit puissant, la bibliothèque pandas offre des fonctionnalités plus avancées pour l'analyse et la manipulation des données. Dans cette étape, nous allons explorer comment utiliser pandas pour un traitement CSV efficace.

Installation de Pandas

Tout d'abord, installons la bibliothèque pandas :

pip install pandas

Sortie attendue :

Collecting pandas
  Downloading pandas-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.3 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.3/12.3 MB 42.6 MB/s eta 0:00:00
...
Successfully installed pandas-2.0.0 numpy-1.24.3 python-dateutil-2.8.2 pytz-2023.3 tzdata-2023.3

Lecture de fichiers CSV avec Pandas

Pandas facilite la lecture, l'analyse et la manipulation des données CSV. Créez un fichier nommé pandas_basic.py :

import pandas as pd
import time

def process_with_pandas(filename):
    print(f"Processing {filename} with pandas...")
    start_time = time.time()

    ## Read the CSV file into a DataFrame
    df = pd.read_csv(filename)

    ## Display basic information
    print(f"\nDataFrame Info:")
    print(f"Shape: {df.shape} (rows, columns)")
    print(f"Column names: {', '.join(df.columns)}")

    ## Display the first 5 rows
    print("\nFirst 5 rows:")
    print(df.head())

    ## Basic statistics
    print("\nSummary statistics for numeric columns:")
    print(df.describe())

    ## Group by analysis
    print("\nTransaction counts by status:")
    status_counts = df['status'].value_counts()
    print(status_counts)

    ## Calculate average amount by status
    print("\nAverage transaction amount by status:")
    avg_by_status = df.groupby('status')['amount'].mean()
    print(avg_by_status)

    ## Calculate total amount by date (first 5 dates)
    print("\nTotal transaction amount by date (first 5 dates):")
    total_by_date = df.groupby('date')['amount'].sum().sort_values(ascending=False).head(5)
    print(total_by_date)

    end_time = time.time()
    print(f"\nProcessed in {end_time - start_time:.2f} seconds")

## Process the transactions file
process_with_pandas('transactions.csv')

Exécutez ce script :

python3 pandas_basic.py

Sortie attendue (tronquée pour plus de brièveté) :

Processing transactions.csv with pandas...

DataFrame Info:
Shape: (50000, 6) (rows, columns)
Column names: transaction_id, date, customer_id, product_id, amount, status

First 5 rows:
  transaction_id        date customer_id product_id   amount    status
0    TXN-00000001  2022-12-19   CUST-5421   PROD-383  385.75  refunded
1    TXN-00000002  2022-02-01   CUST-7078   PROD-442  286.83  completed
2    TXN-00000003  2022-12-24   CUST-2356   PROD-701  364.87    failed
3    TXN-00000004  2022-04-09   CUST-3458   PROD-854  247.73   pending
4    TXN-00000005  2022-03-07   CUST-6977   PROD-307  298.69  completed

Summary statistics for numeric columns:
              amount
count  50000.000000
mean     254.797067
std      141.389125
min       10.010000
25%      127.732500
50%      254.865000
75%      381.387500
max      499.990000

Transaction counts by status:
pending     12598
refunded    12556
completed   12432
failed      12414
Name: status, dtype: int64

Average transaction amount by status:
status
completed    255.028733
failed       254.709444
pending      254.690785
refunded     254.760390
Name: amount, dtype: float64

Total transaction amount by date (first 5 dates):
date
2022-01-20    38883.19
2022-08-30    38542.49
2022-03-10    38331.67
2022-11-29    38103.61
2022-06-24    37954.87
Name: amount, dtype: float64

Processed in 0.11 seconds

Traitement de fichiers CSV volumineux avec Pandas

Bien que pandas soit puissant, il peut consommer beaucoup de mémoire lors du chargement de fichiers CSV volumineux. Pour les très grands fichiers, vous pouvez utiliser le paramètre chunksize pour lire le fichier par blocs. Créez un fichier nommé pandas_chunked.py :

import pandas as pd
import time

def process_large_csv_with_pandas(filename, chunk_size=10000):
    print(f"Processing {filename} with pandas using chunks of {chunk_size} rows...")
    start_time = time.time()

    ## Initialize variables to store aggregated results
    total_rows = 0
    total_amount = 0
    status_counts = {'completed': 0, 'pending': 0, 'failed': 0, 'refunded': 0}
    daily_totals = {}

    ## Process the file in chunks
    for chunk_num, chunk in enumerate(pd.read_csv(filename, chunksize=chunk_size)):
        ## Update row count
        chunk_rows = len(chunk)
        total_rows += chunk_rows

        ## Update total amount
        chunk_amount = chunk['amount'].sum()
        total_amount += chunk_amount

        ## Update status counts
        for status, count in chunk['status'].value_counts().items():
            status_counts[status] += count

        ## Update daily totals
        for date, group in chunk.groupby('date'):
            if date in daily_totals:
                daily_totals[date] += group['amount'].sum()
            else:
                daily_totals[date] = group['amount'].sum()

        print(f"Processed chunk {chunk_num + 1} ({total_rows:,} rows so far)")

    ## Calculate results
    end_time = time.time()
    processing_time = end_time - start_time

    print(f"\nResults after processing {total_rows:,} rows in {processing_time:.2f} seconds:")
    print(f"Total transaction amount: ${total_amount:,.2f}")
    print(f"Average transaction amount: ${total_amount/total_rows:.2f}")

    print("\nTransaction status breakdown:")
    for status, count in status_counts.items():
        percentage = (count / total_rows) * 100
        print(f"  {status}: {count:,} ({percentage:.1f}%)")

    ## Show top 5 days by transaction amount
    print("\nTop 5 days by transaction amount:")
    top_days = sorted(daily_totals.items(), key=lambda x: x[1], reverse=True)[:5]
    for date, amount in top_days:
        print(f"  {date}: ${amount:,.2f}")

## Process the transactions file with chunks
process_large_csv_with_pandas('transactions.csv', chunk_size=10000)

Exécutez ce script :

python3 pandas_chunked.py

Sortie attendue :

Processing transactions.csv with pandas using chunks of 10000 rows...
Processed chunk 1 (10,000 rows so far)
Processed chunk 2 (20,000 rows so far)
Processed chunk 3 (30,000 rows so far)
Processed chunk 4 (40,000 rows so far)
Processed chunk 5 (50,000 rows so far)

Results after processing 50,000 rows in 0.34 seconds:
Total transaction amount: $12,739,853.35
Average transaction amount: $254.80

Transaction status breakdown:
  completed: 12,432 (24.9%)
  pending: 12,598 (25.2%)
  failed: 12,414 (24.8%)
  refunded: 12,556 (25.1%)

Top 5 days by transaction amount:
  2022-01-20: $38,883.19
  2022-08-30: $38,542.49
  2022-03-10: $38,331.67
  2022-11-29: $38,103.61
  2022-06-24: $37,954.87

Filtrage et transformation des données avec Pandas

L'un des grands avantages de pandas est la possibilité de filtrer et de transformer facilement les données. Créez un fichier nommé pandas_filter.py :

import pandas as pd
import time

def filter_and_transform(filename):
    print(f"Filtering and transforming data from {filename}...")
    start_time = time.time()

    ## Read the CSV file
    df = pd.read_csv(filename)

    ## 1. Filter: Get only completed transactions
    completed = df[df['status'] == 'completed']
    print(f"Number of completed transactions: {len(completed)}")

    ## 2. Filter: Get high-value transactions (over $400)
    high_value = df[df['amount'] > 400]
    print(f"Number of high-value transactions (>${400}): {len(high_value)}")

    ## 3. Filter: Transactions from first quarter of 2022
    df['date'] = pd.to_datetime(df['date'])  ## Convert to datetime
    q1_2022 = df[(df['date'] >= '2022-01-01') & (df['date'] <= '2022-03-31')]
    print(f"Number of transactions in Q1 2022: {len(q1_2022)}")

    ## 4. Add a new column: transaction_month
    df['month'] = df['date'].dt.strftime('%Y-%m')

    ## 5. Group by month and status
    monthly_by_status = df.groupby(['month', 'status']).agg({
        'transaction_id': 'count',
        'amount': 'sum'
    }).rename(columns={'transaction_id': 'count'})

    ## Calculate success rate by month (completed / total)
    print("\nTransaction success rates by month:")
    for month, month_data in df.groupby('month'):
        total = len(month_data)
        completed = len(month_data[month_data['status'] == 'completed'])
        success_rate = (completed / total) * 100
        print(f"  {month}: {success_rate:.1f}% ({completed}/{total})")

    ## Save filtered data to a new CSV file
    completed_high_value = df[(df['status'] == 'completed') & (df['amount'] > 300)]
    output_file = 'high_value_completed.csv'
    completed_high_value.to_csv(output_file, index=False)

    end_time = time.time()
    print(f"\nFiltering completed in {end_time - start_time:.2f} seconds")
    print(f"Saved {len(completed_high_value)} high-value completed transactions to {output_file}")

## Filter and transform the data
filter_and_transform('transactions.csv')

Exécutez ce script :

python3 pandas_filter.py

Sortie attendue :

Filtering and transforming data from transactions.csv...
Number of completed transactions: 12432
Number of high-value transactions (>$400): 6190
Number of transactions in Q1 2022: 12348

Transaction success rates by month:
  2022-01: 24.8% (1048/4225)
  2022-02: 25.0% (1010/4034)
  2022-03: 25.4% (1042/4089)
  2022-04: 24.2% (978/4052)
  2022-05: 24.4% (1047/4297)
  2022-06: 24.4% (1046/4280)
  2022-07: 24.7% (1071/4341)
  2022-08: 25.1% (1090/4343)
  2022-09: 26.1% (1091/4177)
  2022-10: 24.1% (1008/4182)
  2022-11: 24.8% (1009/4075)
  2022-12: 25.2% (992/3905)

Filtering completed in 0.38 seconds
Saved 6304 high-value completed transactions to high_value_completed.csv

Avantages de l'utilisation de Pandas

Comme vous pouvez le constater à partir de ces exemples, pandas offre plusieurs avantages pour le traitement CSV :

  1. Fonctionnalités riches : Méthodes intégrées pour le filtrage, le regroupement, l'agrégation et la transformation des données
  2. Performance : Code C optimisé en arrière-plan pour des opérations rapides sur de grands ensembles de données
  3. Analyse de données facile : Moyens simples de calculer des statistiques et d'obtenir des informations
  4. Capacités de visualisation : Intégration facile avec les bibliothèques de traçage (non illustrée dans les exemples)
  5. Traitement par blocs : Capacité à gérer des fichiers plus volumineux que la mémoire disponible

Pour la plupart des tâches d'analyse de données impliquant des fichiers CSV, pandas est l'approche recommandée, sauf si vous avez des contraintes de mémoire spécifiques qui nécessitent l'utilisation du module csv en pur Python.

Résumé

Dans ce tutoriel, vous avez appris plusieurs approches pour traiter efficacement les fichiers CSV en Python, des petits ensembles de données aux grands ensembles qui nécessitent une gestion minutieuse de la mémoire :

  1. Traitement CSV de base : Utilisation du module csv intégré de Python pour lire et écrire des fichiers CSV avec csv.reader et csv.writer.

  2. Traitement basé sur des dictionnaires : Utilisation de csv.DictReader pour travailler avec les données CSV de manière plus intuitive, en accédant aux champs par nom au lieu de l'index.

  3. Techniques de traitement efficaces :

    • Streaming (flux) : Traitement des fichiers ligne par ligne pour une utilisation minimale de la mémoire
    • Chunking (traitement par blocs) : Traitement des fichiers par lots pour une meilleure gestion de la mémoire
  4. Traitement avancé avec Pandas :

    • Lecture de fichiers CSV dans des DataFrames
    • Analyse et filtrage des données
    • Traitement de fichiers volumineux par blocs
    • Transformation et exportation des données

Ces techniques fournissent une boîte à outils complète pour la gestion des fichiers CSV de toute taille en Python. Pour la plupart des tâches d'analyse de données, pandas est la bibliothèque recommandée en raison de ses riches fonctionnalités et de ses performances. Cependant, pour les très grands fichiers ou les tâches de traitement simples, les approches de streaming et de chunking avec le module csv intégré peuvent être plus efficaces en termes de mémoire.

En appliquant la technique appropriée en fonction de vos besoins spécifiques, vous pouvez traiter efficacement les fichiers CSV de toute taille sans rencontrer de problèmes de mémoire.