Wie unterscheiden sich iloc, ix und loc?

633

Kann jemand erklären, wie sich diese drei Schneidemethoden unterscheiden?
Ich habe die Dokumente gesehen und diese Antworten gesehen , aber ich bin immer noch nicht in der Lage zu erklären, wie sich die drei unterscheiden. Für mich scheinen sie größtenteils austauschbar zu sein, weil sie sich auf den unteren Ebenen des Schneidens befinden.

Angenommen, wir möchten die ersten fünf Zeilen von a erhalten DataFrame. Wie kommt es, dass alle drei funktionieren?

df.loc[:5]
df.ix[:5]
df.iloc[:5]

Kann jemand drei Fälle vorstellen, in denen die Unterscheidung der Verwendungen klarer ist?

AZhao
quelle
7
Sehr wichtig, um die SettingWithCopyWarning-Szenarien zu erwähnen: stackoverflow.com/questions/20625582/… und stackoverflow.com/questions/23688307/…
Paul
9
Beachten Sie, dass ix jetzt für die Verwerfung geplant ist: github.com/pandas-dev/pandas/issues/14218
JohnE

Antworten:

966

Hinweis: In Pandas Version 0.20.0 und höher ixist dies veraltet und die Verwendung von locund ilocwird stattdessen empfohlen . Ich habe die Teile dieser Antwort, die ixals Referenz für Benutzer früherer Versionen von Pandas beschrieben werden, intakt gelassen . Nachfolgend wurden Beispiele hinzugefügt, die Alternativen zu zeigen ix .


Hier ist eine Zusammenfassung der drei Methoden:

  • locRuft Zeilen (oder Spalten) mit bestimmten Beschriftungen aus dem Index ab.
  • ilocRuft Zeilen (oder Spalten) an bestimmten Positionen im Index ab (es werden also nur Ganzzahlen verwendet).
  • ixversucht normalerweise, sich so zu verhalten, greift locaber auf das Verhalten zurück, ilocwenn im Index keine Beschriftung vorhanden ist.

Es ist wichtig, einige Feinheiten zu beachten ix, deren Verwendung etwas schwierig sein kann :

  • Wenn der Index vom Typ Integer ist, ixwird nur die beschriftungsbasierte Indizierung verwendet und nicht auf die positionsbasierte Indizierung zurückgegriffen. Wenn sich die Bezeichnung nicht im Index befindet, wird ein Fehler ausgelöst.

  • Wenn der Index nicht nur Ganzzahlen enthält, wird bei einer Ganzzahl ixsofort eine positionsbasierte Indizierung anstelle einer beschriftungsbasierten Indizierung verwendet. Wenn jedoch ixein anderer Typ (z. B. eine Zeichenfolge) angegeben wird, kann die beschriftungsbasierte Indizierung verwendet werden.


Betrachten Sie die folgenden Reihen, um die Unterschiede zwischen den drei Methoden zu veranschaulichen:

>>> s = pd.Series(np.nan, index=[49,48,47,46,45, 1, 2, 3, 4, 5])
>>> s
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN
2    NaN
3    NaN
4    NaN
5    NaN

Wir werden uns das Schneiden mit dem ganzzahligen Wert ansehen 3.

In diesem Fall werden s.iloc[:3]die ersten 3 Zeilen zurückgegeben (da 3 als Position behandelt werden) und s.loc[:3]die ersten 8 Zeilen zurückgegeben (da 3 als Beschriftung behandelt werden):

>>> s.iloc[:3] # slice the first three rows
49   NaN
48   NaN
47   NaN

>>> s.loc[:3] # slice up to and including label 3
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN
2    NaN
3    NaN

>>> s.ix[:3] # the integer is in the index so s.ix[:3] works like loc
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN
2    NaN
3    NaN

Notice s.ix[:3]gibt dieselbe Serie zurück, in der s.loc[:3]zuerst nach dem Label gesucht wird, anstatt an der Position zu arbeiten (und der Index für sist vom Typ Integer).

Was ist, wenn wir es mit einem Integer-Label versuchen, das nicht im Index enthalten ist (sagen wir 6)?

Hier werden s.iloc[:6]die ersten 6 Zeilen der Serie wie erwartet zurückgegeben. s.loc[:6]Löst jedoch einen KeyError aus, da dieser 6nicht im Index enthalten ist.

>>> s.iloc[:6]
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN

>>> s.loc[:6]
KeyError: 6

>>> s.ix[:6]
KeyError: 6

