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


171

Vor kurzem begann ich, von meinem sicheren Ort (R) nach Python zu verzweigen, und bin etwas verwirrt über die Lokalisierung / Auswahl der Zellen in Pandas. Ich habe die Dokumentation gelesen, habe jedoch Schwierigkeiten, die praktischen Auswirkungen der verschiedenen Lokalisierungs- / Auswahloptionen zu verstehen.

  • Gibt es einen Grund , warum ich jemals verwenden .locoder .ilocdie allgemeinste Option über .ix?
  • Ich verstehe , dass .loc, iloc, at, und iatkann einige garantiert Richtigkeit bieten , die .ixnicht bieten kann, aber ich habe auch gelesen , wo die .ixTendenz auf der ganzen Linie die schnellste Lösung.
  • Bitte erläutern Sie die realen Best-Practice-Gründe für die Verwendung von etwas anderem als .ix?


2
locIst die beschriftungsbasierte Indizierung, so dass im Grunde genommen nach einem Wert in einer Zeile gesucht wird, ilocist die ganzzahlige zeilenbasierte Indizierung ixeine allgemeine Methode, die zuerst die beschriftungsbasierte Indizierung durchführt. Wenn dies fehlschlägt, fällt sie auf die Ganzzahlbasis. atist veraltet und es wird empfohlen, dass Sie das nicht mehr verwenden. Die andere zu berücksichtigende Sache ist, was Sie versuchen, da einige dieser Methoden das Schneiden und Spaltenzuweisen ermöglichen, um ehrlich zu sein, sind die Dokumente ziemlich klar: pandas.pydata.org/pandas-docs/stable/indexing.html
EdChum

1
@EdChum - warum sagst du, dass atdas veraltet ist? Ich sehe es nicht in den at (oder iat ) Dokumenten.
Russ

1
Das ist ein Fehler, der nicht veraltet ist. Ich glaube, es wurde darüber gesprochen, ihn zu verwerfen, aber diese Idee wurde
verworfen,

4
Detail Erklärung zwischen loc, ixund ilochier: stackoverflow.com/questions/31593201/...
Alex Riley

Antworten:


142

loc: nur am Index arbeiten
iloc: an Position arbeiten
ix: Sie können Daten aus dem Datenrahmen abrufen, ohne dass sie im Index enthalten sind
: Skalarwerte abrufen . Es ist ein sehr schneller Ort
: Erhalten Sie skalare Werte. Es ist ein sehr schneller iloc

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

Hinweis: Ab sofort ist pandas 0.20.0der .ixIndexer zugunsten der strengeren und Indexer veraltet ..iloc.loc


9
Wenn atund iatsind sehr schnelle Versionen von locund iloc, warum dann locund ilocüberhaupt verwenden?
Ray

57
atund iata, um auf einen Skalar zuzugreifen, d. h. auf ein einzelnes Element im Datenrahmen, locund ilocum gleichzeitig auf mehrere Elemente zuzugreifen und möglicherweise vektorisierte Operationen auszuführen.
ncasas

@ncasas - Wenn ich die Dokumentation richtig gelesen habe, kann .at nur über den Index zugreifen, während .loc auch über den Spaltennamen zugreifen kann. Gibt es eine Möglichkeit, die schnellere .at zu verwenden, aber den Spaltennamen anstelle eines Index zu verwenden? Wie das Ersetzen von x = df.loc [df.Id == source_Id, 'someValue']. ​​Values ​​[0] durch x = df.at [df.Id == source_Id, 'someValue']. Version mit .at löst "ValueError: Bei der basierten Indizierung auf einem Integer-Index können nur Integer-Indexer vorhanden sein"
Vega

94

Aktualisiert für pandas 0.20gegeben, dass ixveraltet ist. Dies zeigt nicht nur , wie zu verwenden loc, iloc, at, iat, set_value, aber wie, gemischte Positions / label basierte Indexierung zu erreichen.


loc- label based
Ermöglicht die Übergabe von 1-D-Arrays als Indexer. Arrays können entweder Slices (Teilmengen) des Index oder der Spalte sein, oder sie können boolesche Arrays sein, deren Länge dem Index oder den Spalten entspricht.

Besonderer Hinweis: Wenn ein Skalarindexer übergeben wird, lockann ein neuer Index- oder Spaltenwert zugewiesen werden, der zuvor nicht vorhanden war.

# 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- positionsbasiert
Ähnlich wie mit locAusnahme von Positionen anstelle von Indexwerten. Sie können jedoch keine neuen Spalten oder Indizes zuweisen.

# 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- label based
Funktioniert sehr ähnlich wie locbei skalaren Indexern. Array-Indexer können nicht bearbeitet werden. Können! Weisen Sie neue Indizes und Spalten zu.

Vorteil gegenüber locist, dass dies schneller ist.
Nachteil ist, dass Sie keine Arrays für Indexer verwenden können.

# 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- positionsbasiert
Funktioniert ähnlich wie iloc. Kann in Array-Indexern nicht funktionieren. Kann nicht! Weisen Sie neue Indizes und Spalten zu.

Vorteil gegenüber ilocist, dass dies schneller ist.
Nachteil ist, dass Sie keine Arrays für Indexer verwenden können.

# 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- label based
Funktioniert sehr ähnlich wie locbei skalaren Indexern. Array-Indexer können nicht bearbeitet werden. Können! Weisen Sie neue Indizes und Spalten zu

