Questo sito utilizza cookie per raccogliere dati statistici.
Privacy Policy
# 📘 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
```python
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:**
| | Nome | Età | Corso | Voto |
| - | ----- | --- | ----------- | ---- |
| 0 | Alice | 17 | Informatica | 88 |
| 1 | Bob | 18 | Informatica | 92 |
| 2 | Carlo | 17 | Scientifico | 75 |
| 3 | Diana | 18 | Scientifico | 85 |
| 4 | Elena | 17 | Informatica | 90 |
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.
```python
df.head()
```
Utile con dataset grandi (1000+ righe), perché evita di stampare tutto.
---
### 4.2. `df.info()` – Tipo di dati e struttura
```python
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
```python
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
```python
df_nome = df["Nome"]
```
Questo restituisce una **Serie**, cioè una colonna singola.
---
### 5.2. Selezionare più colonne
```python
df_nv = df[["Nome", "Voto"]]
```
Restituisce un DataFrame più piccolo.
---
### 5.3. Filtrare righe in base a una condizione
Esempio: studenti con voto ≥ 90
```python
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:
```python
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.
```python
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?
```python
df["Voto"] = df["Voto"] + 2
```
---
### 6.3. Eliminare colonne
utilizzo la funzione `drop` offerta dall'istanza di `DataFrame` specificando quali colonne eliminare (lista)
```python
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`)
```python
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.
```python
df.groupby("Corso")["Voto"].mean()
```
**Output:**
| Corso | Voto medio |
| ----------- | ---------- |
| Informatica | 90 |
| Scientifico | 80 |
---
#### Funzioni di aggregazione più comuni (e cosa significano)
Una volta creato il gruppo, puoi applicare molte funzioni utili:
| Funzione | Significato |
| ----------- | ------------------------------------------------------- |
| `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:
```python
df.groupby("Colonna")["ColonnaNumerica"].funzione()
```
Esempi veloci:
```python
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à)**.
```python
df.groupby(["Corso", "Età"])["Voto"].mean()
```
**Output:**
| Corso | Età | Voto medio |
| ----------- | --- | ---------- |
| Informatica | 17 | 89 |
| Informatica | 18 | 92 |
| Scientifico | 17 | 75 |
| Scientifico | 18 | 85 |
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:
```python
df.groupby("Corso")["Voto"].agg(["mean", "max", "min", "count"])
```
**Output:**
| Corso | mean | max | min | count |
| ----------- | ---- | --- | --- | ----- |
| Informatica | 90 | 92 | 88 | 3 |
| Scientifico | 80 | 85 | 75 | 2 |
---
##### Applicare funzioni diverse a colonne diverse
Puoi anche aggregare più colonne in modo indipendente:
```python
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
```python
df.isnull().sum()
```
Ti dice quante celle vuote ci sono in ogni colonna.
---
### 8.2. Sostituire i valori mancanti
```python
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
```python
df.dropna()
```
---
### 8.4. Trovare duplicati
```python
df.duplicated().sum()
```
---
### 8.5. Rimuovere duplicati
```python
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:
```python
df_encoded = pd.get_dummies(df, columns=["Corso"])
```
Trasforma:
| Nome | Corso |
| ---- | ----------- |
| Bob | Informatica |
in:
| Nome | Corso_Informatica | Corso_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):
| Index | Color | Size |
| ----- | ----- | ------ |
| 0 | Red | Small |
| 1 | Blue | Large |
| 2 | Green | Medium |
| 3 | Blue | Small |
| 4 | Red | Large |
**applico** `df_encoded = pd.get_dummies(df, columns=["Color","Size"])` **e ottengo:**
| Index | Color_Blue | Color_Green | Color_Red | Size_Large | Size_Medium | Size_Small |
| ----- | ---------- | ----------- | --------- | ---------- | ----------- | ---------- |
| 0 | False | False | True | False | False | True |
| 1 | True | False | False | True | False | False |
| 2 | False | True | False | False | True | False |
| 3 | True | False | False | False | False | True |
| 4 | False | False | True | True | False | False |
---
### 9.2. Normalizzare valori numerici
```python
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
```python
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
```python
df[df["Corso"] == "Informatica"]
```
> Filtriamo la tabella mantenendo solo le righe dove la colonna "Corso" vale "Informatica".
---
### 🔹 Chi ha il voto massimo?
```python
df["Voto"].max()
```
> Selezioniamo la colonna “Voto” e chiediamo il suo valore massimo.
---
### 🔹 Media voti per età
```python
df.groupby("Età")["Voto"].mean()
```
> Raggruppiamo per età → per ogni gruppo calcoliamo la media.
---
### 🔹 Aggiungere una colonna "Promosso"
```python
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
```python
df.sort_values(["Corso", "Voto"], ascending=[True, False])
```
> Prima ordina alfabeticamente per corso, poi decrescente per voto.