s.ix[:6]Gemäß den oben genannten Feinheiten wird jetzt ein KeyError ausgelöst, da er versucht, wie zu funktionieren, locaber keinen 6im Index findet. Da unser Index vom Typ Integer ist, ixwird nicht auf das Verhalten zurückgegriffen iloc.

Wenn unser Index jedoch vom gemischten Typ wäre, ixwürde sich eine gegebene Ganzzahl wie ilocsofort verhalten, anstatt einen KeyError auszulösen:

>>> s2 = pd.Series(np.nan, index=['a','b','c','d','e', 1, 2, 3, 4, 5])
>>> s2.index.is_mixed() # index is mix of different types
True
>>> s2.ix[:6] # now behaves like iloc given integer
a   NaN
b   NaN
c   NaN
d   NaN
e   NaN
1   NaN

Denken Sie daran, dass Sie iximmer noch Nicht-Ganzzahlen akzeptieren und sich wie folgt verhalten können loc:

>>> s2.ix[:'c'] # behaves like loc given non-integer
a   NaN
b   NaN
c   NaN

Wenn Sie nur mit Beschriftungen oder nur mit ganzzahligen Positionen indizieren, sollten Sie generell bei unerwarteten Ergebnissen bleiben locoder ilocdiese vermeiden - versuchen Sie es nicht ix.


Kombination von positionsbasierter und labelbasierter Indizierung

Wenn Sie einen DataFrame erhalten, möchten Sie manchmal Beschriftungs- und Positionsindizierungsmethoden für die Zeilen und Spalten mischen.

Betrachten Sie beispielsweise den folgenden DataFrame. Wie schneide ich die Zeilen am besten bis einschließlich 'c' und nehme die ersten vier Spalten?

>>> df = pd.DataFrame(np.nan, 
                      index=list('abcde'),
                      columns=['x','y','z', 8, 9])
>>> df
    x   y   z   8   9
a NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN
d NaN NaN NaN NaN NaN
e NaN NaN NaN NaN NaN

In früheren Versionen von pandas (vor 0.20.0) ixkönnen Sie dies ganz ordentlich tun - wir können die Zeilen nach Beschriftung und die Spalten nach Position aufteilen (beachten Sie, dass für die Spalten ixstandardmäßig positionsbasiertes Slicing verwendet wird, da dies 4kein Spaltenname ist ):

>>> df.ix[:'c', :4]
    x   y   z   8
a NaN NaN NaN NaN
b NaN NaN NaN NaN
c NaN NaN NaN NaN

In späteren Versionen von Pandas können wir dieses Ergebnis mit ilocund mithilfe einer anderen Methode erzielen :

>>> df.iloc[:df.index.get_loc('c') + 1, :4]
    x   y   z   8
a NaN NaN NaN NaN
b NaN NaN NaN NaN
c NaN NaN NaN NaN

get_loc()ist eine Indexmethode, die "die Position des Etiketts in diesem Index ermitteln" bedeutet. Beachten Sie, dass ilocwir diesem Wert 1 hinzufügen müssen, wenn wir auch die Zeile 'c' möchten , da das Schneiden mit den Endpunkt exklusiv ist.

Weitere Beispiele in der Dokumentation von Pandas finden Sie hier .

