panda loc vs. iloc vs. ix vs. at vs. iat?


171

Di recente ho iniziato a diramarmi dal mio posto sicuro (R) in Python e sono un po 'confuso dalla localizzazione / selezione delle celle in Pandas. Ho letto la documentazione ma faccio fatica a comprendere le implicazioni pratiche delle varie opzioni di localizzazione / selezione.

  • C'è un motivo per cui dovrei mai usare .loco .ilocl'opzione più generica .ix?
  • Capisco che .loc, iloce at, iatpuò fornire una correttezza garantita che .ixnon può offrire, ma ho anche letto dove .ixtende ad essere la soluzione più veloce su tutta la linea.
  • Spiega il ragionamento delle migliori pratiche del mondo reale dietro l'utilizzo di qualcosa di diverso da .ix?


3
locè l'indicizzazione basata su etichetta, quindi in sostanza la ricerca di un valore in una riga, ilocè l'indicizzazione basata su riga di numeri interi, ixè un metodo generale che prima esegue l'etichetta, se fallisce, allora si basa sull'intero. atè obsoleto ed è consigliabile non utilizzarlo più. L'altra cosa da considerare è quello che stai cercando di fare poiché alcuni di questi metodi consentono di tagliare e assegnare le colonne, ad essere onesti, i documenti sono abbastanza chiari: pandas.pydata.org/pandas-docs/stable/indexing.html
EdChum

1
@EdChum - cosa ti dice che atè deprecato? Non lo vedo nei documenti at (o iat ).
Russ,

1
Questo è un errore che non è deprecato, penso che si parlasse di deprecarlo, ma questa idea è stata abbandonata perché penso che sia più veloce
EdChum

4
Spiegazione dettagliata tra loc, ixe ilocqui: stackoverflow.com/questions/31593201/…
Alex Riley

Risposte:


142

loc: funziona solo su indice
iloc: lavora su posizione
ix: è possibile ottenere dati da dataframe senza che si trovino nell'indice
in: ottenere valori scalari. È una posizione molto veloce
: ottieni valori scalari. È un iloc molto veloce

http://pyciencia.blogspot.com/2015/05/obtener-y-filtrar-datos-de-un-dataframe.html

Nota: a partire da pandas 0.20.0, l' .ixindicizzatore è deprecato a favore di più rigorosi .iloce .locindicizzatori.


9
Se ate iatsono versioni molto veloci di loce iloc, allora perché usare loce ilocaffatto?
Ray,

57
ate iatun significava accedere uno scalare, cioè, un singolo elemento nel dataframe, mentre loce ilocsono menti accedere a più elementi contemporaneamente, potenzialmente per eseguire operazioni vectorized.
nca

@ncasas - se leggo la documentazione a destra .at può accedere solo tramite indice mentre .loc può accedere anche tramite il nome della colonna. C'è un modo per usare il .at più veloce ma usare il nome della colonna anziché un indice? Come sostituire x = df.loc [df.Id == source_Id, 'someValue']. ​​Valori [0] con x = df.at [df.Id == source_Id, 'someValue']. La versione con .at genera "ValueError: all'indicizzazione basata su un indice intero può avere solo indicizzatori interi"
Vega

94

Aggiornato per pandas 0.20dato che ixè deprecato. Questo dimostra non solo come utilizzare loc, iloc, at, iat, set_value, ma come fare, misto indicizzazione basato posizionale / etichetta.


loc- basato su etichetta
Consente di passare array 1-D come indicizzatori. Le matrici possono essere sezioni (sottoinsiemi) dell'indice o della colonna oppure possono essere matrici booleane di lunghezza uguale all'indice o alle colonne.

Nota speciale: quando viene passato un indicizzatore scalare, è locpossibile assegnare un nuovo indice o valore di colonna che non esisteva prima.

# label based, but we can use position values
# to get the labels from the index object
df.loc[df.index[2], 'ColName'] = 3

df.loc[df.index[1:3], 'ColName'] = 3

iloc- basato sulla posizione
Simile a loctranne con le posizioni piuttosto che i valori dell'indice. Tuttavia, non è possibile assegnare nuove colonne o indici.

# position based, but we can get the position
# from the columns object via the `get_loc` method
df.iloc[2, df.columns.get_loc('ColName')] = 3

