通过另一个数组中的值阈值快速计算numpy数组的元素

时间:2016-08-19 13:58:23

标签: python numpy cumulative-frequency

给定numpy阈值数组,生成满足这些值的另一个数组的计数数组的最有效方法是什么?

假设阈值数组很小并且已排序,并且要计数的值数组是大而且未排序的。

对于valueLevels的每个元素,

示例,请计算大于或等于它的values元素:

import numpy as np

n = int(1e5) # size of example

# example levels: the sequence 0, 1., 2.5, 5., 7.5, 10, 5, ... 50000, 75000
valueLevels =  np.concatenate(
                   [np.array([0.]), 
                    np.concatenate([ [ x*10**y for x in [1., 2.5, 5., 7.5] ] 
                                   for y in range(5) ] ) 
                    ]
                )

np.random.seed(123)
values = np.random.uniform(low=0, high=1e5, size=n)

到目前为止,我已经尝试了列表理解方法。

  • np.array([sum(values>=x) for x in valueLevels])慢得令人无法接受
  • np.array([len(values[values>=x]) for x in valueLevels])是一项改进
  • 排序values确实加快了理解(在本例中,从~7到0.5毫秒),但排序成本(~8毫秒)超过了一次性使用的节省

我现在最好的是理解this approach

%%timeit 
np.array([np.count_nonzero(values>=x) for x in valueLevels])
# 1000 loops, best of 3: 1.26 ms per loop

这可以为我的目的所接受,但出于好奇,

我想知道

  • 如果列表理解是要走的路,可以加速吗?或者,
  • 其他方法更快吗? (我有一种模糊的感觉,可以通过在阈值数组上广播值数组来完成,但我无法弄清楚如何使np.broadcast_arrays()的维度正确。

2 个答案:

答案 0 :(得分:4)

我到目前为止最快的是

%timeit count_nonzero(values >= atleast_2d(valueLevels).T, axis=1)
# 1000 loops, best of 3: 860 µs per loop

sum速度较慢:

%timeit sum(values >= atleast_2d(valueLevels).T, axis=1)
# 100 loops, best of 3: 2.5 ms per loop
@Divakar的版本更慢:

%timeit count_nonzero(values[:, None] >= valueLevels, axis=1)
# 100 loops, best of 3: 3.86 ms per loop

但是,我可能仍然会使用你的列表理解,这个速度并不慢,并且不会创建一个大的2D布尔数组作为中间步骤:

%timeit np.array([np.count_nonzero(values>=x) for x in valueLevels])
# 1000 loops, best of 3: 987 µs per loop

答案 1 :(得分:2)

方法#1 使用np.searchsorted -

values.size - np.searchsorted(values,valueLevels,sorter=values.argsort())

方法#2 使用NumPy broadcasting -

(values[:,None]>=valueLevels).sum(0)