python - values - pandas series from dict
Rendimiento de Pandas DataFrame (5)
Pandas es realmente genial, pero estoy realmente sorprendido de lo ineficiente que es recuperar valores de un Pandas.DataFrame. En el siguiente ejemplo de juguete, incluso el método DataFrame.iloc es más de 100 veces más lento que un diccionario.
La pregunta: ¿la lección aquí es que los diccionarios son la mejor manera de buscar valores? Sí, entiendo que eso es precisamente para lo que fueron hechos. Pero me pregunto si hay algo que me falta sobre el rendimiento de búsqueda de DataFrame.
Me doy cuenta de que esta pregunta es más "reflexionar" que "preguntar", pero aceptaré una respuesta que proporcione información o perspectiva sobre esto. Gracias.
import timeit
setup = ''''''
import numpy, pandas
df = pandas.DataFrame(numpy.zeros(shape=[10, 10]))
dictionary = df.to_dict()
''''''
f = [''value = dictionary[5][5]'', ''value = df.loc[5, 5]'', ''value = df.iloc[5, 5]'']
for func in f:
print func
print min(timeit.Timer(func, setup).repeat(3, 100000))
valor = diccionario [5] [5]
0.130625009537
value = df.loc [5, 5]
19.4681699276
value = df.iloc [5, 5]
17.2575249672
Creo que la forma más rápida de acceder a una célula es
df.get_value(row,column)
df.set_value(row,column,value)
Ambos son más rápidos que (creo)
df.iat(...)
df.at(...)
Experimenté un fenómeno diferente sobre el acceso a la fila del marco de datos. pruebe este sencillo ejemplo en el marco de datos de aproximadamente 10,000,000 de filas. diccionario de rocas.
def testRow(go):
go_dict = go.to_dict()
times = 100000
ot= time.time()
for i in range(times):
go.iloc[100,:]
nt = time.time()
print(''for iloc {}''.format(nt-ot))
ot= time.time()
for i in range(times):
go.loc[100,2]
nt = time.time()
print(''for loc {}''.format(nt-ot))
ot= time.time()
for i in range(times):
[val[100] for col,val in go_dict.iteritems()]
nt = time.time()
print(''for dict {}''.format(nt-ot))
Me encontré con el mismo problema. puedes usar at
para mejorar.
"Dado que la indexación con [] debe manejar una gran cantidad de casos (acceso de etiqueta única, segmentación, indexación boleana, etc.), tiene un poco de sobrecarga para determinar lo que está pidiendo. Si solo desea acceda a un valor escalar, la forma más rápida es usar los métodos at
e iat
, que se implementan en todas las estructuras de datos ".
vea la referencia oficial en http://pandas.pydata.org/pandas-docs/stable/indexing.html capítulo "Obtener y ajustar rápidamente el valor escalar"
Parece que la diferencia de rendimiento ahora es mucho menor (0.21.1 - Olvidé cuál era la versión de Pandas en el ejemplo original). No solo la brecha de rendimiento entre el acceso de diccionario y .loc
redujo (de aproximadamente 335 veces a 126 veces más lento), loc
( iloc
) es menos de dos veces más lenta que at
( iat
) ahora.
In [1]: import numpy, pandas
...: ...: df = pandas.DataFrame(numpy.zeros(shape=[10, 10]))
...: ...: dictionary = df.to_dict()
...:
In [2]: %timeit value = dictionary[5][5]
85.5 ns ± 0.336 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [3]: %timeit value = df.loc[5, 5]
10.8 µs ± 137 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [4]: %timeit value = df.at[5, 5]
6.87 µs ± 64.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [5]: %timeit value = df.iloc[5, 5]
14.9 µs ± 114 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [6]: %timeit value = df.iat[5, 5]
9.89 µs ± 54.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [7]: print(pandas.__version__)
0.21.1
---- Respuesta original a continuación ----
+1 para usar at
o para operaciones escalares. Ejemplo de referencia:
In [1]: import numpy, pandas
...: df = pandas.DataFrame(numpy.zeros(shape=[10, 10]))
...: dictionary = df.to_dict()
In [2]: %timeit value = dictionary[5][5]
The slowest run took 34.06 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 310 ns per loop
In [4]: %timeit value = df.loc[5, 5]
10000 loops, best of 3: 104 µs per loop
In [5]: %timeit value = df.at[5, 5]
The slowest run took 6.59 times longer than the fastest. This could mean that an intermediate result is being cached
100000 loops, best of 3: 9.26 µs per loop
In [6]: %timeit value = df.iloc[5, 5]
10000 loops, best of 3: 98.8 µs per loop
In [7]: %timeit value = df.iat[5, 5]
The slowest run took 6.67 times longer than the fastest. This could mean that an intermediate result is being cached
100000 loops, best of 3: 9.58 µs per loop
Parece que usar at
( iat
) es aproximadamente 10 veces más rápido que loc
( iloc
).
Un dict es para un DataFrame como una bicicleta para un automóvil. Puede pedalear 10 pies en una bicicleta más rápido de lo que puede arrancar un automóvil, ponerlo en marcha, etc., etc. Pero si necesita recorrer una milla, el automóvil gana.
Para ciertos propósitos pequeños y específicos, un dict puede ser más rápido. Y si eso es todo lo que necesita, ¡entonces use un dict, seguro! Pero si necesita / desea el poder y el lujo de un DataFrame, entonces un dict no es un sustituto. No tiene sentido comparar la velocidad si la estructura de datos no satisface primero sus necesidades.
Ahora, por ejemplo, para ser más concretos, un dict es bueno para acceder a las columnas, pero no es tan conveniente para acceder a las filas.
import timeit
setup = ''''''
import numpy, pandas
df = pandas.DataFrame(numpy.zeros(shape=[10, 1000]))
dictionary = df.to_dict()
''''''
# f = [''value = dictionary[5][5]'', ''value = df.loc[5, 5]'', ''value = df.iloc[5, 5]'']
f = [''value = [val[5] for col,val in dictionary.items()]'', ''value = df.loc[5]'', ''value = df.iloc[5]'']
for func in f:
print(func)
print(min(timeit.Timer(func, setup).repeat(3, 100000)))
rendimientos
value = [val[5] for col,val in dictionary.iteritems()]
25.5416321754
value = df.loc[5]
5.68071913719
value = df.iloc[5]
4.56006002426
Entonces el dictado de listas es 5 veces más lento en la recuperación de filas que df.iloc
. El déficit de velocidad aumenta a medida que crece la cantidad de columnas. (El número de columnas es como el número de pies en la analogía de la bicicleta. Cuanto más larga es la distancia, más conveniente se vuelve el automóvil ...)
Este es solo un ejemplo de cuándo un dict de listas sería menos conveniente / más lento que un DataFrame.
Otro ejemplo sería cuando tiene un DatetimeIndex para las filas y desea seleccionar todas las filas entre ciertas fechas. Con un DataFrame puedes usar
df.loc[''2000-1-1'':''2000-3-31'']
No hay una analogía fácil para eso si usaras un dict de listas. Y los bucles de Python que necesitaría utilizar para seleccionar las filas correctas volverían a ser terriblemente lentos en comparación con el DataFrame.