将位于0以下的所有元素转换为矩阵中的0(Python)

时间:2018-01-25 23:22:19

标签: python python-3.x numpy linear-algebra

这是一个矩阵:

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)

4 个答案:

答案 0 :(得分:2)

方法1(原始)

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

方法2(进一步优化)

def transform2(matrix):
    mat = np.asarray(matrix)
    mat *= (mat != 0).cumprod(axis=0, dtype=np.bool)
    return mat

方法3(甚至更优化)

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;操作:

  1. 创建一个包含False(数字0)的布尔掩码,其中mat的元素为0True(数字{{1} })它们是非零的:

    1
  2. 使用数字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==10*00*1,因此&#34;掩码&#34;将是00。它们仅1位于0为零且低于(!)的位置,因为&#34;累积性质&#34;列中的产品(因此mask1)。

  3. 现在,我们希望将axis=0中与mat对应的0元素设置为mask2。为此,我们创建一个0的布尔掩码,其中Truemask2,其他位置为0。通过将逻辑(或二进制)NOT应用于False

    ,可以轻松实现这一点
    mask2

    使用&#34;逻辑&#34; NOT此处创建一个布尔数组,因此我们避免显式类型转换。

  4. 最后,我们使用Boolean Indexing选择mask3 = np.logical_not(mask2) 中需要设置为mat并将其设置为0的元素:

    0
  5. 可选优化

    如果您考虑到这一点,如果我们执行以下操作,我们可以摆脱步骤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%。