pandy loc, iloc, ix, at, iat?

171

Niedawno zacząłem rozgałęziać się z mojego bezpiecznego miejsca (R) do Pythona i jestem trochę zdezorientowany lokalizacją / wyborem komórki w Pandas. Przeczytałem dokumentację, ale staram się zrozumieć praktyczne konsekwencje różnych opcji lokalizacji / wyboru.

  • Czy jest jakiś powód, dla którego powinienem używać .loclub .ilocprzekraczać najbardziej ogólną opcję .ix?
  • Rozumiem, że .loc, iloc, at, i iatmoże zapewnić pewne gwarantowane poprawności że .ixnie może zaoferować, ale ja również czytać gdzie .ixwydaje się być najszybszym rozwiązaniem całej planszy.
  • Proszę wyjaśnić rzeczywiste, najlepsze praktyki uzasadniające używanie czegokolwiek innego niż .ix?
bazgroły
źródło
3
locjest indeksowaniem opartym na etykietach, więc w zasadzie wyszukuje wartość w wierszu, ilocjest indeksowaniem opartym na wierszach całkowitych, ixjest ogólną metodą, która najpierw wykonuje oparte na etykiecie, jeśli to się nie powiedzie, przechodzi do liczb całkowitych. atjest przestarzała i odradza się jej już używanie. Inną rzeczą do rozważenia jest to, co próbujesz zrobić, ponieważ niektóre z tych metod pozwalają na krojenie i przypisywanie kolumn, szczerze mówiąc, dokumenty są dość jasne: pandas.pydata.org/pandas-docs/stable/indexing.html
EdChum
1
@EdChum - co sprawia, że ​​mówisz, że atjest to przestarzałe? Nie widzę tego w dokumentach at (lub iat ).
Russ
1
To błąd, nie jest przestarzały, myślę, że było trochę mowy o jego wycofaniu, ale ten pomysł został odrzucony, ponieważ myślę, że jest szybszy
EdChum
4
Szczegół wyjaśnienie pomiędzy loc, ixi iloctutaj: stackoverflow.com/questions/31593201/...
Alex Riley

Odpowiedzi:

142

loc: działa tylko na indeksie
iloc: działa na pozycji
ix: Możesz pobrać dane z dataframe bez znajdowania się w indeksie
pod adresem: get wartości skalarne. To bardzo szybka lokalizacja
: pobierz wartości skalarne. To bardzo szybki iloc

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

Uwaga: Począwszy od pandas 0.20.0The .ixindekser jest przestarzałe na rzecz bardziej rygorystyczne .iloci .locindeksujących.

lautremont
źródło
9
Jeśli ati iatsą bardzo szybkimi wersjami programu loci iloc, to po co używać lociw ilocogóle?
Ray
57
ata iatprzeznaczone do uzyskiwania dostępu do wartości skalarnej, to znaczy do pojedynczego elementu w ramce danych, podczas gdy loci ilocsą przeznaczone do uzyskiwania dostępu do kilku elementów w tym samym czasie, potencjalnie w celu wykonywania operacji wektoryzowanych.
ncasas
@ncasas - jeśli dobrze przeczytałem dokumentację .at może uzyskać dostęp tylko za pomocą indeksu, a .loc może również uzyskać dostęp przez nazwę kolumny. Czy istnieje sposób, aby użyć szybszego pliku .at, ale użyć nazwy kolumny zamiast indeksu? Podobnie jak zamiana x = df.loc [df.Id == source_Id, 'someValue']. ​​Values ​​[0] przez x = df.at [df.Id == source_Id, 'someValue']. Wersja z rozszerzeniem .at zgłasza „ValueError: At oparte na indeksowaniu na indeksie całkowitoliczbowym może mieć tylko indeksatory całkowite”
Vega,
94

Zaktualizowano, pandas 0.20ponieważ ixjest przestarzały. To pokazuje nie tylko, jak używać loc, iloc, at, iat, set_value, ale jak tego dokonać, mieszane indeksowanie oparciu pozycyjny / etykiety.


loc- oparte na etykietach
Umożliwia przekazywanie tablic 1-D jako indeksatorów. Tablice mogą być wycinkami (podzestawami) indeksu lub kolumny lub mogą to być tablice logiczne o długości równej indeksowi lub kolumnom.

Uwaga specjalna: po przekazaniu indeksatora skalarnego locmożna przypisać nowy indeks lub wartość kolumny, która wcześniej nie istniała.

# 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- na podstawie pozycji
Podobnie jak z locwyjątkiem z pozycjami, a nie wartościami indeksu. Nie możesz jednak przypisać nowych kolumn ani indeksów.

# 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- oparty na etykietach
Działa bardzo podobnie do locindeksatorów skalarnych. Nie można operować na indeksatorach tablic. Mogą! przypisać nowe indeksy i kolumny.

Zaletą przez locto, że jest to szybsze.
Wadą jest to, że nie można używać tablic dla indeksatorów.

# 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- na podstawie pozycji
Działa podobnie do iloc. Nie można pracować w indeksatorach tablic. Nie mogę! przypisać nowe indeksy i kolumny.

Zaletą przez ilocto, że jest to szybsze.
Wadą jest to, że nie można używać tablic dla indeksatorów.

# 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- oparty na etykietach
Działa bardzo podobnie do locindeksatorów skalarnych. Nie można operować na indeksatorach tablic. Mogą! przypisać nowe indeksy i kolumny

Korzyść Bardzo szybko, ponieważ koszty ogólne są bardzo małe!
Wady Jest bardzo mało narzutów, ponieważ pandasnie przeprowadza się wielu kontroli bezpieczeństwa. Używaj na własne ryzyko . Nie jest to również przeznaczone do użytku publicznego.

# 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
Działa podobnie doiloc. Nie można pracować w indeksatorach tablic. Nie mogę! przypisać nowe indeksy i kolumny.

Korzyść Bardzo szybko, ponieważ koszty ogólne są bardzo małe!
Wady Jest bardzo mało narzutów, ponieważ pandasnie przeprowadza się wielu kontroli bezpieczeństwa. Używaj na własne ryzyko . Nie jest to również przeznaczone do użytku publicznego.

# 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)
piRSquared
źródło
Czy jest więc prosty sposób na odczytanie / ustawienie wielu kolumn według pozycji? Dalej, powiedzmy, chciałem dodać tablicę wartości do nowych kolumn, czy jest to łatwe do wykonania?
wordsmith
@wordsmith istnieją łatwe sposoby dołączania nowych kolumn na końcu ramki danych. Albo nawet początek. Jeśli pozycje są zaangażowane, to nie, nie ma łatwego sposobu.
piRSquared
Ta odpowiedź była właśnie tym, czego potrzebowałem! Pandy są z pewnością potężne, ale odbywa się to kosztem uczynienia wszystkiego niezwykle trudnym do zrozumienia i złożenia.
slhck
1
Zauważ, że set_valuezostał wycofany na korzyść wersji 0.21 .ati .iatod wersji 0.21
wycofany
59

Istnieją dwa główne sposoby dokonywania wyborów przez pandy z DataFrame.

  • Według etykiety
  • Według lokalizacji całkowitej

Dokumentacja używa terminu pozycja w odniesieniu do lokalizacji liczb całkowitych . Nie podoba mi się ta terminologia, ponieważ uważam, że jest myląca. Liczba całkowita jest bardziej opisowa i właśnie to .ilocoznacza. Kluczowym słowem jest tutaj INTEGER - musisz używać liczb całkowitych podczas wybierania według lokalizacji całkowitej.

Zanim pokażemy podsumowanie, upewnijmy się, że ...

Rozszerzenie .ix jest przestarzałe i niejednoznaczne i nigdy nie powinno być używane

Istnieją trzy główne indeksatory dla pand. Mamy sam operator indeksujący (nawiasy []) .loc, i .iloc. Podsumujmy je:

  • []- Przede wszystkim wybiera podzbiory kolumn, ale może również wybierać wiersze. Nie można jednocześnie zaznaczyć wierszy i kolumn.
  • .loc - wybiera podzbiory wierszy i kolumn tylko według etykiety
  • .iloc - wybiera podzbiory wierszy i kolumn tylko według lokalizacji całkowitej

Prawie nigdy nie używam .atlub .iatponieważ nie dodają dodatkowej funkcjonalności i przy niewielkim wzroście wydajności. Odradzałbym ich używanie, chyba że masz aplikację wymagającą dużej ilości czasu. Mimo wszystko mamy ich podsumowanie:

  • .at wybiera pojedynczą wartość skalarną w DataFrame tylko według etykiety
  • .iat wybiera pojedynczą wartość skalarną w DataFrame tylko według lokalizacji całkowitej

