Lettura a blocchi di file di grandi dimensioni
Elabori i file che superano la RAM leggendoli a blocchi con chunksize in read_csv e aggregando progressivamente i risultati.
Lettura a blocchi di file di grandi dimensioni è una lezione Pandas & NumPy Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Pandas & NumPy Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Pandas & NumPy Academy include 4 lezioni in totale.
Quando i file superano la RAM
Un collo di bottiglia comune nelle pipeline di dati in produzione è un file CSV più grande della RAM disponibile. Se un file è di 20 GB e il computer dispone di 16 GB di RAM, pd.read_csv('file.csv') si interromperà con un MemoryError. La soluzione è la lettura a blocchi: caricare il file in parti di dimensione fissa, elaborare ogni parte e accumulare i risultati. In questo modo può analizzare file di dimensioni arbitrarie senza caricarli interamente in memoria.
import pandas as pd
import numpy as np
# Simulate a large CSV by writing one
np.random.seed(0)
sample = pd.DataFrame({
'date': pd.date_range('2023-01-01', periods=100000, freq='h'),
'region': np.random.choice(['North','South','East','West'], 100000),
'sales': np.random.randint(100, 1000, 100000)
})
sample.to_csv('/tmp/large_sales.csv', index=False)
print(f'File size: {pd.io.common.get_handle("/tmp/large_sales.csv", "r").handle.seek(0, 2)/1e6:.1f} MB... (simulated)')
print('Rows:', len(sample))Il parametro chunksize in read_csv
Passi chunksize=n a pd.read_csv() per ottenere un iteratore TextFileReader anziché un DataFrame. Ogni iterazione restituisce le n righe successive come DataFrame. In questo modo, in memoria sono presenti solo n righe alla volta. Un buon valore iniziale per chunksize è 100.000 righe: abbastanza piccolo da entrare nella RAM, ma abbastanza grande da mantenere gestibile l'overhead di I/O. Lo adatti in base alla RAM disponibile e al numero di colonne.
import pandas as pd
# Read file in chunks of 25,000 rows
chunk_iter = pd.read_csv('/tmp/large_sales.csv', chunksize=25000)
# Peek at the first chunk
first_chunk = next(chunk_iter)
print('First chunk shape:', first_chunk.shape)
print(first_chunk.head(3))Iterare sui blocchi
Utilizzi un ciclo for sull'iteratore dei blocchi per elaborare ciascun blocco. Per operazioni semplici, come contare le righe, sommare una colonna o filtrare, elabori ogni blocco indipendentemente e accumuli i risultati in un elenco o in un totale progressivo. Chiami sempre l'iteratore all'interno di un'istruzione with oppure lo ricrei per ogni esecuzione della pipeline: gli iteratori vengono consumati una sola volta e non possono essere riavviati.
import pandas as pd
total_rows = 0
total_sales = 0.0
chunk_count = 0
for chunk in pd.read_csv('/tmp/large_sales.csv', chunksize=25000):
total_rows += len(chunk)
total_sales += chunk['sales'].sum()
chunk_count += 1
print(f'Chunks processed: {chunk_count}')
print(f'Total rows: {total_rows:,}')
print(f'Total sales: {total_sales:,.0f}')
print(f'Avg sales per row: {total_sales/total_rows:.2f}')Filtrare le righe durante l'elaborazione a blocchi
Applichi i filtri sulle righe all'interno del ciclo, così da scartare i dati indesiderati prima che vengano accumulati. In questo modo l'utilizzo della memoria rimane contenuto, perché vengono conservate solo le righe che soddisfano i criteri. Ad esempio, per estrarre tutte le righe della regione 'North' da un file di 10 GB, filtri ogni blocco prima di aggiungerlo all'elenco dei risultati. Il pd.concat finale gestisce solo il sottoinsieme filtrato, molto più piccolo.
import pandas as pd
filtered_chunks = []
for chunk in pd.read_csv('/tmp/large_sales.csv', chunksize=25000):
# Keep only North region rows
north = chunk[chunk['region'] == 'North']
if len(north) > 0:
filtered_chunks.append(north)
north_df = pd.concat(filtered_chunks, ignore_index=True)
print(f'North region rows: {len(north_df):,}')
print(f'North total sales: {north_df["sales"].sum():,.0f}')Aggregazione incrementale con GroupBy
Le aggregazioni GroupBy su più blocchi sono più complesse delle semplici somme, perché i gruppi possono estendersi su più blocchi. Il procedimento è il seguente: calcolare somme e conteggi a livello di gruppo per ogni blocco, concatenare questi risultati parziali ed eseguire un groupby finale sui risultati parziali accumulati. Non chiami mai groupby().mean() per ogni blocco per poi calcolare la media delle medie: si otterrebbero risultati errati quando le dimensioni dei gruppi differiscono tra i blocchi.
import pandas as pd
partials = []
for chunk in pd.read_csv('/tmp/large_sales.csv', chunksize=25000):
# Compute sum and count per region in this chunk
partial = chunk.groupby('region')['sales'].agg(['sum', 'count'])
partials.append(partial)
# Combine all partial results
combined = pd.concat(partials).groupby(level=0).sum()
combined['mean'] = combined['sum'] / combined['count']
print('Regional aggregation (chunked):')
print(combined.round(2))Specificare tipi efficienti in termini di memoria al caricamento
Riduca l'utilizzo della memoria durante il caricamento a blocchi specificando in anticipo i dtypes delle colonne in read_csv. In questo modo impedisce a Pandas di allocare tipi troppo grandi per ogni blocco e di scartarli subito dopo. Passi a read_csv() un dizionario come dtype={'region': 'category', 'sales': 'int32'}. Insieme alla lettura a blocchi, questa tecnica può ridurre la memoria di picco a meno del 10% rispetto a un caricamento ingenuo dell'intero file.
import pandas as pd
specified_dtypes = {
'region': 'category',
'sales': 'int32'
}
total_sales = 0
for chunk in pd.read_csv(
'/tmp/large_sales.csv',
chunksize=25000,
dtype=specified_dtypes,
parse_dates=['date']
):
total_sales += chunk['sales'].sum()
# Only 25k rows * (category + int32 + datetime) in RAM at once
print(f'Total sales (memory-efficient): {total_sales:,.0f}')Scrivere i risultati in modo incrementale
Quando è necessario scrivere in un file anche l'output dell'elaborazione di ogni blocco, scriva ogni blocco elaborato man mano, invece di accumulare tutto in memoria. Utilizzi mode='a' (aggiunta) e header=False (dopo il primo blocco) con to_csv(). In questo modo l'occupazione di memoria sia dell'input sia dell'output rimane pari alla dimensione del blocco e la pipeline può elaborare file di dimensioni arbitrarie anche su un computer con memoria limitata.
import pandas as pd
import os
output_path = '/tmp/filtered_output.csv'
# Remove previous output if it exists
if os.path.exists(output_path):
os.remove(output_path)
first_chunk = True
for chunk in pd.read_csv('/tmp/large_sales.csv', chunksize=25000):
# Process: keep only high-value rows
processed = chunk[chunk['sales'] > 800].copy()
# Write: header only on first chunk, append thereafter
processed.to_csv(output_path,
mode='a',
header=first_chunk,
index=False)
first_chunk = False
result = pd.read_csv(output_path)
print(f'High-value rows written: {len(result):,}')
print(f'Average sales (>800): {result["sales"].mean():.1f}')Introduzione a Dask come alternativa immediata
Dask offre un'API simile a quella di Pandas che esegue le operazioni in modo differito e in parallelo sui blocchi, automaticamente. Anziché scrivere manualmente un ciclo di elaborazione a blocchi, scriva dask_df = dd.read_csv('file.csv') e poi utilizzi le stesse operazioni di Pandas: groupby, filtro e merge. Chiami .compute() alla fine per avviare l'esecuzione. Dask è la soluzione più pratica quando la pipeline comprende operazioni complesse in più passaggi, difficili da implementare manualmente con l'elaborazione a blocchi.
# pip install dask
# import dask.dataframe as dd
# Read the large CSV as a Dask DataFrame (lazy — no data loaded yet)
# ddf = dd.read_csv('/tmp/large_sales.csv')
# Operations are lazy — no computation happens until .compute()
# result = ddf.groupby('region')['sales'].mean().compute()
# print(result)
# Key Dask advantages:
# - Automatic chunking (no manual chunksize loops)
# - Parallel execution (multi-core)
# - Familiar Pandas API
# - Works with files larger than RAM
print('Dask extends Pandas to datasets larger than RAM with minimal API changes.')Scegliere la dimensione dei blocchi
La dimensione ideale dei blocchi bilancia due fattori contrapposti: una dimensione troppo piccola (ad esempio 1.000 righe) comporta un overhead elevato per ogni blocco (configurazione dell'I/O del file e creazione del DataFrame) e rende più lungo il ciclo. Una dimensione troppo grande (ad esempio 10 milioni di righe) vanifica lo scopo, caricando troppi dati in RAM contemporaneamente. Un punto di partenza pratico è scegliere blocchi che occupino in memoria 50–200 MB. Per un DataFrame con 10 colonne che occupano in media 8 byte ciascuna, 100.000 righe corrispondono a circa 8 MB per blocco: un valore predefinito sicuro, che lascia molta memoria disponibile.
import pandas as pd
import timeit
# Benchmark different chunk sizes
for chunksize in [10000, 50000, 100000]:
t = timeit.timeit(
lambda: sum(chunk['sales'].sum()
for chunk in pd.read_csv('/tmp/large_sales.csv', chunksize=chunksize)),
number=3
)
print(f'chunksize={chunksize:>7,}: {t/3:.3f}s per pass')Parquet e CSV a confronto per i dati di grandi dimensioni
Se può controllare il formato del file, preferisca Parquet al CSV per i dataset di grandi dimensioni. Parquet è un formato binario colonnare che carica solo le colonne richieste (column pruning), comprime molto meglio del CSV, conserva i dtype (senza nuova inferenza al caricamento) e viene letto da 5 a 20 volte più velocemente di un CSV equivalente. Converta una volta un CSV di grandi dimensioni in Parquet con pd.read_csv('file.csv', chunksize=500000) + to_parquet, quindi utilizzi pd.read_parquet(columns=['col1','col2']) per tutte le letture successive.
import pandas as pd
# Convert our CSV to Parquet (do this once)
df = pd.read_csv('/tmp/large_sales.csv', parse_dates=['date'])
df['region'] = df['region'].astype('category')
df['sales'] = df['sales'].astype('int32')
df.to_parquet('/tmp/large_sales.parquet', index=False)
# Now read only the columns needed — much faster than CSV
sales_by_region = pd.read_parquet(
'/tmp/large_sales.parquet',
columns=['region', 'sales']
)
print('Parquet read result:')
print(sales_by_region.groupby('region')['sales'].mean().round(1))
print('\ndtypes preserved:', sales_by_region.dtypes.to_dict())Schema completo di una pipeline a blocchi
Uno schema completo per elaborare file di grandi dimensioni: 1) specifichi i dtype al momento della lettura; 2) filtri le righe il prima possibile all'interno del ciclo; 3) calcoli aggregazioni parziali per ogni blocco (somma + conteggio, mai la media direttamente); 4) al termine del ciclo, combini i risultati parziali e calcoli le statistiche finali; 5) scriva l'output in modo incrementale se i risultati sono voluminosi. Questo schema gestisce file di qualsiasi dimensione su qualsiasi computer, regolando adeguatamente chunksize.
Controllo rapido
Verifichi la Sua comprensione della lettura a blocchi presentata in questa lezione.
Riepilogo della lezione
In questa lezione ha imparato che chunksize in read_csv restituisce un iteratore che produce un DataFrame per ogni blocco, consentendo di elaborare in modo incrementale file più grandi della RAM; le aggregazioni parziali (somma + conteggio) si accumulano correttamente tra i blocchi, mentre la media non può essere calcolata direttamente come media delle medie; infine, il formato Parquet è la migliore alternativa a lungo termine al CSV per i dataset di grandi dimensioni, grazie a compressione, velocità e conservazione dei dtype. Con questo si conclude il corso sui suggerimenti per le prestazioni di Pandas: ora è pronto per i corsi avanzati B2!
Impara Python con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 30
- Lezioni
- 120
Domande Frequenti
La lezione «Lettura a blocchi di file di grandi dimensioni» è gratuita?
Sì — il testo completo di «Lettura a blocchi di file di grandi dimensioni» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Pandas & NumPy Academy, passa a CoddyKit PRO. Il corso Pandas & NumPy Academy include 4 lezioni in totale.
Cosa imparerò in «Lettura a blocchi di file di grandi dimensioni»?
Elabori i file che superano la RAM leggendoli a blocchi con chunksize in read_csv e aggregando progressivamente i risultati. Eserciti Pandas & NumPy Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Pandas & NumPy Academy?
Non è richiesta alcuna esperienza precedente. Pandas & NumPy Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Lettura a blocchi di file di grandi dimensioni»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Pandas & NumPy Academy?
Sì. Ogni lezione Pandas & NumPy Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Profiling con timeit e memory_profiler
- Evitare iterrows e i cicli Python
- Tipi di dati efficienti per ridurre la memoria
- Lettura a blocchi di file di grandi dimensioni