【问题标题】:fast way to put ones beetween ones in each row of a numpy 2d array在numpy 2d数组的每一行中放置一个的快速方法
【发布时间】:2016-09-07 21:18:25
【问题描述】:

我有一个仅由零和一组成的二维数组 (Q)。我希望在每行 Q 的 1 之间的每个位置填充 1。这是一个示例:

原矩阵:

[0 0 0 1 0 1]
[1 0 0 0 0 0]
[0 0 0 0 0 0]
[1 1 0 1 0 0]
[1 0 0 0 0 1]
[0 1 1 0 0 1]
[1 0 1 0 1 0]

生成的矩阵:

[0 0 0 1 1 1]
[1 0 0 0 0 0]
[0 0 0 0 0 0]
[1 1 1 1 0 0]
[1 1 1 1 1 1]
[0 1 1 1 1 1]
[1 1 1 1 1 0]

我实现了一个算法,它可以工作,但是对于大型数组它效率不高。

def beetween(Q):
    for client in range(len(Q)):
        idStart = findIdStart(Q, client)
        idEnd = findIdEnd(Q, client)
        if idStart != idEnd and idStart > -1 and idEnd > -1:
             for i in range(idStart, idEnd):
                  Q[client][i] = 1
     return Q

def findIdStart(Q, client):
    if Q.ndim > 1:
        l, c = np.array(Q).shape
        for product in range (0, c):
            if Q[client][product] == 1:
                return product
    else:
        idProduct = 1
        Qtemp = Q[client]
        if Qtemp[idProduct] == 1:
            return idProduct
    return -1

def findIdEnd(Q, client):
    if Q.ndim > 1:
        l, c = np.array(Q).shape
        Qtemp = Q[client]
        for product in range(0,c):
            idProduct = (c-1)-product
            if Qtemp[idProduct]==1:
                return idProduct
    else:
        idProduct = 1
        Qtemp = Q[client]
        if Qtemp[idProduct] == 1:
            return idProduct
    return -1

我正在尝试构建更优化的版本,但没有成功:

def beetween(Q):
    l, c = np.shape(Q)
    minIndex = Q.argmax(axis=1)
    maxIndex = c-(np.fliplr(Q).argmax(axis=1))
    Q = np.zeros(shape=(l,c)).astype(np.int)
    for i in range(l):
        Q[i, minIndex[i]:maxIndex[i]] = 1
    return Q

原矩阵:

[0 0 0 1 0 1]
[1 0 0 0 0 0]
[0 0 0 0 0 0]
[1 1 0 1 0 0]
[1 0 0 0 0 1]
[0 1 1 0 0 1]
[1 0 1 0 1 0]

错误的结果

[0 0 0 1 1 1] # OK
[1 0 0 0 0 0] # OK
[1 1 1 1 1 1] # wrong
[1 1 1 1 0 0] # OK
[1 1 1 1 1 1] # OK
[0 1 1 1 1 1] # OK
[1 1 1 1 1 0] # OK

任何人都可以为这个问题提出另一个简单的解决方案吗?

谢谢。

【问题讨论】:

  • 谢谢先生们,所有提出的算法都优雅地解决了这个问题。

标签: python arrays numpy matrix


【解决方案1】:

这是一个单行:

In [25]: Q
Out[25]: 
array([[0, 0, 0, 1, 0, 1],
       [1, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0],
       [1, 1, 0, 1, 0, 0],
       [1, 0, 0, 0, 0, 1],
       [0, 1, 1, 0, 0, 1],
       [1, 0, 1, 0, 1, 0]])

In [26]: np.maximum.accumulate(Q, axis=1) & np.maximum.accumulate(Q[:,::-1], axis=1)[:,::-1]
Out[26]: 
array([[0, 0, 0, 1, 1, 1],
       [1, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 1],
       [0, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 0]])

或者

In [36]: np.minimum(np.maximum.accumulate(Q, axis=1), np.maximum.accumulate(Q[:,::-1], axis=1)[:,::-1])
Out[36]: 
array([[0, 0, 0, 1, 1, 1],
       [1, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 1],
       [0, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 0]])

在任何一种情况下,被组合的两个术语是

In [37]: np.maximum.accumulate(Q, axis=1)
Out[37]: 
array([[0, 0, 0, 1, 1, 1],
       [1, 1, 1, 1, 1, 1],
       [0, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1],
       [0, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1]])

In [38]: np.maximum.accumulate(Q[:,::-1], axis=1)[:,::-1]
Out[38]: 
array([[1, 1, 1, 1, 1, 1],
       [1, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1, 0]])

【讨论】:

    【解决方案2】:

    np.apply_along_axis 的另一个选项:

    import numpy as np
    
    def minMax(A):
        idx = np.where(A == 1)[0]
        if len(idx) > 1:
            A[idx.min():idx.max()] = 1
        return A
    ​
    np.apply_along_axis(minMax, 1, mat)
    
    # array([[0, 0, 0, 1, 1, 1],
    #        [1, 0, 0, 0, 0, 0],
    #        [0, 0, 0, 0, 0, 0],
    #        [1, 1, 1, 1, 0, 0],
    #        [1, 1, 1, 1, 1, 1],
    #        [0, 1, 1, 1, 1, 1],
    #        [1, 1, 1, 1, 1, 0]])
    

    【讨论】:

      【解决方案3】:

      下面的函数查看单行并在其他 1 之间填充 1(如果存在)。它假定数组只包含 0 和 1。

      import numpy as np
      
      def ones_row(row):
          if np.sum(row) >= 2:  # Otherwise, not enough 1s
              inds = np.where(row == 1)[0]
              row[inds[0]:inds[-1]] = 1
          return row
      

      现在您可以使用

      处理整个数组
      for jj in range(len(Q)):
          Q[jj] = ones_row(Q[jj])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-28
        • 2023-03-14
        • 1970-01-01
        • 1970-01-01
        • 2015-08-03
        • 2019-01-20
        • 2016-06-01
        • 1970-01-01
        相关资源
        最近更新 更多