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

Recientemente comencé a expandirme desde mi lugar seguro (R) a Python y estoy un poco confundido por la localización / selección de células en Pandas . He leído la documentación pero me cuesta entender las implicaciones prácticas de las diversas opciones de localización / selección.

  • ¿Hay alguna razón por la que deba usar .loc o .iloc sobre la opción más general .ix ?
  • Entiendo que .loc , iloc , at e iat pueden proporcionar cierta corrección garantizada que .ix no puede ofrecer, pero también he leído dónde .ix tiende a ser la solución más rápida en todos los ámbitos.
  • Explique el razonamiento de las mejores prácticas del mundo real detrás de la utilización de cualquier otra cosa que no sea .ix ?

loc: solo trabajo en index
iloc: trabajo en posición
ix: puede obtener datos de dataframe sin que esté en el índice
en: obtener valores escalares. Es una loc muy rapida
iat: Obtener valores escalares. Es un iloc muy rapido

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

Nota: A partir de pandas 0.20.0 , el indexador .ix está en desuso en favor de los indexadores .iloc y .loc más estrictos.

Actualizado para pandas 0.20 dado que ix está en desuso. Esto demuestra no solo cómo usar loc , iloc , at , iat , set_value , sino también cómo realizar una indexación mixta basada en la posición y la etiqueta.


locbasado en etiqueta
Le permite pasar matrices de 1-D como indexadores. Las matrices pueden ser porciones (subconjuntos) del índice o columna, o pueden ser matrices booleanas que tienen la misma longitud que el índice o las columnas.

Nota especial: cuando se pasa un indexador escalar, loc puede asignar un nuevo índice o valor de columna que no existía 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 

ilocbasado en la posición
Similar a loc excepto con posiciones en lugar de valores de índice. Sin embargo, no puede asignar nuevas columnas o í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 

atlabel based
Funciona muy similar a loc para indexadores escalares. No se puede operar en indexadores de matriz. ¡Poder! Asignar nuevos índices y columnas.

La ventaja sobre loc es que esto es más rápido.
La desventaja es que no se pueden usar matrices para los 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 

iatbasado en la posición
Funciona de manera similar a iloc . No se puede trabajar en indexadores de matriz. ¡No poder! Asignar nuevos índices y columnas.

La ventaja sobre iloc es que esto es más rápido.
La desventaja es que no se pueden usar matrices para los 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_valuebasado en etiqueta
Funciona muy similar a loc para indexadores escalares. No se puede operar en indexadores de matriz. ¡Poder! Asignar nuevos índices y columnas.

Ventaja Súper rápido, porque hay muy poca sobrecarga!
Desventaja Hay muy pocos gastos generales porque los pandas no están haciendo un montón de controles de seguridad. Utilice bajo su propio riesgo . Además, esto no está destinado para 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_value with takable=Truebasado en la posición
Funciona de manera similar a iloc . No se puede trabajar en indexadores de matriz. ¡No poder! Asignar nuevos índices y columnas.

Ventaja Súper rápido, porque hay muy poca sobrecarga!
Desventaja Hay muy pocos gastos generales porque los pandas no están haciendo un montón de controles de seguridad. Utilice bajo su propio riesgo . Además, esto no está destinado para 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) 

Hay dos formas principales en que los pandas hacen selecciones de un DataFrame.

  • Por etiqueta
  • Por ubicación entera

La documentación utiliza el término posición para referirse a la ubicación de enteros . No me gusta esta terminología ya que me parece confusa. La ubicación de enteros es más descriptiva y es exactamente lo que significa .iloc . La palabra clave aquí es INTEGER : debe utilizar números enteros al seleccionar por ubicación de enteros.

Antes de mostrar el resumen, asegurémonos de que …

.ix está en desuso y es ambiguo y nunca debe usarse

Hay tres indexadores primarios para los pandas. Tenemos el operador de indexación (los corchetes [] ), .loc y .iloc . Vamos a resumirlos:

  • [] – Principalmente selecciona subconjuntos de columnas, pero también puede seleccionar filas. No se pueden seleccionar filas y columnas simultáneamente.
  • .loc : selecciona subconjuntos de filas y columnas solo por etiqueta
  • .iloc : selecciona subconjuntos de filas y columnas solo por ubicación de entero