df.iloc[2, 4] = 3

df.iloc[:3, 2:4] = 3

at- basato sull'etichetta
Funziona in modo molto simile a quello locdegli indicizzatori scalari. Impossibile operare sugli indicizzatori di array. Può! assegnare nuovi indici e colonne.

Vantaggio sopra locè che questo è più veloce.
Lo svantaggio è che non è possibile utilizzare le matrici per gli indicizzatori.

# label based, but we can use position values
# to get the labels from the index object
df.at[df.index[2], 'ColName'] = 3

df.at['C', 'ColName'] = 3

iat- funziona in base alla posizione in
modo simile a iloc. Impossibile funzionare negli indicizzatori di array. Non può! assegnare nuovi indici e colonne.

Vantaggio sopra ilocè che questo è più veloce.
Lo svantaggio è che non è possibile utilizzare le matrici per gli indicizzatori.

# position based, but we can get the position
# from the columns object via the `get_loc` method
IBM.iat[2, IBM.columns.get_loc('PNL')] = 3

set_value- basato sull'etichetta
Funziona in modo molto simile a quello locdegli indicizzatori scalari. Impossibile operare sugli indicizzatori di array. Può! assegnare nuovi indici e colonne

Vantaggio Super veloce, perché ci sono pochissime spese generali!
Svantaggio Le spese generali sono molto limitate perché pandasnon si effettuano numerosi controlli di sicurezza. Utilizzare a proprio rischio . Inoltre, questo non è destinato all'uso pubblico.

# label based, but we can use position values
# to get the labels from the index object
df.set_value(df.index[2], 'ColName', 3)

set_valuewithtakable=True - position based
Funziona in modo simile ailoc. Impossibile funzionare negli indicizzatori di array. Non può! assegnare nuovi indici e colonne.

Vantaggio Super veloce, perché ci sono pochissime spese generali!
Svantaggio Le spese generali sono molto limitate perché pandasnon si effettuano numerosi controlli di sicurezza. Utilizzare a proprio rischio . Inoltre, questo non è destinato all'uso pubblico.

# position based, but we can get the position
# from the columns object via the `get_loc` method
df.set_value(2, df.columns.get_loc('ColName'), 3, takable=True)

Quindi, c'è un modo semplice per leggere / impostare più colonne per posizione? Inoltre, ad esempio, volevo aggiungere una matrice di valori ciascuno in nuove colonne, è facile farlo?
Parole del

@wordsmith ci sono modi semplici per aggiungere nuove colonne alla fine del frame di dati. O anche l'inizio. Se le posizioni sono coinvolte, allora no, non c'è un modo semplice.
piRSquared

Questa risposta era proprio quello di cui avevo bisogno! I panda sono certamente potenti, ma ciò comporta il costo di rendere tutto estremamente complicato da capire e mettere insieme.
slhck,

1
Si noti che set_valueè stato deprecato a favore .ate .iatdalla versione 0.21
ned

59

Esistono due modi principali in cui i panda effettuano le selezioni da un DataFrame.

  • Per etichetta
  • Per posizione intera

La documentazione utilizza il termine posizione per fare riferimento alla posizione dei numeri interi . Non mi piace questa terminologia poiché ritengo che sia confusa. La posizione dei numeri interi è più descrittiva ed è esattamente ciò che .ilocrappresenta. La parola chiave qui è INTEGER : è necessario utilizzare numeri interi quando si seleziona in base alla posizione dei numeri interi.

Prima di mostrare il riepilogo assicuriamoci tutti che ...

.ix è obsoleto e ambiguo e non dovrebbe mai essere usato

Esistono tre indicizzatori principali per i panda. Abbiamo l'operatore di indicizzazione stesso (le parentesi []) .loc, e .iloc. Riassumiamoli:

  • []- Seleziona principalmente sottoinsiemi di colonne, ma può anche selezionare righe. Impossibile selezionare contemporaneamente righe e colonne.
  • .loc - seleziona sottoinsiemi di righe e colonne solo per etichetta
  • .iloc - seleziona sottoinsiemi di righe e colonne solo per posizione intera

