在numpy中以矢量化的方式:根据数据块内部的内容有条件地剪切数据块(大小不同)

在numpy中以矢量化的方式:根据数据块内部的内容有条件地剪切数据块(大小不同),numpy,vectorization,Numpy,Vectorization,我有一个整数向量(1D numpy数组),看起来像: 8,1,1,2,8,99,1,2,1,2,8,2,2,8,99,99,8,1,1 (以矢量化的方式)我想过滤掉8之间包含至少一个99值的所有数据 因此,在本例中,我要剪切的数据以粗体列出: 8, 1, 1, 2, 8, 99, 1, 2, 1, 2, 8, 2, 2, 2, 8, 99, 99, 8, 1, 1 如果保证8之间的间距相等,我可以提出矢量化代码来实现这一点。这是代码: inputRaw = np.array([8, 2, 3,

我有一个整数向量(1D numpy数组),看起来像:

8,1,1,2,8,99,1,2,1,2,8,2,2,8,99,99,8,1,1
(以矢量化的方式)我想过滤掉8之间包含至少一个99值的所有数据

因此,在本例中,我要剪切的数据以粗体列出:

8, 1, 1, 2, 8, 99, 1, 2, 1, 2, 8, 2, 2, 2, 8, 99, 99, 8, 1, 1 如果保证8之间的间距相等,我可以提出矢量化代码来实现这一点。这是代码:

inputRaw = np.array([8, 2, 3, 2, 99, 2, 8, 2, 3, 2, 2, 2, 8, 2, 3, 3, 3, 3])
inputPartitioned = np.reshape(inputRaw, (3, 6))
# reshaping it into an array of the form: np.array([[8, 2, 3, 2, 99, 2], [8, 2, 3, 2, 2, 2], [8, 2, 3, 3, 3, 3]])
selectedSections = np.logical_not(np.any(inputPartitioned>8, axis=1))
outputPartitioned = inputPartitioned[selectedSections]
outputFlattened = outputPartitioned.flatten()
我还需要一个掩码或索引来告诉我(在原始索引中)被裁剪的数据。(我需要这个,因为我有第二个数组,我想跟踪它,它与第一个数组共享索引)。我可以这样编码这个掩码(假定8之间的间距相等):

但我不知道在8之间的间距不相等的情况下,如何以矢量化的方式做到这一点

有什么想法吗?这些阵列非常长,因此对大型阵列快速工作的解决方案非常有用。另外,我很有信心,这些“99”总是紧接着一个8,所以这可能是制定算法时有用的信息

这应该可以做到(我避免了“相当自信”部分,所以即使99不是紧接着8之后,它也会运行)

这应该可以做到(我已经避免了“相当自信”的部分,所以即使99不是紧接着一个8,它也会运行)

方法#1

这是一个向量化的例子,用于一般情况,当
99
出现在两个
8
之间时,然后移除/屏蔽这两个
8
之间的所有元素-

def vectorized1_app(a):
    m1 = a==8
    m2 = a==99
    d = m1.cumsum()
    occ_mask = np.bincount(d,m2)<1
    if m1.argmax() > m2.argmax():
        occ_mask[0] = ~occ_mask[0]

    if m1[::-1].argmax() > m2[::-1].argmax():
        occ_mask[-1] = ~occ_mask[-1]
    mask = occ_mask[d]
    return mask
方法#2-B

一些边际性能。将最后一个元素检查的最后一步推到一个零件上,如下图所示-

@njit
def numba2(a, mask_out):
    N = len(a)
    fill = False
    last8_index = 0
    for i in range(N-1):
        if a[i]==8:
            if a[i+1]==99:
                fill = True
            else:
                fill = False
            last8_index = i

        if fill:        
            mask_out[i] = False

    if a[N-1]!=8:
        for i in range(last8_index,N-1):
            mask_out[i] = True

    return mask_out

def numba2_app(a):
    return numba2(a, np.ones(len(a), dtype=np.bool))
请注意,公布的方法的输出是掩码,因此使用这些方法屏蔽输入数组将给我们提供与
数据(掩码)
类似的结果


特殊情况:遮罩到第一个
8
,保持在最后一个
8

我们可以通过两种方式修改app#1-

附件1-Mod 1-

如果您必须修改大小写,以便您希望在最后一次
8
之后也屏蔽,请执行:
m1c=m1.cumsum();d=m1c.clip(min=1,max=m1c.max()-1)
接近#1

这是一个向量化的例子,用于一般情况,当
99
出现在两个
8
之间时,然后移除/屏蔽这两个
8
之间的所有元素-

def vectorized1_app(a):
    m1 = a==8
    m2 = a==99
    d = m1.cumsum()
    occ_mask = np.bincount(d,m2)<1
    if m1.argmax() > m2.argmax():
        occ_mask[0] = ~occ_mask[0]

    if m1[::-1].argmax() > m2[::-1].argmax():
        occ_mask[-1] = ~occ_mask[-1]
    mask = occ_mask[d]
    return mask
方法#2-B

一些边际性能。将最后一个元素检查的最后一步推到一个零件上,如下图所示-

@njit
def numba2(a, mask_out):
    N = len(a)
    fill = False
    last8_index = 0
    for i in range(N-1):
        if a[i]==8:
            if a[i+1]==99:
                fill = True
            else:
                fill = False
            last8_index = i

        if fill:        
            mask_out[i] = False

    if a[N-1]!=8:
        for i in range(last8_index,N-1):
            mask_out[i] = True

    return mask_out

def numba2_app(a):
    return numba2(a, np.ones(len(a), dtype=np.bool))
请注意,公布的方法的输出是掩码,因此使用这些方法屏蔽输入数组将给我们提供与
数据(掩码)
类似的结果


特殊情况:遮罩到第一个
8
,保持在最后一个
8

我们可以通过两种方式修改app#1-

附件1-Mod 1-


如果您必须修改大小写,以便您希望在最后一次
8
之后也屏蔽,请执行:
m1c=m1.cumsum();d=m1c.clip(min=1,max=m1c.max()-1)

另一种numpy方法:

def pp(a):                                            
    m8 = a==8
    m99 = a==99
    m = m8|m99
    i = m.nonzero()[0]
    c8 = m8[i]
    i = i[c8]
    n8 = np.count_nonzero(c8)
    if n8 == 0:
        return np.ones(a.size,bool)
    if c8[-1]:
        d8 = np.empty(n8,bool)
        d8[-1] = False
        d8[:-1] = ~c8[1:][c8[:-1]]
    else:
        d8 = ~c8[1:][c8[:-1]]
    d8[1:]^=d8[:-1]
    m8[i] = d8
    m8[0]^=True
    return np.bitwise_xor.accumulate(m8)
例如:

a = np.array([8, 1, 1, 2, 8, 99, 1, 2, 1, 2, 8, 2, 2, 2, 8, 99, 99, 8, 1, 1])
a[pp(a)]
# array([8, 1, 1, 2, 8, 2, 2, 2, 8, 1, 1])

另一种numpy方法:

def pp(a):                                            
    m8 = a==8
    m99 = a==99
    m = m8|m99
    i = m.nonzero()[0]
    c8 = m8[i]
    i = i[c8]
    n8 = np.count_nonzero(c8)
    if n8 == 0:
        return np.ones(a.size,bool)
    if c8[-1]:
        d8 = np.empty(n8,bool)
        d8[-1] = False
        d8[:-1] = ~c8[1:][c8[:-1]]
    else:
        d8 = ~c8[1:][c8[:-1]]
    d8[1:]^=d8[:-1]
    m8[i] = d8
    m8[0]^=True
    return np.bitwise_xor.accumulate(m8)
例如:

a = np.array([8, 1, 1, 2, 8, 99, 1, 2, 1, 2, 8, 2, 2, 2, 8, 99, 99, 8, 1, 1])
a[pp(a)]
# array([8, 1, 1, 2, 8, 2, 2, 2, 8, 1, 1])

你为什么需要这个?也许有更好的解决方案。原始阵列是如何创建的?为什么需要这个?也许有更好的解决方案。原始阵列是如何创建的?谢谢您的回答。这是最容易理解的答案,非常感谢!我在奖励你和迪瓦卡之间的赏金之间左右为难。谢谢你的回答。这是最容易理解的答案,非常感谢!我在奖励你和迪瓦卡之间的赏金之间左右为难。谢谢你的回答。我会在一段时间内复习的。谢谢你的回答。过段时间我会看一遍的。啊,著名的迪瓦卡!你的回答总是给我留下深刻印象。谢谢你的回答。我从来没有听说过numba,所以谢谢你的推荐——我会在有时间的时候尝试学习一些。对于尝试1,我发现Yoni的答案更容易理解。两者之间是否存在“功能”差异?您是否特别推荐您的方法(可能像bincount()这样的函数通常很有用?@StevenSagona Well
bincount
只是一种基于bin获取计数的简洁方法,因此可以基于那些
99的
来检测是否存在。如果你想了解Yoni的one和我的app#1之间的功能差异,我看到了一个差异,这就是我在结尾处为边境案件提供的附加If else。因此,假设输入是
[1,99,8,99,1,2,1,2,8,2,2,2,8,99,2,1]
。我认为前两个元素会在输出掩码中得到
T
,同样的,最后4个元素也会得到
T
,因为对于那些元素,
[8,99,.8]
的“孤岛”模式不存在。@StevenSagona基于这一点的结果在我的和Yoni的上似乎不同。所以,我想我不得不问你——这种情况的预期结果是什么?啊,好吧,我明白了!我不小心,没有具体说明我想要的边缘案例。在我的情况下,技术上我希望[1,1,8,99,1,2,2,8,2,2,8,99,2,1]变成[8,2,2,2,2](在前8个之前切断数据)并且[1,1,8,99,1,2,1,1,2,2,2,2,8,99,2,2,2,2,2,1,1]变成[8,2,2,2,2,2,2,8,1,1](在最后8个之后留下数据)。对不起,我说的模棱两可!我想我可以修改你写的代码来涵盖那个特殊的“边缘案例”。啊,著名的divaker!你的回答总是给我留下深刻印象。谢谢你的回答。我从来没有听说过numba,所以谢谢你的推荐——我会在有时间的时候尝试学习一些。对于尝试1,我
def pp(a):                                            
    m8 = a==8
    m99 = a==99
    m = m8|m99
    i = m.nonzero()[0]
    c8 = m8[i]
    i = i[c8]
    n8 = np.count_nonzero(c8)
    if n8 == 0:
        return np.ones(a.size,bool)
    if c8[-1]:
        d8 = np.empty(n8,bool)
        d8[-1] = False
        d8[:-1] = ~c8[1:][c8[:-1]]
    else:
        d8 = ~c8[1:][c8[:-1]]
    d8[1:]^=d8[:-1]
    m8[i] = d8
    m8[0]^=True
    return np.bitwise_xor.accumulate(m8)
a = np.array([8, 1, 1, 2, 8, 99, 1, 2, 1, 2, 8, 2, 2, 2, 8, 99, 99, 8, 1, 1])
a[pp(a)]
# array([8, 1, 1, 2, 8, 2, 2, 2, 8, 1, 1])