python - example - La forma más rápida de procesar numéricamente 2d-array: dataframe vs series vs array vs numba
pandas dataframe (2)
Editar para agregar : no creo que los puntos de referencia numba sean justos, notas debajo
Estoy tratando de comparar diferentes enfoques para procesar datos numéricamente para el siguiente caso de uso:
- Conjunto de datos bastante grande (más de 100.000 registros)
- Más de 100 líneas de código bastante simple (z = x + y)
- No es necesario ordenar o indexar
En otras palabras, no se necesita la generalidad completa de series y marcos de datos, aunque se incluyen aquí b / c, siguen siendo formas convenientes de encapsular los datos y, a menudo, hay un procesamiento previo o posterior que requiere la generalidad de los pandas. matrices numpy.
Pregunta : En base a este caso de uso, ¿son adecuados los siguientes puntos de referencia y, de no ser así, cómo puedo mejorarlos?
# importing pandas, numpy, Series, DataFrame in standard way
from numba import jit
nobs = 10000
nlines = 100
def proc_df():
df = DataFrame({ ''x'': np.random.randn(nobs),
''y'': np.random.randn(nobs) })
for i in range(nlines):
df[''z''] = df.x + df.y
return df.z
def proc_ser():
x = Series(np.random.randn(nobs))
y = Series(np.random.randn(nobs))
for i in range(nlines):
z = x + y
return z
def proc_arr():
x = np.random.randn(nobs)
y = np.random.randn(nobs)
for i in range(nlines):
z = x + y
return z
@jit
def proc_numba():
xx = np.random.randn(nobs)
yy = np.random.randn(nobs)
zz = np.zeros(nobs)
for j in range(nobs):
x, y = xx[j], yy[j]
for i in range(nlines):
z = x + y
zz[j] = z
return zz
Resultados (Win 7, estación de trabajo Xeon de 3 años de antigüedad (quad-core). Distribución de anaconda estándar y reciente o muy cercana).
In [1251]: %timeit proc_df()
10 loops, best of 3: 46.6 ms per loop
In [1252]: %timeit proc_ser()
100 loops, best of 3: 15.8 ms per loop
In [1253]: %timeit proc_arr()
100 loops, best of 3: 2.02 ms per loop
In [1254]: %timeit proc_numba()
1000 loops, best of 3: 1.04 ms per loop # may not be valid result (see note below)
Editar para agregar (respuesta a jeff) resultados alternativos de pasar df / series / array a funciones en lugar de crearlas dentro de funciones (es decir, mover las líneas de código que contienen ''randn'' de la función interna a la función externa):
10 loops, best of 3: 45.1 ms per loop
100 loops, best of 3: 15.1 ms per loop
1000 loops, best of 3: 1.07 ms per loop
100000 loops, best of 3: 17.9 µs per loop # may not be valid result (see note below)
Nota sobre los resultados de numba : creo que el compilador numba debe estar optimizando en el ciclo for y reduciendo el ciclo for a una única iteración. No lo sé, pero es la única explicación que puedo dar, ya que no podría ser 50 veces más rápido que numpy, ¿verdad? Pregunta de seguimiento aquí: ¿Por qué numba es más rápido que numpy aquí?
Bueno, realmente no estás cronometrando las mismas cosas aquí (o más bien, estás cronometrando diferentes aspectos).
P.ej
In [6]: x = Series(np.random.randn(nobs))
In [7]: y = Series(np.random.randn(nobs))
In [8]: %timeit x + y
10000 loops, best of 3: 131 µs per loop
In [9]: %timeit Series(np.random.randn(nobs)) + Series(np.random.randn(nobs))
1000 loops, best of 3: 1.33 ms per loop
Entonces [8] veces la operación real, mientras que [9] incluye la sobrecarga para la creación de la serie (y la generación de números aleatorios) MÁS la operación real
Otro ejemplo es proc_ser
vs proc_df
. El proc_df
incluye la sobrecarga de la asignación de una columna particular en el DataFrame (que en realidad es diferente para una creación inicial y posterior reasignación).
Entonces crea la estructura (también puedes cronometrar eso, pero eso es un problema aparte). Realice exactamente la misma operación y cítelos.
Además, dices que no necesitas alineación. Pandas te da esto de manera predeterminada (y no es una forma realmente fácil de desactivarlo, aunque es solo una simple comprobación si ya están alineados). Mientras esté en Numba, debe alinearlos ''manualmente''.
Siguiendo con la respuesta de @Jeff. El código se puede optimizar aún más.
nobs = 10000
x = pd.Series(np.random.randn(nobs))
y = pd.Series(np.random.randn(nobs))
%timeit proc_ser()
%timeit x + y
%timeit x.values + y.values
100 loops, best of 3: 11.8 ms per loop
10000 loops, best of 3: 107 µs per loop
100000 loops, best of 3: 12.3 µs per loop