Есть ли более быстрая альтернатива np.diff? - PullRequest
0 голосов
/ 25 октября 2018

Меня интересует скорость следующей функции:

def cch(tau):
    return np.sum(abs(-1*np.diff(cartprod)-tau)<0.001)

Где "cartprod" - это переменная для списка, который выглядит следующим образом:

cartprod = np.ndarray([[0.0123,0.0123],[0.0123,0.0459],...])

Длинаиз этого списка около 25 миллионов.По сути, я пытаюсь найти значительно более быстрый способ вернуть список различий для каждого списка пар в этом np.ndarray.Есть ли алгоритм или функция, которая быстрее, чем np.diff?Или np.diff конец все будет всем?Я также открыт для всего остального.

РЕДАКТИРОВАТЬ: Спасибо всем за ваши решения!

Ответы [ 3 ]

0 голосов
/ 25 октября 2018

Я думаю, что вы попали в стену, неоднократно возвращая несколько np.arrays длиной ~ 25 миллионов, а не np.diff медленным.Я написал эквивалентную функцию, которая перебирает массив и подсчитывает результаты по мере продвижения.Функция должна быть соединена с Numba, чтобы быть быстрой.Я надеюсь, что это приемлемо.

arr = np.random.rand(25000000, 2)

def cch(tau, cartprod):
    return np.sum(abs(-1*np.diff(cartprod)-tau)<0.001)
%timeit cch(0.01, arr)

@jit(nopython=True)
def cch_jit(tau, cartprod):
    count = 0
    tau = -tau
    for i in range(cartprod.shape[0]):
        count += np.less(np.abs(tau - (cartprod[i, 1]- cartprod[i, 0])), 0.001)
    return count
%timeit cch_jit(0.01, arr)

производит

294 ms ± 2.82 ms 
42.7 ms ± 483 µs 

, что примерно в 6 раз быстрее.

0 голосов
/ 28 октября 2018

Просто из любопытства я сравнил решения @Divakar numbersxpr и @alexdor numba.jit .Реализация numexpr.evaluate кажется в два раза быстрее, чем при использовании jit-компилятора numba.Результаты показаны для 100 прогонов каждый:

np.sum:          111.07543396949768
numexpr:         12.282189846038818
JIT:             6.2505223751068115
'np.sum' returns same result as 'numexpr'
'np.sum' returns same result as 'jit'
'numexpr' returns same result as 'jit'

Сценарий, поэтому воспроизведите результаты:

import numpy as np
import time
import numba
import numexpr

arr = np.random.rand(25000000, 2)
runs = 100

def cch(tau, cartprod):
    return np.sum(abs(-1*np.diff(cartprod)-tau)<0.001)

def cch_ne(tau, cartprod):
    d = {'a0':cartprod[:,0],'a1':cartprod[:,1], 'tau': tau}
    count = np.count_nonzero(numexpr.evaluate('abs(a0-a1-tau)<0.001',d))
    return count

@numba.jit(nopython=True)
def cch_jit(tau, cartprod):
    count = 0
    tau = -tau
    for i in range(cartprod.shape[0]):
        count += np.less(np.abs(tau - (cartprod[i, 1]- cartprod[i, 0])), 0.001)
    return count

start = time.time()
for x in range(runs):
    x1 = cch(0.01, arr)
print('np.sum:\t\t', time.time() - start)

start = time.time()
for x in range(runs):
    x2 = cch_ne(0.01, arr)
print('numexpr:\t', time.time() - start)

x3 = cch_jit(0.01, arr)
start = time.time()
for x in range(runs):
    x3 = cch_jit(0.01, arr)
print('JIT:\t\t', time.time() - start)

if x1 == x2: print('\'np.sum\' returns same result as \'numexpr\'')
if x1 == x3: print('\'np.sum\' returns same result as \'jit\'')
if x2 == x3: print('\'numexpr\' returns same result as \'jit\'')
0 голосов
/ 25 октября 2018

Мы можем использовать multi-core с numexpr модулем для больших данных и для повышения эффективности памяти и, следовательно, производительности с некоторой помощью от array-slicing -

import numexpr as ne

def cch_numexpr(a, tau):
    d = {'a0':a[:,0],'a1':a[:,1]}
    return np.count_nonzero(ne.evaluate('abs(a0-a1-tau)<0.001',d))

Пробный прогони время для данных размером 25M -

In [83]: cartprod = np.random.rand(25000000,2)

In [84]: cch(cartprod, tau=0.5) == cch_numexpr(cartprod, tau=0.5)
Out[84]: True

In [85]: %timeit cch(cartprod, tau=0.5)
10 loops, best of 3: 150 ms per loop

In [86]: %timeit cch_numexpr(cartprod, tau=0.5)
10 loops, best of 3: 25.5 ms per loop

Около 6x ускорение.

Это было с 8 потоками.Таким образом, с большим количеством потоков, доступных для вычислений, это должно улучшиться дальше.Related post о том, как управлять многоядерными функциями.

...