¿Cómo iterar sobre filas en un DataFrame en Pandas?

1954

Tengo un DataFramepandas:

import pandas as pd
inp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}]
df = pd.DataFrame(inp)
print df

Salida:

   c1   c2
0  10  100
1  11  110
2  12  120

Ahora quiero iterar sobre las filas de este marco. Para cada fila quiero poder acceder a sus elementos (valores en celdas) por el nombre de las columnas. Por ejemplo:

for row in df.rows:
   print row['c1'], row['c2']

¿Es posible hacer eso en pandas?

Encontré esta pregunta similar . Pero no me da la respuesta que necesito. Por ejemplo, se sugiere usar allí:

for date, row in df.T.iteritems():

o

for row in df.iterrows():

Pero no entiendo qué es el rowobjeto y cómo puedo trabajar con él.

romano
fuente
11
Df.iteritems () itera sobre columnas y no filas. Por lo tanto, para hacerlo iterar sobre filas, debe transponer (la "T"), lo que significa que cambia las filas y las columnas entre sí (se refleja en diagonal). Como resultado, efectivamente itera el marco de datos original sobre sus filas cuando usa df.T.iteritems ()
Stefan Gruenwald
12
Si eres nuevo en este hilo y eres un principiante en los pandas, ¡NO LO INTERESES! La iteración sobre marcos de datos es un antipatrón, y es algo que no debe hacer a menos que quiera acostumbrarse a esperar mucho. Dependiendo de lo que intente hacer, posiblemente haya alternativas mucho mejores . iter*Las funciones deben utilizarse en circunstancias muy raras. También relacionado .
cs95
19
A diferencia de lo que dice cs95, existen razones perfectamente válidas para querer iterar sobre un marco de datos, por lo que los nuevos usuarios no deben sentirse desanimados. Un ejemplo es si desea ejecutar algún código utilizando los valores de cada fila como entrada. Además, si su marco de datos es razonablemente pequeño (por ejemplo, menos de 1000 elementos), el rendimiento no es realmente un problema.
oulenz
1
@oulenz: si por alguna extraña razón quieres evitar usar la API para el propósito para el que fue diseñada (transformaciones de datos de alto rendimiento), entonces sé mi invitado. Pero, al menos, no lo use iterrows, hay mejores formas de iterar sobre un DataFrame, también podría iterar sobre una lista de listas en ese punto. Si está en el punto en el que no está haciendo nada más que iterar sobre DataFrames, realmente no hay ningún beneficio en usar un DataFrame (suponiendo que iterar sobre él es lo único que está haciendo con él). Solo mi 2c.
cs95
8
Yo segundo @oulenz. Por lo que puedo decir pandases la elección de leer un archivo csv, incluso si el conjunto de datos es pequeño. Simplemente es más fácil programar manipular los datos con las API
Chris

Respuestas:

2640

DataFrame.iterrows es un generador que produce tanto índice como fila

import pandas as pd
import numpy as np

df = pd.DataFrame([{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}])

for index, row in df.iterrows():
    print(row['c1'], row['c2'])

Output: 
   10 100
   11 110
   12 120
waitingkuo
fuente
207
Nota: "Debido a que iterrows devuelve una Serie para cada fila, no conserva los tipos de letra en las filas". Además, "Nunca debe modificar algo sobre lo que está iterando". Según pandas 0.19.1 docs
viddik13
3
@ viddik13 esa es una gran nota gracias. Debido a eso, me encontré con un caso donde los valores numéricos como 431341610650donde se lee como 4.31E+11. ¿Hay alguna forma de preservar los tipos?
Aziz Alto
26
@AzizAlto uso itertuples, como se explica a continuación. Ver también pandas.pydata.org/pandas-docs/stable/generated/…
Axel
101
No use las flechas. Itertuples es más rápido y conserva el tipo de datos. Más información
James L.
11
De la documentación : "Iterar a través de objetos pandas es generalmente lento. En muchos casos, no es necesario iterar manualmente sobre las filas [...]". Su respuesta es correcta (en el contexto de la pregunta) pero no menciona esto en ninguna parte, por lo que no es muy buena.
cs95
464

¿Cómo iterar sobre filas en un DataFrame en Pandas?

Respuesta: NO HACER * !

