Tutorial su pandas
Impara pandas da zero: Series, DataFrame, filtri, groupby, valori mancanti, merge e visualizzazione dati con esempi Python chiari.
pandas è la libreria Python più utilizzata per lavorare con dati strutturati (tabulari). Fornisce due strutture dati fondamentali — Series e DataFrame — oltre a un ricco insieme di strumenti per caricare, pulire, trasformare, aggregare e visualizzare i dati.
Questo capitolo copre tutto ciò di cui hai bisogno per passare da zero alla produttività con pandas: installazione, strutture dati, lettura di file, selezione e filtraggio dei dati, gestione dei valori mancanti, raggruppamento, unione e grafici di base.
Installazione di pandas
Installa pandas con pip:
pip install pandasSe intendi seguire gli esempi di grafici più avanti in questo capitolo, installa anche Matplotlib:
pip install matplotlibDopo l'installazione, importa pandas usando l'alias convenzionale pd:
import pandas as pdLe due strutture dati fondamentali
Series
Una Series è un array monodimensionale con etichette. Ogni elemento ha un valore e un'etichetta di indice corrispondente (per impostazione predefinita, interi che partono da 0).
import pandas as pd
scores = pd.Series([88.5, 92.0, 79.5, 95.0])
print(scores)Output:
0 88.5
1 92.0
2 79.5
3 95.0
dtype: float64Puoi fornire etichette di indice personalizzate per rendere i dati auto-descrittivi:
scores = pd.Series(
[88.5, 92.0, 79.5, 95.0],
index=['Alice', 'Bob', 'Carol', 'Dave']
)
print(scores)
print(scores['Bob']) # 92.0Output:
Alice 88.5
Bob 92.0
Carol 79.5
Dave 95.0
dtype: float64
92.0Una Series con un indice significativo è simile a un dizionario Python, ma supporta operazioni vettorializzate ed è integrata nel resto dell'API di pandas.
DataFrame
Un DataFrame è una tabella bidimensionale con righe e colonne etichettate — pensalo come un foglio di calcolo o una tabella SQL caricata in Python. Ogni colonna è internamente una Series che condivide lo stesso indice di riga.
Creazione di un DataFrame da un dizionario di liste
Output:
name age score
0 Alice 25 88.5
1 Bob 30 92.0
2 Carol 28 79.5
3 Dave 35 95.0Le chiavi del dizionario diventano nomi di colonna; i valori del dizionario diventano le colonne. L'indice di riga assume per impostazione predefinita i valori 0, 1, 2, 3.
Attributi utili per ispezionare un DataFrame subito dopo la creazione:
| Attributo / Metodo | Cosa restituisce |
|---|---|
df.shape | Tupla di (rows, columns) |
df.dtypes | Tipo di dato di ciascuna colonna |
df.columns | Etichette delle colonne |
df.index | Etichette delle righe |
df.head(n) | Prime n righe (default 5) |
df.tail(n) | Ultime n righe (default 5) |
df.describe() | Statistiche riassuntive per le colonne numeriche |
df.info() | Nomi delle colonne, tipi e conteggi non nulli |
Lettura di dati da file
Nei progetti reali raramente si creano DataFrame a mano. pandas può leggere decine di formati di file.
Lettura di un file CSV
import pandas as pd
df = pd.read_csv('sales.csv')
print(df.head())
print(df.shape) # e.g. (1000, 5)
print(df.dtypes)pd.read_csv() deduce automaticamente i tipi delle colonne. Opzioni comuni:
sep=';'— cambia il delimitatore (il default è la virgola)index_col='id'— usa una colonna come indice di rigaparse_dates=['date']— analizza una colonna come datetimenrows=500— legge solo le prime 500 righe (utile per file di grandi dimensioni)
Lettura di un file Excel
df = pd.read_excel('report.xlsx', sheet_name='Sheet1')Richiede la dipendenza opzionale openpyxl: pip install openpyxl.
Scrittura dei dati su file
df.to_csv('output.csv', index=False) # CSV without the row index column
df.to_excel('output.xlsx', index=False) # ExcelSelezione dei dati
Selezione delle colonne
Seleziona una singola colonna per ottenere una Series:
ages = df['age']
print(type(ages)) # <class 'pandas.core.series.Series'>Seleziona più colonne per ottenere un DataFrame:
subset = df[['name', 'score']]
print(subset)Output:
name score
0 Alice 88.5
1 Bob 92.0
2 Carol 79.5
3 Dave 95.0Selezione di righe con loc e iloc
pandas fornisce due selettori di righe principali:
loc— seleziona per etichetta (valore dell'indice)iloc— seleziona per posizione intera (base 0)
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Carol', 'Dave'],
'age': [25, 30, 28, 35],
'score': [88.5, 92.0, 79.5, 95.0],
}
df = pd.DataFrame(data)
print(df.loc[1]) # row with index label 1
print()
print(df.iloc[0]) # first row by position
print()
print(df.loc[1:2]) # rows with labels 1 and 2 (inclusive)
print()
print(df.iloc[0:2]) # rows at positions 0 and 1 (end is exclusive)Output:
name Bob
age 30
score 92.0
Name: 1, dtype: object
name Alice
age 25
score 88.5
Name: 0, dtype: object
name age score
1 Bob 30 92.0
2 Carol 28 79.5
name age score
0 Alice 25 88.5
1 Bob 30 92.0Nota la differenza: loc[1:2] è basato sulle etichette e inclusivo su entrambi i lati; iloc[0:2] è basato sulla posizione ed esclusivo sul lato destro (come i normali slice di Python).
Puoi anche selezionare una cella specifica:
print(df.loc[1, 'score']) # 92.0 — by label
print(df.iloc[0, 2]) # 88.5 — by positionFiltraggio delle righe
Filtra le righe usando una condizione booleana all'interno delle parentesi quadre:
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Carol', 'Dave'],
'age': [25, 30, 28, 35],
'score': [88.5, 92.0, 79.5, 95.0],
}
df = pd.DataFrame(data)
# Rows where age is greater than 28
print(df[df['age'] > 28])Output:
name age score
1 Bob 30 92.0
3 Dave 35 95.0Combina più condizioni con & (e) o | (o). Racchiudi sempre ciascuna condizione tra parentesi:
# Age > 25 AND score >= 90
print(df[(df['age'] > 25) & (df['score'] >= 90)])Output:
name age score
1 Bob 30 92.0
3 Dave 35 95.0Usa isin() per filtrare in base a un elenco di valori:
print(df[df['name'].isin(['Alice', 'Carol'])])Aggiunta e modifica di colonne
Aggiungi una nuova colonna assegnandole un valore:
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Carol', 'Dave'],
'age': [25, 30, 28, 35],
'score': [88.5, 92.0, 79.5, 95.0],
}
df = pd.DataFrame(data)
# Add a column with a calculated value
df['grade'] = df['score'].apply(lambda x: 'A' if x >= 90 else 'B')
print(df)Output:
name age score grade
0 Alice 25 88.5 B
1 Bob 30 92.0 A
2 Carol 28 79.5 B
3 Dave 35 95.0 Aapply() esegue una funzione su ogni elemento di una colonna. Per operazioni aritmetiche semplici puoi usare direttamente operazioni vettorializzate — sono più veloci di apply():
df['score_scaled'] = df['score'] / 100 # no apply() neededRinomina le colonne con rename():
df = df.rename(columns={'score': 'exam_score', 'age': 'years_old'})Rimuovi una colonna con drop():
df = df.drop(columns=['grade'])Ordinamento dei dati
Ordina un DataFrame per una o più colonne usando sort_values():
import pandas as pd
data = {
'department': ['Eng', 'Eng', 'HR', 'HR', 'Eng'],
'name': ['Alice', 'Bob', 'Carol', 'Dave', 'Eve'],
'salary': [90000, 95000, 70000, 72000, 88000],
}
df = pd.DataFrame(data)
print(df.sort_values('salary', ascending=False))Output:
department name salary
1 Eng Bob 95000
0 Eng Alice 90000
4 Eng Eve 88000
3 HR Dave 72000
2 HR Carol 70000Ordina per più colonne — per esempio, dipartimento in ordine crescente, poi stipendio in ordine decrescente all'interno di ciascun dipartimento:
df_sorted = df.sort_values(['department', 'salary'], ascending=[True, False])
print(df_sorted)Gestione dei valori mancanti
I dataset del mondo reale contengono quasi sempre valori mancanti. pandas li rappresenta come NaN (Not a Number).
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Carol', 'Dave'],
'age': [25, None, 28, 35],
'score': [88.5, 92.0, None, 95.0],
}
df = pd.DataFrame(data)
# Count missing values per column
print(df.isnull().sum())Output:
name 0
age 1
score 1
dtype: int64Riempimento dei valori mancanti
Sostituisci NaN con un valore fisso o una statistica:
df_filled = df.fillna({
'age': df['age'].mean(), # fill with column mean
'score': df['score'].median() # fill with column median
})
print(df_filled)Output:
name age score
0 Alice 25.000000 88.5
1 Bob 29.333333 92.0
2 Carol 28.000000 92.0
3 Dave 35.000000 95.0Eliminazione delle righe con valori mancanti
df_dropped = df.dropna()
print(df_dropped)Output:
name age score
0 Alice 25.0 88.5
3 Dave 35.0 95.0Quando riempire e quando eliminare: eliminare le righe comporta perdita di dati e può introdurre distorsioni se i valori non mancano in modo casuale. Il riempimento (imputazione) è generalmente preferibile quando i dati mancanti sono sparsi. Per i flussi di lavoro di machine learning, vedi il capitolo Scale per la standardizzazione delle feature numeriche dopo l'imputazione.
Raggruppamento dei dati
groupby() suddivide il DataFrame in gruppi, applica una funzione a ciascun gruppo e combina i risultati. È l'equivalente pandas di GROUP BY in SQL.
import pandas as pd
data = {
'department': ['Eng', 'Eng', 'HR', 'HR', 'Eng'],
'name': ['Alice', 'Bob', 'Carol', 'Dave', 'Eve'],
'salary': [90000, 95000, 70000, 72000, 88000],
}
df = pd.DataFrame(data)
print(df.groupby('department')['salary'].mean())Output:
department
Eng 91000.0
HR 71000.0
Name: salary, dtype: float64Applica più funzioni di aggregazione contemporaneamente usando agg():
print(df.groupby('department')['salary'].agg(['mean', 'min', 'max', 'count']))Output:
mean min max count
department
Eng 91000.0 88000 95000 3
HR 71000.0 70000 72000 2Unione e concatenazione di DataFrame
Unione (come SQL JOIN)
Usa pd.merge() per combinare due DataFrame su una colonna chiave comune:
import pandas as pd
employees = pd.DataFrame({
'emp_id': [1, 2, 3],
'name': ['Alice', 'Bob', 'Carol'],
'dept_id': [10, 20, 10],
})
departments = pd.DataFrame({
'dept_id': [10, 20],
'dept_name': ['Engineering', 'HR'],
})
merged = pd.merge(employees, departments, on='dept_id')
print(merged)Output:
emp_id name dept_id dept_name
0 1 Alice 10 Engineering
1 2 Bob 20 HR
2 3 Carol 10 EngineeringIl comportamento predefinito è un inner join (solo le righe con una chiave corrispondente in entrambi i DataFrame). Controlla il tipo di join con how:
how='left'— tutte le righe del DataFrame sinistro, le righe corrispondenti di quello destrohow='right'— tutte le righe del DataFrame destro, le righe corrispondenti di quello sinistrohow='outer'— tutte le righe di entrambi i DataFrame;NaNdove non c'è corrispondenza
Concatenazione (impilamento di DataFrame)
Usa pd.concat() per impilare verticalmente DataFrame con le stesse colonne:
import pandas as pd
q1 = pd.DataFrame({'name': ['Alice', 'Bob'], 'sales': [120, 95]})
q2 = pd.DataFrame({'name': ['Carol', 'Dave'], 'sales': [110, 130]})
combined = pd.concat([q1, q2], ignore_index=True)
print(combined)Output:
name sales
0 Alice 120
1 Bob 95
2 Carol 110
3 Dave 130ignore_index=True reimposta l'indice di riga in modo che vada da 0 a 3 invece di ripetere 0 e 1 da ciascun DataFrame di origine.
Statistiche descrittive
pandas rende semplice calcolare statistiche riassuntive su un intero DataFrame o su singole colonne:
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Carol', 'Dave'],
'age': [25, 30, 28, 35],
'score': [88.5, 92.0, 79.5, 95.0],
}
df = pd.DataFrame(data)
print(df[['age', 'score']].describe())Output:
age score
count 4.000000 4.000000
mean 29.500000 88.750000
std 4.203173 6.714412
min 25.000000 79.500000
25% 27.250000 86.250000
50% 29.000000 90.250000
75% 31.250000 92.750000
max 35.000000 95.000000Le statistiche individuali sono disponibili anche come metodi diretti: df['score'].mean(), df['score'].std(), df['score'].median(), df['age'].max().
Visualizzazione di base dei dati
pandas si integra con Matplotlib in modo da poter creare grafici direttamente da un DataFrame con il metodo .plot(). Installa Matplotlib prima se non l'hai ancora fatto: pip install matplotlib.
Grafico a linee
import pandas as pd
import matplotlib.pyplot as plt
data = {
'month': ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
'revenue': [15000, 18000, 16500, 21000, 23000],
}
df = pd.DataFrame(data)
df.plot(kind='line', x='month', y='revenue', marker='o', title='Monthly Revenue')
plt.ylabel('Revenue ($)')
plt.tight_layout()
plt.show()Grafico a barre
df.plot(kind='bar', x='month', y='revenue', color='steelblue', title='Monthly Revenue')
plt.ylabel('Revenue ($)')
plt.xticks(rotation=0)
plt.tight_layout()
plt.show()Valori comuni per il parametro kind:
kind | Tipo di grafico |
|---|---|
'line' | Grafico a linee |
'bar' | Grafico a barre verticali |
'barh' | Grafico a barre orizzontali |
'hist' | Istogramma |
'box' | Box plot |
'scatter' | Grafico a dispersione (richiede x e y) |
'pie' | Grafico a torta |
Per grafici più avanzati, vedi i capitoli Matplotlib Introduction e Matplotlib Scatter Plot.
Errori comuni
SettingWithCopyWarning: quando filtri un DataFrame e poi cerchi di modificare il risultato, pandas potrebbe avvisarti che stai modificando una copia anziché l'originale. Usa .copy() per essere esplicito:
# Safe: work on an explicit copy
young = df[df['age'] < 30].copy()
young['group'] = 'junior'Indicizzazione concatenata: df['col'][0] = value potrebbe o non potrebbe modificare il DataFrame originale. Usa sempre df.loc[0, 'col'] = value per l'assegnazione.
Nomi di colonna con spazi: se una colonna si chiama "first name", devi usare la notazione con parentesi quadre — df['first name'] — non la notazione a punto (df.first name è un errore di sintassi).
Integer vs. float dopo fillna: riempire NaN in una colonna intera con un numero promuove la colonna a float64 perché NaN è un float. Usa pd.Int64Dtype() (intero nullable) se hai bisogno di mantenere la semantica degli interi con valori mancanti.
Capitoli correlati
- NumPy Tutorial — la libreria di array su cui è costruito pandas
- Matplotlib Introduction — crea grafici di qualità professionale dai tuoi dati
- Matplotlib Scatter Plot — visualizza le relazioni tra due variabili numeriche
- Data Distribution — comprendi come i valori sono distribuiti in un dataset
- Scale — normalizza e standardizza le feature numeriche prima della modellazione
- Categorical Data — codifica le colonne non numeriche per il machine learning
- Train/Test Split — suddividi un DataFrame pandas in set di training e test
- SciPy Tutorial — funzioni statistiche e scientifiche che complementano pandas