Tengo una 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. 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 objeto row y cómo puedo trabajar con él.

1754
Roman 10 may. 2013 a las 11:04

18 respuestas

La mejor respuesta

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
2347
cs95 21 jun. 2019 a las 03:26

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']
75
PJay 7 nov. 2016 a las 09:09

Para ver y modificar valores, usaría iterrows(). En un bucle for y usando el desempaquetado de tuplas (vea el ejemplo: i, row), uso el row para ver solo 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í el row en el bucle es 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 i y loc y especificar el DataFrame para hacer el trabajo.

3
Hossein 27 feb. 2019 a las 00:35

Debe usar df.iterrows(). Aunque iterar fila por fila no es especialmente eficiente ya que se deben crear Series objetos.

194
cs95 11 dic. 2019 a las 18:42

Puede escribir su 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 todas las columnas 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);

enter image description here

enter image description here

17
piRSquared 7 nov. 2017 a las 04:29

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
146
e9t 1 jun. 2016 a las 09:00

Para recorrer todas las filas en un dataframe puedes usar:

for x in range(len(date_example.index)):
    print date_example['Date'].iloc[x]
13
Pedro Lobito 4 abr. 2017 a las 20:46

Para recorrer todas las filas en un dataframe y usar valores de cada fila convenientemente , namedtuples se puede convertir en 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.

6
Herpes Free Engineer 24 abr. 2018 a las 08:48

También puede hacer indexación numpy 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 lanzar

np.asarray(all)
imgs[:] = cv2.resize(imgs[:], (224,224) ) #resize every image in an hdf5 file
1
James L. 1 dic. 2017 a las 18:22

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

Respuesta: ¡NO!

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 un lote de espera.

¿Quieres imprimir un DataFrame? Utilice 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 (ciclo vainilla for)
  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()

iterrows y 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 el procesamiento secuencial, que en realidad es lo único que estas funciones son útil para.

Llamamiento a la autoridad
La página de documentos en la iteración tiene un enorme recuadro 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 [...].


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 en 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.


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 para sugerir esa lista de comprensiones son lo suficientemente rápidos (e incluso a veces más rápidos) 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
result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].values]

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.


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.

enter image description here

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.


Referencias

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

292
d-cubed 31 dic. 2019 a las 16:16

Hay una manera de iterar a través de filas 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 DataFrame:

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.

5
Zeitgeist 17 oct. 2019 a las 15:26

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]])
1
shubham ranjan 19 ene. 2019 a las 06:53

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}
6
cs95 13 abr. 2019 a las 23:06

Algunas bibliotecas (por ejemplo, una biblioteca de interoperabilidad 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 la 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.

0
morganics 10 dic. 2019 a las 09:36

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)
30
Lucas B 17 ene. 2018 a las 09:41

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])
0
mjr2000 16 mar. 2019 a las 22:33

También puede 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)
85
cheekybastard 1 jun. 2015 a las 06:24
 for ind in df.index:
     print df['c1'][ind], df['c2'][ind]
14
cs95 7 may. 2019 a las 06:37
16476924