比较dtype为object的numpy数组

8

我的问题是“为什么?:”

aa[0]
array([[405, 162, 414, 0,
        array([list([1, 9, 2]), 18, (405, 18, 207), 64, 'Universal'],
      dtype=object),
        0, 0, 0]], dtype=object)

aaa
array([[405, 162, 414, 0,
        array([list([1, 9, 2]), 18, (405, 18, 207), 64, 'Universal'],
      dtype=object),
        0, 0, 0]], dtype=object)

np.array_equal(aaa,aa[0])
False

这些数组完全相同。
我的最小示例无法复制这个问题:
be=np.array([1],dtype=object)

be
array([1], dtype=object)

ce=np.array([1],dtype=object)

ce
array([1], dtype=object)

np.array_equal(be,ce)
True

这个也不行:

ce=np.array([np.array([1]),'5'],dtype=object)

be=np.array([np.array([1]),'5'],dtype=object)

np.array_equal(be,ce)
True

然而,要重现我的问题,请尝试以下操作:
be=np.array([[405, 162, 414, 0, np.array([list([1, 9, 2]), 18, (405, 18, 207), 64, 'Universal'],dtype=object),0, 0, 0]], dtype=object)

ce=np.array([[405, 162, 414, 0, np.array([list([1, 9, 2]), 18, (405, 18, 207), 64, 'Universal'],dtype=object),0, 0, 0]], dtype=object)

np.array_equal(be,ce)
False

np.array_equal(be[0],ce[0])
False

我不知道为什么它们不相等。并且,额外的问题是,如何比较它们? 我需要一种高效的方法来检查 aaa 是否在堆栈 aa 中。 我没有使用 aaa in aa,因为会出现 DeprecationWarning: elementwise == comparison failed; this will raise an error in the future. 的警告,并且如果有人想知道,它仍然返回 False

我还尝试过什么?:

np.equal(be,ce)
*** ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

np.all(be,ce)
*** TypeError: only integer scalar arrays can be converted to a scalar index

all(be,ce)
*** TypeError: all() takes exactly one argument (2 given)

all(be==ce)
*** TypeError: 'bool' object is not iterable

np.where(be==ce)
(array([], dtype=int64),)

以下这些代码我无法在控制台中运行,所有的代码都会求值为 False,其中一些还会产生弃用警告:

import numpy as np

ce=np.array([[405, 162, 414, 0, np.array([list([1, 9, 2]), 18, (405, 18, 207), 64, 'Universal'],dtype=object),0, 0, 0]], dtype=object)

be=np.array([[405, 162, 414, 0, np.array([list([1, 9, 2]), 18, (405, 18, 207), 64, 'Universal'],dtype=object),0, 0, 0]], dtype=object)

print(np.any([bee in ce for bee in be]))

print(np.any([bee==cee for bee in be for cee in ce]))

print(np.all([bee in ce for bee in be]))

print(np.all([bee==cee for bee in be for cee in ce]))

当然,其他问题 告诉我这应该可以工作...


顺便说一下:我正在使用递归函数来限制递归次数,所以如果有人知道如何高效地完成这个任务,甚至在评估为True时停止比较,可能是类似于*[break if x == aaa for x in aa]*的东西,如果可能的话。我将永远感激不尽!;-) - DonQuiKong
2
正如@user2357112在这里所解释的那样,"NumPy旨在为刚性多维数字网格设计。尝试获取除刚性多维网格以外的任何内容都将是痛苦的。"或者@juanpa.arrivillaga说:"故事的寓意:不要使用dtype=object数组。它们是受限制的Python列表,具有更差的性能特征,并且numpy不能处理这些对象数组中类似序列的容器的情况。" - keepAlive
@Kanak 如果我需要执行 aa[:,0:3]/np.array([1,9,2]),使用列表将使这些操作变得非常困难。如果您有任何建议,我完全可以使用另一个容器。但我不想分割信息,因为我的代码已经足够难以阅读,而且从不同的地方获取属于一起的数据会让它更加混乱。 - DonQuiKong
使用对象 dtype 数组进行计算有时成功,有时失败。某些操作可以正常工作(尽管比数值类型的运行速度慢),而其他操作则不行。很多情况下取决于对象元素是否实现了必要的方法。 - hpaulj
@hpaulj 有更好的方法吗?我愿意听取任何建议。 - DonQuiKong
3个回答

6
为了对数组进行逐元素比较,您可以使用numpy.equal()函数,并在关键字参数中添加dtype=numpy.object,例如:
In [60]: np.equal(be, ce, dtype=np.object)
Out[60]: 
array([[True, True, True, True,
        array([ True,  True,  True,  True,  True]), True, True, True]],
      dtype=object)

P.S. 使用 NumPy 版本 1.15.2 和 Python 3.6.6 进行检查。

编辑

从版本 1.15 的发布说明中得知,

https://docs.scipy.org/doc/numpy-1.15.1/release.html#comparison-ufuncs-accept-dtype-object-overriding-the-default-bool

