简体   繁体   English

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

[英]How do you 'remove' a numpy array from a list of numpy arrays?

If I have a list of numpy arrays, then using remove method returns a value error.如果我有一个 numpy 数组列表,那么使用 remove 方法会返回一个值错误。

For example:例如:

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

Would give me会给我

ValueError: The truth value of an array with more than one element is ambiguous. ValueError:包含多个元素的数组的真值不明确。 Use a.any() or a.all()使用 a.any() 或 a.all()

I can't seem to get the all() to work, is it just not possible?我似乎无法让 all() 工作,这是不可能的吗?

The problem here is that when two numpy arrays are compared with ==, as in the remove() and index() methods, a numpy array of boolean values (the element by element comparisons) is returned which is interpretted as being ambiguous.这里的问题是,当两个 numpy 数组与 == 进行比较时,如在 remove() 和 index() 方法中,返回一个布尔值的 numpy 数组(逐元素比较),这被解释为不明确。 A good way to compare two numpy arrays for equality is to use numpy's array_equal() function.比较两个 numpy 数组是否相等的一个好方法是使用 numpy 的 array_equal() 函数。

Since the remove() method of lists doesn't have a key argument (like sort() does), I think that you need to make your own function to do this.由于列表的 remove() 方法没有关键参数(就像 sort() 一样),我认为您需要创建自己的函数来执行此操作。 Here's one that I made:这是我做的一个:

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.')

If you need it to be faster then you could Cython-ize it.如果您需要它更快,那么您可以对它进行 Cython 化。

Here you go:干得好:

list.pop(1)

Update:更新:

list.pop(list.index(element))

I don't think you can get around traversing the list to find the position of the element.我不认为你可以绕过遍历列表来找到元素的位置。 Don't worry about it.别担心。 Python will, by default use a good searching algorithm to find it at least cost for you.默认情况下,Python 会使用一种好的搜索算法来为您找到最少的成本。

Use Python Basic Functionalities使用 Python 基本功能

The following solution uses the list.index(element) method from the list of arrays.以下解决方案使用数组列表中的list.index(element)方法。

Searching for a numpy.ndarray needs to be able to hash numpy.ndarray instances.搜索numpy.ndarray需要能够散列 numpy.ndarray 实例。 Therefore, we need to implement a hashing algorithm.因此,我们需要实现一个哈希算法。 This is fairly simple, although the code presented looks a bit long, most of the lines are used for checking for edge cases or the addition of comments.这相当简单,虽然呈现的代码看起来有点长,但大部分行用于检查边缘情况或添加注释。

You can copy paste the code into a file and run it from the command line or a SDK as PyCharm.您可以将代码复制粘贴到文件中,然后从命令行或 SDK 作为 PyCharm 运行它。

You need to know about你需要知道

  • [].index(element) [].index(元素)
  • hash (hashing and hash collisions) hash(散列和散列冲突)
  • how to hash a numpy array如何散列一个numpy数组

Note:笔记:

  • hash collisions can lead to wrong decisions, you need to decide yourself about the probability and impact哈希冲突会导致错误的决定,你需要自己决定概率和影响
  • only the first occurence of the array is removed, should there be several with the same data.如果有多个具有相同数据的数组,则仅删除数组的第一次出现。

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)

Use Base Functionalities from Python and Numpy使用 Python 和 Numpy 的基本功能

You can run the following one-liner to get the result ...您可以运行以下单行代码以获得结果...

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)

... or copy paste the following in a script and experiment a bit. ...或将以下内容复制粘贴到脚本中并进行一些实验。

You need你需要

  • numpy.allclose to compare numpy arrays up to floating point representation error numpy.allclose 将 numpy 数组与浮点表示错误进行比较
  • zip压缩
  • list comprehension列表理解
  • the concept of a mask面具的概念

Note, ...笔记, ...

  • this solution returns a list without all occurencies of the array we searched for此解决方案返回一个列表,其中没有我们搜索的数组的所有出现
  • the returned list has references to the np.ndarray instances also referred from the initial list.返回的列表包含对 np.ndarray 实例的引用,也从初始列表引用。 There are no copies!没有副本!

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM