【问题标题】:Create binary array of matching rows in an array using numpy?使用numpy在数组中创建匹配行的二进制数组?
【发布时间】:2018-03-29 11:56:45
【问题描述】:

我想创建一个二进制数组,在 numpy 数组中显示所有匹配的行。在这种情况下,如果原始矩阵的i 行与原始矩阵的j 行相同,则在新矩阵的j 列下,第i 个索引将对应于1

例如,如果矩阵如下所示:

[ [a b c]
  [d e f]
  [a b c]
  [d e f]]

我要输出的是

[[1 0 1 0]
 [0 1 0 1]
 [1 0 1 0]
 [0 1 0 1]]

现在,我正在通过这样的循环进行操作:

same_mat=np.empty((agents,agents))
for i in range(matrix.shape[0]):
    same_mat[:,i]=np.all(matrix[i,:]==matrix,axis=1)

但是,这很慢,因为它必须单独遍历原始矩阵中的每一行才能生成新矩阵中的每一列。是否有任何矢量化方式可以更快地做到这一点?

谢谢

【问题讨论】:

    标签: python arrays numpy matrix vectorization


    【解决方案1】:

    方法 #1: 我们可以简单地将数组扩展两个 3D 版本并进行比较,从而让 broadcasting 发挥作用 -

    (arr[:,None] == arr).all(2).astype(int)
    

    示例运行 -

    In [19]: a,b,c,d,e,f = 4,7,3,1,8,2
        ...: arr = np.array([
        ...:   [a, b, c],
        ...:   [d ,e, f],
        ...:   [a ,b, c],
        ...:   [d ,e, f]])
        ...: 
    
    In [20]: arr
    Out[20]: 
    array([[4, 7, 3],
           [1, 8, 2],
           [4, 7, 3],
           [1, 8, 2]])
    
    In [21]: (arr[:,None] == arr).all(2).astype(int)
    Out[21]: 
    array([[1, 0, 1, 0],
           [0, 1, 0, 1],
           [1, 0, 1, 0],
           [0, 1, 0, 1]])
    

    方法 #2: 使用 views 的内存高效方法,因为我们将每一行减少到一个 ,然后执行 broadcasted-comparison -

    # https://stackoverflow.com/a/44999009/ @Divakar
    def view1D(a): # a is array
        a = np.ascontiguousarray(a)
        void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
        return a.view(void_dt).ravel()
    
    arr1D = view1D(arr)
    out = (arr1D[:,None] == arr1D).astype(int)
    

    方法 #3: 出于对内置插件的喜爱,这里有另一个在理论上与前一个类似,但使用 np.unique 和新的 axis 功能 -

    ids = np.unique(arr, axis=0, return_inverse=1)[1]
    out = (ids[:,None] == ids).astype(int)
    

    方法 #4: 另一种根据每行在其他行中的唯一性来标记每行的方法是将每行视为2D 网格上的线性索引等价物,从而为我们提供更多获取ids 的高效方法 -

    ids = arr.dot((arr.max()-arr.min()+1)**np.arange(arr.shape[1]))
    out = (ids[:,None] == ids).astype(int)
    

    如果我们保证有正数,请跳过arr.min()

    我们在这里需要小心,因为数字的巨大变化或大量的列会导致溢出。因此,在使用这种方法时请牢记这些。

    额外的东西

    为了发挥最大性能,使用uint8 作为输出dtype,这似乎很好,因为我们只需要在输出中包含0s1s,如下面的时序所示 -

    In [41]: bool_arr = np.random.rand(100,100)>0.5
    
    In [42]: %timeit bool_arr.astype(int)
        ...: %timeit bool_arr.astype(np.uint8)
        ...: 
    100000 loops, best of 3: 4.15 µs per loop
    1000000 loops, best of 3: 897 ns per loop
    
    In [43]: bool_arr = np.random.rand(5000,5000)>0.5
    
    In [44]: %timeit bool_arr.astype(int)
        ...: %timeit bool_arr.astype(np.uint8)
        ...: 
    10 loops, best of 3: 21 ms per loop
    100 loops, best of 3: 3.16 ms per loop
    

    【讨论】:

    • 非常感谢。我将测试它们并计时,然后报告哪个更快(也与循环相比),以便其他有类似问题的用户可以了解他们可能想要使用什么。
    • 有趣的是,与循环相比,方法 1 并没有节省时间。但是,我的机器没有 GPU,实际运行时我将使用带 GPU 的机器。也许会测试然后发布时间结果。非常感谢您付出所有这些努力!
    猜你喜欢
    • 1970-01-01
    • 2014-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-05
    • 1970-01-01
    相关资源
    最近更新 更多