2012-06-06 10 views
30

¿Cuáles son las diferencias en el rendimiento y el comportamiento entre el uso de la función nativa sum de Python y el numpy.sum de NumPy? sum funciona en las matrices de NumPy y numpy.sum funciona en las listas de Python y ambos devuelven el mismo resultado efectivo (no han probado casos extremos como el desbordamiento) pero diferentes tipos.suma de Python contra Numpy.sum de NumPy

>>> import numpy as np 
>>> np_a = np.array(range(5)) 
>>> np_a 
array([0, 1, 2, 3, 4]) 
>>> type(np_a) 
<class 'numpy.ndarray') 

>>> py_a = list(range(5)) 
>>> py_a 
[0, 1, 2, 3, 4] 
>>> type(py_a) 
<class 'list'> 

# The numerical answer (10) is the same for the following sums: 
>>> type(np.sum(np_a)) 
<class 'numpy.int32'> 
>>> type(sum(np_a)) 
<class 'numpy.int32'> 
>>> type(np.sum(py_a)) 
<class 'numpy.int32'> 
>>> type(sum(py_a)) 
<class 'int'> 

Editar: Creo que mi pregunta práctica que aquí se podría utilizar numpy.sum en una lista de números enteros Python sea más rápido que el uso de Python propia sum?

Además, ¿cuáles son las implicaciones (incluido el rendimiento) del uso de un número entero de Python frente a un escalador numpy.int32? Por ejemplo, para a += 1, ¿existe una diferencia de comportamiento o rendimiento si el tipo de a es un número entero de Python o numpy.int32? Tengo curiosidad por saber si es más rápido usar un tipo de datos escalar NumPy como numpy.int32 para un valor que se agrega o resta mucho en el código de Python.

Para aclaración, estoy trabajando en una simulación bioinformática que consiste en parte en colapsar numpy.ndarray s multidimensional en sumas escalares individuales que luego se procesan adicionalmente. Estoy usando Python 3.2 y NumPy 1.6.

¡Gracias de antemano!

Respuesta

42

Me puse curioso y lo sincronicé. numpy.sum parece mucho más rápido para las matrices numpy, pero mucho más lento en las listas.

import numpy as np 
import timeit 

x = range(1000) 
# or 
#x = np.random.standard_normal(1000) 

def pure_sum(): 
    return sum(x) 

def numpy_sum(): 
    return np.sum(x) 

n = 10000 

t1 = timeit.timeit(pure_sum, number = n) 
print 'Pure Python Sum:', t1 
t2 = timeit.timeit(numpy_sum, number = n) 
print 'Numpy Sum:', t2 

Resultado cuando x = range(1000):

Pure Python Sum: 0.445913167735 
Numpy Sum: 8.54926219673 

Resultado cuando x = np.random.standard_normal(1000):

Pure Python Sum: 12.1442425643 
Numpy Sum: 0.303303771848 

estoy usando Python 2.7.2 y 1.6.1 Numpy

+0

+1, pero ¿no tienes estos resultados al revés? – dawg

+0

@drewk, sí, los tuve al revés. ¡Gracias por señalar esto! Fijo. – Akavall

+0

Tiene razón cuando 'np.sum' es más rápido cuando se usa' np.array'. Pero si mide 'np.sum (np.array object)' y 'sum (list object)', ambos funcionan casi por igual. – xyres

5

Numpy debe ser mucho más rápido, especialmente cuando sus datos ya son una matriz numpy.

Las matrices numeradas son una capa delgada sobre una matriz C estándar. Cuando numpy sum itera sobre esto, no está haciendo una verificación de tipo y es muy rápido. La velocidad debe ser comparable a hacer la operación usando el estándar C.

En comparación, usando la suma de python primero tiene que convertir la matriz numpy a una matriz python, y luego iterar sobre esa matriz. Tiene que hacer algún tipo de comprobación y generalmente va a ser más lento.

La cantidad exacta de python sum es más lenta que numpy sum no está bien definida ya que la suma de python va a ser una función algo optimizada en comparación con escribir su propia función de suma en python.

+5

No 'convierte' la matriz numpy - una matriz numpy ya es iterable en Python. Por otro lado, 'numpy.sum' puede tener que convertir una lista en una matriz numpy, lo que explicaría los resultados del tiempo de @ Akavall. –

+1

Independientemente de si la conversión se produce como una matriz en matriz o mediante el encasillado de elementos individuales, en algún nivel se convertirá el elemento (de/a tipos nativos), y ese fue el punto que intentaba hacer. – Claris

3

Tenga en cuenta que Python suma de Las matrices numpy multidimensionales solo realizarán una suma a lo largo del primer eje:

sum(np.array([[[2,3,4],[4,5,6]],[[7,8,9],[10,11,12]]])) 
Out[47]: 
array([[ 9, 11, 13], 
     [14, 16, 18]]) 

np.sum(np.array([[[2,3,4],[4,5,6]],[[7,8,9],[10,11,12]]]), axis=0) 
Out[48]: 
array([[ 9, 11, 13], 
     [14, 16, 18]]) 

np.sum(np.array([[[2,3,4],[4,5,6]],[[7,8,9],[10,11,12]]])) 
Out[49]: 81 
1

Esta es una extensión del answer post above by Akavall. A partir de esa respuesta, puede ver que np.sum realiza más rápido para los objetos np.array, mientras que sum realiza más rápido para los objetos list.Para ampliar eso:

En funcionamiento np.sum para np.array objeto Vs.sum para un objeto list, parece que realizan cuello a cuello.

# I'm running IPython 

In [1]: x = range(1000) # list object 

In [2]: y = np.array(x) # np.array object 

In [3]: %timeit sum(x) 
100000 loops, best of 3: 14.1 µs per loop 

In [4]: %timeit np.sum(y) 
100000 loops, best of 3: 14.3 µs per loop 

arriba, sum es un poco pequeña más rápido que np.array, aunque, a veces me he visto np.sum tiempos para ser 14.1 µs, también. Pero sobre todo, es 14.3 µs.