La iteración en los pandas es un antipatrón, y es algo que solo debe hacer cuando haya agotado todas las demás opciones. No debe usar ninguna función con " iter" en su nombre durante más de unos pocos miles de filas o tendrá que acostumbrarse a muchas esperas.

¿Quieres imprimir un DataFrame? Uso DataFrame.to_string().

¿Quieres calcular algo? En ese caso, busque métodos en este orden (lista modificada desde aquí ):

  1. Vectorización
  2. Rutinas de Cython
  3. Lista de comprensiones ( forbucle de vainilla )
  4. DataFrame.apply(): i) Reducciones que se pueden realizar en cython, ii) Iteración en el espacio python
  5. DataFrame.itertuples() y iteritems()
  6. DataFrame.iterrows()

iterrowsy itertuples(ambos reciben muchos votos en respuestas a esta pregunta) deben usarse en circunstancias muy raras, como generar objetos de fila / tuplas de nombre para procesamiento secuencial, que es realmente lo único para lo que estas funciones son útiles.

Apelar a la autoridad
La página de documentos en la iteración tiene un enorme cuadro rojo de advertencia que dice:

Iterar a través de objetos de pandas es generalmente lento. En muchos casos, no es necesario iterar manualmente sobre las filas [...].

* En realidad es un poco más complicado que "no". df.iterrows()es la respuesta correcta a esta pregunta, pero "vectorizar sus operaciones" es la mejor. Reconoceré que hay circunstancias en las que no se puede evitar la iteración (por ejemplo, algunas operaciones en las que el resultado depende del valor calculado para la fila anterior). Sin embargo, se necesita cierta familiaridad con la biblioteca para saber cuándo. Si no está seguro de si necesita una solución iterativa, probablemente no. PD: Para saber más sobre mi justificación para escribir esta respuesta, salte al final.


Más rápido que el bucle: vectorización , Cython

Una buena cantidad de operaciones y cálculos básicos son "vectorizados" por pandas (ya sea a través de NumPy o mediante funciones Cythonized). Esto incluye aritmética, comparaciones, (la mayoría) reducciones, remodelación (como pivotar), uniones y operaciones grupales. Consulte la documentación sobre la funcionalidad básica esencial para encontrar un método vectorizado adecuado para su problema.

Si no existe ninguno, siéntase libre de escribir el suyo usando extensiones de cython personalizadas .


Siguiente mejor cosa: Lista de comprensiones *

La lista de comprensiones debe ser su próximo puerto de escala si 1) no hay una solución vectorizada disponible, 2) el rendimiento es importante, pero no lo suficientemente importante como para pasar por la molestia de cifrar su código, y 3) está tratando de realizar una transformación de elementos en tu código Hay una buena cantidad de evidencia que sugiere que las comprensiones de listas son lo suficientemente rápidas (e incluso a veces más rápidas) para muchas tareas comunes de pandas.

La formula es simple,

# iterating over one column - `f` is some function that processes your data
result = [f(x) for x in df['col']]
# iterating over two columns, use `zip`
result = [f(x, y) for x, y in zip(df['col1'], df['col2'])]
# iterating over multiple columns - same data type
result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].to_numpy()]
# iterating over multiple columns - differing data type
result = [f(row[0], ..., row[n]) for row in zip(df['col1'], ..., df['coln'])]

Si puede encapsular su lógica de negocios en una función, puede usar una comprensión de lista que la llame. Puede hacer que las cosas arbitrariamente complejas funcionen a través de la simplicidad y la velocidad de Python sin procesar.

Las
comprensiones de la lista de advertencias suponen que es fácil trabajar con sus datos; lo que eso significa es que sus tipos de datos son consistentes y no tiene NaN, pero esto no siempre se puede garantizar.

  1. El primero es más obvio, pero cuando se trata de NaNs, prefiera los métodos pandas incorporados si existen (porque tienen una lógica de manejo de casos de esquina mucho mejor), o asegúrese de que su lógica comercial incluya la lógica de manejo de NaN adecuada.
  2. Cuando se trata de tipos de datos mixtos, debe repetir en zip(df['A'], df['B'], ...)lugar de hacerlo, df[['A', 'B']].to_numpy()ya que este último implícitamente eleva los datos al tipo más común. Como ejemplo, si A es numérico y B es una cadena, to_numpy()convertirá toda la matriz en una cadena, que puede no ser lo que desea. Afortunadamente, hacer zipping en las columnas es la solución más sencilla para esto.

