numpy.all与对象dtypes的奇怪行为

时间:2015-07-09 15:17:13

标签: python numpy

给定一个dtype=object数组,numpy.all/any返回最后一个对象。例如:

>>> from string import ascii_lowercase
>>> x = np.array(list(ascii_lowercase), dtype=object)
>>> x.all()
'z'

在研究这个问题时,除了this seemingly unrelated SO post之外我找不到更多内容,这让我发现这是一个在numpy中的漏洞(截至2015年3月):first reportmore relevant issue。发布这个,以便其他人努力解决这个问题可以更有效地找到这些信息。

1 个答案:

答案 0 :(得分:3)

numpy版本1.8.2中,np.anynp.all表现为经典的短路逻辑和/或功能。 LISP行为浮现在脑海中。 Python的andor运算符执行此操作。

一些例子:

In [203]: np.all(np.array([[1,2],1,[],[1,2,3]],dtype=object))
Out[203]: []

In [204]: np.any(np.array([[1,2],1,[],[1,2,3]],dtype=object))
Out[204]: [1, 2]

In [205]: np.any(np.array([0,[],[1,2],1,[],[1,2,3]],dtype=object))
Out[205]: [1, 2]

In [206]: np.all(np.array([True,False,[1,2],1,[],[1,2,3]],dtype=object))
Out[206]: False

np.all返回逻辑上为False的第一个项目;否则最后一项。 np.any逻辑上为True的第一个项目;否则最后一项。

在LISP世界中,这被认为是一个有用的特征。一旦结果清楚,它不仅会停止评估元素,而且可以使用该返回值的标识。

有没有办法使用and/or运算符和某种map或reduce来复制此行为?

In [8]: 0 or [] or [1,2] or 1 or [1,2,3]
Out[8]: [1, 2]

???([0,[],[1,2],1,[1,2,3]])

正如评论中所建议的那样:

In [26]: reduce(lambda a,b:a and b, np.array([1,2,3,[1,2,3]],dtype=object))
Out[26]: [1, 2, 3]

这可能实际上并不会使整个循环短路。相反,它会使每一步都短路,并向前传播该值。使用lambda a,b:b and a返回列表中的第1项,而不是最后一项。可以使用计时来测试它是否在整个阵列中循环(或不)。

np.allufunc,定义为np.logical_and.reduce

https://github.com/numpy/numpy/blob/master/numpy/core/_methods.py

umr_all = um.logical_and.reduce
def _all(a, axis=None, dtype=None, out=None, keepdims=False):
    return umr_all(a, axis, dtype, out, keepdims)
dtype = object的

logical_andc source

中定义

https://github.com/numpy/numpy/blob/master/numpy/core/src/umath/funcs.inc.src

/* Emulates Python's 'a and b' behavior */
static PyObject *
npy_ObjectLogicalAnd(PyObject *i1, PyObject *i2)

同样适用于np.any。其他地方定义了数字dtype版本。

有一个补丁强制np.all/any返回dtype=bool。但是通过直接致电np.logical_all,您可以自己控制。

In [304]: np.logical_or.reduce(np.array([0,[1,2,3],4],dtype=object))
Out[304]: [1, 2, 3]

In [305]: np.logical_or.reduce(np.array([0,[1,2,3],4],dtype=object),dtype=bool)
Out[305]: True