【问题标题】:Intervaled argmax for a NumPy array with intervals defined by another arrayNumPy 数组的间隔 argmax,间隔由另一个数组定义
【发布时间】:2017-10-11 21:13:39
【问题描述】:

我有一个排序的非唯一数字的一维数组。他们重复的次数是随机的。 它与具有相同大小的权重数组相关联。对于给定的一系列相同元素,相关的一系列权重可能也可能有重复元素,也可能没有重复元素,并且在整个权重数组中,可能有也可能没有重复元素。例如:

pos     = np.array([3, 3, 7, 7, 9, 9, 9, 10, 10])
weights = np.array([2, 10, 20, 8, 5, 7, 15, 7, 2])

我需要提取pos 的唯一元素数组,但其中唯一元素是权重最大的元素。

我想出的工作解决方案涉及循环:

pos     = np.array([3, 3, 7, 7, 9, 9, 9, 10, 10])
weights = np.array([2, 10, 20, 8, 5, 7, 15, 7, 2])
# Get the number of occurences of the elements in pos but throw away the unique array, it's not the one I want.
_, ucounts = np.unique(pos, return_counts=True)
# Initialize the output array.
unique_pos_idx = np.zeros([ucounts.size], dtype=np.uint32)

last = 0
for i in range(ucounts.size):
    maxpos = np.argmax( weights[last:last+ucounts[i]] )
    unique_pos_idx[i] = last + maxpos
    last += ucounts[i]

# Result is:
# unique_pos_idx = [1 2 6 7]

但我没有使用太多 Python 语言或 Numpy(除了使用 numpy 数组),所以我想知道是否有比上述 Cython 版本更 Pythonesque 和/或更有效的解决方案?

谢谢

【问题讨论】:

    标签: arrays numpy unique extraction weighted


    【解决方案1】:

    这是一种矢量化方法 -

    sidx = np.lexsort([weights,pos])
    out = sidx[np.r_[np.flatnonzero(pos[1:] != pos[:-1]), -1]]
    

    可能的性能改进 -

    1] 使用scaling 获取排序索引sidx 的更快方法-

    sidx = (pos*(weights.max()+1) + weights).argsort()
    

    2] 使用boolean-indexing 可以加快最后的索引,特别是在处理许多这样的间隔/分组时 -

    out = sidx[np.concatenate((pos[1:] != pos[:-1], [True]))]
    

    运行时测试

    所有方法:

    def org_app(pos, weights):
        _, ucounts = np.unique(pos, return_counts=True)
        unique_pos_idx = np.zeros([ucounts.size], dtype=np.uint32)    
        last = 0
        for i in range(ucounts.size):
            maxpos = np.argmax( weights[last:last+ucounts[i]] )
            unique_pos_idx[i] = last + maxpos
            last += ucounts[i]
        return unique_pos_idx
    
    def vec_app(pos, weights):
        sidx = np.lexsort([weights,pos])
        return sidx[np.r_[np.flatnonzero(pos[1:] != pos[:-1]), -1]]
    
    def vec_app_v2(pos, weights):
        sidx = (pos*(weights.max()+1) + weights).argsort()
        return sidx[np.concatenate((pos[1:] != pos[:-1], [True]))]
    

    时间和验证 -

    对于设置,让我们使用示例并将其平铺10000 倍并进行缩放,因为我们打算创建1000 倍更多的间隔。另外,让我们在weights 中使用唯一的数字,这样argmax 索引就不会被相同的数字混淆:

    In [155]: # Setup input
         ...: pos = np.array([3, 3, 7, 7, 9, 9, 9, 10, 10,])
         ...: pos = (pos + 10*np.arange(10000)[:,None]).ravel()
         ...: weights = np.random.choice(10*len(pos), size=len(pos), replace=0)
         ...: 
         ...: print np.allclose(org_app(pos, weights), vec_app(pos, weights))
         ...: print np.allclose(org_app(pos, weights), vec_app_v2(pos, weights))
         ...: 
    True
    True
    
    In [156]: %timeit org_app(pos, weights)
         ...: %timeit vec_app(pos, weights)
         ...: %timeit vec_app_v2(pos, weights)
         ...: 
    10 loops, best of 3: 56.4 ms per loop
    100 loops, best of 3: 14.8 ms per loop
    1000 loops, best of 3: 1.77 ms per loop
    
    In [157]: 56.4/1.77 # Speedup with vectorized one over loopy
    Out[157]: 31.864406779661017
    

    【讨论】:

    • 非常感谢@Divakar。我在你的回复中学到了很多技巧。在上面的代码中,我是否应该考虑 np.flatnonzero(pos[1:] != pos[:-1]) 在某种程度上是在数组中定位唯一元素的另一种方法?从我的角度来看,就好像我们拒绝了导数为零的地方,而保留了其余的地方。我是否理解正确,您通过考虑这种排序方式将 -1 附加到它,以便最后一个元素必然是具有最大权重的元素?
    • @user31412 np.flatnonzero(pos[1:] != pos[:-1]) 基本上是通过单移切片的切片获取区间更改的索引。我们需要这些,因为我们打算获得每个组的最后一个,因为 lexsort/argsort 将代表每个组/间隔的最大 arg。最后一个 -1 是必需的,因为切片会错过获取最后一组的最后一个元素。所以,我们手动添加。这为我们提供了最后一组的 argmax,因为 sidx 会将那个作为最后一个元素。希望这是有道理的。
    • 当然,这对我来说很有意义。我将使用您提供的不同方法。非常感谢。一旦我确定我理解了您所写的所有内容,我就会将这个答案标记为已接受。
    • 在实际情况下,可以有相同的权重。那时会发生什么?对我来说,如果与相同的pos 元素相关的权重相同,那么选择什么pos 索引并不重要,但这对于算法来说也可以吗?比如放慢速度或类似的东西?
    • @Wall-E 缩放:pos*(weights.max()+1) + weights 就像使用 pos 作为键一样。您需要使用kind 的方式是:(pos*(weights.max()+1) + weights).argsort(kind='mergesort')。这将为您提供您所追求的确定性结果。
    猜你喜欢
    • 1970-01-01
    • 2021-01-26
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 2016-05-17
    • 1970-01-01
    • 2014-10-05
    • 2014-02-11
    相关资源
    最近更新 更多