Comparison ufuncs accept dtype=object, overriding the default bool

This allows object arrays of symbolic types, which override == and 
other operators to return expressions, to be compared elementwise with 
np.equal(a, b, dtype=object).

我尝试了你的代码,但是出现了“未找到与指定签名和强制转换匹配的循环以进行ufunc equal”错误。可能是dtype出了问题? - Saket Kumar Singh
我得到了相同的错误。(现在我将其移出了一个错放的try语句) - DonQuiKong
可能是Python 2 / 3的问题吧? - DonQuiKong
可能是版本问题。它在我的3.6和1.15.1环境下可以工作。 - hpaulj
@hpaulj,对于我来说,在Python 3.6和Numpy 1.14.5+上无法正常工作。 - DonQuiKong
1
我可以确认,升级 numpy 解决了这个问题。唯一的更改是将 numpy 从1.14.5 升级到 1.15.2 ,现在它评估为 True。谢谢! - DonQuiKong

2
为了补充@kmario23的答案,那么做什么呢?
def wrpr(bools):
    try:
      # ints  = bools.flatten().prod()
        fltn_bools = np.hstack(bools)
    except: # should not pass silently.
        fltn_bools = np.array(wrpr(a) for a in bools)        
    ints = fltn_bools.prod()
    if isinstance(ints, np.ndarray):
        return wrpr(ints)
    return bool(ints)

最后,
>>> wrpr(np.equal(ce, be, dtype=np.object))
True

使用numpy1.15.1和Python 3.6.5以及numpy1.15.1和Python 2.7.13进行检查。


但是,正如这里所评论的:

NumPy旨在用于刚性多维数字网格。尝试获取除刚性多维网格之外的任何内容都将很痛苦。(@user2357112, Jul 31 '17 at 23:10)

和/或

故事的寓意:不要使用dtype=object数组。它们是受限制的Python列表,具有更差的性能特征,并且numpy不能处理这些对象数组中类似序列的容器的情况。 (@juanpa.arrivillaga, Jul 31 '17 at 23:38)


1
我刚试了一下,升级numpy解决了这个问题。(从1.14.5到1.15.2) - DonQuiKong
wrpr(np.array([np.array([True, True]), np.array([True, True, True])])) 怎么样?我得到了 _ValueError: operands could not be broadcast together with shapes (2,) (3,)_。 - Hlib Babii
确实如@HlibBabii所说。看看新的wrpr定义,它可能适合你,同时仍然可以完成以前的工作。 - keepAlive
@keepAlive 对于 np.array([np.array([[True, True]]), np.array([True, True, True])] 仍然无法解决。确实很痛苦 :) - Hlib Babii
1
@HlibBabii 最新版本的 wrpr 可以正常工作。已经使用你提供的两个示例进行了测试。 - keepAlive
显示剩余2条评论

2
您看到的行为在此处有所记录这里

弃用¶

...

对象数组的相等比较

未来,对象数组的比较操作 == 和 np.equal 将不再使用身份检查。例如:

>

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

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

a == b

即使 a 和 b 中的数组是同一个对象,也将始终返回 False(未来会返回错误)。

如果广播或元素比较失败,则等于运算符 == 在未来会像 np.equal 一样引发错误。

将 arr == None 进行比较将来会执行逐元素比较,而非仅返回 False。代码应该使用 arr is None。

所有这些更改目前都会产生 Deprecation- 或 FutureWarnings。

到目前为止,很清楚了。或者说呢?

从 @kmario23 的回答中可以看出,在版本 15.2 中,这些更改尚未完全实施。

使情况变得更糟的是,考虑以下内容:
>>> A = np.array([None, a])
>>> A1 = np.array([None, a])
>>> At = np.array([None, a[:2]])
>>> 
>>> A==A1
False
>>> A==At
array([ True, False])
>>> 

看起来当前的行为更像是偶然而不是精心计划的结果。
我怀疑这是否归结于在逐个元素比较中是否引发异常,请参见此处此处
如果包含数组的两个相应元素本身就是具有兼容形状的数组,如A==A1,它们的比较会产生一个布尔数组。试图将其转换为标量布尔值会引发异常。目前,该异常被捕获并返回标量False。
A==At示例中,当比较最后两个元素时引发异常,因为它们的形状无法广播。这被捕获并且该元素的比较返回标量False,这就是为什么包含数组的比较返回“正常”的布尔数组的原因。
那么@kmario23和@Kanak提出的解决方法呢?他们是否可行?
好的,是的...
>>> np.equal(A, A1, dtype=object)
array([True, array([ True,  True,  True])], dtype=object)
>>> wrpr(np.equal(A, A1, dtype=object))
True

...并且不行。

>>> AA = np.array([None, A])
>>> AA1 = np.array([None, A1])
>>> np.equal(AA, AA1, dtype=object)
array([True, False], dtype=object)
>>> wrpr(np.equal(AA, AA1, dtype=object))
False

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