【问题标题】:How can i find the intersection of two multidimensional arrays faster?如何更快地找到两个多维数组的交集?
【发布时间】:2021-09-08 01:49:34
【问题描述】:

有两个具有不同行数的多维布尔数组。我想在公共行中快速找到 True 值的索引。我写了以下代码,但它太慢了。 有没有更快的方法来做到这一点?

a=np.random.choice(a=[False, True], size=(100,100))
b=np.random.choice(a=[False, True], size=(1000,100))

for i in a:
    for j in b:
        if np.array_equal(i, j):
          print(np.where(i))

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    如果你想比较 NDarrays 元素,我会这样做:

    import numpy as np
    
    # data
    a = np.random.choice(a = [False, True], size = (100,100))
    b = np.random.choice(a = [False, True], size = (1000,100))
    
    # extract matching coordinates
    match = np.where((a == b[:100,:]) == True)
    match = list(zip(*match))
    
    # first 20 coordinates match
    print("Number of matches:", len(match))
    print(match[:20])
    

    【讨论】:

    • 使用list(zip())(几乎)与for循环相同,这对于速度来说毫无用处。
    • 那么,我认为我们不能再快了。 NDarrays 毕竟是数组,所以你必须在某些时候循环它们以提取坐标......
    • 重点是为此使用纯 numpy。正在做某事......也许我可以做到
    • 使用 cdist 查看solution
    【解决方案2】:

    a的每一行与b的每一行的比较可以通过使用np.newaxisnp.tile使a的形状可广播到b的形状来进行

    import numpy as np
    
    a=np.random.choice(a=[True, False], size=(2,5))
    b=np.random.choice(a=[True, False], size=(10,5))
    broadcastable_a = np.tile(a[:, np.newaxis, :], (1, b.shape[0], 1))
    a_equal_b = np.equal(b, broadcastable_a)
    indexes = np.where(a_equal_b)
    indexes = np.stack(np.array(indexes[1:]), axis=1)
    

    【讨论】:

    • 我认为它不会起作用,因为它只将b 作为块而不是按行进行比较。也许我没有正确理解。还请添加代码以将 .where 的结果转换回所需的索引。也请显示输出。
    【解决方案3】:

    让我们从一个有意义且通常会打印一些内容的问题的版本开始:

    a = np.random.choice(a=[False, True], size=(2, 2))
    b = np.random.choice(a=[False, True], size=(4, 2))
    
    print(f"a: \n {a}")
    print(f"b: \n {b}")
    
    matches = []
    for i, x in enumerate(a):
        for j, y in enumerate(b):
            if np.array_equal(x, y):
                matches.append((i, j))
    

    使用scipy.cdist 的解决方案将a 中的所有行与b 中的所有行进行比较,使用汉明距离进行布尔向量比较:

    import numpy as np
    import scipy
    from scipy import spatial
    
    d = scipy.spatial.distance.cdist(a, b, metric='hamming')
    cdist_matches = np.where(d == 0)
    mathces_values = [(a[i], b[j]) for (i, j) in matches]
    cdist_values = a[cdist_matches[0]], b[cdist_matches[1]]
    print(f"matches_inds = \n{matches}")
    print(f"matches = \n{mathces_values}")
    
    print(f"cdist_inds = \n{cdist_matches}")
    print(f"cdist_matches =\n {cdist_values}")
    

    出来:

    a: 
     [[ True False]
     [False False]]
    b: 
     [[ True  True]
     [ True False]
     [False False]
     [False  True]]
    matches_inds = 
    [(0, 1), (1, 2)]
    matches = 
    [(array([ True, False]), array([ True, False])), (array([False, False]), array([False, False]))]
    cdist_inds = 
    (array([0, 1], dtype=int64), array([1, 2], dtype=int64))
    cdist_matches =
     (array([[ True, False],
           [False, False]]), array([[ True, False],
           [False, False]]))
    
    

    如果您不想 import scipy,请参阅 this 以获得纯 numpy 实现

    【讨论】:

    • @Gulzar 我在下面添加了一个解决方案,如果我正确理解了问题,则将 a 广播到 b 并将 a 的每一行与 b 的每一行进行比较
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    相关资源
    最近更新 更多