import numpy as np
mat = np.random.randint(2, size=(100000,100))
我希望遍历这个矩阵,如果每个row
完全包含1或0,我希望将state
变量更改为该值。state
的初始值为0。
state = 0
for row in mat:
if set(row) == {1}:
state = 1
elif set(row) == {0}:
state = 0
else:
row[:] = state
谁能告诉我如何利用numpy
来向量化这个循环并加速它?
因此,对于示例输入
array([[0, 1, 0],
[0, 0, 1],
[1, 1, 1],
[0, 0, 1],
[0, 0, 1]])
在这种情况下,预期输出将是
array([[0, 0, 0],
[0, 0, 0],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
发布于 2019-06-26 08:33:35
下面是一个简单快速的numpy方法:
import numpy as np
def pp():
m,n = a.shape
A = a.sum(axis=1)
A = np.where((A==0)|(A==n))[0]
if not A.size:
return np.ones_like(a) if state else np.zeros_like(a)
st = np.concatenate([np.arange(A[0]!=0), A, [m]])
v = a[st[:-1],0]
if A[0]:
v[0] = state
return np.broadcast_to(v.repeat(st[1:]-st[:-1])[:,None],(m,n))
我用这个做了一些计时
state=0
a = (np.random.random((100000,100))<np.random.random((100000,1))).astype(int)
简单的测试用例:
0.8655898020006134 # me
4.089095343002555 # Alain T.
2.2958932030014694 # Divakar 1
2.2178015549980046 # & 2
发布于 2019-06-26 02:37:58
通过利用np.accumulate,您可以在没有任何循环的情况下完成此操作
R = 5 # 100000
C = 3 # 100
mat = np.random.randint(2, size=(R,C))
print(mat) # original matrix
state = np.zeros((1,C)) # or np.ones((1,C))
mat = np.concatenate([state,mat]) # insert state row
zRows = np.isin(np.sum(mat,1),[0,C]) # all zeroes or all ones
iRows = np.arange(R+1) * zRows.astype(np.int) # base indexes
mat = mat[np.maximum.accumulate(iRows)][1:] # indirection, remove state
print(mat) # modified
#original
[[0 0 1]
[1 1 1]
[1 0 1]
[0 0 0]
[1 0 1]]
# modified
[[0 0 0]
[1 1 1]
[1 1 1]
[0 0 0]
[0 0 0]]
它的工作方式是为需要更改的行准备一个间接数组。这是通过行索引的np.arange完成的,其中我们将需要替换的索引设置为零。累积最大索引会将每个被替换的行映射到它之前的全零或全一行。
例如:
[ 0, 1, 2, 3, 4, 5 ] # row indexes
[ 0, 1, 0, 0, 1, 0 ] # rows that are all zeroes or all ones (zRows)
[ 0, 1, 0, 0, 4, 0 ] # multiplied (iRows)
[ 0, 1, 1, 1, 4, 4 ] # np.maximum.accumulate
这为我们提供了一个索引列表,其中的行内容应该从中获取。
状态由在执行操作之前在矩阵开始处插入的额外行表示,在执行操作后删除。
这个解决方案对于非常小的矩阵(5x3)会稍微慢一些,但对于较大的矩阵(100000x100: 0.7秒对14秒),它可以让您的速度提高20倍。
https://stackoverflow.com/questions/56757804
复制相似问题