W3docs

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 pandas

Se intendi seguire gli esempi di grafici più avanti in questo capitolo, installa anche Matplotlib:

pip install matplotlib

Dopo l'installazione, importa pandas usando l'alias convenzionale pd:

import pandas as pd

Le 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: float64

Puoi 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.0

Output:

Alice    88.5
Bob      92.0
Carol    79.5
Dave     95.0
dtype: float64
92.0

Una 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

python— editable, runs on the server

Output:

    name  age  score
0  Alice   25   88.5
1    Bob   30   92.0
2  Carol   28   79.5
3   Dave   35   95.0

Le 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 / MetodoCosa restituisce
df.shapeTupla di (rows, columns)
df.dtypesTipo di dato di ciascuna colonna
df.columnsEtichette delle colonne
df.indexEtichette 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 riga
  • parse_dates=['date'] — analizza una colonna come datetime
  • nrows=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)  # Excel

Selezione 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.0

Selezione 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.0

Nota 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 position

Filtraggio 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.0

Combina 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.0

Usa 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     A

apply() 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() needed

Rinomina 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   70000

Ordina 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: int64

Riempimento 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.0

Eliminazione 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.0

Quando 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: float64

Applica 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      2

Unione 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  Engineering

Il 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 destro
  • how='right' — tutte le righe del DataFrame destro, le righe corrispondenti di quello sinistro
  • how='outer' — tutte le righe di entrambi i DataFrame; NaN dove 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    130

ignore_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.000000

Le 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:

kindTipo 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

Was this page helpful?