Casi nunca uso .at o .iat ya que no agregan ninguna funcionalidad adicional y solo con un pequeño aumento de rendimiento. Desaconsejaría su uso a menos que tenga una aplicación muy sensible al tiempo. En cualquier caso, tenemos su resumen:

  • .at selecciona un solo valor escalar en el DataFrame solo por etiqueta
  • .iat selecciona un solo valor escalar en el DataFrame solo por ubicación de enteros

Además de la selección por etiqueta y ubicación de enteros, existe una selección booleana también conocida como indexación booleana .


Los ejemplos que explican .loc , .iloc , selección booleana y .at y .iat se muestran a continuación

Primero nos enfocaremos en las diferencias entre .loc y .iloc . Antes de hablar sobre las diferencias, es importante comprender que los DataFrames tienen tags que ayudan a identificar cada columna y cada fila. Echemos un vistazo a un DataFrame de muestra:

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

introduzca la descripción de la imagen aquí

Todas las palabras en negrita son las tags. Las tags, age , color , food , height , score y state se utilizan para las columnas . Las otras tags, Jane , Nick , Aaron , Penelope , Dean , Christina , Cornelia se usan como tags para las filas. En conjunto, estas tags de fila se conocen como el índice .


Las formas principales de seleccionar filas particulares en un DataFrame son con los indizadores .loc y .iloc . Cada uno de estos indexadores también se puede usar para seleccionar columnas simultáneamente, pero es más fácil concentrarse en las filas por ahora. Además, cada uno de los indexadores usa un conjunto de corchetes que siguen inmediatamente a su nombre para hacer sus selecciones.

.loc selecciona datos solo por tags

Primero hablaremos sobre el indexador .loc que solo selecciona datos por el índice o las tags de columna. En nuestro DataFrame de muestra, proporcionamos nombres significativos como valores para el índice. Muchos DataFrames no tendrán nombres significativos y, en su lugar, predeterminarán solo los números enteros de 0 a n-1, donde n es la longitud del DataFrame.

Hay tres entradas diferentes que puedes usar para .loc

  • Una cuerda
  • Una lista de cuerdas
  • Corte de notación usando cadenas como los valores de inicio y parada.

Seleccionando una sola fila con .loc con una cadena

Para seleccionar una sola fila de datos, coloque la etiqueta de índice dentro de los corchetes que siguen a .loc .

 df.loc['Penelope'] 

Esto devuelve la fila de datos como una serie.

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

Seleccionando múltiples filas con .loc con una lista de cadenas

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

Esto devuelve un DataFrame con las filas en el orden especificado en la lista:

introduzca la descripción de la imagen aquí

Seleccionando múltiples filas con .loc con notación de segmento

La notación de corte se define mediante los valores de inicio, parada y paso. Cuando se corta por etiqueta, pandas incluye el valor de parada en la devolución. Las siguientes rebanadas de Aaron a Dean, inclusive. El tamaño de su paso no está definido explícitamente, pero está predeterminado en 1.

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

introduzca la descripción de la imagen aquí

Los cortes complejos se pueden tomar de la misma manera que las listas de Python.

.iloc selecciona datos solo por ubicación de enteros

Vamos ahora a .iloc . Cada fila y columna de datos en un DataFrame tiene una ubicación entera que lo define. Esto es además de la etiqueta que se muestra visualmente en la salida. La ubicación de enteros es simplemente el número de filas / columnas desde la parte superior / izquierda que comienza en 0.

Hay tres entradas diferentes que puedes usar para .iloc

  • Un entero
  • Una lista de enteros
  • Corte de notación utilizando enteros como valores de inicio y parada.

Seleccionando una sola fila con .iloc con un entero

 df.iloc[4] 

Esto devuelve la quinta fila (ubicación de entero 4) como una serie

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

Seleccionando múltiples filas con .iloc con una lista de enteros

 df.iloc[[2, -2]] 

Esto devuelve un DataFrame de la tercera y segunda a las últimas filas:

introduzca la descripción de la imagen aquí

Seleccionando múltiples filas con .iloc con notación de corte

 df.iloc[:5:3] 

introduzca la descripción de la imagen aquí


Selección simultánea de filas y columnas con .loc y .iloc

Una excelente capacidad de ambos .loc/.iloc es su capacidad para seleccionar filas y columnas simultáneamente. En los ejemplos anteriores, todas las columnas se devolvieron de cada selección. Podemos elegir columnas con los mismos tipos de entradas que hacemos para las filas. Simplemente necesitamos separar la selección de filas y columnas con una coma .

Por ejemplo, podemos seleccionar las filas Jane y Dean con solo la altura de las columnas, la puntuación y el estado de esta manera:

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

introduzca la descripción de la imagen aquí

Esto utiliza una lista de tags para las filas y notación de división para las columnas

Naturalmente, podemos hacer operaciones similares con .iloc usando solo números enteros.

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

Selección simultánea con tags y localización de enteros.

.ix se usó para hacer selecciones simultáneamente con tags y ubicación de enteros que fue útil pero confuso y ambiguo a veces y afortunadamente ha sido desaprobado. En el caso de que necesite realizar una selección con una combinación de tags y ubicaciones de enteros, deberá realizar ambas tags de selecciones o ubicaciones de enteros.

Por ejemplo, si queremos seleccionar las filas Nick y Cornelia junto con las columnas 2 y 4, podríamos usar .loc al convertir los enteros en tags con lo siguiente:

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

O alternativamente, convierta las tags de índice en enteros con el método de índice get_loc .

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

Selección booleana

El indexador .loc también puede hacer selección booleana. Por ejemplo, si estamos interesados ​​en encontrar todas las filas en las que la edad es superior a 30 y devolver solo las columnas de food y score , podemos hacer lo siguiente:

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

Puede replicar esto con .iloc pero no puede pasarle una serie booleana. Debes convertir la serie booleana en una matriz numpy como esta:

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

Seleccionando todas las filas

Es posible usar .loc/.iloc solo para la selección de la columna. Puedes seleccionar todas las filas usando dos puntos como este:

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

introduzca la descripción de la imagen aquí


El operador de indexación, [] , puede dividir filas y columnas también, pero no simultáneamente.

La mayoría de las personas están familiarizadas con el propósito principal del operador de indexación de DataFrame, que es seleccionar columnas. Una cadena selecciona una sola columna como Serie y una lista de cadenas selecciona varias columnas como un Marco de datos.

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

Usando una lista selecciona múltiples columnas

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

introduzca la descripción de la imagen aquí

Con lo que las personas están menos familiarizadas, es que, cuando se usa la notación de sector, la selección se realiza por tags de fila o por ubicación de enteros. Esto es muy confuso y algo que casi nunca uso pero funciona.

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

introduzca la descripción de la imagen aquí

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

introduzca la descripción de la imagen aquí

La .loc/.iloc explícita de .loc/.iloc para seleccionar filas es altamente preferida. El operador de indexación solo no puede seleccionar filas y columnas simultáneamente.

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

Selección por .at y .iat

La selección con .at es casi idéntica a .loc pero solo selecciona una ‘celda’ en su DataFrame. Normalmente nos referimos a esta celda como un valor escalar. Para usar .loc , .loc una etiqueta de fila y columna separadas por una coma.

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

La selección con .iat es casi idéntica a .iloc pero solo selecciona un único valor escalar. Debe pasarle un número entero para las ubicaciones de fila y columna

 df.iat[2, 5] 'FL' 
 df = pd.DataFrame({'A':['a', 'b', 'c'], 'B':[54, 67, 89]}, index=[100, 200, 300]) df AB 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 

Empecemos con esta pequeña 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)) 

Así lo tendremos

 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 esto tenemos:

 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 

Por lo tanto, no podemos usar .iat para el subconjunto, donde debemos usar .iloc solamente.

Pero intentemos ambos para seleccionar un df más grande y verifiquemos la velocidad …

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

Así que con .loc podemos administrar subconjuntos y con .at solo un escalar, pero .at es más rápido que .loc

🙂