Posterior a consultar con especialistas en esta materia, programadores de diversas ramas y maestros dimos con la respuesta al dilema y la dejamos plasmada en esta publicación.
Solución:
DataFrame.iterrows
es un generador que produce tanto el índice como la fila (como una serie):
import pandas as pd
df = pd.DataFrame('c1': [10, 11, 12], 'c2': [100, 110, 120])
for index, row in df.iterrows():
print(row['c1'], row['c2'])
10 100
11 110
12 120
¿Cómo iterar sobre filas en un DataFrame en Pandas?
Respuesta: NO*!
La iteración en Pandas es un anti-patrón y es algo que solo debe hacer cuando haya agotado todas las demás opciones. No debe utilizar ninguna función con “iter
“en su nombre durante más de unos pocos miles de filas o tendrá que acostumbrarse a un lote de esperar.
¿Quieres imprimir un DataFrame? Usar DataFrame.to_string()
.
¿Quieres calcular algo? En ese caso, busque métodos en este orden (lista modificada desde aquí):
- Vectorización
- Rutinas de Cython
- Lista de comprensiones (vainilla
for
círculo) DataFrame.apply()
: i) Reducciones que se pueden realizar en Cython, ii) Iteración en el espacio PythonDataFrame.itertuples()
yiteritems()
DataFrame.iterrows()
iterrows
y itertuples
(ambos reciben muchos votos en las respuestas a esta pregunta) deben usarse en circunstancias muy raras, como generar objetos de fila / nombres de tuplas para el procesamiento secuencial, que es realmente para lo único que son útiles estas funciones.
Apelar a la autoridad
La página de documentación sobre la iteración tiene un enorme cuadro de advertencia rojo que dice:
La iteración a través de los objetos pandas suele ser lenta. 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 algo de familiaridad con la biblioteca para saber cuándo. Si no está seguro de si necesita una solución iterativa, probablemente no la necesite. PD: Para saber más sobre mi razón de ser para escribir esta respuesta, vaya al final.
Más rápido que el bucle: vectorización, Cython
Un buen número de operaciones y cálculos básicos son “vectorizados” por pandas (ya sea mediante NumPy o mediante funciones Cythonized). Esto incluye aritmética, comparaciones, (la mayoría) de reducciones, remodelación (como pivotar), uniones y operaciones de grupo. Consulte la documentación sobre la funcionalidad básica esencial para encontrar un método vectorizado adecuado para su problema.
Si no existe ninguno, no dude en escribir el suyo propio utilizando extensiones Cython personalizadas.
Siguiente mejor cosa: comprensiones de listas*
Las listas por comprensión deberían 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 cythonizar su código, y 3) está tratando de realizar una transformación de elementos en su código. Existe 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 fórmula 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 empresarial en una función, puede usar una lista de comprensión que la llame. Puede hacer que cosas arbitrariamente complejas funcionen a través de la simplicidad y la velocidad del código Python sin procesar.
Advertencias
Las listas por comprensión asumen 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.
- El primero es más obvio, pero cuando se trata de NaN, prefiera los métodos pandas integrados si existen (porque tienen una lógica de manejo de casos de esquina mucho mejor), o asegúrese de que su lógica empresarial incluya la lógica de manejo de NaN adecuada.
- Al tratar con mixed tipos de datos sobre los que debe iterar
zip(df['A'], df['B'], ...)
en lugar dedf[['A', 'B']].to_numpy()
ya que este último eleva implícitamente los datos al tipo más común. Como ejemplo, si A es numérico y B es string,to_numpy()
echará todo el array para string, que puede no ser lo que quieres. Afortunadamentezip
Hacer ping sus columnas juntas es la solución más sencilla para esto.
* Su millaje puede variar por las razones descritas en el Advertencias sección 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 desempeño de los métodos discutidos anteriormente.
Código de evaluación comparativa, para su referencia. La línea en la parte inferior mide una función escrita en numpandas, un estilo de Pandas que se mezcla fuertemente con NumPy para exprimir el máximo rendimiento. Se debe evitar escribir código numpandas a menos que sepa lo que está haciendo. Apéguese a la API donde pueda (es decir, prefiera vec
sobre vec_numpy
).
Debo mencionar, sin embargo, 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 sobre sus datos antes de decidirse por uno.
Otras lecturas
-
10 minutos para pandas y funcionalidad básica esencial: enlaces útiles que le presentan Pandas y su biblioteca de funciones vectorizadas * / cythonizadas.
-
Mejora del rendimiento: una introducción a la documentación sobre cómo mejorar las operaciones estándar de Pandas.
-
¿Los bucles for en pandas son realmente malos? ¿Cuándo debería importarme? – un escrito detallado por mí sobre las listas por comprensión y su idoneidad para varias operaciones (principalmente aquellas que involucran datos no numéricos)
-
¿Cuándo debería (no) querer usar pandas apply () en mi código? –
apply
es lento (pero no tan lento como eliter*
familia. Sin embargo, hay situaciones en las que uno puede (o debe) considerarapply
como una alternativa seria, especialmente en algunosGroupBy
operaciones).
* Pandas string los métodos son “vectorizados” en el sentido de que se especifican en la serie pero operan en cada elemento. Los mecanismos subyacentes siguen siendo iterativos, porque string Las operaciones son intrínsecamente difíciles de vectorizar.
Por qué escribí esta respuesta
Una tendencia común que noto de los nuevos usuarios es hacer preguntas del tipo “¿Cómo puedo iterar sobre mi gl para hacer X?”. Mostrando código que llama iterrows()
mientras haces algo dentro de un for
círculo. He aquí por qué. Es probable que un nuevo usuario de la biblioteca que no haya sido introducido en el concepto de vectorización visualice el código que resuelve su problema iterando sobre sus datos para hacer algo. Sin saber cómo iterar sobre un DataFrame, lo primero que hacen es buscar en Google y terminar aquí, en esta pregunta. Luego ven la respuesta aceptada que les dice cómo hacerlo, cierran los ojos y ejecutan este código sin siquiera 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 todos los problemas, 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 iniciar una guerra de iteración versus vectorización, pero quiero que los nuevos usuarios estén informados cuando desarrollen soluciones a sus problemas con esta biblioteca.
Primero considere si realmente necesita iterar sobre filas en un DataFrame. Consulte esta respuesta para conocer las alternativas.
Si aún necesita iterar sobre las filas, puede usar los métodos a continuación. Nota algunos advertencias importantes que no se mencionan en ninguna de las otras respuestas.
-
DataFrame.iterrows ()
for index, row in df.iterrows(): print(row["c1"], row["c2"])
-
DataFrame.itertuples ()
for row in df.itertuples(index=True, name='Pandas'): print(row.c1, row.c2)
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:
dtype
puede que no coincida de una fila a otraComo iterrows devuelve una serie para cada fila, no conserva dtypes en las filas (los dtypes se conservan en las columnas para DataFrames). Para preservar dtypes mientras se itera sobre las filas, es mejor usar itertuples () que devuelve las tuplas con nombre de los valores y que generalmente es mucho más rápido que iterrows ()
-
iterrows: no modificar filas
Debería nunca modificar algo sobre lo que estás iterando. No se garantiza que esto 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á ningún efecto.
Utilice DataFrame.apply () en su lugar:
new_df = df.apply(lambda x: x * 2)
-
itertuples:
Se cambiará el nombre de los nombres de las columnas 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.
Consulte los documentos de pandas sobre la iteración para obtener más detalles.
Comentarios y calificaciones
Eres capaz de apoyar nuestra faena exponiendo un comentario y puntuándolo te damos las gracias.