Non uso quasi mai .ato .iatpoiché non aggiungono funzionalità aggiuntive e con solo un piccolo aumento delle prestazioni. Scoraggerei il loro uso a meno che tu non abbia un'applicazione molto sensibile al tempo. Indipendentemente da ciò, abbiamo il loro riassunto:

  • .at seleziona un singolo valore scalare nel DataFrame solo dall'etichetta
  • .iat seleziona un singolo valore scalare nel DataFrame solo per posizione intera

Oltre alla selezione per etichetta e posizione intera, esiste anche una selezione booleana nota anche come indicizzazione booleana .


Esempi che spiegano .loc, .ilocselezione booleana .ate .iatsono mostrati di seguito

In primo luogo ci concentreremo sulle differenze tra .loce .iloc. Prima di parlare delle differenze, è importante capire che DataFrames ha etichette che aiutano a identificare ogni colonna e ogni riga. Diamo un'occhiata a un DataFrame di esempio:

df = pd.DataFrame({'age':[30, 2, 12, 4, 32, 33, 69],
                   'color':['blue', 'green', 'red', 'white', 'gray', 'black', 'red'],
                   'food':['Steak', 'Lamb', 'Mango', 'Apple', 'Cheese', 'Melon', 'Beans'],
                   'height':[165, 70, 120, 80, 180, 172, 150],
                   'score':[4.6, 8.3, 9.0, 3.3, 1.8, 9.5, 2.2],
                   'state':['NY', 'TX', 'FL', 'AL', 'AK', 'TX', 'TX']
                   },
                  index=['Jane', 'Nick', 'Aaron', 'Penelope', 'Dean', 'Christina', 'Cornelia'])

inserisci qui la descrizione dell'immagine

Tutte le parole in grassetto sono le etichette. Le etichette, age, color, food, height, scoree statesono utilizzati per le colonne . Gli altri marchi, Jane, Nick, Aaron, Penelope, Dean, Christina, Corneliasono usati come etichette per le righe. Collettivamente, queste etichette di riga sono note come indice .


I modi principali per selezionare determinate righe in un DataFrame sono con gli indicizzatori .loce .iloc. Ognuno di questi indicizzatori può anche essere utilizzato per selezionare contemporaneamente le colonne, ma per ora è più semplice concentrarsi solo sulle righe. Inoltre, ciascuno degli indicizzatori utilizza una serie di parentesi che seguono immediatamente il loro nome per effettuare le selezioni.

.loc seleziona i dati solo dalle etichette

Parleremo prima .locdell'indicizzatore che seleziona i dati solo dalle etichette dell'indice o della colonna. Nel nostro DataFrame di esempio, abbiamo fornito nomi significativi come valori per l'indice. Molti DataFrame non avranno nomi significativi e, invece, saranno predefiniti solo ai numeri interi da 0 a n-1, dove n è la lunghezza (numero di righe) del DataFrame.

Ci sono molti input diversi che puoi usare per .loctre di essi

  • Una stringa
  • Un elenco di stringhe
  • Taglia la notazione usando le stringhe come valori di inizio e fine

Selezione di una singola riga con .loc con una stringa

Per selezionare una singola riga di dati, posizionare l'etichetta dell'indice all'interno delle parentesi seguenti .loc.

df.loc['Penelope']

Ciò restituisce la riga di dati come una serie

age           4
color     white
food      Apple
height       80
score       3.3
state        AL
Name: Penelope, dtype: object

Selezione di più righe con .loc con un elenco di stringhe

df.loc[['Cornelia', 'Jane', 'Dean']]

Ciò restituisce un DataFrame con le righe nell'ordine specificato nell'elenco:

inserisci qui la descrizione dell'immagine

Selezione di più righe con .loc con notazione slice

La notazione delle sezioni è definita da un valore di avvio, arresto e step. Quando si taglia per etichetta, i panda includono il valore di arresto nel ritorno. Le seguenti sezioni da Aaron a Dean, incluso. La dimensione del passo non è definita in modo esplicito, ma per impostazione predefinita è 1.

df.loc['Aaron':'Dean']

inserisci qui la descrizione dell'immagine

Le sezioni complesse possono essere prese allo stesso modo delle liste Python.

.iloc seleziona i dati solo per posizione intera

Passiamo ora a .iloc. Ogni riga e colonna di dati in un DataFrame ha una posizione intera che lo definisce. Ciò si aggiunge all'etichetta visualizzata visivamente nell'output. La posizione intera è semplicemente il numero di righe / colonne dall'alto / a sinistra a partire da 0.