Oprócz selekcji według etykiety i lokalizacji liczby całkowitej istnieje selekcja logiczna znana również jako indeksowanie logiczne .


Przykłady objaśniające .loc, .iloc, wybór i logiczny .ati .iatsą przedstawione niżej

Najpierw skupimy się na różnicach między .loci .iloc. Zanim porozmawiamy o różnicach, ważne jest, aby zrozumieć, że ramki DataFrames mają etykiety, które pomagają zidentyfikować każdą kolumnę i każdy wiersz. Przyjrzyjmy się przykładowej ramce DataFrame:

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

wprowadź opis obrazu tutaj

Wszystkie pogrubione słowa to etykiety. Etykiety, age, color, food, height, scorei statesą wykorzystywane do kolumn . Pozostałe etykiety, Jane, Nick, Aaron, Penelope, Dean, Christina, Corneliasą używane jako etykiety wierszy. Zbiorczo te etykiety wierszy są nazywane indeksami .


Podstawowymi sposobami wybierania określonych wierszy w DataFrame są indeksatory .loci .iloc. Każdy z tych indeksatorów może również służyć do jednoczesnego wybierania kolumn, ale na razie łatwiej jest skupić się na wierszach. Ponadto każdy z indeksatorów używa zestawu nawiasów, które są bezpośrednio następujące po ich nazwie, aby dokonać wyboru.

.loc wybiera dane tylko według etykiet

Najpierw porozmawiamy o .locindeksatorze, który wybiera dane tylko według indeksu lub etykiet kolumn. W naszej przykładowej ramce DataFrame podaliśmy znaczące nazwy jako wartości indeksu. Wiele ramek DataFrame nie będzie miało żadnych znaczących nazw, a zamiast tego domyślnie będzie to tylko liczby całkowite od 0 do n-1, gdzie n to długość (liczba wierszy) ramki DataFrame.

Istnieje wiele różnych wejść, których możesz użyć dla .loctrzech z nich

  • Sznurek
  • Lista ciągów
  • Notacja wycinków przy użyciu łańcuchów jako wartości początkowej i końcowej

Wybieranie pojedynczego wiersza z .loc z ciągiem

Aby zaznaczyć pojedynczy wiersz danych, umieść etykietę indeksu w następujących nawiasach .loc.

df.loc['Penelope']

Zwraca wiersz danych jako serię

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

Wybieranie wielu wierszy za pomocą .loc z listą ciągów

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

Zwraca DataFrame z wierszami w kolejności określonej na liście:

wprowadź opis obrazu tutaj

Wybieranie wielu wierszy za pomocą .loc z notacją plasterków

Notacja wycinka jest definiowana przez wartości początkowe, końcowe i krokowe. Podczas krojenia według etykiety pandy zawierają wartość zatrzymania w zwrocie. Następujące wycinki od Aarona do Deana włącznie. Rozmiar kroku nie jest jawnie zdefiniowany, ale domyślnie wynosi 1.

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

wprowadź opis obrazu tutaj

Złożone wycinki można pobierać w taki sam sposób, jak listy w Pythonie.

.iloc wybiera dane tylko według lokalizacji całkowitej

Przejdźmy teraz do .iloc. Każdy wiersz i kolumna danych w ramce DataFrame zawiera liczbę całkowitą, która ją definiuje. Jest to dodatek do etykiety, która jest wizualnie wyświetlana w wyniku. Lokalizacja liczby całkowitej to po prostu liczba wierszy / kolumn od góry / od lewej, zaczynając od 0.

Istnieje wiele różnych wejść, których możesz użyć dla .iloctrzech z nich

  • Liczba całkowita
  • Lista liczb całkowitych
  • Notacja wycinków przy użyciu liczb całkowitych jako wartości początkowej i końcowej

Wybieranie pojedynczego wiersza z .iloc z liczbą całkowitą

df.iloc[4]

Zwraca piąty wiersz (liczba całkowita 4) jako serię

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

Wybieranie wielu wierszy za pomocą .iloc z listą liczb całkowitych

df.iloc[[2, -2]]

Zwraca DataFrame trzeciego i przedostatniego wiersza:

wprowadź opis obrazu tutaj

Wybieranie wielu wierszy za pomocą .iloc z notacją wycinków

df.iloc[:5:3]

wprowadź opis obrazu tutaj


Jednoczesny wybór wierszy i kolumn z .loc i .iloc