* YMMV por los motivos descritos en la sección Advertencias anterior.


Un ejemplo obvio

Demostremos la diferencia con un ejemplo simple de agregar dos columnas de pandas A + B. Esta es una operación vectorizable, por lo que será fácil contrastar el rendimiento de los métodos discutidos anteriormente.

ingrese la descripción de la imagen aquí

Código de evaluación comparativa, para su referencia.

Sin embargo, debo mencionar que no siempre es así de seco. A veces, la respuesta a "cuál es el mejor método para una operación" es "depende de sus datos". Mi consejo es probar diferentes enfoques en sus datos antes de decidirse por uno.


Otras lecturas

* Los métodos de cadena de pandas están "vectorizados" en el sentido de que se especifican en la serie pero operan en cada elemento. Los mecanismos subyacentes siguen siendo iterativos, porque las operaciones de cadena son inherentemente difíciles de vectorizar.


¿Por qué escribí esta respuesta?

Una tendencia común que noto de los nuevos usuarios es hacer preguntas de la forma "¿cómo puedo iterar sobre mi df para hacer X?". Mostrando código que llama iterrows()mientras hace algo dentro de un bucle for. Aquí es por qué. Un nuevo usuario de la biblioteca que no haya sido introducido al concepto de vectorización probablemente visualizará el código que resuelve su problema al iterar sobre sus datos para hacer algo. Sin saber cómo iterar sobre un DataFrame, lo primero que hacen es buscarlo en Google y terminar aquí, en esta pregunta. Luego ven la respuesta aceptada que les dice cómo hacerlo, y cierran los ojos y ejecutan este código sin preguntarse primero si la iteración no es lo correcto.

El objetivo de esta respuesta es ayudar a los nuevos usuarios a comprender que la iteración no es necesariamente la solución a cada problema, y ​​que podrían existir soluciones mejores, más rápidas y más idiomáticas, y que vale la pena invertir tiempo en explorarlas. No estoy tratando de comenzar una guerra de iteración contra vectorización, pero quiero que los nuevos usuarios estén informados cuando desarrollen soluciones a sus problemas con esta biblioteca.

cs95
fuente
24
Esta es la única respuesta que se centra en las técnicas idiomáticas que uno debe usar con los pandas, por lo que es la mejor respuesta para esta pregunta. Aprender a obtener la respuesta correcta con el código correcto (en lugar de la respuesta correcta con el código incorrecto , es decir, ineficiente, no escala, demasiado adecuado para datos específicos) es una gran parte del aprendizaje de los pandas (y los datos en general).
LinkBerest
3
Sin embargo, creo que estás siendo injusto con el ciclo for, ya que son solo un poco más lentos que la comprensión de la lista en mis pruebas. El truco es hacer un bucle en zip(df['A'], df['B'])lugar de df.iterrows().
Noche imperecedera
2
@ImperishableNight Nada en absoluto; El objetivo de esta publicación no es denunciar la iteración en general, sino denunciar específicamente el uso de la iterrows()iteración y denunciarla de forma implícita siempre que existan mejores alternativas. forlos bucles por sí solos están bien, pero las comprensiones de listas son mejores si realiza transformaciones iterativas por elementos.
cs95
1
@sdbbs que hay, use sort_values ​​para ordenar sus datos, luego llame a to_string () en el resultado.
cs95
1
En Lista de comprensiones, el ejemplo de "iterar sobre varias columnas" necesita una advertencia: DataFrame.valuesconvertirá cada columna a un tipo de datos común. DataFrame.to_numpy()hace esto también Afortunadamente podemos usar zipcon cualquier cantidad de columnas.
David Wasserman
397

Primero considere si realmente necesita iterar sobre filas en un DataFrame. Vea esta respuesta para alternativas.

Si aún necesita iterar sobre filas, puede usar los métodos a continuación. Tenga en cuenta algunas advertencias importantes que no se mencionan en ninguna de las otras respuestas.

itertuples() se supone que es más rápido que iterrows()

