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

Tengo un DataFrame de pandas:

 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. Por 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 los pandas?

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

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

o

 for row in df.iterrows(): 

Pero no entiendo qué es el objeto de la row y cómo puedo trabajar con él.

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

 for index, row in df.iterrows(): print(row['c1'], row['c2']) Output: 10 100 11 110 12 120 

Para recorrer la fila de DataFrame en pandas, se puede usar:

  • 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 getattr(row, "c1"), getattr(row, "c2") 

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

Pero tenga en cuenta, según los documentos (pandas 0.21.1 en este momento):

  • iterrows: dtype podría no coincidir de una fila a otra

    Debido a que iterrows devuelve una Serie para cada fila, no conserva los tipos a lo largo de las filas (los tipos se conservan en las columnas para DataFrames).

  • iterrows: no modificar filas

    Nunca debes modificar algo sobre lo que estás iterando. Esto no está garantizado para trabajar en todos los casos. Dependiendo de los tipos de datos, el iterador devuelve una copia y no una vista, y la escritura no tendrá efecto.

    Utilice DataFrame.apply () en su lugar:

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

    Los nombres de las columnas serán renombrados a nombres posicionales si son identificadores de Python no válidos, se repiten o comienzan con un guión bajo. Con un gran número de columnas (> 255), se devuelven las tuplas normales.

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 

También puede usar df.apply() para iterar sobre filas y acceder a varias 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) 

Puede utilizar 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'] 

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

 for i, row in df.iterrows(): for j, column in row.iteritems(): print(column) 

Utilice itertuples () . Es más rápido que iterrows () :

 for row in df.itertuples(): print "c1 :",row.c1,"c2 :",row.c2 

Puedes escribir tu propio iterador que implementa 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 objective es realizar la misma tarea con más eficiencia.


Para el dataframe 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 subcontratar 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); 

introduzca la descripción de la imagen aquí

introduzca la descripción de la imagen aquí

Para hacer un bucle de todas las filas en un dataframe puede usar:

 for x in range(len(date_example.index)): print date_example['Date'].iloc[x] 

En mi humilde opinión, la decisión más simple

  for ind in df.index: print df['c1'][ind], df['c2'][ind] 

Para hacer un bucle de todas las filas en un dataframe y usar los valores de cada fila de manera conveniente , las namedtuples se pueden convertir a ndarray s 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 , el índice se agrega como el primer elemento de la tupla , lo que puede ser indeseable para algunas aplicaciones.

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

No lo hagas

La iteración en pandas es un anti-patrón, y es algo que solo deberías querer hacer cuando hayas agotado todas las opciones posibles. No debe considerar el uso de ninguna función con ” iter ” en su nombre para nada más que unos pocos miles de filas o tendrá que acostumbrarse a esperar mucho .

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

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

  1. Vectorización
  2. Rutinas de cython
  3. List Comprehensions ( for bucle)
  4. DataFrame.apply()
    yo. Reducciones que se pueden realizar en cython.
    ii. Iteración en el espacio python.
  5. DataFrame.itertuples() e iteritems()
  6. DataFrame.iterrows()

iterrows e itertuples (ambos reciben muchos votos en las respuestas a esta pregunta) deben usarse en circunstancias muy raras, como generar objetos de fila / nombres para el procesamiento secuencial, en el que estas funciones son buenas.

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

Iterar a través de los objetos pandas es generalmente lento. En muchos casos, la iteración manual sobre las filas no es necesaria […].


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 a través de NumPy, o mediante funciones Cythonized). Esto incluye aritmética, comparaciones, (la mayoría) reducciones, remodelación (como el giro), 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, siéntase libre de escribir su propio uso de extensiones de cython personalizadas.


La mejor cosa siguiente: Lista de comprensión

Si está iterando porque no hay una solución vectorizada disponible, y el rendimiento es importante (pero no lo suficientemente importante como para resolver el problema de la citonización de su código) use una lista de comprensión, como la siguiente opción mejor / más simple.

Para iterar sobre filas usando una sola columna, use

 result = [f(x) for x in df['col']] 

Para iterar sobre filas usando varias columnas, puede usar

 # two column format result = [f(x, y) for x, y in zip(df['col1'], df['col2'])] # many column format result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].values] 

Si necesita un índice de fila de enteros mientras está iterando, use enumerate :

 result = [f(...) for i, row in enumerate(df[...].values)] 

(donde df.index[i] obtiene la etiqueta de índice).

Si puede convertirlo en una función, puede usar la comprensión de lista. Puede hacer que las cosas complejas y arbitrarias funcionen a través de la simplicidad y la velocidad de Python en bruto.

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} 

¿Por qué complicar las cosas?

Sencillo.

 import pandas as pd import numpy as np # Here is an example dataframe df_existing = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD')) 

 for idx,row in df_existing.iterrows(): print row['A'],row['B'],row['C'],row['D'] 

También puedes hacer indexación numpy para incluso mayores aceleraciones. No es realmente iterador, 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. Estos índices / selecciones se supone que actúan como matrices Numpy ya, pero me encontré con problemas y era necesario emitir

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

Hay tantas formas de iterar sobre las filas en el dataframe de pandas. Una forma muy sencilla 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]]) 

Este ejemplo utiliza iloc para aislar cada dígito en el dataframe.

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

Tanto para ver como para modificar valores, usaría iterrows() . En un bucle for y utilizando el desempaquetado de tuplas (vea el ejemplo: i, row ), uso la row solo para ver el valor y uso i con el método loc cuando quiero modificar los valores. Como se indicó en las respuestas anteriores, aquí no debe modificar algo sobre lo que está iterando.

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

Aquí la row en el bucle es una copia de esa fila, y no una vista de ella. Por lo tanto, NO debe escribir algo como la row['A'] = 'New_Value' , no modificará el DataFrame. Sin embargo, puede usar i y loc y especificar el dataframe para realizar el trabajo.