Ci sono molti input diversi che puoi usare per .iloctre di essi

  • Un numero intero
  • Un elenco di numeri interi
  • Taglia la notazione usando numeri interi come valori di inizio e fine

Selezione di una singola riga con .iloc con un numero intero

df.iloc[4]

Ciò restituisce la quinta riga (posizione intera 4) come una serie

age           32
color       gray
food      Cheese
height       180
score        1.8
state         AK
Name: Dean, dtype: object

Selezione di più righe con .iloc con un elenco di numeri interi

df.iloc[[2, -2]]

Ciò restituisce un DataFrame della terza e seconda all'ultima riga:

inserisci qui la descrizione dell'immagine

Selezione di più righe con .iloc con notazione slice

df.iloc[:5:3]

inserisci qui la descrizione dell'immagine


Selezione simultanea di righe e colonne con .loc e .iloc

Un'ottima capacità di entrambi .loc/.ilocè la possibilità di selezionare contemporaneamente righe e colonne. Negli esempi sopra, tutte le colonne sono state restituite da ciascuna selezione. Siamo in grado di scegliere colonne con gli stessi tipi di input utilizzati per le righe. Dobbiamo semplicemente separare la selezione di righe e colonne con una virgola .

Ad esempio, possiamo selezionare le righe Jane e Dean con solo l'altezza delle colonne, segnare e dichiarare in questo modo:

df.loc[['Jane', 'Dean'], 'height':]

inserisci qui la descrizione dell'immagine

Questo utilizza un elenco di etichette per le righe e la notazione delle sezioni per le colonne

Naturalmente possiamo fare operazioni simili .ilocusando solo numeri interi.

df.iloc[[1,4], 2]
Nick      Lamb
Dean    Cheese
Name: food, dtype: object

Selezione simultanea con etichette e posizione intera

.ixè stato usato per effettuare selezioni simultaneamente con etichette e posizione di numeri interi che a volte era utile ma confusa e ambigua e per fortuna è stato deprecato. Nel caso in cui sia necessario effettuare una selezione con una combinazione di etichette e posizioni di numeri interi, sarà necessario effettuare sia le etichette di selezione sia le posizioni di numeri interi.

Ad esempio, se vogliamo selezionare le righe Nicke Corneliainsieme alle colonne 2 e 4, potremmo utilizzare .locconvertendo i numeri interi in etichette con quanto segue:

col_names = df.columns[[2, 4]]
df.loc[['Nick', 'Cornelia'], col_names] 

In alternativa, converti le etichette degli indici in numeri interi con il get_locmetodo index.

labels = ['Nick', 'Cornelia']
index_ints = [df.index.get_loc(label) for label in labels]
df.iloc[index_ints, [2, 4]]

Selezione booleana

L'indicizzatore .loc può anche fare una selezione booleana. Ad esempio, se siamo interessati a trovare tutte le righe in cui l'età è superiore a 30 e restituiscono solo le colonne foode score, possiamo fare quanto segue:

df.loc[df['age'] > 30, ['food', 'score']] 

Puoi replicarlo con .ilocma non puoi passargli una serie booleana. È necessario convertire la serie booleana in un array intorpidito come questo:

df.iloc[(df['age'] > 30).values, [2, 4]] 

Selezione di tutte le righe

È possibile utilizzare .loc/.ilocsolo per la selezione delle colonne. Puoi selezionare tutte le righe usando i due punti come questo:

df.loc[:, 'color':'score':2]

inserisci qui la descrizione dell'immagine


L'operatore di indicizzazione [], può tagliare anche può selezionare righe e colonne ma non contemporaneamente.

Molte persone hanno familiarità con lo scopo principale dell'operatore di indicizzazione DataFrame, ovvero selezionare le colonne. Una stringa seleziona una singola colonna come Serie e un elenco di stringhe seleziona più colonne come DataFrame.

df['food']

Jane          Steak
Nick           Lamb
Aaron         Mango
Penelope      Apple
Dean         Cheese
Christina     Melon
Cornelia      Beans
Name: food, dtype: object

L'uso di un elenco consente di selezionare più colonne

df[['food', 'score']]

inserisci qui la descrizione dell'immagine

