Corso
Una delle cose fastidiose che tutti cerchiamo di capire quando impariamo Pandas è la distinzione tra .loc e .iloc.
Mettiamo fine a questa confusione e chiariremo la differenza tra questi due metodi. Ti darò molti esempi e spero che la distinzione sarà molto più chiara alla fine di questo blog.
Cosa sono .loc e .iloc in Pandas?
Sia .loc che .iloc sono attributi essenziali dei DataFrame di Pandas e vengono usati per selezionare sottoinsiemi specifici di dati. Il loro scopo è accedere e permettere di manipolare una parte specifica del DataFrame invece dell’intero DataFrame.
|
Caratteristica |
.loc |
.iloc |
|
Sintassi |
df.loc[row_indexer, column_indexer] |
df.iloc[row_indexer, column_indexer] |
|
Metodo di indicizzazione |
Indicizzazione basata su etichette |
Indicizzazione basata su posizione |
|
Usato come riferimento |
Etichette (nomi) di righe e colonne |
Indici numerici di righe e colonne (a partire da 0) |
Come si vede dalla tabella, la sintassi sembra molto simile. La differenza sta in come usiamo gli argomenti row_indexer e column_indexer. Questo perché i due metodi offrono approcci diversi all’indicizzazione dei dati: mentre .loc indicizza in base ai nomi delle etichette, .iloc prende come argomenti la posizione numerica di righe e colonne.
Esaminiamo ciascuno dei due metodi nel dettaglio, iniziando da .loc.
Usare .loc: selezione per etichette
Per illustrare i concetti, consideriamo un ipotetico database clienti rappresentato da questo DataFrame chiamato df, con il Customer ID che rappresenta l’indice di riga:
|
Customer ID |
Name |
Country |
Region |
Age |
|
C123 |
John Doe |
United States |
North America |
67 |
|
C234 |
Petra Müller |
Germany |
Europe |
51 |
|
C345 |
Ali Khan |
Pakistan |
Asia |
19 |
|
C456 |
Maria Gonzalez |
Mexico |
North America |
26 |
|
C567 |
David Lee |
China |
Asia |
40 |
Ci sono quattro modi principali per selezionare righe con .loc. Includono:
- Selezionare una singola riga
- Selezionare più righe
- Selezionare un intervallo di righe
- Selezione condizionale delle righe
Selezionare una singola riga con .loc
Per selezionare una singola riga, usiamo l’etichetta della riga che vogliamo recuperare come row_indexer. Di conseguenza, la sintassi è: df.loc['row_label']. Usiamola per mostrare tutte le informazioni del nostro cliente Ali Khan:
df.loc['C345']
|
C345 |
|
|
Name |
Ali Khan |
|
Country |
Pakistan |
|
Region |
Asia |
|
Age |
19 |
Selezionare più righe con .loc
Se vogliamo selezionare più righe che non necessariamente si susseguono in ordine, dobbiamo passare un elenco delle loro etichette di riga come argomento row_indexer. Questo significa che dobbiamo usare non una ma due paia di parentesi quadre: una per la sintassi normale di .loc e una per l’elenco delle etichette.
La riga df.loc[['row_label_1', 'row_label_2']] restituirà le due righe del DataFrame df specificate nell’elenco. Diciamo che vogliamo conoscere non solo le informazioni su Ali Khan ma anche su David Lee:
df.loc[['C345', 'C567']]
|
Customer ID |
Name |
Country |
Region |
Age |
|
C345 |
Ali Khan |
Pakistan |
Asia |
19 |
|
C567 |
David Lee |
China |
Asia |
40 |
Selezionare un intervallo di righe con .loc
Possiamo selezionare un intervallo di righe passando la prima e l’ultima etichetta di riga con i due punti in mezzo: df.loc['row_label_start':'row_label_end']. Potremmo mostrare le prime quattro righe del nostro DataFrame così:
df.loc['C123' : 'C456']
|
Customer ID |
Name |
Country |
Region |
Signup Date |
|
C123 |
John Doe |
United States |
North America |
67 |
|
C234 |
Petra Müller |
Germany |
Europe |
51 |
|
C345 |
Ali Khan |
Pakistan |
Asia |
19 |
|
C456 |
Maria Gonzalez |
Mexico |
North America |
26 |
Ci sono due cose da tenere a mente qui:
- L’output include la riga specificata in
row_label_end. Questo è diverso in.iloc, che vedremo più avanti. - Usiamo solo un paio di parentesi quadre, anche se vogliamo recuperare più righe. Non usiamo un elenco per specificare le varie righe, quindi usare due parentesi quadre restituirebbe un
SyntaxError.
Selezione condizionale delle righe con .loc
Possiamo anche restituire righe in base a un’espressione condizionale. Possiamo filtrare tutte le righe in base al fatto che soddisfino o meno una certa condizione e mostrare solo quelle che la soddisfano.
La sintassi corrispondente è df.loc[conditional_expression], con conditional_expression che è un’affermazione sui valori ammessi in una specifica colonna.
Per colonne con dati non numerici (come Name o Country), l’affermazione può usare solo l’operatore di uguale o diverso, poiché non esiste un ordine tra i valori. Potremmo, per esempio, restituire tutte le righe dei clienti che non provengono dall’Asia:
df.loc[df['Region'] != 'Asia']
|
Customer ID |
Name |
Country |
Region |
Age |
|
C123 |
John Doe |
United States |
North America |
67 |
|
C234 |
Petra Müller |
Germany |
Europe |
51 |
|
C456 |
Maria Gonzalez |
Mexico |
North America |
26 |
Selezionare una singola colonna con .loc
Per selezionare colonne, dobbiamo specificare l’argomento column_indexer, che viene dopo l’argomento row_indexer. Se vogliamo specificare solo il column_indexer, dobbiamo in qualche modo indicare che vogliamo restituire tutte le righe e filtrare solo sulle colonne. Vediamo come si fa!
Selezionare una singola colonna si può fare specificando il column_indexer con l’etichetta della rispettiva colonna. Per recuperare tutte le righe, dobbiamo specificare il row_indexer con un semplice due punti. Arriviamo a una sintassi di questo tipo: df.loc[:, 'column_name'].
Mostriamo il Name di ogni cliente:
df.loc[:, 'Name']
|
Customer ID |
Name |
|
C123 |
John Doe |
|
C234 |
Petra Müller |
|
C345 |
Ali Khan |
|
C456 |
Maria Gonzalez |
|
C567 |
David Lee |
Selezionare più colonne con .loc
Analogamente alla selezione di più righe, dobbiamo passare un elenco di etichette di colonna se vogliamo restituire più colonne di un DataFrame che non necessariamente si susseguono in ordine: df.loc[:, [col_label_1, 'col_label_2']].
Supponendo di voler aggiungere l’Age di tutti i clienti al nostro ultimo output, funzionerebbe così:
df.loc[:, ['Name', 'Age']]
|
Customer ID |
Name |
Age |
|
C123 |
John Doe |
67 |
|
C234 |
Petra Müller |
51 |
|
C345 |
Ali Khan |
19 |
|
C456 |
Maria Gonzalez |
26 |
|
C567 |
David Lee |
40 |
Selezionare un intervallo di colonne con .loc
Usare i due punti tra le etichette di due colonne selezionerà tutte le colonne nell’intervallo ordinato tra le due specificate. È inclusivo della colonna finale, il che significa che la colonna denominata col_end verrà selezionata anch’essa nella sintassi standard, che è la seguente: df.loc[:, 'col_start':'col_end'].
Se fossimo interessati al Name, al Country e alla Region dei nostri clienti, la nostra riga di codice potrebbe essere:
df.loc[:, 'Name':'Region']
|
Customer ID |
Name |
Country |
Region |
|
C123 |
John Doe |
United States |
North America |
|
C234 |
Petra Müller |
Germany |
Europe |
|
C345 |
Ali Khan |
Pakistan |
Asia |
|
C456 |
Maria Gonzalez |
Mexico |
North America |
|
C567 |
David Lee |
China |
Asia |
Selezione combinata di righe e colonne con .loc
È anche possibile specificare sia il row_indexer che il column_indexer. Questo può essere usato per recuperare un singolo dato, cioè una cella del DataFrame. Per farlo, specifichiamo una riga e una colonna usando la sintassi df.loc['row_label', 'column_name'] .
Il caso più utile è restituire un sotto-DataFrame che si concentri esattamente sull’insieme di righe e colonne che ci interessano. È possibile specificare entrambi gli indicizzatori come elenchi usando le parentesi quadre, oppure come intervalli usando i due punti, e persino combinarli con un’espressione condizionale per la selezione delle righe.
Ecco un esempio che restituisce il Name, il Country e la Region di ogni cliente con un’Age superiore a 30:
df.loc[df['Age'] > 30, 'Name':'Region']
|
Customer ID |
Name |
Country |
Region |
|
C123 |
John Doe |
United States |
North America |
|
C234 |
Petra Müller |
Germany |
Europe |
|
C567 |
David Lee |
China |
Asia |
Usare .iloc: selezione per posizione intera
.iloc seleziona per posizione invece che per etichetta. Questa è la sintassi standard per usare .iloc: df.iloc[row_indexer, column_indexer]. Ci sono due aspetti particolari a cui prestare attenzione:
- Conteggio a partire da 0: la prima riga e la prima colonna hanno indice 0, la seconda indice 1, ecc.
- Esclusione del valore finale dell’intervallo: quando si usa un intervallo, la riga o la colonna specificata dopo i due punti non è inclusa nella selezione.
Selezionare una singola riga con .iloc
Una singola riga può essere selezionata usando l’intero che rappresenta il numero di indice di riga come row_indexer. Non servono virgolette perché stiamo inserendo un numero intero e non una stringa etichetta come abbiamo fatto con .loc. Per restituire la prima riga di un DataFrame chiamato df, inserisci df.iloc[0].
Nel nostro DataFrame di esempio, proprio questa riga di codice restituisce le informazioni di John Doe:
df.iloc[0]
|
C123 |
|
|
Name |
John Doe |
|
Country |
United States |
|
Region |
North America |
|
Age |
67 |
Selezionare più righe con .iloc
Selezionare più righe funziona in .iloc come in .loc: inseriamo gli interi degli indici di riga in un elenco tra parentesi quadre. La sintassi è: df.iloc[[0, 3, 4]].
Il relativo output nella nostra tabella clienti è mostrato sotto:
df.iloc[[0, 3, 4]]
|
Customer ID |
Name |
Country |
Region |
Age |
|
C123 |
John Doe |
United States |
North America |
67 |
|
C456 |
Maria Gonzalez |
Mexico |
North America |
26 |
|
C567 |
David Lee |
China |
Asia |
40 |
Selezionare un intervallo di righe con .iloc
Per selezionare un intervallo di righe, usiamo i due punti tra due interi di indice di riga specificati. Ora dobbiamo prestare attenzione all’esclusività menzionata in precedenza.
Possiamo prendere la riga df.iloc[1:4] come esempio per illustrare questo concetto. Il numero di indice 1 significa la seconda riga, quindi il nostro intervallo inizia lì. L’intero 4 rappresenta la quinta riga – ma poiché .iloc non è inclusivo nella selezione di intervallo, il nostro output includerà tutte le righe fino a quella immediatamente precedente. Quindi restituirà la seconda, la terza e la quarta riga.
Dimostriamo che la riga funziona come dovrebbe:
df.iloc[1:4]
|
Customer ID |
Name |
Country |
Region |
Age |
|
C234 |
Petra Müller |
Germany |
Europe |
51 |
|
C345 |
Ali Khan |
Pakistan |
Asia |
19 |
|
C456 |
Maria Gonzalez |
Mexico |
North America |
26 |
Selezionare una singola colonna con .iloc
La logica della selezione delle colonne usando .iloc segue quanto abbiamo imparato finora. Vediamo come funziona per singole colonne, più colonne e intervalli di colonne.
Proprio come con .loc, è importante specificare il row_indexer prima di poter passare al column_indexer. Per recuperare i valori della terza colonna di df per ogni riga, inseriamo df.iloc[:, 2] .
Poiché Region è la terza colonna nel nostro DataFrame, verrà recuperata come conseguenza di quella riga di codice:
df.iloc[:, 2]
|
Customer ID |
Region |
|
C123 |
North America |
|
C234 |
Europe |
|
C345 |
Asia |
|
C456 |
North America |
|
C567 |
Asia |
Selezionare più colonne con .iloc
Per selezionare più colonne che non sono necessariamente contigue, possiamo di nuovo inserire un elenco contenente interi come column_indexer. La riga df.iloc[:, [0, 3]] restituisce sia la prima che la quarta colonna.
Nel nostro caso, le informazioni visualizzate sono il Name e l’Age di ciascun cliente:
df.iloc[:, [0, 3]]
|
Customer ID |
Name |
Age |
|
C123 |
John Doe |
67 |
|
C234 |
Petra Müller |
51 |
|
C345 |
Ali Khan |
19 |
|
C456 |
Maria Gonzalez |
26 |
|
C567 |
David Lee |
40 |
Selezionare un intervallo di colonne con .iloc
Per la selezione di intervalli usando .iloc, la logica del column_indexer segue quella del row_indexer. La colonna rappresentata dall’intero dopo i due punti non è inclusa nell’output. Per recuperare la seconda e la terza colonna, la riga di codice dovrebbe essere: df.iloc[:, 1:3].
La riga qui sotto restituisce tutte le informazioni geografiche che abbiamo sui nostri clienti:
df.iloc[:, 1:3]
|
Customer ID |
Country |
Region |
|
C123 |
United States |
North America |
|
C234 |
Germany |
Europe |
|
C345 |
Pakistan |
Asia |
|
C456 |
Mexico |
North America |
|
C567 |
China |
Asia |
Selezione combinata di righe e colonne con .iloc
Possiamo mettere insieme ciò che abbiamo imparato su .iloc per combinare la selezione di righe e colonne. Anche qui è possibile restituire una singola cella o un sotto-DataFrame. Per restituire la singola cella all’intersezione tra riga 3 e colonna 4, inseriamo df.iloc[2, 3].
Così come con .loc, possiamo specificare entrambi gli indicizzatori come elenchi usando le parentesi quadre, oppure come intervalli usando i due punti. Se vogliamo selezionare righe usando espressioni condizionali, tecnicamente è possibile anche con .iloc, ma non è consigliato. Usare i nomi delle etichette e .loc di solito è molto più intuitivo e meno incline a errori.
Questo ultimo esempio mostra Country, Region e Age per la prima, seconda e quinta riga del nostro DataFrame:
df.iloc[[0,1,4], 1:4]
|
Customer ID |
Country |
Region |
Age |
|
C123 |
United States |
North America |
67 |
|
C234 |
Germany |
Europe |
51 |
|
C567 |
China |
Asia |
40 |
.iloc vs .loc: quando usare l’uno o l’altro
In generale, c’è una semplice regola pratica in cui la scelta del metodo dipende dalla tua conoscenza del DataFrame:
- Usa
.locquando conosci le etichette (nomi) delle righe/colonne. - Usa
.ilocquando conosci le posizioni intere delle righe/colonne.
Alcuni scenari favoriscono per loro natura .loc o .iloc. Per esempio, iterare sulle righe o sulle colonne è più semplice e intuitivo usando interi piuttosto che etichette. Come abbiamo già detto, filtrare le righe in base a condizioni sui valori delle colonne è meno soggetto a errori usando i nomi delle colonne.
|
Scenari che favoriscono .loc |
Scenari che favoriscono .iloc |
|
Il tuo DataFrame ha nomi significativi per indici/colonne. |
Stai iterando su righe/colonne in base alla loro posizione. |
|
Devi filtrare in base a condizioni sui valori delle colonne. |
I nomi di indici/colonne non sono rilevanti per il tuo compito. |
KeyError, NameError e IndexError con .loc e .iloc
Vediamo i possibili problemi. Un’insidia comune quando si usa .loc è imbattersi in un KeyError. Questo errore si verifica quando proviamo ad accedere a un’etichetta di riga o colonna che non esiste nel nostro DataFrame. Per evitarlo, dobbiamo sempre assicurarci che le etichette che stiamo usando siano accurate, che corrispondano alle etichette esistenti nel tuo DataFrame e ricontrollare eventuali refusi.
Inoltre, è importante usare sempre le virgolette per le etichette specificate con .loc. Dimenticarle restituirà un NameError.
Un IndexError può verificarsi quando si usa .iloc se specifichiamo una posizione intera che è al di fuori dell’intervallo valido degli indici del nostro DataFrame. Ciò accade quando l’indice a cui stai tentando di accedere non esiste, perché è oltre il numero di righe o colonne del tuo DataFrame o perché è un valore negativo. Per prevenire questo errore, controlla le dimensioni del tuo DataFrame e usa valori di indice appropriati all’interno dell’intervallo valido.
Conclusione
Spero che questo blog ti sia stato utile e che la distinzione tra .loc e .iloc ora sia chiara. Per approfondire, ecco alcuni buoni passi successivi:
Tom è un data scientist e formatore tecnico. Scrive e gestisce i tutorial e i post del blog di DataCamp su data science. In precedenza, Tom ha lavorato nella data science presso Deutsche Telekom.