Vorteil Super schnell, weil es sehr wenig Overhead gibt!
Nachteil Der Aufwand ist sehr gering, da pandaskeine Sicherheitsüberprüfungen durchgeführt werden. Die Verwendung erfolgt auf eigenes Risiko . Dies ist auch nicht für den öffentlichen Gebrauch bestimmt.

# 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 - positions based
Funktioniert ähnlich wieiloc. Kann in Array-Indexern nicht funktionieren. Kann nicht! Weisen Sie neue Indizes und Spalten zu.

Vorteil Super schnell, weil es sehr wenig Overhead gibt!
Nachteil Der Aufwand ist sehr gering, da pandaskeine Sicherheitsüberprüfungen durchgeführt werden. Die Verwendung erfolgt auf eigenes Risiko . Dies ist auch nicht für den öffentlichen Gebrauch bestimmt.

# 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)

Gibt es eine einfache Möglichkeit, mehrere Spalten nach Position zu lesen / festzulegen? Angenommen, ich wollte jeweils ein Array von Werten in neue Spalten einfügen. Ist dies einfach?
Wortschmied

@wordsmith Es gibt einfache Möglichkeiten, neue Spalten an das Ende des Datenrahmens anzuhängen. Oder sogar der Anfang. Wenn die Positionen beteiligt sind, gibt es keinen einfachen Weg.
piRSquared

Diese Antwort war genau das, was ich brauchte! Pandas ist sicherlich mächtig, aber das geht zu Lasten der extrem komplizierten Verständlichkeit und Zusammenstellung.
Slhck

1
Beachten Sie, dass set_valuezugunsten .atund .iatseit Version 0.21
nedned

59

Es gibt zwei Möglichkeiten, wie Pandas eine Auswahl aus einem DataFrame treffen können.

  • Nach Etikett
  • Nach ganzzahliger Position

In der Dokumentation wird der Begriff Position verwendet, um auf die Ganzzahlposition zu verweisen . Ich mag diese Terminologie nicht, da ich sie für verwirrend halte. Die Ganzzahlposition ist aussagekräftiger und genau das, wofür sie .ilocsteht. Das Schlüsselwort hier ist INTEGER - Sie müssen Ganzzahlen verwenden, wenn Sie nach Ganzzahlposition auswählen.

Bevor wir die Zusammenfassung anzeigen, stellen wir alle sicher, dass ...

.ix ist veraltet und mehrdeutig und sollte niemals verwendet werden

Es gibt drei primäre Indexer für Pandas. Wir haben den Indexierungsoperator selbst (die Klammern []) .loc, und .iloc. Fassen wir sie zusammen:

  • []- Wählt hauptsächlich Teilmengen von Spalten aus, kann aber auch Zeilen auswählen. Zeilen und Spalten können nicht gleichzeitig ausgewählt werden.
  • .loc - Wählt Teilmengen von Zeilen und Spalten nur nach Beschriftung aus
  • .iloc - Wählt Teilmengen von Zeilen und Spalten nur nach ganzzahliger Position aus

Ich benutze fast nie .atoder .iatda sie keine zusätzlichen Funktionen hinzufügen und mit nur einer kleinen Leistungssteigerung. Ich würde von ihrer Verwendung abraten, es sei denn, Sie haben eine sehr zeitkritische Anwendung. Unabhängig davon haben wir ihre Zusammenfassung:

  • .at Wählt einen einzelnen Skalarwert im DataFrame nur nach Beschriftung aus
  • .iat Wählt einen einzelnen Skalarwert im DataFrame nur nach ganzzahliger Position aus

Zusätzlich zur Auswahl nach Label und Integer-Position gibt es eine boolesche Auswahl, die auch als boolesche Indizierung bezeichnet wird .


Beispiele erklärt .loc, .iloc, boolean Auswahl und .atund .iatunten

Wir werden uns zunächst 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 jede Zeile 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 Etiketten, Jane, Nick, Aaron, Penelope, Dean, Christina, Corneliasind , als Markierungen für die Zeilen verwendet. Zusammen werden diese Zeilenbeschriftungen als Index bezeichnet .


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 (Anzahl der Zeilen) des DataFrames ist.

Es gibt viele verschiedene Eingänge, die Sie für .locdrei von ihnen verwenden können

  • 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 viele verschiedene Eingänge, die Sie für .ilocdrei von ihnen verwenden können

  • 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 mit nur der Spaltenhöhe, der 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 wie folgt in ein numpy-Array 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 Slice 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

Was die Leute weniger kennen, 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'

Auswahl durch .atund.iat

Die Auswahl mit .atist nahezu identisch mit .loc, wählt jedoch nur eine einzelne 'Zelle' in Ihrem DataFrame aus. Wir bezeichnen diese Zelle normalerweise als Skalarwert. Übergeben Sie zur Verwendung .atsowohl eine durch Komma getrennte Zeilen- als auch eine Spaltenbezeichnung.

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

Die Auswahl mit .iatist nahezu identisch mit .iloc, wählt jedoch nur einen einzelnen Skalarwert aus. Sie müssen eine Ganzzahl für die Zeilen- und Spaltenpositionen übergeben

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

Beginnen wir mit diesem kleinen 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))

Wir werden es so haben

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

Damit haben wir:

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

Daher können wir .iat nicht für Teilmengen verwenden, in denen wir nur .iloc verwenden müssen.

Aber versuchen wir beide, aus einem größeren df auszuwählen und die Geschwindigkeit zu überprüfen ...

# -*- 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

Mit .loc können wir also Teilmengen verwalten und mit .at nur einen einzigen Skalar, aber .at ist schneller als .loc

:-)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.