Pero tenga en cuenta, de acuerdo con los documentos (pandas 0.24.2 en este momento):

  • Iterrows: dtypepodría no coincidir de fila a fila

    Debido a que iterrows devuelve una serie para cada fila, no conserva los tipos de letra en las filas (los tipos de letra se conservan en las columnas para los marcos de datos). Para conservar los tipos de letra mientras se itera sobre las filas, es mejor usar itertuples () que devuelve las denominadas tuplas de los valores y que generalmente es mucho más rápido que iterrows ()

  • Iterrows: no modifique filas

    Nunca debe modificar algo sobre lo que está iterando. No se garantiza que funcione en todos los casos. Dependiendo de los tipos de datos, el iterador devuelve una copia y no una vista, y escribir en él no tendrá efecto.

    Utilice DataFrame.apply () en su lugar:

    new_df = df.apply(lambda x: x * 2)
  • itertuples:

    Los nombres de las columnas se renombrarán a nombres posicionales si son identificadores de Python no válidos, se repiten o comienzan con un guión bajo. Con una gran cantidad de columnas (> 255), se devuelven tuplas regulares.

Vea los documentos de pandas en iteración para más detalles.

viddik13
fuente
44
Solo una pequeña pregunta de alguien que lee este hilo tanto tiempo después de su finalización: ¿cómo se compara df.apply () con itertuples en términos de eficiencia?
Raul Guarini
44
Nota: también puede decir algo como for row in df[['c1','c2']].itertuples(index=True, name=None):incluir solo ciertas columnas en el iterador de fila.
Brian Burns
12
En lugar de getattr(row, "c1"), puedes usar solo row.c1.
viraptor
1
Estoy aproximadamente 90% seguro de que si usa en getattr(row, "c1")lugar de row.c1, pierde cualquier ventaja de rendimiento de itertuples, y si realmente necesita llegar a la propiedad a través de una cadena, debe usar iterrows en su lugar.
Noctiphobia
3
Me he topado con esta pregunta porque, aunque sabía que había dividir-aplicar-combinar, todavía necesitaba iterar sobre un DataFrame (como dice la pregunta). No todos tienen el lujo de mejorar numbay cython(los mismos documentos dicen que "siempre vale la pena optimizar en Python primero"). Escribí esta respuesta para ayudar a otros a evitar problemas (a veces frustrantes) ya que ninguna de las otras respuestas menciona estas advertencias. Engañar a alguien o decir "eso es lo correcto" nunca fue mi intención. He mejorado la respuesta.
viddik13
201

Deberías usar df.iterrows() . Aunque iterar fila por fila no es especialmente eficiente ya que los Seriesobjetos tienen que ser creados.

Wes McKinney
fuente
12
¿Es esto más rápido que convertir el DataFrame en una matriz numpy (a través de valores.) Y operar directamente en la matriz? Tengo el mismo problema, pero terminé convirtiéndome en una matriz numpy y luego usando cython.
vgoklani
12
@vgoklani Si iterar fila por fila es ineficiente y tiene una matriz numpy que no es objeto, entonces seguramente usar la matriz numpy sin procesar será más rápido, especialmente para matrices con muchas filas. debe evitar iterar sobre las filas a menos que sea absolutamente necesario
Phillip Cloud
77
He realizado algunas pruebas sobre el consumo de tiempo para df.iterrows (), df.itertuples () y zip (df ['a'], df ['b']) y publiqué el resultado en la respuesta de otro pregunta: stackoverflow.com/a/34311080/2142098
Richard Wong
154

Si bien iterrows()es una buena opción, a veces itertuples()puede ser mucho más rápido:

df = pd.DataFrame({'a': randn(1000), 'b': randn(1000),'N': randint(100, 1000, (1000)), 'x': 'x'})

%timeit [row.a * 2 for idx, row in df.iterrows()]
# => 10 loops, best of 3: 50.3 ms per loop

