2012-06-06 17 views
30

Jakie są różnice w wydajności i zachowaniu między używaniem natywnej funkcji Pythona sum a NumPy's numpy.sum? sum działa na tablicach NumPy i numpy.sum działa na listach Pythona i zwracają one ten sam efektywny wynik (nie testowały przypadków brzegowych, takich jak przepełnienie), ale różne typy.Suma Pythona kontra NumPy's numpy.sum

>>> 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'> 

Edit: Myślę, że moje pytanie jest tu praktyczne byłoby korzystania numpy.sum na liście liczb Python być szybciej niż przy użyciu własnego sum Python?

Dodatkowo, jakie są implikacje (w tym wydajność) używania liczby całkowitej Python versus skalar numpy.int32? Na przykład dla parametru a += 1 występuje różnica w zachowaniu lub wydajności, jeśli typ a jest liczbą całkowitą Python lub numpy.int32? Jestem ciekawy, czy jest to szybsze użycie skalarnego typu danych NumPy, takiego jak numpy.int32 dla wartości, która jest dodawana lub odejmowana w kodzie Pythona.

Dla wyjaśnienia, pracuję nad symulacją bioinformatyczną, która częściowo składa się z zapadających wielowymiarowych numpy.ndarray s na pojedyncze sumy skalarne, które są następnie przetwarzane dodatkowo. Używam Python 3.2 i NumPy 1.6.

Z góry dziękuję!

Odpowiedz

42

Byłem ciekawy i zaplanowałem to. numpy.sum wydaje się znacznie szybsze dla numpy tablic, ale znacznie wolniej na listach.

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 

Wynik kiedy x = range(1000):

Pure Python Sum: 0.445913167735 
Numpy Sum: 8.54926219673 

Wynik kiedy x = np.random.standard_normal(1000):

Pure Python Sum: 12.1442425643 
Numpy Sum: 0.303303771848 

Używam Python 2.7.2 i 1.6.1 Numpy

+0

+1, ale czy nie masz tych wyników wstecz? – dawg

+0

@drewk, Tak, miałem je od tyłu. Dziękujemy za zwrócenie na to uwagi! Naprawiony. – Akavall

+0

Masz rację, że 'np.sum' jest szybszy, gdy używasz' np.array'. Ale jeśli wybierzesz 'np.sum (np.array object)' i 'sum (obiekt listy)', oba wykonają prawie jednakowo. – xyres

5

Numpy powinien być znacznie szybszy, szczególnie gdy dane są już tablicą numpy.

Macierze Numpy to cienka warstwa na standardowej macierzy C. Gdy numpy sum iteruje nad tym, to nie robi sprawdzania typu i jest bardzo szybki. Prędkość powinna być porównywalna do wykonywania operacji przy użyciu standardowego C.

Dla porównania, przy użyciu sumy Pythona musi najpierw przekonwertować tablicę numpy do tablicy Pythona, a następnie iterować po tej tablicy. Musi przeprowadzić pewne sprawdzenie i generalnie będzie wolniej.

Dokładna kwota, którą suma Pythona jest wolniejsza niż suma numpy, nie jest dobrze zdefiniowana, ponieważ suma Pythona będzie nieco zoptymalizowana w porównaniu z pisaniem własnej funkcji sumowania w pythonie.

+5

Nie "konwertuje" tablicy numpy - tablica numpy jest już możliwa do sprawdzenia w Pythonie. Z drugiej strony, 'numpy.sum' może wymagać przekonwertowania listy na tablicę numpy, która wyjaśniałaby czasy synchronizacji @Akavall. –

+1

Bez względu na to, czy konwersja występuje jako tablica do tablicy, czy przez typowanie poszczególnych elementów, to na pewnym poziomie będzie konwertowanie elementu (z/na typy natywne), i to było celem, który próbowałem wprowadzić. – Claris

3

pamiętać, że suma na Python wielowymiarowe tablice numpy wykonają tylko sumę wzdłuż pierwszej osi:

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

Jest to rozszerzenie do answer post above by Akavall. Z tej odpowiedzi można zobaczyć, że np.sum działa szybciej dla obiektów np.array, natomiast sum wykonuje szybciej dla obiektów list.Aby rozwinąć:

Po uruchomieniu np.sum dla obiektu Vs.sum dla obiektu list, wydaje się, że wykonują od szyi do szyi.

# 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 

Powyżej sum jest malutki nieco szybciej niż np.array, choć czasami widziałem np.sum czasy się 14.1 µs też. Ale najczęściej jest to 14.3 µs.