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

171

Recentemente, comecei a ramificar do meu lugar seguro (R) para o Python e estou um pouco confuso com a localização / seleção de células no Pandas. Eu li a documentação, mas estou lutando para entender as implicações práticas das várias opções de localização / seleção.

  • Existe uma razão pela qual eu deveria usar .locou .ilocsobre a opção mais geral .ix?
  • Eu entendo que .loc, iloc, at, e iatpode fornecer alguma correção a garantia de que .ixnão pode oferecer, mas eu também li que .ixtende a ser a solução mais rápida através da placa.
  • Explique o raciocínio das melhores práticas do mundo real por trás da utilização de algo que não seja .ix?
rabiscos
fonte
3
locé uma indexação baseada em rótulo; portanto, basicamente, procurar um valor em uma linha, ilocé uma indexação baseada em linha inteira, ixé um método geral que primeiro executa com base em rótulo; se isso falhar, ele passará a ser baseado em número inteiro. atestá obsoleto e é recomendável que você não use mais isso. A outra coisa a considerar é o que você está tentando fazer, pois alguns desses métodos permitem fatiar e atribuir colunas, para ser honesto, os documentos são bem claros: pandas.pydata.org/pandas-docs/stable/indexing.html
EdChum
1
@ EdChum - o que faz você dizer que atestá obsoleto? Não o vejo nos documentos at (ou iat ).
Russ
1
Isso é um erro que não é obsoleto, eu acho que houve alguma conversa de depreciativo, mas essa idéia foi abandonada porque eu acho que é mais rápido
EdChum
4
Detalhe explicação entre loc, ixe ilocaqui: stackoverflow.com/questions/31593201/...
Alex Riley

Respostas:

142

loc: trabalhe apenas no índice
iloc: trabalhe na posição
ix: você pode obter dados do dataframe sem que estejam no índice
em: obter valores escalares. É um local muito rápido
: obtenha valores escalares. É um iloc muito rápido

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

Nota: A partir de pandas 0.20.0, o .ixindexador foi descontinuado em favor dos mais rigorosos .iloce .locindexadores.

Lautremont
fonte
9
Se ate iatsão versões muito rápidas de loce iloc, em seguida, por que usar loce ilocem tudo?
Raio
57
ateo iatum destinado a aceder a um escalar, isto é, um único elemento da trama de dados, ao mesmo tempo loce ilocsão mentos para aceder a vários elementos ao mesmo tempo, potencialmente, para executar operações vectorized.
Nsas 7/16
@ncasas - se eu ler a documentação corretamente, o .at só pode acessar pelo índice, enquanto o .loc também pode acessar pelo nome da coluna. Existe uma maneira de usar o .at mais rápido, mas use o nome da coluna em vez de um índice? Como substituir x = df.loc [df.Id == source_Id, 'someValue']. ​​Values ​​[0] por x = df.at [df.Id == source_Id, 'someValue']. Versão com .at lança "ValueError: na indexação baseada em um índice inteiro pode ter apenas indexadores inteiros"
Vega
94

Atualizado por pandas 0.20causa de ixdescontinuação. Isso demonstra não apenas como usar loc, iloc, at, iat, set_value, mas como realizar, a indexação com base posicional / label mista.


loc- baseado em etiqueta
Permite passar matrizes 1-D como indexadores. As matrizes podem ser fatias (subconjuntos) do índice ou coluna, ou podem ser matrizes booleanas com comprimento igual ao índice ou colunas.

Nota especial: quando um indexador escalar é passado, é locpossível atribuir um novo índice ou valor de coluna que não existia antes.

# 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- baseado em posição
Similar a locexceto com posições em vez dos valores de índice. No entanto, você não pode atribuir novas colunas ou índices.

# 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- baseado em etiqueta
Funciona muito semelhante ao locdos indexadores escalares. Não pode operar em indexadores de matriz. Lata! atribua novos índices e colunas.

Vantagem sobre locé que este é mais rápido.
A desvantagem é que você não pode usar matrizes para indexadores.

# 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- baseado em posição
Funciona de maneira semelhante a iloc. Não é possível trabalhar em indexadores de matriz. Não podes! atribua novos índices e colunas.

Vantagem sobre ilocé que este é mais rápido.
A desvantagem é que você não pode usar matrizes para indexadores.

# 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- baseado em etiqueta
Funciona muito semelhante ao locdos indexadores escalares. Não pode operar em indexadores de matriz. Lata! atribuir novos índices e colunas

Vantagem Super rápido, porque há muito pouca sobrecarga!
Desvantagem Há muito pouca sobrecarga porque pandasnão está realizando muitas verificações de segurança. Use por sua conta e risco . Além disso, isso não se destina ao uso público.

# 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_valuecomtakable=True - posição com base
funciona de forma semelhante ailoc. Não é possível trabalhar em indexadores de matriz. Não podes! atribua novos índices e colunas.

