【问题标题】:Fast counts of elements of numpy array by value thresholds in another array通过另一个数组中的值阈值快速计算 numpy 数组的元素
【发布时间】:2016-12-26 17:25:20
【问题描述】:

给定一个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() 获得正确的维度。

【问题讨论】:

    标签: python numpy cumulative-frequency


    【解决方案1】:

    目前最快的是

    %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
    

    【讨论】:

    • 很高兴知道如何使用 2D 方法,+1。在性能方面,我也没有看到决定性的差异。如果没有上级出现,我会接受这个。谢谢。
    • 是的,我错误地沿着较长的数组添加了新轴,在那里付出了代价。 count_nonzero 做得很好!
    【解决方案2】:

    方法 #1 使用 np.searchsorted -

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

    方法 #2 使用 NumPy broadcasting -

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

    【讨论】:

    • 方法 #1 每个循环需要整个 8.06 毫秒
    • 这有助于通过确定广播方法不一定更快来回答问题 -- +1
    • @TimFuchs 对一个巨大的数组进行排序也没有帮助:)
    • @C8H10N4O2 如果values 已经排序,我们将避免np.searchsorted 中的sorter,这样加速会很大。
    • @C8H10N4O2 另外,broadcasting 更快,正如@Tim 的帖子中使用atleast_2d 所做的那样。
    猜你喜欢
    • 2014-02-17
    • 1970-01-01
    • 2018-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多