繁体   English   中英

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

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

如果我有一个 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() 工作,这是不可能的吗?

这里的问题是,当两个 numpy 数组与 == 进行比较时,如在 remove() 和 index() 方法中,返回一个布尔值的 numpy 数组(逐元素比较),这被解释为不明确。 比较两个 numpy 数组是否相等的一个好方法是使用 numpy 的 array_equal() 函数。

由于列表的 remove() 方法没有关键参数(就像 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 化。

干得好:

list.pop(1)

更新:

list.pop(list.index(element))

我不认为你可以绕过遍历列表来找到元素的位置。 别担心。 默认情况下,Python 会使用一种好的搜索算法来为您找到最少的成本。

使用 Python 基本功能

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

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

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

你需要知道

  • [].index(元素)
  • hash(散列和散列冲突)
  • 如何散列一个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)

使用 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 数组与浮点表示错误进行比较
  • 压缩
  • 列表理解
  • 面具的概念

笔记, ...

  • 此解决方案返回一个列表,其中没有我们搜索的数组的所有出现
  • 返回的列表包含对 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)

暂无
暂无

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

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