【问题标题】:Test if a numpy array is a member of a list of numpy arrays, and remove it from the list测试 numpy 数组是否是 numpy 数组列表的成员,并将其从列表中删除
【发布时间】:2019-04-03 13:12:37
【问题描述】:

当测试一个 numpy 数组 c 是否是一个 numpy 数组 CNTS 列表的成员时:

import numpy as np

c = np.array([[[ 75, 763]],
              [[ 57, 763]],
              [[ 57, 749]],
              [[ 75, 749]]])

CNTS = [np.array([[[  78, 1202]],
                  [[  63, 1202]],
                  [[  63, 1187]],
                  [[  78, 1187]]]),
        np.array([[[ 75, 763]],
                  [[ 57, 763]],
                  [[ 57, 749]],
                  [[ 75, 749]]]),
        np.array([[[ 72, 742]],
                  [[ 58, 742]],
                  [[ 57, 741]],
                  [[ 57, 727]],
                  [[ 58, 726]],
                  [[ 72, 726]]]),
        np.array([[[ 66, 194]],
                  [[ 51, 194]],
                  [[ 51, 179]],
                  [[ 66, 179]]])]

print(c in CNTS)

我明白了:

ValueError:具有多个元素的数组的真值不明确。使用 a.any() 或 a.all()

不过,答案相当明确:c 正好是 CNTS[1],所以 c in CNTS 应该返回 True!

如何正确测试 numpy 数组是否是 numpy 数组列表的成员?

删除时也会出现同样的问题:

CNTS.remove(c)

ValueError:具有多个元素的数组的真值不明确。使用 a.any() 或 a.all()

应用程序:测试opencv 轮廓(numpy 数组)是否是轮廓列表的成员,例如 Remove an opencv contour from a list of contours

【问题讨论】:

  • @DavidG 真正的问题(对于application)不仅是测试成员资格,而且还从 numpy 数组列表中删除了一个 numpy 数组,我在问题中添加了更多细节。这不是真正的重复。
  • 我觉得你可以用bool(sum((map(lambda x: np.array_equal(x,c), CNTS))))
  • @RudolfMorkovskyi。你可以只使用any,它也会造成短路
  • 所有数组的大小都一样吗?
  • @MadPhysicist 不,那些数组是contours,即点列表,可以是矩形(4 个点)、五边形(5 个点)等。

标签: python arrays list numpy


【解决方案1】:

您收到错误是因为in 实质上在CNTS 的每个元素x 上调用bool(c == x)。引发错误的是 __bool__ 转换:

>>> c == CNTS[1]
array([[[ True,  True]],
       [[ True,  True]],
       [[ True,  True]],
       [[ True,  True]]])

>>> bool(_)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

这同样适用于删除,因为它会测试每个元素是否相等。

遏制

解决方案是使用np.array_equal 或对每个比较应用all 方法:

any(np.array_equal(c, x) for x in CNTS)

any((c == x).all() for x in CNTS)

删除

要执行删除,您对元素的索引比对它的存在更感兴趣。我能想到的最快方法是迭代索引,使用 CNTS 的元素作为比较键:

index = next((i for i, x in enumerate(CNTS) if (c == x).all()), -1)

此选项可以很好地短路,并返回-1 作为默认索引,而不是引发StopIteration。如果您更喜欢错误,可以将参数 -1 删除为 next。如果您愿意,可以将(c == x).all() 替换为np.array_equal(c, x)

现在您可以照常删除:

del CNTS[index]

【讨论】:

  • 谢谢@MadPhysicist。正如我在已编辑的问题中提到的,目标是测试成员资格以最终将其删除(如果存在于 numpy 数组列表中)。后者你会怎么做?
  • @Basj。更新为包括删除
  • 确实很奇怪(我赞成所有 3 个答案)@MadPhysicist!
【解决方案2】:

此解决方案适用于这种情况:

def arrayisin(array, list_of_arrays):
    for a in list_of_arrays:
        if np.array_equal(array, a):
            return True
    return False

此函数遍历数组列表并测试与其他数组的相等性。所以用法是:

>>> arrayisin(c, CNTS)
True

要从列表中删除数组,可以获取数组的索引,然后使用list.pop。在函数get_index 中,我们枚举数组列表,这意味着我们压缩列表的索引和列表的内容。如果有匹配,我们返回匹配的索引。

def get_index(array, list_of_arrays):
    for j, a in enumerate(list_of_arrays):
        if np.array_equal(array, a):
            return j
    return None

idx = get_index(c, CNTS)  # 1
CNTS.pop(idx)

list.pophttps://docs.python.org/3/tutorial/datastructures.html的文档请看python数据结构教程

【讨论】:

  • 谢谢@Jakub。正如我在问题中提到的,目标是测试成员资格以最终将其删除(如果存在于 numpy 数组列表中)。你会怎么做?
【解决方案3】:

使用del 删除要删除的列表的索引。

del CNTS[int(np.where(list(np.array_equal(row, c) for row in CNTS))[0])]

CNTS

[array([[[  78, 1202]],

        [[  63, 1202]],

        [[  63, 1187]],

        [[  78, 1187]]]), array([[[ 72, 742]],

        [[ 58, 742]],

        [[ 57, 741]],

        [[ 57, 727]],

        [[ 58, 726]],

        [[ 72, 726]]]), array([[[ 66, 194]],

        [[ 51, 194]],

        [[ 51, 179]],

        [[ 66, 179]]])]

【讨论】:

  • 这不会短路,并创建一个额外的numpy数组,只是为了调用np.where...
  • 感谢@MadPhysicist,答案已修改
  • 我尝试运行您更新的代码,但它不像宣传的那样工作。 np.where 会将任何输入包装在一个数组中。生成器不会扩展,因此无论如何它都会为您提供索引 0(因为生成器对象是真实的)。
  • 我建议您使用 list 回到您的原始答案。虽然不是最佳的,但效果很好。
  • int(np.where(list(np.array_equal(row, c) for row in CNTS))[0]) -> 1,int(np.where((np.array_equal(row, c) for row in CNTS))[0]) -> 0。我使用的是 numpy 1.14.2。也许在第 15 版中,生成器被扩展了?
猜你喜欢
  • 1970-01-01
  • 2011-03-10
  • 2015-03-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-13
  • 2020-09-15
  • 2017-03-08
  • 2022-01-16
相关资源
最近更新 更多