Ciò che le persone hanno meno familiarità è che, quando viene utilizzata la notazione delle sezioni, la selezione avviene per etichette di riga o per posizione di numero intero. Questo è molto confuso e qualcosa che non uso quasi mai ma funziona.

df['Penelope':'Christina'] # slice rows by label

inserisci qui la descrizione dell'immagine

df[2:6:2] # slice rows by integer location

inserisci qui la descrizione dell'immagine

La spiegazione di .loc/.ilocper selezionare le righe è altamente preferita. Il solo operatore di indicizzazione non è in grado di selezionare contemporaneamente righe e colonne.

df[3:5, 'color']
TypeError: unhashable type: 'slice'

Selezione di .ate.iat

La selezione con .atè quasi identica a .locma seleziona solo una singola "cella" in DataFrame. Di solito ci riferiamo a questa cella come valore scalare. Per usarlo .at, passa sia un'etichetta di riga che di colonna separate da una virgola.

df.at['Christina', 'color']
'black'

La selezione con .iatè quasi identica a .ilocma seleziona solo un singolo valore scalare. È necessario passargli un numero intero per entrambe le posizioni di riga e colonna

df.iat[2, 5]
'FL'

31
df = pd.DataFrame({'A':['a', 'b', 'c'], 'B':[54, 67, 89]}, index=[100, 200, 300])

df

                        A   B
                100     a   54
                200     b   67
                300     c   89
In [19]:    
df.loc[100]

Out[19]:
A     a
B    54
Name: 100, dtype: object

In [20]:    
df.iloc[0]

Out[20]:
A     a
B    54
Name: 100, dtype: object

In [24]:    
df2 = df.set_index([df.index,'A'])
df2

Out[24]:
        B
    A   
100 a   54
200 b   67
300 c   89

In [25]:    
df2.ix[100, 'a']

Out[25]:    
B    54
Name: (100, a), dtype: int64

4

Cominciamo con questo piccolo df:

import pandas as pd
import time as tm
import numpy as np
n=10
a=np.arange(0,n**2)
df=pd.DataFrame(a.reshape(n,n))

Lo faremo così

df
Out[25]: 
        0   1   2   3   4   5   6   7   8   9
    0   0   1   2   3   4   5   6   7   8   9
    1  10  11  12  13  14  15  16  17  18  19
    2  20  21  22  23  24  25  26  27  28  29
    3  30  31  32  33  34  35  36  37  38  39
    4  40  41  42  43  44  45  46  47  48  49
    5  50  51  52  53  54  55  56  57  58  59
    6  60  61  62  63  64  65  66  67  68  69
    7  70  71  72  73  74  75  76  77  78  79
    8  80  81  82  83  84  85  86  87  88  89
    9  90  91  92  93  94  95  96  97  98  99

Con questo abbiamo:

df.iloc[3,3]
Out[33]: 33

df.iat[3,3]
Out[34]: 33

df.iloc[:3,:3]
Out[35]: 
    0   1   2   3
0   0   1   2   3
1  10  11  12  13
2  20  21  22  23
3  30  31  32  33



df.iat[:3,:3]
Traceback (most recent call last):
   ... omissis ...
ValueError: At based indexing on an integer index can only have integer indexers

Quindi non possiamo usare .iat per il sottoinsieme, dove dobbiamo usare solo .iloc.

Ma proviamo entrambi a selezionare da un df più grande e controlliamo la velocità ...

# -*- coding: utf-8 -*-
"""
Created on Wed Feb  7 09:58:39 2018

@author: Fabio Pomi
"""

import pandas as pd
import time as tm
import numpy as np
n=1000
a=np.arange(0,n**2)
df=pd.DataFrame(a.reshape(n,n))
t1=tm.time()
for j in df.index:
    for i in df.columns:
        a=df.iloc[j,i]
t2=tm.time()
for j in df.index:
    for i in df.columns:
        a=df.iat[j,i]
t3=tm.time()
loc=t2-t1
at=t3-t2
prc = loc/at *100
print('\nloc:%f at:%f prc:%f' %(loc,at,prc))

loc:10.485600 at:7.395423 prc:141.784987

Quindi con .loc possiamo gestire sottoinsiemi e con .at solo un singolo scalare, ma .at è più veloce di .loc

:-)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.