📘 Pandas – Capire e manipolare i dati in modo semplice

Una guida spiegata, con esempi utili e un tono amichevole.


1. Perché esiste Pandas?

Quando iniziamo a lavorare seriamente con i dati (analisi, grafici, machine learning…) scopriamo una cosa:

In Python la lista da sola non basta.

Le liste sono ottime, i dizionari anche… ma quando i dati diventano tabellari (come un Excel), iniziamo a voler fare operazioni del tipo:

  • “Mostrami solo le righe che rispettano una certa condizione”
  • “Calcolami la media dei voti per ogni classe”
  • “Riordina i dati in base a una colonna”
  • “Gestisci i valori mancanti”
  • “Convertimi automaticamente le categorie in numeri”

Con le strutture base di Python tutto questo si può fare, certo… ma richiede molte righe, molta pazienza e parecchi cicli for.

Pandas fa tutto questo in una riga sola e lo fa in modo leggibile.


2. Cos’è un DataFrame e perché è così importante?

Il DataFrame è il cuore di Pandas. È una “super tabella”, pensata per essere:

  • facile da leggere (somiglia a un Excel)
  • facile da manipolare (usa metodi chiari)
  • veloce internamente (è ottimizzato in C)
  • flessibile (colonne di tipi diversi, filtri rapidi, raggruppamenti…)

Un DataFrame è come un foglio di calcolo: ha righe (con un indice) e colonne (ognuna con un nome).

Per rendere tutto molto concreto, iniziamo subito con una tabella di esempio.


3. Un esempio concreto: tabella studenti

import pandas as pd

data = {
    "Nome": ["Alice", "Bob", "Carlo", "Diana", "Elena"],
    "Età": [17, 18, 17, 18, 17],
    "Corso": ["Informatica", "Informatica", "Scientifico", "Scientifico", "Informatica"],
    "Voto": [88, 92, 75, 85, 90]
}

df = pd.DataFrame(data)
df

Output:

NomeEtàCorsoVoto
0Alice17Informatica88
1Bob18Informatica92
2Carlo17Scientifico75
3Diana18Scientifico85
4Elena17Informatica90

Vedi come appare subito leggibile?

  • ogni colonna ha un nome
  • ogni riga ha un indice
  • ogni cella è raggiungibile facilmente

4. Come leggere e capire un DataFrame

Prima di manipolare qualsiasi tabella, serve capirla.

Pandas offre alcune funzioni “diagnostiche”, molto utili.


4.1. df.head() – Guarda le prime righe

Serve per una sbirciatina iniziale, come quando apri un file Excel.

df.head()

Utile con dataset grandi (1000+ righe), perché evita di stampare tutto.


4.2. df.info() – Tipo di dati e struttura

df.info()

Questo comando risponde a domande del tipo:

  • quante righe ci sono?
  • quante colonne?
  • di che tipo sono i valori? (numeri, stringhe…)
  • ci sono valori mancanti?

È fondamentale prima di fare machine learning: devi sapere com’è formato il dataset.


4.3. df.describe() – Statistiche numeriche veloci

df.describe()

Ti fa vedere:

  • media
  • deviazione standard
  • minimo e massimo
  • quartili

È uno dei modi più rapidi per capire “come si distribuiscono” i numeri del dataset.


5. Selezionare e filtrare i dati

(ovvero: come estrarre solo ciò che ci interessa)

Un DataFrame può essere filtrato in vari modi. Vediamoli con esempi reali sulla tabella degli studenti.


5.1. Selezionare una colonna

df_nome = df["Nome"]

Questo restituisce una Serie, cioè una colonna singola.


5.2. Selezionare più colonne

df_nv = df[["Nome", "Voto"]]

Restituisce un DataFrame più piccolo.


5.3. Filtrare righe in base a una condizione

Esempio: studenti con voto ≥ 90

bravissimi = df[df["Voto"] >= 90]

Perché è comodo? Perché questo tipo di operazione con liste richiederebbe un for, un if e una lista nuova. Con Pandas basta una riga.


5.4. Filtri multipli

Studentesse/i di Informatica con voto ≥ 85:

bravi_informatica = df[(df["Voto"] >= 85) & (df["Corso"] == "Informatica")]

Il bello è che la sintassi sembra quasi “linguaggio naturale”.


6. Aggiungere, modificare e rimuovere colonne


