使用numpy在数组中创建匹配行的二进制数组?

时间:2017-10-17 17:44:32

标签: python arrays numpy matrix vectorization

我想创建一个二进制数组,显示numpy数组中的所有匹配行。在这种情况下,如果新矩阵的下一列j,如果原始矩阵中的行1与来自行i的行j相同,则第i个索引将对应[ [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)

现在,我通过这样的循环来做这件事:

SELECT IF(Condition < Y, 'Less Than Y', 'GTE Y'), AVG(stars)
FROM long expression
GROUP BY 1

然而,这很慢,因为它必须单独遍历原始矩阵中的每一行,以生成新矩阵中的每一列。有没有任何矢量化方法可以更快地完成这项工作?

由于

1 个答案:

答案 0 :(得分:2)

方法#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 - < / p>

# 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