%timeit [row[1] * 2 for row in df.itertuples()]
# => 1000 loops, best of 3: 541 µs per loop
e9t
fuente
55
Gran parte de la diferencia horaria en sus dos ejemplos parece deberse al hecho de que parece estar usando indexación basada en etiquetas para el comando .iterrows () e indexación basada en enteros para el comando .itertuples ().
Alex
2
Para un marco de datos basado en datos financieros (marca de tiempo y flotante 4x), el itertuples es 19,57 veces más rápido que el de mi máquina. Solo for a,b,c in izip(df["a"],df["b"],df["c"]:es casi igual de rápido.
Harbun
77
¿Puedes explicar por qué es más rápido?
Abe Miessler
44
@AbeMiessler iterrows()encajona cada fila de datos en una Serie, mientras itertuples()que no.
miradulo
3
Tenga en cuenta que el orden de las columnas es en realidad indeterminado, ya que dfse crea a partir de un diccionario, por lo que row[1]podría referirse a cualquiera de las columnas. Resulta que los tiempos son más o menos los mismos para el entero frente a las columnas flotantes.
Brian Burns, el
88

También puedes usar df.apply() para iterar sobre filas y acceder a múltiples columnas para una función.

docs: DataFrame.apply ()

def valuation_formula(x, y):
    return x * y * 0.5

df['price'] = df.apply(lambda row: valuation_formula(row['x'], row['y']), axis=1)
bastardo descarado
fuente
¿El df ['precio'] se refiere al nombre de una columna en el marco de datos? Estoy tratando de crear un diccionario con valores únicos de varias columnas en un archivo csv. Utilicé su lógica para crear un diccionario con claves y valores únicos y obtuve un error que indica TypeError: ("los objetos 'Series' son mutables, por lo tanto no se pueden descifrar", u'currió en el índice 0 ')
SRS
Código: df ['Workclass'] = df.apply (fila lambda: dic_update (fila), axis = 1) final de línea id = 0 final de línea def dic_update (fila): si la fila no está en dic: dic [fila] = id id = id + 1
SRS
No importa, lo tengo. Cambió la línea de llamada de función a df_new = df ['Workclass']. Apply (lo mismo)
SRS
2
Tener el eje predeterminado en 0 es lo peor
zthomas.nc
99
Tenga en cuenta que applyno se "itera" sobre las filas, sino que aplica una función en fila. El código anterior no funcionaría si realmente haces iteraciones necesidad y Indices de, por ejemplo, al comparar los valores a través de diferentes filas (en ese caso se puede hacer nada más que la iteración).
Gented
82

Puede usar la función df.iloc de la siguiente manera:

for i in range(0, len(df)):
    print df.iloc[i]['c1'], df.iloc[i]['c2']
PJay
fuente
1
Sé que uno debe evitar esto a favor de las flechas o itertuplas, pero sería interesante saber por qué. ¿Alguna idea?
rocarvaj
12
Esta es la única técnica válida que conozco si desea preservar los tipos de datos y también hacer referencia a las columnas por su nombre. itertuplesconserva los tipos de datos, pero elimina cualquier nombre que no le guste. iterrowshace lo contrario
Ken Williams
66
Pasé horas tratando de atravesar las idiosincrasias de las estructuras de datos de los pandas para hacer algo simple Y expresivo. Esto da como resultado un código legible.
Sean Anderson el
Si bien for i in range(df.shape[0])puede acelerar este enfoque un poco, todavía es aproximadamente 3.5 veces más lento que el enfoque iterrows () anterior para mi aplicación.
Kim Miller
En grandes Datafrmes esto parece mejor ya que my_iter = df.itertuples()toma el doble de memoria y mucho tiempo para copiarlo. mismo para iterrows().
Bastiaan
33

Estaba buscando Cómo iterar en filas Y columnas y terminé aquí, así:

for i, row in df.iterrows():
    for j, column in row.iteritems():
        print(column)
Lucas B
fuente
18

Puedes escribir tu propio iterador que implemente namedtuple

from collections import namedtuple

def myiter(d, cols=None):
    if cols is None:
        v = d.values.tolist()
        cols = d.columns.values.tolist()
    else:
        j = [d.columns.get_loc(c) for c in cols]
        v = d.values[:, j].tolist()

    n = namedtuple('MyTuple', cols)

    for line in iter(v):
        yield n(*line)

Esto es directamente comparable a pd.DataFrame.itertuples. Mi objetivo es realizar la misma tarea con más eficiencia.


Para el marco de datos dado con mi función:

list(myiter(df))

[MyTuple(c1=10, c2=100), MyTuple(c1=11, c2=110), MyTuple(c1=12, c2=120)]

O con pd.DataFrame.itertuples:

list(df.itertuples(index=False))

[Pandas(c1=10, c2=100), Pandas(c1=11, c2=110), Pandas(c1=12, c2=120)]

Una prueba completa
Probamos hacer que todas las columnas estén disponibles y subconjunto de las columnas.

def iterfullA(d):
    return list(myiter(d))

def iterfullB(d):
    return list(d.itertuples(index=False))

def itersubA(d):
    return list(myiter(d, ['col3', 'col4', 'col5', 'col6', 'col7']))

def itersubB(d):
    return list(d[['col3', 'col4', 'col5', 'col6', 'col7']].itertuples(index=False))

res = pd.DataFrame(
    index=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
    columns='iterfullA iterfullB itersubA itersubB'.split(),
    dtype=float
)

for i in res.index:
    d = pd.DataFrame(np.random.randint(10, size=(i, 10))).add_prefix('col')
    for j in res.columns:
        stmt = '{}(d)'.format(j)
        setp = 'from __main__ import d, {}'.format(j)
        res.at[i, j] = timeit(stmt, setp, number=100)

res.groupby(res.columns.str[4:-1], axis=1).plot(loglog=True);

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

piRSquared
fuente
2
Para las personas que no quieren leer el código: la línea azul es intertuples, la línea naranja es una lista de un iterador a través de un bloque de rendimiento. interrowsNo se compara.
James L.
18

¿Cómo iterar eficientemente?

Si realmente tiene que iterar un marco de datos de pandas, probablemente querrá evitar usar iterrows () . Existen diferentes métodos y lo habitual iterrows()está lejos de ser el mejor. itertuples () puede ser 100 veces más rápido.

En breve:

  • Como regla general, use df.itertuples(name=None). En particular, cuando tiene un número fijo de columnas y menos de 255 columnas. Ver punto (3)
  • De lo contrario, use df.itertuples()excepto si sus columnas tienen caracteres especiales como espacios o '-'. Ver punto (2)
  • Es posible usarlo itertuples()incluso si su marco de datos tiene columnas extrañas usando el último ejemplo. Ver punto (4)
  • Solo use iterrows()si no puede las soluciones anteriores. Ver punto (1)

Diferentes métodos para iterar sobre filas en un marco de datos de pandas:

Genere un marco de datos aleatorio con un millón de filas y 4 columnas:

    df = pd.DataFrame(np.random.randint(0, 100, size=(1000000, 4)), columns=list('ABCD'))
    print(df)

1) Lo habitual iterrows()es conveniente pero muy lento:

start_time = time.clock()
result = 0
for _, row in df.iterrows():
    result += max(row['B'], row['C'])

total_elapsed_time = round(time.clock() - start_time, 2)
print("1. Iterrows done in {} seconds, result = {}".format(total_elapsed_time, result))

2) El valor predeterminado itertuples()ya es mucho más rápido, pero no funciona con nombres de columna como My Col-Name is very Strange(debe evitar este método si sus columnas se repiten o si el nombre de una columna no se puede convertir simplemente en un nombre de variable de Python):

start_time = time.clock()
result = 0
for row in df.itertuples(index=False):
    result += max(row.B, row.C)

total_elapsed_time = round(time.clock() - start_time, 2)
print("2. Named Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

3) El valor predeterminado itertuples()usando name = None es aún más rápido pero realmente no es conveniente ya que debe definir una variable por columna.

start_time = time.clock()
result = 0
for(_, col1, col2, col3, col4) in df.itertuples(name=None):
    result += max(col2, col3)

total_elapsed_time = round(time.clock() - start_time, 2)
print("3. Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

4) Finalmente, el nombre itertuples()es más lento que el punto anterior, pero no tiene que definir una variable por columna y funciona con nombres de columna como My Col-Name is very Strange.

start_time = time.clock()
result = 0
for row in df.itertuples(index=False):
    result += max(row[df.columns.get_loc('B')], row[df.columns.get_loc('C')])

total_elapsed_time = round(time.clock() - start_time, 2)
print("4. Polyvalent Itertuples working even with special characters in the column name done in {} seconds, result = {}".format(total_elapsed_time, result))

Salida:

         A   B   C   D
0       41  63  42  23
1       54   9  24  65
2       15  34  10   9
3       39  94  82  97
4        4  88  79  54
...     ..  ..  ..  ..
999995  48  27   4  25
999996  16  51  34  28
999997   1  39  61  14
999998  66  51  27  70
999999  51  53  47  99

[1000000 rows x 4 columns]