6.1. Creare una nuova colonna

Esempio: normalizzare il voto su scala 0–1.

df["Voto_norm"] = df["Voto"] / 100

Perché è importante? Molti algoritmi di machine learning funzionano meglio con valori normalizzati (0,1).


6.2. Modificare una colonna esistente

Se voglio aggiungere 2 voti a tutti gli studenti posso semplicemente aggiungere 2 a tutta la colonna voto, faclie no?

df["Voto"] = df["Voto"] + 2

6.3. Eliminare colonne

utilizzo la funzione drop offerta dall’istanza di DataFrame specificando quali colonne eliminare (lista)

df = df.drop(columns=["Voto_norm"])

7. Ordinare e raggruppare


7.1. Ordinare i dati

utilizzo la funzione sort_values offerta dall’istanza di DataFrame specificando in base a quele colonna ordinare e se in modo crescente (ascending=True) o decrescente (ascending=False)

df.sort_values("Voto", ascending=False)

Per capire “chi ha preso il voto più alto”.


7.2. Raggruppamenti – groupby()

Il metodo groupby() è uno degli strumenti più potenti di Pandas perché permette di riorganizzare i dati in gruppi e applicare funzioni di aggregazione per ottenere informazioni sintetiche (proprio come in SQL 😉).

L’idea è semplice:

“Raggruppa le righe che hanno lo stesso valore in una (o più) colonne, e poi calcola qualcosa su ogni gruppo.”

È un po’ come dire: “fammi la media per ogni classe”, “quanti studenti ci sono per ogni età”, “voto massimo in ogni combinazione corso–età”, ecc.


Raggruppare per una singola colonna

Esempio: media dei voti per corso.

df.groupby("Corso")["Voto"].mean()

Output:

CorsoVoto medio
Informatica90
Scientifico80

Funzioni di aggregazione più comuni (e cosa significano)

Una volta creato il gruppo, puoi applicare molte funzioni utili:

FunzioneSignificato
mean()media dei valori
sum()somma del gruppo
max()valore massimo
min()valore minimo
count()numero di elementi (escludendo NaN)
size()numero di righe (inclusi NaN)
median()mediana
std()deviazione standard
var()varianza
nunique()quanti valori diversi compaiono (anche su stringhe)

La sintassi è sempre:

df.groupby("Colonna")["ColonnaNumerica"].funzione()

Esempi veloci:

df.groupby("Corso")["Voto"].max()
df.groupby("Età")["Voto"].count()
df.groupby("Corso")["Voto"].std()

Raggruppare più colonne insieme

groupby() permette anche di raggruppare per due o più colonne, creando gruppi multidimensionali.

Esempio: media dei voti per coppia (Corso, Età).

df.groupby(["Corso", "Età"])["Voto"].mean()

Output:

CorsoEtàVoto medio
Informatica1789
Informatica1892
Scientifico1775
Scientifico1885

Questo è molto utile quando vuoi analizzare differenze tra categorie incrociate: corso × età, classe × sezione, genere × fascia d’età, ecc.


Applicare più aggregazioni in una volta

Pandas permette di applicare più funzioni insieme usando agg().

Esempio:

df.groupby("Corso")["Voto"].agg(["mean", "max", "min", "count"])

Output:

Corsomeanmaxmincount
Informatica9092883
Scientifico8085752

Applicare funzioni diverse a colonne diverse

Puoi anche aggregare più colonne in modo indipendente:

df.groupby("Corso").agg({
    "Voto": ["mean", "max"],
    "Età": "count"
})
  • groupby() crea gruppi di righe che condividono lo stesso valore in una o più colonne.
  • su ogni gruppo applichi una funzione, che “riassume” numericamente il gruppo.
  • è perfetto per ottenere statistiche, confronti e analisi descrittive.
  • è uno degli strumenti più usati per preparare dati al machine learning o alla visualizzazione.

8. Pulizia dei dati – una fase cruciale nel ML

Molti dataset reali sono sporchi:

  • valori mancanti
  • duplicati
  • tipi sbagliati
  • categorie inconsistenti

La pulizia dei dati è uno dei passaggi più importanti nel machine learning.


8.1. Trovare valori mancanti

df.isnull().sum()

Ti dice quante celle vuote ci sono in ogni colonna.


8.2. Sostituire i valori mancanti

df.fillna(0)

