2014-01-26 3 views
4

У меня есть массив numpy, содержащий 10^8 поплавков, и вы хотите подсчитать, сколько из них> = заданный порог. Скорость имеет решающее значение, поскольку операция должна выполняться на большом количестве таких массивов. Конкурсанты до сих пор являютсяСамый быстрый способ подсчета значений массива выше порогового значения в numpy

np.sum(myarray >= thresh) 

np.size(np.where(np.reshape(myarray,-1) >= thresh)) 

Ответы на Count all values in a matrix greater than a value предполагают, что np.where() будет быстрее, но я нашел противоречивые результаты синхронизации. Я имею в виду это для некоторые реализаций и булевых условий np.size (np.where (cond)) быстрее, чем np.sum (cond), но для некоторых он медленнее.

В частности, если значительная часть записей удовлетворяет условию, то np.sum (cond) значительно быстрее, но если небольшая часть (возможно, менее десятая), то np.size (np.where (cond)) выигрывает.

вопрос распадается на 2 части:

  • Любые другие предложения?
  • Имеет ли смысл, что время np.size (np.where (cond)) увеличивается с количеством записей, для которых cond является истинным?
+0

numexpr или Numba, вероятно, может ускорить процесс, избегая создания промежуточного массива. – user2357112

+1

есть также np.count_nonzero, который намного быстрее, чем логическая сумма в новых версиях numpy. – seberg

ответ

2

Использование cython может стать достойной альтернативой.

import numpy as np 
cimport numpy as np 
cimport cython 
from cython.parallel import prange 


DTYPE_f64 = np.float64 
ctypedef np.float64_t DTYPE_f64_t 


@cython.boundscheck(False) 
@cython.wraparound(False) 
@cython.nonecheck(False) 
cdef int count_above_cython(DTYPE_f64_t [:] arr_view, DTYPE_f64_t thresh) nogil: 

    cdef int length, i, total 
    total = 0 
    length = arr_view.shape[0] 

    for i in prange(length): 
     if arr_view[i] >= thresh: 
      total += 1 

    return total 


@cython.boundscheck(False) 
@cython.wraparound(False) 
@cython.nonecheck(False) 
def count_above(np.ndarray arr, DTYPE_f64_t thresh): 

    cdef DTYPE_f64_t [:] arr_view = arr.ravel() 
    cdef int total 

    with nogil: 
     total = count_above_cython(arr_view, thresh) 
    return total 

Сроки различных предлагаемых методов.

myarr = np.random.random((1000,1000)) 
thresh = 0.33 

In [6]: %timeit count_above(myarr, thresh) 
1000 loops, best of 3: 693 µs per loop 

In [9]: %timeit np.count_nonzero(myarr >= thresh) 
100 loops, best of 3: 4.45 ms per loop 

In [11]: %timeit np.sum(myarr >= thresh) 
100 loops, best of 3: 4.86 ms per loop 

In [12]: %timeit np.size(np.where(np.reshape(myarr,-1) >= thresh)) 
10 loops, best of 3: 61.6 ms per loop 

С большим массивом:

In [13]: myarr = np.random.random(10**8) 

In [14]: %timeit count_above(myarr, thresh) 
10 loops, best of 3: 63.4 ms per loop 

In [15]: %timeit np.count_nonzero(myarr >= thresh) 
1 loops, best of 3: 473 ms per loop 

In [16]: %timeit np.sum(myarr >= thresh) 
1 loops, best of 3: 511 ms per loop 

In [17]: %timeit np.size(np.where(np.reshape(myarr,-1) >= thresh)) 
1 loops, best of 3: 6.07 s per loop 
+0

Я предполагаю, что это будет зависеть от аппаратного обеспечения, а на cython вы можете легко распараллелить. С -O3 в cython (без его медленного) и разработки numpy на моем компьютере они выполняются почти одинаково (небольшой край для cython, но код numpy намного быстрее с несмежными массивами, хотя вы можете это исправить). Однако вы действительно должны использовать 'ssize_t' /' np.intp_t' и * not * int, что является ошибкой в ​​противном случае. – seberg

Смежные вопросы