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

Recientemente comencé a ramificarme 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 alguna vez deba usar .loc o .iloc sobre la opción más general .ix ?
  • Entiendo que .loc , iloc , at y 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.
  • Por favor explique el razonamiento del mundo real y las mejores prácticas detrás de utilizar algo que no sea .ix .

loc: solo trabajo en el índice
iloc: trabajar en posición
ix: puede obtener datos del dataframe sin que esté en el índice
at: obtener valores escalares. Es un loc muy rápido
iat: Obtenga valores escalares. Es un iloc muy rápido

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 cómo lograr una indexación mixta posicional / basada en tags.


loclabel based
Le permite pasar matrices de 1-D como indexadores. Las matrices pueden ser divisiones (subconjuntos) del índice o columna, o pueden ser matrices booleanas de igual longitud que el índice o las columnas.

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

ilocposición basada
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 

at etiqueta basada
Funciona muy similar al loc para indexadores escalares. No se puede operar en indexadores de array. ¡Poder! asignar nuevos índices y columnas.

La ventaja sobre loc es que esto es más rápido.
La desventaja es que no puede usar arrays 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 

iatposición basada
Funciona de manera similar a iloc . No se puede trabajar en indexadores de array. ¡No poder! asignar nuevos índices y columnas.

La ventaja sobre iloc es que esto es más rápido.
La desventaja es que no puede usar arrays 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_valuelabel based
Funciona muy similar al loc para indexadores escalares. No se puede operar en indexadores de array. ¡Poder! asignar nuevos índices y columnas

Ventaja Super rápido, ¡porque hay muy poca carga!
Desventaja Hay muy pocos gastos generales porque los pandas no están haciendo un montón de controles de seguridad. Use bajo su propio riesgo . Además, esto no es 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 array. ¡No poder! asignar nuevos índices y columnas.

Ventaja Super rápido, ¡porque hay muy poca carga!
Desventaja Hay muy pocos gastos generales porque los pandas no están haciendo un montón de controles de seguridad. Use bajo su propio riesgo . Además, esto no es 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) 
 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 

Hay dos formas principales en que los pandas realizan selecciones desde un DataFrame.

  • Por etiqueta
  • Por Entero Ubicación

La documentación usa la posición del término para referirse a la ubicación entera . No me gusta esta terminología porque siento que es confusa. La ubicación del entero es más descriptiva y es exactamente lo que significa .iloc . La palabra clave aquí es INTEGER : debes usar números enteros cuando selecciones por ubicación entera.

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

.ix es obsoleto y ambiguo y nunca debe ser utilizado

Hay tres indexadores principales para pandas. Tenemos el propio 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 al mismo tiempo.
  • .loc : selecciona subconjuntos de filas y columnas solo por etiqueta
  • .iloc : selecciona subconjuntos de filas y columnas solo por la ubicación entera

Casi nunca uso .at o .iat ya que no agregan ninguna funcionalidad adicional y con solo un pequeño aumento en el rendimiento. Disuadiría su uso a menos que tengas una aplicación muy sensible al tiempo. De todos modos, tenemos su resumen:

  • .at selecciona un único valor escalar en el DataFrame solo por etiqueta
  • .iat selecciona un único valor escalar en el DataFrame solo por la ubicación entera

Además de la selección por etiqueta y ubicación entera, 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 DataFrames tiene tags que ayudan a identificar cada columna y cada fila. Echemos un vistazo a un DataFrame de ejemplo:

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

enter image description here

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


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

.loc selecciona datos solo por tags

Primero hablaremos sobre el indexador .loc que solo selecciona los datos por las tags de índice o columna. En nuestro dataframe de ejemplo, hemos proporcionado nombres significativos como valores para el índice. Muchos DataFrames no tendrán ningún nombre significativo y, en cambio, tendrán como valor predeterminado solo los enteros de 0 a n-1, donde n es la longitud del DataFrame.

Hay tres entradas diferentes que puede usar para .loc

  • Una cuerda
  • Una lista de cadenas
  • Notación de división usando cadenas como los valores de inicio y detención

Seleccionar una sola fila con .loc con una cadena

Para seleccionar una sola fila de datos, coloque la etiqueta índice dentro de los paréntesis siguientes 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 

Seleccionar 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:

enter image description here

Seleccionar múltiples filas con .loc con notación de división

La notación de división se define mediante los valores de inicio, detención y paso. Cuando se corta por etiqueta, pandas incluye el valor de detención en la devolución. Las siguientes partes de Aaron a Dean, inclusive. Su tamaño de paso no está definido explícitamente, sino que está predeterminado en 1.

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

enter image description here

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

.iloc selecciona los datos solo por la ubicación entera

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

Hay tres entradas diferentes que puede usar para .iloc

  • Un entero
  • Una lista de enteros
  • Notación de división usando números enteros como los valores de inicio y detención

Seleccionar una sola fila con .iloc con un entero

 df.iloc[4] 

Esto devuelve la 5ª fila (ubicación entera 4) como una serie

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

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

 df.iloc[[2, -2]] 

Esto devuelve un DataFrame de la tercera y la segunda a la última fila:

enter image description here

Seleccionar múltiples filas con .iloc con notación de división

 df.iloc[:5:3] 

enter image description here


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, se devolvieron todas las columnas 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 fila y columna con una coma .

Por ejemplo, podemos seleccionar las filas Jane y Dean con solo las columnas height, score y state como esta:

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

enter image description here

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

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

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

Selección simultánea con tags y ubicación entera

.ix se usó para hacer selecciones simultáneamente con tags y ubicaciones enteras, lo que fue útil pero confuso y ambiguo a veces y afortunadamente ha sido desaprobado. En el caso de que necesite hacer una selección con una combinación de tags y ubicaciones enteras, tendrá que hacer tanto las tags de selección como las ubicaciones enteras.

Por ejemplo, si queremos seleccionar las filas Nick y Cornelia junto con las columnas 2 y 4, podríamos usar .loc convirtiendo 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 una selección booleana. Por ejemplo, si estamos interesados ​​en encontrar todas las filas en las que la edad es superior a 30 y devolvimos 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 pasarlo a una serie booleana. Debe convertir la serie Boolean en una matriz numpy como esta:

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

Seleccionar todas las filas

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

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

enter image description here


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

La mayoría de las personas están familiarizadas con el objective principal del operador de indexación de DataFrame, que es seleccionar columnas. Una cadena selecciona una sola columna como una serie y una lista de cadenas selecciona múltiples columnas como un DataFrame.

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

Usar una lista selecciona múltiples columnas

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

enter image description here

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

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

enter image description here

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

enter image description here

La .loc/.iloc de .loc/.iloc para seleccionar filas es muy preferida. El operador de indexación por sí 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 sola ‘celda’ en su DataFrame. Por lo general, nos referimos a esta celda como un valor escalar. Para usar .loc , páselo por una etiqueta de fila y columna separados 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' 

Comencemos con este pequeño 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)) 

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 solo debemos usar .iloc.

Pero intentemos ambos para seleccionar de un df más grande y revisemos 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 

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

🙂