这是一个矩阵:
matrix = [[1, 1, 1, 0],
[0, 5, 0, 1],
[2, 1, 3, 10]]
我想将0以下的所有位置元素更改为0(在同一列上)。
结果矩阵将是:
matrix = [[1, 1, 1, 0],
[0, 5, 0, 0],
[0, 1, 0, 0]]
到目前为止我试过这个。回报是空的
import numpy as np
def transform(matrix):
newmatrix = np.asarray(matrix)
i = 0
j = 0
for j in range(0,len(matrix[0])-1):
while i < int(len(matrix))-1 and j < int(len(matrix[0]))-1:
if newmatrix[i][j] == 0:
np.put(newmatrix,newmatrix[i+1][j], 0 )
i +=1
return print (newmatrix)
答案 0 :(得分:2)
import numpy as np
def transform(matrix):
mat = np.asarray(matrix)
mat[np.logical_not(np.not_equal(mat, 0).cumprod(axis=0))] = 0
# Alternatively:
# mat[~(mat != 0).cumprod(axis=0, dtype=np.bool)] = 0
# or,
# mat[~((mat != 0).cumprod(axis=0, dtype=np.bool))] = 0
return mat
然后,根据您的示例数据,我得到以下mat
:
In [195]: matrix = [[1, 1, 1, 0],
...: [0, 5, 0, 1],
...: [2, 1, 3, 10]]
In [196]: transform(matrix)
Out[196]:
array([[1, 1, 1, 0],
[0, 5, 0, 0],
[0, 1, 0, 0]])
def transform2(matrix):
mat = np.asarray(matrix)
mat *= (mat != 0).cumprod(axis=0, dtype=np.bool)
return mat
def transform3(matrix):
mat = np.asarray(matrix)
mat *= mat.cumprod(axis=0, dtype=np.bool)
return mat
让我们看一下主要陈述(在方法1中):
mat[np.logical_not(np.not_equal(mat, 0).cumprod(axis=0))] = 0
我们可以把它分成几个&#34;小学&#34;操作:
创建一个包含False
(数字0
)的布尔掩码,其中mat
的元素为0
和True
(数字{{1} })它们是非零的:
1
使用数字mask1 = np.not_equal(mat, 0)
为0的事实,使用cumprod()
函数(可在此处找到一个很好的解释:https://www.mathworks.com/help/matlab/ref/cumprod.html)
False
由于mask2 = mask1.cumprod(axis=0)
和1*1==1
或0*0
为0*1
,因此&#34;掩码&#34;将是0
或0
。它们仅1
位于0
为零且低于(!)的位置,因为&#34;累积性质&#34;列中的产品(因此mask1
)。
现在,我们希望将axis=0
中与mat
对应的0
元素设置为mask2
。为此,我们创建一个0
的布尔掩码,其中True
为mask2
,其他位置为0
。通过将逻辑(或二进制)NOT应用于False
:
mask2
使用&#34;逻辑&#34; NOT此处创建一个布尔数组,因此我们避免显式类型转换。
最后,我们使用Boolean Indexing选择mask3 = np.logical_not(mask2)
中需要设置为mat
并将其设置为0
的元素:
0
如果您考虑到这一点,如果我们执行以下操作,我们可以摆脱步骤3和4:
mat[mask3] = 0
参见&#34;方法2&#34;以上部分是完整的实施。
有几个额外的答案使用mask2 = mask1.cumprod(axis=0, dtype=np.bool) #convert result to boolean type
mat *= mask2 # combined step 3&4
。从根本上说,所有这些方法都围绕着numpy.ufunc.accumulate()
是&#34;特殊&#34; 0
意义上的价值,或者在@ DSM答案的情况下,0*anything==0
并让False=0<True=0
执行&#34;累积&#34;在阵列上操作。
性能有一些变化,但大多数都是最小的,除了我的方法#1比其他方法慢。
以下是更多功能的定时测试。注意:为了正确执行测试,我们需要使用大型数组。小阵列测试将测量开销,兑现等。
numpy
我的初始解决方案(方法1)速度最慢,而其他方法速度要快得多。 @DanielF原始方法因使用布尔索引而稍慢(但优化后的变体与其他优化方法一样快)。
答案 1 :(得分:1)
这是一个简单的(虽然不是优化的)算法:
import numpy as np
from numba import jit
m = np.array([[1, 1, 1, 0],
[0, 5, 0, 1],
[2, 1, 3, 10]])
@jit(nopython=True)
def zeroer(m):
a, b = m.shape
for j in range(b):
for i in range(a):
if m[i, j] == 0:
m[i:, j] = 0
break
return m
zeroer(m)
# [[1 1 1 0]
# [0 5 0 0]
# [0 1 0 0]]
答案 2 :(得分:1)
cumprod
方法的一个变体是使用累积最小值(或最大值)。我更喜欢这个,因为如果你愿意的话,你可以用它来避免任何算术操作,尽管很难对它进行处理:
In [37]: m
Out[37]:
array([[ 1, 1, 1, 0],
[ 0, 5, 0, 1],
[ 2, 1, 3, 10]])
In [38]: m * np.minimum.accumulate(m != 0)
Out[38]:
array([[1, 1, 1, 0],
[0, 5, 0, 0],
[0, 1, 0, 0]])
In [39]: np.where(np.minimum.accumulate(m != 0), m, 0)
Out[39]:
array([[1, 1, 1, 0],
[0, 5, 0, 0],
[0, 1, 0, 0]])
答案 3 :(得分:1)
使用np.logical_and.accumulate
的@AGNGazer解决方案的更优化版本以及整数的隐式布尔转换(不需要大量乘法)
def transform(matrix):
mat = np.asarray(matrix)
mat[~np.logical_and.accumulate(mat, axis = 0)] = 0
return mat
transform(m)
Out:
array([[1, 1, 1, 0],
[0, 5, 0, 0],
[0, 1, 0, 0]])
时序:
%timeit transform2(m) # AGN's solution
The slowest run took 44.73 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 9.93 µs per loop
%timeit transform(m)
The slowest run took 9.00 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 7.99 µs per loop
m = np.random.randint(0,5,(100,100))
%timeit transform(m)
The slowest run took 6.03 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 43.9 µs per loop
%timeit transform2(m)
The slowest run took 4.09 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 50.4 µs per loop
看起来速度提高了15%。