Saltar al contenido

¿Cuál es la forma más eficiente de recorrer los marcos de datos con pandas?

Solución:

Las versiones más recientes de pandas ahora incluyen una función incorporada para iterar sobre filas.

for index, row in df.iterrows():

    # do some logic here

O, si lo desea, úselo más rápido itertuples()

Pero, la sugerencia de unutbu de usar funciones numpy para evitar iterar sobre filas producirá el código más rápido.

Pandas se basa en matrices NumPy. La clave para acelerar con las matrices NumPy es realizar sus operaciones en toda la matriz a la vez, nunca fila por fila o elemento por elemento.

Por ejemplo, si close es una matriz 1-d, y desea el cambio porcentual diario,

pct_change = close[1:]/close[:-1]

Esto calcula la matriz completa de cambios porcentuales como una declaración, en lugar de

pct_change = []
for row in close:
    pct_change.append(...)

Así que intenta evitar el bucle de Python for i, row in enumerate(...) por completo, y piense en cómo realizar sus cálculos con operaciones en toda la matriz (o marco de datos) como un todo, en lugar de fila por fila.

Como se mencionó anteriormente, el objeto pandas es más eficiente cuando procesa toda la matriz a la vez. Sin embargo, para aquellos que realmente necesitan recorrer un DataFrame de pandas para realizar algo, como yo, encontré al menos tres formas de hacerlo. He hecho una pequeña prueba para ver cuál de los tres consume menos tiempo.

t = pd.DataFrame({'a': range(0, 10000), 'b': range(10000, 20000)})
B = []
C = []
A = time.time()
for i,r in t.iterrows():
    C.append((r['a'], r['b']))
B.append(time.time()-A)

C = []
A = time.time()
for ir in t.itertuples():
    C.append((ir[1], ir[2]))    
B.append(time.time()-A)

C = []
A = time.time()
for r in zip(t['a'], t['b']):
    C.append((r[0], r[1]))
B.append(time.time()-A)

print B

Resultado:

[0.5639059543609619, 0.017839908599853516, 0.005645036697387695]

Probablemente esta no sea la mejor manera de medir el consumo de tiempo, pero es rápido para mí.

Aquí hay algunos pros y contras en mi humilde opinión:

  • .iterrows (): devuelve elementos de índice y fila en variables separadas, pero significativamente más lento
  • .itertuples (): más rápido que .iterrows (), pero devuelve el índice junto con los elementos de la fila, ir[0] es el índice
  • zip: el más rápido, pero sin acceso al índice de la fila

EDITAR 10/11/2020

Por lo que vale, aquí hay un punto de referencia actualizado con algunas otras alternativas (rendimiento con MacBookPro 2,4 GHz Intel Core i9 8 núcleos 32 Go 2667 MHz DDR4)

import sys
import tqdm
import time
import pandas as pd

B = []
t = pd.DataFrame({'a': range(0, 10000), 'b': range(10000, 20000)})
for _ in tqdm.tqdm(range(10)):
    C = []
    A = time.time()
    for i,r in t.iterrows():
        C.append((r['a'], r['b']))
    B.append({"method": "iterrows", "time": time.time()-A})

    C = []
    A = time.time()
    for ir in t.itertuples():
        C.append((ir[1], ir[2]))
    B.append({"method": "itertuples", "time": time.time()-A})

    C = []
    A = time.time()
    for r in zip(t['a'], t['b']):
        C.append((r[0], r[1]))
    B.append({"method": "zip", "time": time.time()-A})

    C = []
    A = time.time()
    for r in zip(*t.to_dict("list").values()):
        C.append((r[0], r[1]))
    B.append({"method": "zip + to_dict('list')", "time": time.time()-A})

    C = []
    A = time.time()
    for r in t.to_dict("records"):
        C.append((r["a"], r["b"]))
    B.append({"method": "to_dict('records')", "time": time.time()-A})

    A = time.time()
    t.agg(tuple, axis=1).tolist()
    B.append({"method": "agg", "time": time.time()-A})

    A = time.time()
    t.apply(tuple, axis=1).tolist()
    B.append({"method": "apply", "time": time.time()-A})

print(f'Python {sys.version} on {sys.platform}')
print(f"Pandas version {pd.__version__}")
print(
    pd.DataFrame(B).groupby("method").agg(["mean", "std"]).xs("time", axis=1).sort_values("mean")
)

## Output

Python 3.7.9 (default, Oct 13 2020, 10:58:24) 
[Clang 12.0.0 (clang-1200.0.32.2)] on darwin
Pandas version 1.1.4
                           mean       std
method                                   
zip + to_dict('list')  0.002353  0.000168
zip                    0.003381  0.000250
itertuples             0.007659  0.000728
to_dict('records')     0.025838  0.001458
agg                    0.066391  0.007044
apply                  0.067753  0.006997
iterrows               0.647215  0.019600
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *