El uso de la indexación booleana con datos de muestra funcionó bien, pero a medida que aumenté el tamaño de los datos, el tiempo de cálculo se está exponencialmente largo (ejemplo a continuación). ¿Alguien sabe una manera de aumentar la velocidad de ese indexador booleano en particular?
import pandas as pd
import numpy as np
a = pd.date_range('2019-01-01', '2019-12-31',freq = '1T')
b = np.random.normal(size = len(a), loc = 50)
c = pd.DataFrame(index = a, data = b, columns = ['price'])
1500 filas:
z = c.head(1500)
z[z.index.map(lambda x : 8 <= x.hour <= 16 ) & z.index.map(lambda x : x.weekday() < 5 )]
CPU times: user 149 ms, sys: 8.71 ms, total: 158 ms Wall time: 157 ms
5000 filas:
z = c.head(5000)
z[z.index.map(lambda x : 8 <= x.hour <= 16 ) & z.index.map(lambda x : x.weekday() < 5 )]
CPU times: user 14.1 s, sys: 9.07 s, total: 23.2 s Wall time: 23.2 s
Intenté con z = c.head(10000)
, pero me está tomando más de 15 minutos calcular, así que paré ... El tamaño de los datos en los que quiero usar ese indexador es de aproximadamente 30000 filas.
2 respuestas
La razón por la que esto no funciona rápido es porque realiza una asignación con una expresión lambda
, lo que significa que para cada elemento, se realizará una llamada a la función. Por lo general, esta no es una buena idea si desea procesar datos en forma masiva. Puede acelerar esto con:
hour = z.index.hour
z[(8 <= hour) & (hour <= 16) & (z.index.weekday < 5)]
Con z = c
(un total de 524'161 filas), obtenemos los siguientes tiempos:
>>> z = c
>>> timeit(lambda: z[(8 <= z.index.hour) & (z.index.hour <= 16) & (z.index.weekday < 5)], number=100)
11.825318349001464
Entonces esto se ejecuta en un total de ~ 118 milisegundos por ejecución.
Cuando usamos las primeras 5'000 filas, obtenemos:
>>> z = c.head(5000)
>>> timeit(lambda: z[(8 <= z.index.hour) & (z.index.hour <= 16) & (z.index.weekday < 5)], number=100)
0.1542488380218856
Entonces esto se ejecuta en 1.5 milisegundos por ejecución.
Tanto z.index.map(lambda x : 8 <= x.hour <= 16)
como z.index.map(lambda x: x.weekday() < 5)
se ejecutan casi al instante. El problema ocurre cuando los combina con el operador bit a bit y &
.
Pd.Index.map devuelve otro objeto pd.Index. Y el operador &
en los objetos Index realmente establece la intersección; no es "elemento sabio y". Si observa el resultado, verá que no es lo que espera, es 5000 True
s. La razón por la que está tardando tanto es que estas comparaciones devuelven valores booleanos que, por supuesto, están duplicados y la intersección del índice falla en esa situación.
La forma correcta de manejar esto es, por supuesto, utilizando operaciones vectorizadas, pero si de alguna manera necesita comparar elementos de dos objetos pd.Index, puede hacerlo convirtiéndolos en matrices numpy:
res1 = z.index.map(lambda x : 8 <= x.hour <= 16 ).to_numpy()
res2 = z.index.map(lambda x : x.weekday() < 5 ).to_numpy()
z[res1 & res2]
Preguntas relacionadas
Nuevas preguntas
python
Python es un lenguaje de programación multipropósito, de tipificación dinámica y de múltiples paradigmas. Está diseñado para ser rápido de aprender, comprender y usar, y hacer cumplir una sintaxis limpia y uniforme. Tenga en cuenta que Python 2 está oficialmente fuera de soporte a partir del 01-01-2020. Aún así, para preguntas de Python específicas de la versión, agregue la etiqueta [python-2.7] o [python-3.x]. Cuando utilice una variante de Python (por ejemplo, Jython, PyPy) o una biblioteca (por ejemplo, Pandas y NumPy), inclúyala en las etiquetas.