【问题标题】:Delete element from multi-dimensional numpy array by value按值从多维numpy数组中删除元素
【发布时间】:2017-04-11 15:07:24
【问题描述】:

给定一个 numpy 数组

a = np.array([[0, -1, 0], [1, 0, 0], [1, 0, -1]])

删除所有值为-1的元素以获取表单数组的最快方法是什么

np.array([[0, 0], [1, 0, 0], [1, 0]])

【问题讨论】:

  • NumPy 数组是刚性网格 - 如果您尝试制作一个参差不齐的数组,您将进入对象数组的可怕世界,性能下降,没有任何东西可以正常工作。仔细考虑这样做是否真的是一个好主意,以及您是否真的应该使用 NumPy。

标签: python numpy


【解决方案1】:

您可能会考虑的另一种方法:

def iterative_numpy(a):
    mask = a != 1
    out = np.array([ a[i,mask[i]] for i xrange(a.shape[0]) ])
    return out

Divakar 的方法loop_compr_based 计算沿掩码行的总和以及该结果的累积总和。这种方法避免了这种求和仍然需要遍历a 的行。它还返回一个数组数组。这很烦人,out 必须使用语法out[1][2] 而不是out[1,2] 进行索引。将时间与矩阵随机整数矩阵进行比较:

In [4]: a = np.random.random_integers(-1,1, size = (3,30))

In [5]: %timeit iterative_numpy(a)
100000 loops, best of 3: 11.1 us per loop

In [6]: %timeit loop_compr_based(a)
10000 loops, best of 3: 20.2 us per loop

In [7]: a = np.random.random_integers(-1,1, size = (30,3))

In [8]: %timeit iterative_numpy(a)
10000 loops, best of 3: 59.5 us per loop

In [9]: %timeit loop_compr_based(a)
10000 loops, best of 3: 30.8 us per loop

In [10]: a = np.random.random_integers(-1,1, size = (30,30))

In [11]: %timeit iterative_numpy(a)
10000 loops, best of 3: 64.6 us per loop

In [12]: %timeit loop_compr_based(a)
10000 loops, best of 3: 36 us per loop

当列多于行时,iterative_numpy 胜出。当行多于列时,loop_compr_based 获胜,但首先转置a 将提高这两种方法的性能。当尺寸相同时,loop_compr_based 是最好的。

重要的边讨论

在实现之外,重要的是要注意任何具有非均匀形状的 numpy 数组不是实际数组,因为值不占用内存的连续部分,并且此外,通常的数组操作将无法按预期工作。

举个例子:

>>> a = np.array([[1,2,3],[1,2],[1]])
>>> a*2
array([[1, 2, 3, 1, 2, 3], [1, 2, 1, 2], [1, 1]], dtype=object)

请注意,numpy 实际上告诉我们这不是通常的带有注释dtype=object 的 numpy 数组。

因此,最好只制作一个 list numpy 数组并相应地使用它们。

【讨论】:

    【解决方案2】:

    方法 #1: 使用 NumPy 拆分数组 -

    def split_based(a, val):
        mask = a!=val
        p = np.split(a[mask],mask.sum(1)[:-1].cumsum())
        out = np.array(list(map(list,p)))
        return out
    

    方法 #2: 使用循环理解,但循环内的工作最少 -

    def loop_compr_based(a, val):
        mask = a!=val
        stop = mask.sum(1).cumsum()
        start = np.append(0,stop[:-1])
        am = a[mask].tolist()
        out = np.array([am[start[i]:stop[i]] for i  in range(len(start))])
        return out
    

    示例运行 -

    In [391]: a
    Out[391]: 
    array([[ 0, -1,  0],
           [ 1,  0,  0],
           [ 1,  0, -1],
           [-1, -1,  8],
           [ 3,  7,  2]])
    
    In [392]: split_based(a, val=-1)
    Out[392]: array([[0, 0], [1, 0, 0], [1, 0], [8], [3, 7, 2]], dtype=object)
    
    In [393]: loop_compr_based(a, val=-1)
    Out[393]: array([[0, 0], [1, 0, 0], [1, 0], [8], [3, 7, 2]], dtype=object)
    

    运行时测试-

    In [387]: a = np.random.randint(-2,10,(1000,1000))
    
    In [388]: %timeit split_based(a, val=-1)
    10 loops, best of 3: 161 ms per loop
    
    In [389]: %timeit loop_compr_based(a, val=-1)
    10 loops, best of 3: 29 ms per loop
    

    【讨论】:

    • 对于 Python 3,我相信方法 #1 的最后一行必须是:out = np.array(list(map(list,p)))
    • @capitalistpug 对我来说,方法 #2 比方法 #1 快 5 倍:a = np.random.randint(-2,10,(1000,1000))
    • 我在使用 py3 时犯了一个错误,你知道 map 是一个迭代器。
    【解决方案3】:

    使用indexes = np.where(a == -1) 获取元素的索引 Find indices of elements equal to zero from numpy array

    然后用np.delete(your_array, indexes)按索引删除特定元素 How to remove specific elements in a numpy array

    【讨论】:

    • 这不会在多维数组中保留正确的值。
    • 想要的结果不是多维数组。这是一个不规则数组(或对象数组)的列表。
    【解决方案4】:

    这个怎么样?

    print([[y for y in x if y > -1] for x in a])
    [[0, 0], [1, 0, 0], [1, 0]]
    

    【讨论】:

    • 不是一个 numpy 解决方案。如果你使用它,效率很可能会受到影响。
    【解决方案5】:

    对于您可能想要对此类数组执行的几乎所有操作,您可以使用masked array

    a = np.array([[0, -1, 0], [1, 0, 0], [1, 0, -1]])
    
    b=np.ma.masked_equal(a,-1)
    
    b
    Out[5]: 
    masked_array(data =
     [[0 -- 0]
     [1 0 0]
     [1 0 --]],
                 mask =
     [[False  True False]
     [False False False]
     [False False  True]],
           fill_value = -1)
    

    如果你真的想要参差不齐的数组,可以.compressed() by line

    c=np.array([b[i].compressed() for i in range(b.shape[0])])
    
    c
    Out[10]: array([array([0, 0]), array([1, 0, 0]), array([1, 0])], dtype=object)
    

    【讨论】:

      猜你喜欢
      • 2012-04-27
      • 2011-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多