Jedną z doskonałych możliwości obu .loc/.ilocjest możliwość jednoczesnego wybierania wierszy i kolumn. W powyższych przykładach wszystkie kolumny zostały zwrócone z każdego wyboru. Możemy wybierać kolumny z tymi samymi typami danych wejściowych, co w przypadku wierszy. Musimy po prostu oddzielić wiersz i zaznaczenie kolumny przecinkiem .

Na przykład możemy wybrać wiersze Jane i Dean tylko z wysokością kolumn, wynikiem i stanem w następujący sposób:

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

wprowadź opis obrazu tutaj

Używa to listy etykiet dla wierszy i notacji wycinków dla kolumn

Możemy naturalnie wykonywać podobne operacje .ilocużywając tylko liczb całkowitych.

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

Jednoczesna selekcja z etykietami i lokalizacją całkowitą

.ixbył używany do dokonywania wyborów jednocześnie z etykietami i lokalizacją liczb całkowitych, co było przydatne, ale czasami mylące i niejednoznaczne, i na szczęście zostało wycofane. W przypadku, gdy musisz dokonać wyboru za pomocą kombinacji etykiet i lokalizacji całkowitych, musisz wybrać zarówno etykiety, jak i lokalizacje całkowite.

Na przykład, jeśli chcemy wybrać wiersze Nicki Corneliarazem z kolumnami 2 i 4, możemy użyć .loc, konwertując liczby całkowite na etykiety z następującym:

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

Lub alternatywnie przekonwertuj etykiety indeksu na liczby całkowite za pomocą get_locmetody indeksu.

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

Wybór logiczny

Indeksator .loc może również wybierać wartości logiczne. Na przykład, jeśli interesuje nas znalezienie wszystkich wierszy, w których wiek jest powyżej 30 lat i zwrócenie tylko kolumn foodi score, możemy wykonać następujące czynności:

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

Możesz to powtórzyć za pomocą, .ilocale nie możesz przekazać tego serii boolowskiej. Musisz przekonwertować serię boolowską na tablicę numpy, taką jak ta:

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

Zaznaczanie wszystkich wierszy

Można użyć .loc/.iloctylko do wyboru kolumny. Możesz zaznaczyć wszystkie wiersze, używając dwukropka w ten sposób:

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

wprowadź opis obrazu tutaj


Operator indeksowania,, []może wycinać, może również zaznaczać wiersze i kolumny, ale nie jednocześnie.

Większość ludzi zna główny cel operatora indeksowania DataFrame, którym jest wybieranie kolumn. Ciąg wybiera jedną kolumnę jako serię, a lista ciągów wybiera wiele kolumn jako DataFrame.

df['food']

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

Korzystanie z listy powoduje wybranie wielu kolumn

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

wprowadź opis obrazu tutaj

To, z czym ludzie są mniej zaznajomieni, to fakt, że gdy używany jest zapis wycinków, selekcja odbywa się według etykiet wierszy lub według położenia liczb całkowitych. Jest to bardzo zagmatwane i prawie nigdy nie używam, ale działa.

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

wprowadź opis obrazu tutaj

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

wprowadź opis obrazu tutaj

.loc/.ilocPreferowana jest jednoznaczność wybierania wierszy. Sam operator indeksowania nie może jednocześnie zaznaczyć wierszy i kolumn.

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

Wybór przez .ati.iat

Wybór z .atjest prawie identyczny z, .locale wybiera tylko jedną „komórkę” w ramce DataFrame. Zwykle nazywamy tę komórkę wartością skalarną. Aby użyć .at, przekaż mu zarówno etykietę wiersza, jak i kolumny oddzielone przecinkiem.

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

Zaznaczenie za pomocą .iatjest prawie identyczne, .ilocale wybiera tylko jedną wartość skalarną. Musisz przekazać mu liczbę całkowitą dla lokalizacji wierszy i kolumn

df.iat[2, 5]
'FL'
Ted Petrou
źródło
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
Lydia
źródło
4

Zacznijmy od tego małego 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))

Będziemy mieć

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

Dzięki temu mamy:

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

Dlatego nie możemy używać .iat dla podzbioru, gdzie musimy używać tylko .iloc.

Ale spróbujmy zarówno wybrać z większego df, jak i sprawdźmy prędkość ...

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

Więc z .loc możemy zarządzać podzbiorami, a z .at tylko pojedynczym skalarem, ale .at jest szybszy niż .loc

:-)

Fabio Pomi
źródło