找到2d切片的交集

时间:2015-09-24 21:56:10

标签: python arrays numpy intersection

我想获取B行:

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

    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与数组一起使用。

    感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

我首先要简化你的规则。暂时忽略形状,让我们将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)
    

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

  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)
    
  5. 将所有内容放在一起,并在最后一步中组合any次调用,即可获得上述功能。

答案 1 :(得分:0)

如果我理解正确,您可以使用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]])