是否有np.diff的更快替代品?

时间:2018-10-25 02:28:30

标签: python performance numpy time-complexity

我担心以下功能的速度:

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],...])

此列表的长度约为2500万。基本上,我正在尝试找到一种更快的方法来为该np.ndarray中的每个配对列表返回差异列表。有没有比np.diff更快的算法方式或功能?或者,np.diff结束了吗?我也欢迎其他任何人。

编辑:谢谢大家的解决方案!

3 个答案:

答案 0 :(得分:3)

array-slicing的帮助下,我们可以利用multi-core with numexpr module处理大数据并提高内存效率,从而提高性能。

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了解如何控制多核功能。

答案 1 :(得分:3)

我认为您正在通过反复返回多个长度约为2500万的np.array而不是缓慢的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倍。

答案 2 :(得分:1)

出于好奇,我比较了@Divakar numexpr和@alexdor numba.jit的解决方案。 numexpr.evaluate的实现似乎是使用numba的jit编译器的两倍。显示了每次运行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\'')