Vantagem Super rápido, porque há muito pouca sobrecarga!
Desvantagem Há muito pouca sobrecarga porque pandasnão está realizando muitas verificações de segurança. Use por sua conta e risco . Além disso, isso não se destina ao uso público.

# 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
fonte
Então, existe uma maneira simples de ler / definir várias colunas por posição? Além disso, digamos, eu queria adicionar uma matriz de valores cada uma em novas colunas, isso é fácil?
wordsmith
@wordsmith existem maneiras fáceis de adicionar novas colunas ao final do quadro de dados. Ou até o começo. Se as posições estiverem envolvidas, não, não há uma maneira fácil.
piRSquared
Esta resposta foi exatamente o que eu precisava! O panda é certamente poderoso, mas isso custa às custas de tornar tudo extremamente complicado de entender e reunir.
Slhck 7/02
1
Note-se que set_valuefoi preterido em favor de .ate .iatdesde a versão 0.21
nedned
59

Há duas maneiras principais pelas quais os pandas fazem seleções em um DataFrame.

  • Por etiqueta
  • Por local inteiro

A documentação usa o termo posição para se referir ao local inteiro . Não gosto dessa terminologia, pois sinto que é confusa. A localização inteira é mais descritiva e é exatamente o que .ilocsignifica. A palavra-chave aqui é INTEGER - você deve usar números inteiros ao selecionar por local inteiro.

Antes de mostrar o resumo, vamos ter certeza de que ...

.ix está obsoleto e ambíguo e nunca deve ser usado

Existem três indexadores principais para pandas. Temos o próprio operador de indexação (os colchetes []) .loc, e .iloc. Vamos resumir eles:

  • []- Seleciona principalmente subconjuntos de colunas, mas também pode selecionar linhas. Não é possível selecionar simultaneamente linhas e colunas.
  • .loc - seleciona subconjuntos de linhas e colunas somente por rótulo
  • .iloc - seleciona subconjuntos de linhas e colunas apenas por localização inteira

Eu quase nunca uso .atou .iatporque eles não adicionam funcionalidade adicional e apenas com um pequeno aumento de desempenho. Eu desencorajaria o uso deles, a menos que você tenha um aplicativo muito sensível ao tempo. Independentemente disso, temos o resumo deles:

  • .at seleciona um único valor escalar no DataFrame apenas por rótulo
  • .iat seleciona um único valor escalar no DataFrame apenas por local inteiro

Além da seleção por rótulo e local inteiro, existe a seleção booleana também conhecida como indexação booleana .


Exemplos explicando .loc, .iloc, booleano selecção e .ate .iatsão mostrados abaixo

Vamos nos concentrar primeiro nas diferenças entre .loce .iloc. Antes de falarmos sobre as diferenças, é importante entender que os DataFrames têm rótulos que ajudam a identificar cada coluna e cada linha. Vamos dar uma olhada em um exemplo de 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'])

insira a descrição da imagem aqui

Todas as palavras em negrito são os rótulos. As etiquetas, age, color, food, height, scoree statesão usados para as colunas . Os outros rótulos, Jane, Nick, Aaron, Penelope, Dean, Christina, Corneliasão usados como rótulos para as linhas. Coletivamente, esses rótulos de linha são conhecidos como índice .


As principais maneiras de selecionar linhas específicas em um DataFrame são com os indexadores .loce .iloc. Cada um desses indexadores também pode ser usado para selecionar colunas simultaneamente, mas é mais fácil focar apenas nas linhas por enquanto. Além disso, cada um dos indexadores usa um conjunto de colchetes que seguem imediatamente seu nome para fazer suas seleções.

.loc seleciona dados apenas por rótulos

Primeiro, falaremos sobre o .locindexador, que seleciona apenas os dados pelos rótulos do índice ou da coluna. Em nosso exemplo DataFrame, fornecemos nomes significativos como valores para o índice. Muitos DataFrames não terão nomes significativos e, em vez disso, usarão como padrão apenas os números inteiros de 0 a n-1, onde n é o comprimento (número de linhas) do DataFrame.

Existem muitas entradas diferentes que você pode usar para .loctrês delas são

  • Uma linha
  • Uma lista de strings
  • Notação de fatia usando cadeias como valores de início e parada

Selecionando uma única linha com .loc com uma sequência

Para selecionar uma única linha de dados, coloque o rótulo do índice dentro dos colchetes a seguir .loc.

df.loc['Penelope']

Isso retorna a linha de dados como uma série

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

Selecionando várias linhas com .loc com uma lista de cadeias

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

Isso retorna um DataFrame com as linhas na ordem especificada na lista:

insira a descrição da imagem aqui

Selecionando várias linhas com .loc com notação de fatia

A notação de fatia é definida pelos valores de início, parada e etapa. Ao fatiar por etiqueta, os pandas incluem o valor de parada no retorno. As seguintes fatias de Aaron a Dean, inclusive. Seu tamanho da etapa não é explicitamente definido, mas o padrão é 1.

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

insira a descrição da imagem aqui

Fatias complexas podem ser obtidas da mesma maneira que as listas Python.

.iloc seleciona dados apenas por localização inteira

Vamos agora voltar para .iloc. Cada linha e coluna de dados em um DataFrame tem um local inteiro que o define. Isso é um acréscimo ao rótulo que é exibido visualmente na saída. O local inteiro é simplesmente o número de linhas / colunas da parte superior / esquerda começando em 0.

Existem muitas entradas diferentes que você pode usar para .iloctrês delas são

  • Um inteiro
  • Uma lista de números inteiros
  • Notação de fatia usando números inteiros como valores inicial e final

Selecionando uma única linha com .iloc com um número inteiro

df.iloc[4]

Isso retorna a 5ª linha (local inteiro 4) como uma Série

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

Selecionando várias linhas com .iloc com uma lista de números inteiros

df.iloc[[2, -2]]

Isso retorna um DataFrame da terceira e da segunda à última linhas:

insira a descrição da imagem aqui

Selecionando várias linhas com .iloc com notação de fatia

df.iloc[:5:3]

insira a descrição da imagem aqui


Seleção simultânea de linhas e colunas com .loc e .iloc

Uma excelente capacidade de ambos .loc/.ilocé a capacidade de selecionar linhas e colunas simultaneamente. Nos exemplos acima, todas as colunas foram retornadas de cada seleção. Podemos escolher colunas com os mesmos tipos de entradas que fazemos para as linhas. Simplesmente precisamos separar a seleção de linha e coluna com uma vírgula .

Por exemplo, podemos selecionar as linhas Jane e Dean com apenas as colunas altura, pontuação e estado da seguinte forma:

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

insira a descrição da imagem aqui

Isso usa uma lista de rótulos para as linhas e notação de fatia para as colunas

Naturalmente, podemos realizar operações semelhantes .ilocusando apenas números inteiros.

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

Seleção simultânea com rótulos e localização de número inteiro

.ixfoi usado para fazer seleções simultaneamente com rótulos e local inteiro, o que foi útil, mas às vezes confuso e ambíguo e, felizmente, foi preterido. No caso de você precisar fazer uma seleção com uma mistura de rótulos e locais inteiros, será necessário fazer rótulos de seleção ou locais inteiros.

Por exemplo, se quisermos selecionar linhas Nicke, Corneliajuntamente com as colunas 2 e 4, poderíamos usar .locconvertendo os números inteiros em rótulos com o seguinte:

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

Ou, alternativamente, converta os rótulos de índice em números inteiros com o get_locmétodo index.

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

Seleção booleana

O indexador .loc também pode fazer a seleção booleana. Por exemplo, se estivermos interessados ​​em encontrar todas as linhas com idade acima de 30 anos e retornar apenas as colunas foode score, podemos fazer o seguinte:

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

Você pode replicar isso com, .ilocmas não pode transmitir uma série booleana. Você deve converter a série booleana em uma matriz numpy como esta:

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

Selecionando todas as linhas

É possível usar .loc/.ilocapenas para seleção de coluna. Você pode selecionar todas as linhas usando dois pontos como este:

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

insira a descrição da imagem aqui


O operador de indexação,, []pode fatiar, pode selecionar linhas e colunas também, mas não simultaneamente.

A maioria das pessoas conhece o objetivo principal do operador de indexação DataFrame, que é selecionar colunas. Uma cadeia de caracteres seleciona uma única coluna como uma série e uma lista de cadeias seleciona várias colunas como um DataFrame.

df['food']

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

O uso de uma lista seleciona várias colunas

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

insira a descrição da imagem aqui

O que as pessoas estão menos familiarizadas é que, quando a notação de fatia é usada, a seleção acontece por rótulos de linha ou por local inteiro. Isso é muito confuso e algo que quase nunca uso, mas funciona.

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

insira a descrição da imagem aqui

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

insira a descrição da imagem aqui

A explicitação de .loc/.ilocpara selecionar linhas é altamente preferida. O operador de indexação sozinho não pode selecionar linhas e colunas simultaneamente.

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

Seleção por .ate.iat

A seleção com .até quase idêntica, .locmas apenas seleciona uma única 'célula' no seu DataFrame. Geralmente, nos referimos a essa célula como um valor escalar. Para usar .at, passe um rótulo de linha e coluna separados por vírgula.

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

A seleção com .iaté quase idêntica, .ilocmas somente seleciona um único valor escalar. Você deve passar um número inteiro para os locais de linha e coluna

df.iat[2, 5]
'FL'
Ted Petrou
fonte
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
fonte
4

Vamos começar com este pequeno 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))

Nós vamos ter

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

Com isso, temos:

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

Portanto, não podemos usar .iat para subconjunto, onde devemos usar apenas .iloc.

Mas vamos tentar ambos para selecionar um df maior e vamos verificar a velocidade ...

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

Portanto, com .loc, podemos gerenciar subconjuntos e com .at apenas um único escalar, mas .at é mais rápido que .loc

:-)

Fabio Pomi
fonte