gpt4 book ai didi

python - 如何通过矩阵numpy向量化循环

转载 作者:太空狗 更新时间:2023-10-30 01:17:53 24 4
gpt4 key购买 nike

假设我有一个 100000 x 100 的矩阵

import numpy as np

mat = np.random.randint(2, size=(100000,100))

我想遍历这个矩阵,如果每个 row 完全包含 1 或 0,我希望将 state 变量更改为该值。如果状态没有改变,我希望将整个 row 设置为 state 的值。 state的初始值为0。

天真地在 for 循环中,这可以按如下方式完成

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]])

最佳答案

方法 #1:NumPy 向量化

这是一个矢量化的 -

def check_all(a, state): # a is input matrix/array
# Get zeros and ones all masks
zm = (a==0).all(1)
om = (a==1).all(1)

# "Attach" boundaries with False values at the start of these masks.
# These will be used to detect rising edges (as indices) on these masks.
zma = np.r_[False,zm]
oma = np.r_[False,om]

omi = np.flatnonzero(oma[:-1] < oma[1:])
zmi = np.flatnonzero(zma[:-1] < zma[1:])

# Group the indices and the signatures (values as 1s and -1s)
ai = np.r_[omi,zmi]
av = np.r_[np.ones(len(omi),dtype=int),-np.ones(len(zmi),dtype=int)]

# Sort the grouped-indices, thus we would know the positions
# of these group starts. Then index into the signatures/values
# and indices with those, giving us the information on how these signatures
# occur through the length of the input
sidx = ai.argsort()
val,aidx = av[sidx],ai[sidx]

# The identical consecutive signatures are to be removed
mask = np.r_[True,val[:-1]!=val[1:]]
v,i = val[mask],aidx[mask]

# Also, note that we are assigning all 1s as +1 signature and all 0s as -1
# So, in case the starting signature is a 0, assign a value of 0
if v[0]==-1:
v[0] = 0

# Initialize 1D o/p array, which stores the signatures as +1s and -1s.
# The bigger level idea is that performing cumsum at the end would give us the
# desired 1D output
out1d = np.zeros(len(a),dtype=a.dtype)

# Assign the values at i positions
out1d[i] = v

# Finally cumsum to get desired output
out1dc = out1d.cumsum()

# Correct the starting positions based on starting state value
out1dc[:i[0]] = state

# Convert to 2D view for mem. and perf. efficiency
out = np.broadcast_to(out1dc[:,None],a.shape)
return out

方法 #2:基于 Numba

这是另一个基于 numba 的内存和性能。效率 -

@njit(parallel=True)
def func1(zm, om, out, start_state, cur_state):
# This outputs 1D version of required output.

# Start off with the starting given state
newval = start_state

# Loop through zipped zeros-all and ones-all masks and in essence do :
# Switch between zeros and ones based on whether the other ones
# are occuring through or not, prior to the current state
for i,(z,o) in enumerate(zip(zm,om)):
if z and cur_state:
cur_state = ~cur_state
newval = 0
if o and ~cur_state:
cur_state = ~cur_state
newval = 1
out[i] = newval
return out

def check_all_numba(a, state):
# Get zeros and ones all masks
zm = (a==0).all(1)
om = (a==1).all(1)

# Decide the starting state
cur_state = zm.argmax() < om.argmax()

# Initialize 1D o/p array with given state values
out1d = np.full(len(a), fill_value=state)
func1(zm, om, out1d, state, cur_state)

# Broadcast into the 2D view for memory and perf. efficiency
return np.broadcast_to(out1d[:,None],a.shape)

关于python - 如何通过矩阵numpy向量化循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56757804/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com