【问题标题】:Find intersection of 2d slices of arrays查找二维数组切片的交集
【发布时间】:2015-09-27 04:35:44
【问题描述】:

我想获取B 的行,其中:

  1. 如果A[:,0] 等于B[:,0]B[:,2],则A[:,1] 必须分别等于B[:,1]B[:,3]
  2. A[:,0] 不等于 B[i,0]B[i,2]

例如:

A=np.array([[101,  1],
            [103,  3]])

B=np.array([[100,1,101,1],
            [100,1,102,1],
            [100,1,103,3],
            [100,2,101,2],
            [100,2,103,2],
            [101,1,100,3],
            [101,1,103,2],
            [101,4,100,4],
            [101,4,103,4],
            [104,5,102,3]])

R=np.array([[100,1,101,1],
            [100,1,102,1],
            [100,1,103,3],
            [101,1,100,3],
            [104,5,102,3]])

我从这里 (Implementation of numpy in1d for 2D arrays?) 尝试了解决方案,但我收到错误消息,因为我无法将 view 与数组切片一起使用。

感谢您的帮助!

【问题讨论】:

  • 那么,case 1case 2 是否都必须为 TRUE 才能从 B 中选择行。此外,在case 1 中,"then" 是否意味着 "A[:,0] is equal to either B[:,0] or B[:,2]""[:,1] has to be equal to B[:,1] or B[:,3]" 必须再次为真才能从 B 中选择行?
  • @Divakar,case 1 是一个条件语句,而 case 2 只是一个语句。无论2 为真,1 均无效(1 中的if 为假,因此支持条件)。单独的前半部分1 不是选择过滤器(A[:,0] 是否匹配B[:, even] 中的一个无关紧要,只有匹配时才重要,然后A[:, 1] 匹配相应的B[:, odd])。因此,逻辑上大小写2 可以忽略,并且您得到相同的行。也许@user3357979 可以确认?
  • @askewchan 是正确的
  • @user3357979,收到您的评论并注意到我的代码中有错误;它适用于您的示例,但有一个极端情况,它错过了两对 A 中的匹配项可能被交叉的地方。请参阅我更新的答案。如果[103,1,101,3]B 中,它应该从输出中排除([101,3] 对违反了暗示),但我的代码接受了它,因为它在检查暗示之前结合了A 对(这取决于 其中 A 对匹配)。

标签: python arrays numpy intersection


【解决方案1】:

我将从简化您的规则开始。现在忽略形状,让我们将AB 视为对列表。那么您的要求是,如果一对中的左伙伴匹配A 中的一个左伙伴,那么右伙伴也必须匹配。

这是material implication的定义,写成left match → right match。好的部分是

(x → y) 仅在either (x is false) or (y is true) 的情况下为真

后者很容易编码。对您而言,left matchx = A[..., 0] == B[..., 0]right matchy = A[..., 1] == B[..., 1]。所以要检查x → y,你只需检查not(x) or y,它可以写成~x | y

要处理形状,请使用整形使leftright 仅沿一个轴(最后一个轴),然后广播以检查与A 中的任一对匹配,然后检查条件B 的每一行中的所有对都满足。总而言之,这看起来像这样(详细解释见下文):

def implicate(A, B):
    # axes: (i, apair, bpair, partner)
    a = A[None, :, None, :]
    b = B.reshape(-1, 1, 2, 2)
    m = a == b
    m = ~m[...,0] | m[...,1] # require the implication rule along last axis
    m = m.all((1,2))         # both pairs in each A and B must comply (axes 1,2)
    return m, B[m]           # probably want to return only one of these