1. Iterrows done in 104.96 seconds, result = 66151519
2. Named Itertuples done in 1.26 seconds, result = 66151519
3. Itertuples done in 0.94 seconds, result = 66151519
4. Polyvalent Itertuples working even with special characters in the column name done in 2.94 seconds, result = 66151519

Este artículo es una comparación muy interesante entre iterrows e itertuples

Romain Capron
fuente
14

Para recorrer todas las filas en un dataframepuede usar:

for x in range(len(date_example.index)):
    print date_example['Date'].iloc[x]
CONvid19
fuente
1
Esto es indexación encadenada. No recomiendo hacer esto.
cs95
@ cs95 ¿Qué recomendarías en su lugar?
CONvid19
Si desea que esto funcione, llame a df.columns.get_loc para obtener la posición del índice entero de la columna de fecha (fuera del ciclo), luego use una sola llamada de indexación iloc dentro.
cs95
14
 for ind in df.index:
     print df['c1'][ind], df['c2'][ind]
Grag2015
fuente
1
¿Cómo es el rendimiento de esta opción cuando se usa en un marco de datos grande (millones de filas, por ejemplo)?
Bazyli Debowski
Honestamente, no sé exactamente, creo que en comparación con la mejor respuesta, el tiempo transcurrido será casi el mismo, porque ambos casos usan la construcción "para". Pero la memoria puede ser diferente en algunos casos.
Grag2015
44
Esto es indexación encadenada. ¡No uses esto!
cs95
7

A veces un patrón útil es:

# Borrowing @KutalmisB df example
df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])
# The to_dict call results in a list of dicts
# where each row_dict is a dictionary with k:v pairs of columns:value for that row
for row_dict in df.to_dict(orient='records'):
    print(row_dict)

Lo que resulta en:

{'col1':1.0, 'col2':0.1}
{'col1':2.0, 'col2':0.2}
Zach
fuente
6

Para bucle todas las filas de una dataframey de uso de los valores de cada fila convenientemente , namedtuplespueden ser convertidos a ndarrays. Por ejemplo:

df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])

Iterando sobre las filas:

for row in df.itertuples(index=False, name='Pandas'):
    print np.asarray(row)

resultados en:

[ 1.   0.1]
[ 2.   0.2]

Tenga en cuenta que si index=True, se añade el índice como el primer elemento de la tupla , que puede ser indeseable para algunas aplicaciones.

Ingeniero libre de herpes
fuente
5

Hay una forma de iterar filas de lanzamiento mientras se obtiene un DataFrame a cambio, y no una Serie. No veo que nadie mencione que puede pasar el índice como una lista para que la fila se devuelva como un Marco de datos:

for i in range(len(df)):
    row = df.iloc[[i]]

Tenga en cuenta el uso de corchetes dobles. Esto devuelve un DataFrame con una sola fila.

Zeitgeist
fuente
Esto fue muy útil para obtener la enésima fila más grande en un marco de datos después de la ordenación. ¡Gracias!
Jason Harrison, el
3

Para ver y modificar valores, usaría iterrows(). En un bucle for y usando el desempaquetado de tuplas (vea el ejemplo:) i, row, uso rowsolo para ver el valor y lo uso icon el locmétodo cuando quiero modificar los valores. Como se indicó en respuestas anteriores, aquí no debe modificar algo sobre lo que está iterando.

for i, row in df.iterrows():
    df_column_A = df.loc[i, 'A']
    if df_column_A == 'Old_Value':
        df_column_A = 'New_value'  

Aquí, rowen el bucle hay una copia de esa fila, y no una vista de ella. Por lo tanto, NO debe escribir algo como row['A'] = 'New_Value', no modificará el DataFrame. Sin embargo, puede usar iy locespecificar DataFrame para hacer el trabajo.

Hossein
fuente
2

Sé que llego tarde a la parte que responde, pero solo quería agregar a la respuesta de @ cs95 anterior, que creo que debería ser la respuesta aceptada. En su respuesta, muestra que la vectorización de pandas supera ampliamente a otros métodos de pandas para calcular cosas con marcos de datos.

Quería agregar que si primero convierte el marco de datos en una matriz numpy y luego usa la vectorización, es aún más rápido que la vectorización de marco de datos pandas (y eso incluye el tiempo para volver a convertirlo en una serie de marco de datos).

Si agrega las siguientes funciones al código de referencia de @ cs95, esto se vuelve bastante evidente:

