【问题标题】:How to threshold vectors [u,v] in a 2D numpy array?如何在二维 numpy 数组中阈值向量 [u,v]?
【发布时间】:2019-10-05 16:54:30
【问题描述】:

我写了一个阈值函数 TH(arr, threshold),它接受向量 [u,v] 的二维数组,如果 u 和 v 的绝对值都低于指定阈值,则将它们设置为 0。

该函数由 2 个 for 循环组成,可以完成这项工作,但需要大量计算(我在大型数据集上运行它)。

例子:

[u, v] --> 输出(阈值 = 1)

[2, 2] --> [2, 2]

[2, .1] --> [2, .1]

[.1,.1] --> [0, 0]

我可以使用哪些其他方法/函数来更有效地解决此问题(使用列表理解或其他方法)?

这里有一些代码:

import numpy as np
import time
start = time.time()

def TH(arr, threshold):
    for idx, value in enumerate(arr):
        for i, item in enumerate(value):
            if np.abs(item[0]) < threshold and np.abs(item[1]) < threshold:
                arr[idx][i][0] = 0.0
                arr[idx][i][1] = 0.0
    return arr

a = np.array([[[.5,.8], [3,4], [3,.1]],
              [[0,2], [.5,.5], [.3,3]],
              [[.4,.4], [.1,.1], [.5,5]]])

a = TH(a, threshold = 1)
print(a)

end = time.time()
print("Run time: ", end-start)

输出:

[[[0.  0. ]
  [3.  4. ]
  [3.  0.1]]

 [[0.  2. ]
  [0.  0. ]
  [0.3 3. ]]

 [[0.  0. ]
  [0.  0. ]
  [0.5 5. ]]]

Run time:  0.0009984970092773438

【问题讨论】:

    标签: python arrays numpy threshold


    【解决方案1】:

    简单地将沿最后一个轴的两个元素切片,并以矢量化的方式执行相同的操作以获得掩码,最后将掩码索引到输入数组中以分配0s -

    mask = (np.abs(arr[...,0]) < threshold) & (np.abs(arr[...,1]) < threshold)
    arr[mask] = 0
    

    请注意,arr[...,0] 是另一种放置 arr[:,:,0] 的方式,旨在沿最后一个轴对通用 ndarray 进行切片。同样,对于arr[...,1]

    或者,预先计算绝对值并使用它们与threshold 进行比较,并在最后一个轴上查找all 匹配以获得相同的掩码 -

    ab = np.abs(arr)
    mask = (ab < threshold).all(-1)
    

    或者,计算绝对值后使用相同的切片方法-

    mask = (ab[...,0] < threshold) & (ab[...,1] < threshold)
    

    对于大型数组,我们还可以利用numexpr module -

    import numexpr as ne
    
    m0 = ne.evaluate('abs(arr)<threshold')
    mask = m0[...,0] & m0[...,1]
    

    时间安排 -

    In [209]: arr = np.random.rand(1080,1920,2)
    
    In [210]: threshold = 1
    
    In [211]: %timeit (np.abs(arr[...,0])<threshold) & (np.abs(arr[...,1])<threshold)
    100 loops, best of 3: 10.2 ms per loop
    
    In [212]: %timeit np.abs(arr).all(1)
    10 loops, best of 3: 34.5 ms per loop
    
    In [213]: %%timeit
         ...: ab = np.abs(arr)
         ...: (ab[...,0] < threshold) & (ab[...,1] < threshold)
         ...: 
    100 loops, best of 3: 11 ms per loop
    
    In [214]: %%timeit
         ...: m0 = ne.evaluate('abs(arr)<threshold')
         ...: m0[...,0] & m0[...,1]
         ...: 
    100 loops, best of 3: 4.79 ms per loop
    

    【讨论】:

    • 到目前为止,我更新了 2 个阈值函数。以下是不同方法的执行时间(在 25 帧视频上运行): 我的方法,322.09 秒。您提出的第一种方法,28.78 秒。第二种方法,29.32 秒。第三种方法,28.36 秒。平均而言,您提出的所有解决方案似乎都比我的初始功能快 10 倍。感谢您的帮助和明确的解释!
    • @MarkH 感谢您带着这些性能数据回来!好奇 - 您正在使用的 arr 的典型形状是什么?
    • 我使用的每个数组都包含表示视频帧某些特征的数据(RGB 值、光流向量 [u,v]、幅度、角度...)。所以我的数组的形状类似于框架的大小(例如:(1080,1920,2))。在阈值和清理之后,我将好的值存储在一个数组中以训练机器学习模型。该数组具有 25 帧的形状 (51 840 000, 5)。背景:我正在研究人类行为识别。
    • @MarkH 添加了一个numexpr,它利用了多核。这可能会进一步提高性能。
    • 我测试了它,并没有发现时间上有任何差异。每个循环的时序改进是否会如此之小,以至于整体变化可以忽略不计? (10.2-4.79)ms * 25 个循环 = 135.25ms 在 25 帧上运行时快。注意:由于我使用的数学模型,我的代码中存在大约 +-0.5s 的一些差异,这可能是我看不到差异的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-21
    • 2018-05-17
    • 2020-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多