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

15

如果我有一个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]))

给我会出现一个 ValueError:具有多个元素的数组的真值是模棱两可的。使用 a.any() 或 a.all()。

我似乎无法让 all() 起作用,这不可能吗?


只是提醒一下,使用 list 作为变量并不是一个好主意,因为它是 Python 中的关键字。这可能会在以后给你带来麻烦。 - Justin Peel
是的,谢谢。我在尝试解决这个问题时被咬了一口,使用list()将数组转换为列表,然后使用remove等方法。 - matt_s
4个回答

15
这里的问题是,当使用“==”比较两个numpy数组时(如remove()和index()方法中),将返回一个numpy布尔值数组(逐元素比较),这被解释为具有二义性。比较两个numpy数组是否相等的一种好方法是使用numpy的array_equal()函数。
由于列表的remove()方法没有key参数(就像sort()方法一样),我认为你需要自己编写一个函数来进行比较并删除。下面是我写的一个函数:
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进行优化。


3

这里是你需要的:

list.pop(1)

更新:

list.pop(list.index(element))

我认为您无法避免遍历列表来查找元素的位置。不用担心,Python会默认使用高效的搜索算法,以最小的代价帮助您找到所需元素。


谢谢,我意识到这对我的示例有效,但实际上我需要做的是我不知道要删除的数组的位置。我认为可以使用remove方法而不是使用循环来找到更好的方法。 - matt_s
4
谢谢你帮我解决这个问题。如果我在 numpy 数组中使用 list.index() 方法,会再次出现模棱两可的 truth 错误提示,嗯。 - matt_s

2

使用 Python 的基本功能

下面的解决方案使用了列表数组的 list.index(element) 方法。

搜索 numpy.ndarray 需要能够哈希 numpy.ndarray 实例。因此,我们需要实现一个哈希算法。这是相当简单的,虽然所呈现的代码看起来有点长,但大多数行都用于检查边缘情况或添加注释。

您可以将代码复制粘贴到文件中,并从命令行或 PyCharm 作为 SDK 运行它。

你需要知道:

  • [].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)

1

使用 Python 和 Numpy 的基本功能

您可以运行以下一行代码来获取结果...

import numpy as np

# Your inputs ...
l = [np.array([1, 1, 1]), np.array([2, 2, 2]), np.array([3, 3, 3])]
array_to_remove = np.array([2, 2, 2])

# My result ...
result = [a for a, skip in zip(l, [np.allclose(a, array_to_remove) for a in l]) if not skip]

print(result)

...或者将以下内容复制粘贴到脚本中并进行一些实验。

您需要:

  • numpy.allclose:比较numpy数组,直到浮点表示错误
  • zip
  • 列表推导式
  • 掩码的概念

请注意:

  • 此解决方案返回一个列表,其中不包含我们搜索的数组的所有出现次数
  • 返回的列表具有对最初列表中也引用的np.ndarray实例的引用。没有副本!

import numpy as np


def remove(array, arrays):
    """
    Remove the `array` from the `list` of `arrays`
    Returns list with remaining arrays by keeping the order.

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

    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'

    # We use np.allclose for comparing arrays, this will work even if there are
    # floating point representation differences.
    # The idea is to create a boolean mask of the same lenght as the input arrays.
    # Then we loop over the arrays-elements and the mask-elements and skip the
    # flagged elements
    mask = [np.allclose(a, array) for a in arrays]
    return [a for a, skip in zip(arrays, mask) if not skip]


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.
    _arrays = remove(np.array([2, 2, 2]), arrays)

    # Let's check the result
    print(_arrays)

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接