Sostituisce i valori nulli con il valore 0 (ma potrebbe essere qualsiasi cosa… anche la media)


8.3. Eliminare righe incomplete

In alternativa possiamo semplicemente eliminare (droppare) le righe con almeno un valore nullo

df.dropna()

8.4. Trovare duplicati

df.duplicated().sum()

8.5. Rimuovere duplicati

df.drop_duplicates()

9. Preparare i dati per il Machine Learning

Quando prepariamo un dataset per un modello di ML, dobbiamo:

  1. trasformare categorie in numeri
  2. normalizzare i valori
  3. separare features e target
  4. dividere in train/test

9.1. Convertire colonne categoriche in numeri

Pandas lo fa automaticamente:

df_encoded = pd.get_dummies(df, columns=["Corso"])

Trasforma:

NomeCorso
BobInformatica

in:

NomeCorso_InformaticaCorso_Scientifico

Questo è ciò che serve alla maggior parte dei modelli ML.

Altro esempio

Ho questa tabella con due colonne categoriche (colore e dimensione dove ognuna ha tre valori possibili):

IndexColorSize
0RedSmall
1BlueLarge
2GreenMedium
3BlueSmall
4RedLarge

applico df_encoded = pd.get_dummies(df, columns=["Color","Size"]) e ottengo:

IndexColor_BlueColor_GreenColor_RedSize_LargeSize_MediumSize_Small
0FalseFalseTrueFalseFalseTrue
1TrueFalseFalseTrueFalseFalse
2FalseTrueFalseFalseTrueFalse
3TrueFalseFalseFalseFalseTrue
4FalseFalseTrueTrueFalseFalse

9.2. Normalizzare valori numerici

df["Voto_norm"] = (df["Voto"] - df["Voto"].min()) / (df["Voto"].max() - df["Voto"].min())

In questo esempio trasporto tutti i voti in un range che parte da 0 (sottraggo a tutti i voti il voto minimo) e poi divido ogni voto per l’ampiezza dell’intervallo (max-min). In questo otterrò valori compresi in [0,1]


9.3. Separare features e target

X = df[["Età", "Voto"]]
y = df["Corso"]

In questo modo otterrò in X un dataframe con le sole colonne “Età” e “Voto” e in Y un dataframe con la sola colonna “Corso”. Questo risulterà estremamente utile quando dovremo addestrare un modello di machine learning perché dovremo esplicitare al modello quali sono i valori di partenza (dati in ingresso (X)) e quali sono quelli da predire (output (Y))


10. Ricettario di esempi utili, spiegati


🔹 Studenti di Informatica

df[df["Corso"] == "Informatica"]

Filtriamo la tabella mantenendo solo le righe dove la colonna “Corso” vale “Informatica”.


🔹 Chi ha il voto massimo?

df["Voto"].max()

Selezioniamo la colonna “Voto” e chiediamo il suo valore massimo.


🔹 Media voti per età

df.groupby("Età")["Voto"].mean()

Raggruppiamo per età → per ogni gruppo calcoliamo la media.


🔹 Aggiungere una colonna “Promosso”

df["Promosso"] = df["Voto"] >= 85

Assegno alla nuova colonna “Promosso” l’esito della condizione voto >= 85. Ricordiamoci che questa condizione viene fatta per tutta la tabella contemporaneamente.

Creare colonne target binarie (due valori) è spesso molto utile per “dire” al mostro modello di ML che una specifica feature sappiamo essere utile.

Perchè è così utile?

Noi umani sappiamo che i voti 5, 6 o 7 sono differenti, lo capisce anche il computer. Il computer sa che 5!=6 e 5!=7 e 6!=7. Noi umani sappiamo anche che eseguire il salto da 5 a 6 è molto più pesante che eseguire il salto tra 6 e 7. In maniera assoluta (6-5 e 7-6) sono lo stesso salto (1) ma contestualizzato nel registro scolastico sappiamo che i voti >= 6 sono positivi (“verdi”) mentre quelli inferiori al 6 sono negativi (“rossi”). Di conseguenza, se vogliamo che anche i nostri modelli di ML siano al corrente di questa relazione presente nei dati ma “nascosta” o implicita dobbiamo renderla esplicita.


🔹 Ordinare per corso e poi voto

df.sort_values(["Corso", "Voto"], ascending=[True, False])

Prima ordina alfabeticamente per corso, poi decrescente per voto.