根据网格将索引向左移动

时间:2018-07-24 13:14:03

标签: python numpy vectorization

比方说,我有一个包含允许和禁止区域的网格。

import numpy as np
forbidden = np.array([False, False, False, False, False, False,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True, False, False, False, False, False, False,
       False, False,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True, False, False, False,
       False, False, False, False, False, False, False, False, False,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
       False, False, False, False, False, False, False, False, False,
       False, False, False, False, False, False,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True, False, False, False, False, False, False,
       False, False, False, False, False, False, False, False, False,
       False, False,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  False])

现在,我在(0,149)之间有一堆网格点。如果它们似乎在禁区中,我想“将它们移到左侧”,直到它们移出禁区。

例如,

idx = 13
forbidden[idx]  # is True, hence we want to move to the left
forbidden[5] # is False, and it is the "first index" where this is such

同时

idx = 5
forbidden[idx] = # is False, so this index stays the way it is

因此,getCorrectIndex(13) == getCorrectIndex(5) == 5

一种低效率的编码方式:

def getCorrectIndex(idx, forbidden):
    # this trusts that the forbidden[0] == False, which is Okay
    for remove in range(0, idx):
        if not forbidden[idx - remove]:
            return idx - remove

针对索引数组的矢量化方法将是最佳选择,但如果没有这种愚蠢的循环,我什至无法提出正确的方法……在此我不胜感激!< / p>

2 个答案:

答案 0 :(得分:0)

这是一种实现方法。不确定是否会比解决方案更好。

第一步,获取所有False节点的索引:

b = np.where(forbidden == False)[0]

这将返回

array([  0,   1,   2,   3,   4,   5,  30,  31,  32,  33,  34,  35,  36,
    37,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,
    90,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102,
   103, 104, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
   131, 132, 133, 134, 135, 136], dtype=int64)

然后,在该列表的切片部分再次使用whereamax,以使最高索引低于当前索引。然后使用b上的索引来获得False数组上最高的forbidden索引。

>>> index = 15
>>> first_left_false = b[np.amax(np.where(b<index))]
>>> first_left_false
5

该函数可能看起来像这样:

def getCorrectIndex(index, forbidden):
    if forbidden[index] == False:
         return index
    b = np.where(forbidden == False)[0]
    res = b[np.amax(np.where(b<index))]
    return res

或者,如果您要预先计算b数组,可以将其略微缩短:

def getCorrectIndex(index, b, forbidden):
     if forbidden[index] == False:
         return index
     else:
         return b[np.amax(np.where(b<index))]

答案 1 :(得分:0)

您可以使用np.maximum.accumulate将布尔数组转换为以前允许的最新索引,然后只需查找第idx个元素

首先创建一个索引数组,将禁止的位置设置为0。accumulate返回函数的滚动应用,在这种情况下为maximum,并且maximum与{{1 }},它应用于两个数组,返回元素级的max数组。

max

改为右移

将禁止位置设置为任何大于或等于数组长度的值,并在反向查找数组上使用lookup = np.arange(len(forbidden)) lookup[forbidden] = 0 lookup = np.maximum.accumulate(lookup) lookup[13] # 5 lookup[5] # 5 lookup[149] # 136 。这基本上与上面的左移方法相同。

np.minimum.accumulate