Alex Riley
quelle
12
Tolle Erklärung! Eine verwandte Frage, die ich immer hatte, ist, welche Beziehung loc, iloc und ix gegebenenfalls zu SettingWithCopy-Warnungen haben. Es gibt einige Dokumentation ist aber um ehrlich zu sein ich bin immer noch ein wenig verwirrt pandas.pydata.org/pandas-docs/stable/...
measureallthethings
3
@measureallthethings : loc, ilocund ixkann die Warnung trotzdem auslösen, wenn sie miteinander verkettet sind. Wenn Sie das Beispiel DataFrame in den verknüpften Dokumenten verwenden, wird dfmi.loc[:, 'one'].loc[:, 'second']die Warnung ausgelöst, genau wie dfmi['one']['second']beim ersten Indizierungsvorgang möglicherweise eine Kopie der Daten (anstelle einer Ansicht) zurückgegeben wird.
Alex Riley
Was verwenden Sie, wenn Sie einen DateIndex mit einem Datum oder ähnlichem suchen möchten df.ix[date, 'Cash']?
cjm2671
@ cjm2671: beides locoder ixsollte in diesem Fall funktionieren. Gibt beispielsweise df.loc['2016-04-29', 'Cash']alle Zeilenindizes mit diesem bestimmten Datum aus der Spalte "Bargeld" zurück. (Sie können beim Abrufen von Indizes mit Zeichenfolgen so genau sein, wie Sie '2016-01'möchten. Wählen Sie beispielsweise alle Datumsangaben aus, die in den Januar 2016 fallen. `` 2016-01-02 11 'wählt die Datumsangaben am 2. Januar 2016 mit der Zeit 11 aus: ??: ?? .)
Alex Riley
Falls Sie diese Antwort irgendwann aktualisieren möchten, finden Sie hier Vorschläge zur Verwendung von loc / iloc anstelle von ix github.com/pandas-dev/pandas/issues/14218
JohnE
142

ilocfunktioniert basierend auf der ganzzahligen Positionierung. Unabhängig von Ihren Zeilenbeschriftungen können Sie beispielsweise immer die erste Zeile abrufen

df.iloc[0]

oder die letzten fünf Zeilen, indem Sie tun

df.iloc[-5:]

Sie können es auch für die Spalten verwenden. Dies ruft die 3. Spalte ab:

df.iloc[:, 2]    # the : in the first position indicates all rows

Sie können sie kombinieren, um Schnittpunkte von Zeilen und Spalten zu erhalten:

df.iloc[:3, :3] # The upper-left 3 X 3 entries (assuming df has 3+ rows and columns)

.locVerwenden Sie andererseits benannte Indizes. Richten wir einen Datenrahmen mit Zeichenfolgen als Zeilen- und Spaltenbeschriftungen ein:

df = pd.DataFrame(index=['a', 'b', 'c'], columns=['time', 'date', 'name'])

Dann können wir die erste Reihe durch bekommen

df.loc['a']     # equivalent to df.iloc[0]

und die zweiten beiden Zeilen der 'date'Spalte von

df.loc['b':, 'date']   # equivalent to df.iloc[1:, 1]

und so weiter. Jetzt ist es wohl erwähnenswert, dass die Standard - Zeilen- und Spaltenindizes für einen DataFrameganze Zahl von 0 und in diesem Fall ilocund locwürde in der gleichen Art und Weise arbeiten. Deshalb sind Ihre drei Beispiele gleichwertig. Wenn Sie einen nicht numerischen Index wie Zeichenfolgen oder Datumsangaben hätten, würde dies einen Fehler auslösen df.loc[:5] .

Sie können den Spaltenabruf auch einfach mithilfe der folgenden Datenrahmen durchführen __getitem__:

df['time']    # equivalent to df.loc[:, 'time']

Angenommen, Sie möchten Position und benannte Indizierung mischen, dh Indizierung mithilfe von Namen in Zeilen und Positionen in Spalten (zur Verdeutlichung meine ich die Auswahl aus unserem Datenrahmen, anstatt einen Datenrahmen mit Zeichenfolgen im Zeilenindex und Ganzzahlen in zu erstellen der Spaltenindex). Hier kommt Folgendes ins .ixSpiel:

df.ix[:2, 'time']    # the first two rows of the 'time' column

Ich denke, es ist auch erwähnenswert, dass Sie auch boolesche Vektoren an die locMethode übergeben können. Zum Beispiel:

 b = [True, False, True]
 df.loc[b] 

Gibt die 1. und 3. Reihe von zurück df. Dies entspricht der df[b]Auswahl, kann aber auch zum Zuweisen über boolesche Vektoren verwendet werden:

df.loc[b, 'name'] = 'Mary', 'John'
JoeCondron
quelle
Entspricht df.iloc [:,:] allen Zeilen und Spalten?
Alvis
Es ist so, wie es wäre df.loc[:, :]. Es kann verwendet werden, um die Werte des Ganzen neu zuzuweisen DataFrameoder eine Ansicht davon zu erstellen.
JoeCondron
119

Meiner Meinung nach ist die akzeptierte Antwort verwirrend, da ein DataFrame mit nur fehlenden Werten verwendet wird. Ich habe auch nicht wie der Begriff positionsbasierte für .ilocund stattdessen lieber ganze Zahl Lage , da es viel mehr beschreibend ist und genau das, was .ilocsteht. Das Schlüsselwort ist INTEGER - .ilocbraucht INTEGERS.

Weitere Informationen finden Sie in meiner äußerst detaillierten Blogserie zur Auswahl von Teilmengen


.ix ist veraltet und mehrdeutig und sollte niemals verwendet werden

Da .ixes veraltet ist, werden wir uns nur auf die Unterschiede zwischen .locund konzentrieren .iloc.

Bevor wir über die Unterschiede sprechen, ist es wichtig zu verstehen, dass DataFrames Beschriftungen haben, mit denen jede Spalte und jeder Index identifiziert werden kann. Schauen wir uns einen Beispiel-DataFrame an:

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'])

Geben Sie hier die Bildbeschreibung ein

Alle fett gedruckten Wörter sind die Bezeichnungen. Die Etiketten, age, color, food, height, scoreund statesind für die verwendeten Spalten . Die anderen Labels Jane, Nick, Aaron, Penelope, Dean, Christina, Corneliasind für den verwendeten Index .


Die primären Möglichkeiten zum Auswählen bestimmter Zeilen in einem DataFrame sind die Indexer .locund .iloc. Jeder dieser Indexer kann auch zur gleichzeitigen Auswahl von Spalten verwendet werden. Es ist jedoch einfacher, sich vorerst nur auf Zeilen zu konzentrieren. Außerdem verwendet jeder der Indexer eine Reihe von Klammern, die unmittelbar auf seinen Namen folgen, um seine Auswahl zu treffen.

.loc wählt Daten nur anhand von Beschriftungen aus

Wir werden zuerst über den .locIndexer sprechen, der nur Daten anhand der Index- oder Spaltenbezeichnungen auswählt. In unserem Beispiel DataFrame haben wir aussagekräftige Namen als Werte für den Index angegeben. Viele DataFrames haben keine aussagekräftigen Namen und verwenden stattdessen standardmäßig nur die Ganzzahlen von 0 bis n-1, wobei n die Länge des DataFrames ist.

Es gibt drei verschiedene Eingänge, für die Sie verwenden können .loc

  • Ein Faden
  • Eine Liste von Zeichenfolgen
  • Slice-Notation mit Strings als Start- und Stoppwert

Auswählen einer einzelnen Zeile mit .loc mit einer Zeichenfolge

Um eine einzelne Datenzeile auszuwählen, platzieren Sie die Indexbezeichnung in den folgenden Klammern .loc.

df.loc['Penelope']

Dies gibt die Datenzeile als Serie zurück

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

Auswählen mehrerer Zeilen mit .loc mit einer Liste von Zeichenfolgen

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

Dies gibt einen DataFrame mit den Zeilen in der in der Liste angegebenen Reihenfolge zurück:

Geben Sie hier die Bildbeschreibung ein

Auswählen mehrerer Zeilen mit .loc mit Slice-Notation

Die Slice-Notation wird durch Start-, Stopp- und Schrittwerte definiert. Beim Schneiden nach Etikett enthält Pandas den Stoppwert in der Rückgabe. Die folgenden Scheiben von Aaron bis einschließlich Dean. Die Schrittgröße ist nicht explizit definiert, sondern standardmäßig 1.

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

Geben Sie hier die Bildbeschreibung ein

Komplexe Slices können auf die gleiche Weise wie Python-Listen erstellt werden.

.iloc wählt Daten nur nach ganzzahliger Position aus

Wenden wir uns nun zu .iloc. Jede Zeile und Spalte von Daten in einem DataFrame hat eine ganzzahlige Position, die sie definiert. Dies gilt zusätzlich zu der Beschriftung, die in der Ausgabe visuell angezeigt wird . Die ganzzahlige Position ist einfach die Anzahl der Zeilen / Spalten von oben / links, beginnend bei 0.

Es gibt drei verschiedene Eingänge, für die Sie verwenden können .iloc

  • Eine ganze Zahl
  • Eine Liste von ganzen Zahlen
  • Slice-Notation mit ganzen Zahlen als Start- und Stoppwerte

Auswählen einer einzelnen Zeile mit .iloc mit einer Ganzzahl

df.iloc[4]

Dies gibt die 5. Zeile (ganzzahlige Position 4) als Serie zurück

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

Auswählen mehrerer Zeilen mit .iloc mit einer Liste von Ganzzahlen

df.iloc[[2, -2]]

Dies gibt einen DataFrame der dritten und vorletzten Zeile zurück:

Geben Sie hier die Bildbeschreibung ein

Auswählen mehrerer Zeilen mit .iloc mit Slice-Notation

df.iloc[:5:3]

Geben Sie hier die Bildbeschreibung ein


Gleichzeitige Auswahl von Zeilen und Spalten mit .loc und .iloc

Eine hervorragende Fähigkeit von beiden .loc/.ilocist ihre Fähigkeit, sowohl Zeilen als auch Spalten gleichzeitig auszuwählen. In den obigen Beispielen wurden alle Spalten von jeder Auswahl zurückgegeben. Wir können Spalten mit denselben Eingabetypen auswählen wie für Zeilen. Wir müssen lediglich die Zeilen- und Spaltenauswahl durch ein Komma trennen .

Zum Beispiel können wir die Zeilen Jane und Dean nur mit der Spaltenhöhe, Punktzahl und dem Status wie folgt auswählen:

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

Geben Sie hier die Bildbeschreibung ein

Dies verwendet eine Liste von Beschriftungen für die Zeilen und eine Slice-Notation für die Spalten

Wir können natürlich ähnliche Operationen ausführen, .ilocindem wir nur ganze Zahlen verwenden.

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

Gleichzeitige Auswahl mit Beschriftungen und ganzzahliger Position

.ixwurde verwendet, um gleichzeitig mit Beschriftungen und ganzzahligen Positionen eine Auswahl zu treffen, was nützlich, aber manchmal verwirrend und mehrdeutig war und zum Glück veraltet ist. Für den Fall, dass Sie eine Auswahl mit einer Mischung aus Beschriftungen und ganzzahligen Positionen treffen müssen, müssen Sie sowohl Ihre Auswahlbeschriftungen als auch ganzzahlige Positionen treffen.

Wenn wir beispielsweise Zeilen Nickund CorneliaSpalten 2 und 4 auswählen möchten , können wir .locdie Ganzzahlen in Beschriftungen mit den folgenden Angaben konvertieren:

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

Alternativ können Sie die Indexbezeichnungen mit der get_locIndexmethode in Ganzzahlen konvertieren .

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

Boolesche Auswahl

Der .loc-Indexer kann auch eine boolesche Auswahl treffen. Wenn wir beispielsweise daran interessiert sind, alle Zeilen zu finden, in denen das Alter über 30 liegt, und nur die Spalten foodund zurückzugeben, scorekönnen wir Folgendes tun:

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

Sie können dies mit replizieren, .ilocaber Sie können ihm keine boolesche Reihe übergeben. Sie müssen die boolesche Reihe in ein numpy-Array wie folgt konvertieren:

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

Alle Zeilen auswählen

Es kann .loc/.ilocnur für die Spaltenauswahl verwendet werden. Sie können alle Zeilen mit einem Doppelpunkt wie folgt auswählen:

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

Geben Sie hier die Bildbeschreibung ein


Der Indizierungsoperator []kann auch Zeilen und Spalten auswählen, jedoch nicht gleichzeitig.

Die meisten Benutzer kennen den Hauptzweck des DataFrame-Indexierungsoperators, nämlich die Auswahl von Spalten. Eine Zeichenfolge wählt eine einzelne Spalte als Serie aus, und eine Liste von Zeichenfolgen wählt mehrere Spalten als DataFrame aus.

df['food']

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

Durch die Verwendung einer Liste werden mehrere Spalten ausgewählt

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

Geben Sie hier die Bildbeschreibung ein

Weniger vertraut ist, dass bei Verwendung der Slice-Notation die Auswahl nach Zeilenbeschriftungen oder nach ganzzahliger Position erfolgt. Das ist sehr verwirrend und etwas, das ich fast nie benutze, aber es funktioniert.

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

Geben Sie hier die Bildbeschreibung ein

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

Geben Sie hier die Bildbeschreibung ein

Die Aussage .loc/.iloczur Auswahl von Zeilen wird sehr bevorzugt. Der Indizierungsoperator allein kann keine Zeilen und Spalten gleichzeitig auswählen.

df[3:5, 'color']
TypeError: unhashable type: 'slice'
Ted Petrou
quelle
6
Wow, dies war eine der sehr gut artikulierten und klaren Erklärungen, die mir jemals zu einem Programmierthema begegnet sind. Was Sie im letzten Abschnitt über die normale Indizierung erklärt haben, die entweder für Zeilen oder Spalten funktioniert, ist einer der Gründe, warum wir loc und iloc haben Methode. Ich bin auf diese Einschränkung im Datencamp-Kurs gestoßen. a.) Was geben df.columns und df.index zurück? Ist es eine Liste von Zeichenfolgen? Wenn es sich um eine Liste handelt, darf auf zwei Elemente wie diese df.columns [[2,4]] in einer Liste zugegriffen werden? b.) Kann ich get_loc () für df.columns aufrufen? c.) Warum müssen wir bei iloc df ['age']> 30.values ​​nennen?
Pragun
Die beste Antwort, die ich je gesehen habe.
Max
Dies ist eine wirklich gute Antwort. Ich fand es gut, dass es nicht viel mit ix zu tun hat, was veraltet und sinnlos ist, tief zu tauchen. Vielen Dank.
Omabena