它是如何应用于您的系统的。

  1. 要绕过形状,只需很好地使用广播,然后检查上述是否适用于行中的所有对。

    a = A[None, :, None, :] # or A.reshape(1, A.shape[0], 1, A.shape[1]) to add two broadcasting axes
    b = B.reshape(-1, 1, 2, 2) # this is B.reshape(10, 1, 2, 2) without needing to know 10
    

    这为每个 ab 提供了四个维度:(i, a_pair, b_pair, partner),也就是说,您在第一个轴上切片以沿 i 移动(B 中的行),第二个选择哪个(的二)A 中的配对,第三个对 B 执行相同操作,最后一个选择每对中的两个合作伙伴中的哪一个。为了概括这一点(如果您事先不知道其中任何一个的形状),您可以使用:

    a = A[None, :, None, :] # or A.reshape(1, -1, 1, 2)
    b = B.reshape(len(B), 1, -1, 2)
    

    -1s 允许 AB 中的任意数量的对。 2s 假设我们正在讨论配对。

  2. 现在我们可以得到一个匹配数组:

    m = a == b
    

    形状为(10, 2, 2, 2),再次代表(i, a_pair, b_pair, partner)

  3. 接下来,我们应用材料含义的要求,如上所述。为了更容易阅读,我们首先将所有左伙伴与右伙伴分开,然后检查条件是否成立。这里有

    left  = m[...,0]
    right = m[...,1]
    m = ~left | right
    

    消除最后一个轴partner,留下(i, b_pair)

  4. 最后,我们要确保该规则适用于 B 的每一行中的所有对,这是由 b_pair 轴 (2) 给出的。

    m = m.all(2)
    

    当然它必须符合A 中所有对的匹配(a_pair 轴为 1):

    m = m.all(1)
    

将它们放在一起,并结合最后一步中的any 调用,就得到了上面的函数。

【讨论】:

  • 谢谢您,您的编辑后效果很好!我遇到的一个问题是m = m.all((1,2))。它不断抛出TypeError: an integer is required。我只是把它分成m = m.all(2)m = m.all(1)
  • 也许最近才引入了该功能。我用 numpy 1.9.2 进行了测试。如果这两个轴的形状只有两个(如示例中所示),如果速度是一个问题,我建议不要对all 进行两次调用,而是类似于m = m[...,0] | m[...,1] 之类的,相当于m.all(-1)-1... 都给出了最后一个轴。还要确保按照你的顺序(2 然后 1),因为每个轴都会删除一个轴并改变它们的数字。
【解决方案2】:

如果我对问题的理解正确,您可以使用np.in1d -

# Mask for A[:,0] is equal to either B[:,0] or B[:,2]
mask1 = (np.in1d(B[:,::2],A[:,0]).reshape(-1,2)).any(1)

# Mask for A[:,1] has to be equal to B[:,1] or B[:,3]
mask2 = (np.in1d(B[:,1::2],A[:,1]).reshape(-1,2)).any(1)

# Mask for A[:,0] is not equal to either B[i,0] and B[i,2]
mask3 = ~(np.in1d(B[:,::2],A[:,0]).reshape(-1,2)).any(1)

# Finally combine all masks as per requirements
out = B[(mask1 & mask2) | mask3]

示例运行 -

In [361]: A
Out[361]: 
array([[101,   1],
       [103,   3]])

In [362]: B
Out[362]: 
array([[100,   1, 101,   1],
       [100,   1, 102,   1],
       [100,   1, 103,   3],
       [100,   2, 101,   2],
       [100,   2, 103,   2],
       [101,   1, 100,   3],
       [101,   1, 103,   2],
       [101,   4, 100,   4],
       [101,   4, 103,   4],
       [104,   5, 102,   3]])

In [363]: out
Out[363]: 
array([[100,   1, 101,   1],
       [100,   1, 102,   1],
       [100,   1, 103,   3],
       [101,   1, 100,   3],
       [101,   1, 103,   2],
       [104,   5, 102,   3]])

【讨论】:

  • 我认为这与 OP 中的预期结果不符。
  • @askewchan 是的,我认为预期的输出有错误。发布了我在 cmets 中感到困惑的事情。
猜你喜欢
  • 2018-05-06
  • 1970-01-01
  • 1970-01-01
  • 2013-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多