通过另一个数组中的值阈值快速计算 numpy 数组的元素
Fast counts of elements of numpy array by value thresholds in another array
给定一个 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()
. 获取正确的尺寸
方法 #1 使用 np.searchsorted
-
values.size - np.searchsorted(values,valueLevels,sorter=values.argsort())
方法 #2 使用 NumPy broadcasting
-
(values[:,None]>=valueLevels).sum(0)
到目前为止我最快的是
%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
给定一个 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()
. 获取正确的尺寸
方法 #1 使用 np.searchsorted
-
values.size - np.searchsorted(values,valueLevels,sorter=values.argsort())
方法 #2 使用 NumPy broadcasting
-
(values[:,None]>=valueLevels).sum(0)
到目前为止我最快的是
%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