def np_vectorization(df):
    np_arr = df.to_numpy()
    return pd.Series(np_arr[:,0] + np_arr[:,1], index=df.index)

def just_np_vectorization(df):
    np_arr = df.to_numpy()
    return np_arr[:,0] + np_arr[:,1]

ingrese la descripción de la imagen aquí

repelente de insectos
fuente
1

También puede hacer numpyindexación para acelerar aún más. Realmente no está iterando, pero funciona mucho mejor que la iteración para ciertas aplicaciones.

subset = row['c1'][0:5]
all = row['c1'][:]

También es posible que desee convertirlo en una matriz. Se supone que estos índices / selecciones ya deben actuar como matrices de Numpy, pero me encontré con problemas y necesitaba emitir

np.asarray(all)
imgs[:] = cv2.resize(imgs[:], (224,224) ) #resize every image in an hdf5 file
James L.
fuente
1

Hay tantas formas de iterar sobre las filas en el marco de datos de pandas. Una forma muy simple e intuitiva es:

df=pd.DataFrame({'A':[1,2,3], 'B':[4,5,6],'C':[7,8,9]})
print(df)
for i in range(df.shape[0]):
    # For printing the second column
    print(df.iloc[i,1])
    # For printing more than one columns
    print(df.iloc[i,[0,2]])
shubham ranjan
fuente
0

Este ejemplo usa iloc para aislar cada dígito en el marco de datos.

import pandas as pd

 a = [1, 2, 3, 4]
 b = [5, 6, 7, 8]

 mjr = pd.DataFrame({'a':a, 'b':b})

 size = mjr.shape

 for i in range(size[0]):
     for j in range(size[1]):
         print(mjr.iloc[i, j])
mjr2000
fuente
0

Algunas bibliotecas (por ejemplo, una biblioteca de interoperabilidad de Java que uso) requieren que los valores se pasen en una fila a la vez, por ejemplo, si se transmiten datos. Para replicar la naturaleza de transmisión, 'transmito' mis valores de trama de datos uno por uno, escribí lo siguiente, que es útil de vez en cuando.

class DataFrameReader:
  def __init__(self, df):
    self._df = df
    self._row = None
    self._columns = df.columns.tolist()
    self.reset()
    self.row_index = 0

  def __getattr__(self, key):
    return self.__getitem__(key)

  def read(self) -> bool:
    self._row = next(self._iterator, None)
    self.row_index += 1
    return self._row is not None

  def columns(self):
    return self._columns

  def reset(self) -> None:
    self._iterator = self._df.itertuples()

  def get_index(self):
    return self._row[0]

  def index(self):
    return self._row[0]

  def to_dict(self, columns: List[str] = None):
    return self.row(columns=columns)

  def tolist(self, cols) -> List[object]:
    return [self.__getitem__(c) for c in cols]

  def row(self, columns: List[str] = None) -> Dict[str, object]:
    cols = set(self._columns if columns is None else columns)
    return {c : self.__getitem__(c) for c in self._columns if c in cols}

  def __getitem__(self, key) -> object:
    # the df index of the row is at index 0
    try:
        if type(key) is list:
            ix = [self._columns.index(key) + 1 for k in key]
        else:
            ix = self._columns.index(key) + 1
        return self._row[ix]
    except BaseException as e:
        return None

  def __next__(self) -> 'DataFrameReader':
    if self.read():
        return self
    else:
        raise StopIteration

  def __iter__(self) -> 'DataFrameReader':
    return self

Que se puede usar:

for row in DataFrameReader(df):
  print(row.my_column_name)
  print(row.to_dict())
  print(row['my_column_name'])
  print(row.tolist())

Y conserva la asignación de valores / nombres para las filas que se iteran. Obviamente, es mucho más lento que usar apply y Cython como se indicó anteriormente, pero es necesario en algunas circunstancias.

morganics
fuente
0

En breve

  • Use vectorización si es posible
  • Si la operación no se puede vectorizar, use las comprensiones de la lista
  • Si necesita un solo objeto que represente una fila completa, use itertuples
  • Si lo anterior es demasiado lento, intente más rápido.
  • Si todavía es demasiado lento, pruebe la rutina Cython

Detalles en este video

Punto de referencia Punto de referencia de iteración sobre filas en un marco de datos de pandas

artoby
fuente