如何从numpy数组列表中“移除”一个numpy数组?

15 投票
4 回答
18186 浏览
提问于 2025-04-16 00:40

如果我有一个包含多个numpy数组的列表,使用remove方法时会出现值错误。

举个例子:

import numpy as np

l = [np.array([1,1,1]),np.array([2,2,2]),np.array([3,3,3])]

l.remove(np.array([2,2,2]))

这样会让我看到

值错误:一个包含多个元素的数组的真假值是模糊的。请使用a.any()或a.all()

我好像无法让all()正常工作,这是不是根本不可能呢?

4 个回答

2

使用Python基本功能

下面的解决方案使用了 list.index(element) 这个方法,它是用在数组列表上的。

如果要查找 numpy.ndarray,就需要能够对这些实例进行哈希处理。因此,我们需要实现一个哈希算法。这其实很简单,尽管代码看起来有点长,但大部分行都是用来检查一些特殊情况或者添加注释的。

你可以把代码复制粘贴到一个文件里,然后通过命令行或者像PyCharm这样的开发工具来运行它。

你需要了解以下内容:

  • [].index(element)
  • 哈希(哈希处理和哈希冲突)
  • 如何对numpy数组进行哈希处理

注意:

  • 哈希冲突可能会导致错误的判断,你需要自己考虑这种情况的可能性和影响。
  • 如果有多个相同数据的数组,只有第一个会被移除。

import numpy as np


def remove(array, arrays):
    """
    Remove the `array` from the `list` of `arrays`
    Operates inplace on the `list` of `arrays` given

    :param array: `np.ndarray`
    :param arrays: `list:np.ndarray`
    :return: None
    """

    assert isinstance(arrays, list), f'Expected a list, got {type(arrays)} instead'
    assert isinstance(array, np.ndarray), f'Expected a numpy.ndarray, got {type(array)} instead'
    for a in arrays:
        assert isinstance(a, np.ndarray), f'Expected a numpy.ndarray instances in arrays, found {type(a)} instead'

    # Numpy ndarrays are not hashable by default, so we create
    # our own hashing algorithm. The following will do the job ...
    def _hash(a):
        return hash(a.tobytes())

    try:
        # We create a list of hashes and search for the index
        # of the hash of the array we want to remove.
        index = [_hash(a) for a in arrays].index(_hash(array))
    except ValueError as e:
        # It might be, that the array is not in the list at all.
        print(f'Array not in list. Leaving input unchanged.')
    else:
        # Only in the case of no exception we pop the array
        # with the same index/position from the original
        # arrays list
        arrays.pop(index)


if __name__ == '__main__':

    # Let's start with the following arrays as given in the question
    arrays = [np.array([1, 1, 1]), np.array([2, 2, 2]), np.array([3, 3, 3])]
    print(arrays)

    # And remove this array instance from it.
    # Note, this is a new instance, so the object id is
    # different. Structure and values coincide.
    remove(np.array([2, 2, 2]), arrays)

    # Let's check the result
    print(arrays)

    # Let's check, whether our edge case handling works.
    remove(np.array([1, 2, 3]), arrays)
3

给你看看:

list.pop(1)

更新:

list.pop(list.index(element))

我觉得你无法避免要遍历整个列表来找到元素的位置。别担心,Python 默认会使用一种不错的搜索算法,帮你以最低的成本找到它。

15

这里的问题是,当用 == 比较两个 numpy 数组时,比如在 remove() 和 index() 方法中,会返回一个布尔值的 numpy 数组(就是逐个元素比较的结果),这个结果会被认为是模糊的。比较两个 numpy 数组是否相等的好方法是使用 numpy 的 array_equal() 函数。

由于列表的 remove() 方法没有像 sort() 那样的 key 参数,所以我觉得你需要自己写一个函数来实现这个功能。这里有一个我写的例子:

def removearray(L,arr):
    ind = 0
    size = len(L)
    while ind != size and not np.array_equal(L[ind],arr):
        ind += 1
    if ind != size:
        L.pop(ind)
    else:
        raise ValueError('array not found in list.')

如果你需要它运行得更快,可以考虑用 Cython 来加速。

撰写回答