为什么numpy.sum在添加生成器的元素时返回float64而不是uint64?

时间:2012-12-15 07:56:59

标签: python numpy

我刚刚遇到numpy.sum的这种奇怪行为:

>>> import numpy
>>> ar = numpy.array([1,2,3], dtype=numpy.uint64)
>>> gen = (el for el in ar)
>>> lst = [el for el in ar]
>>> numpy.sum(gen)
6.0
>>> numpy.sum(lst)
6
>>> numpy.sum(iter(lst))
<listiterator object at 0x87d02cc>

根据文档,结果应与可迭代的dtype相同,但为什么在第一种情况下返回numpy.float64而不是numpy.uint64? 为什么最后一个例子不会返回任何类型的总和,也不会引起任何错误?

2 个答案:

答案 0 :(得分:6)

通常,在使用生成器时,numpy函数并不总是能达到预期效果。要创建numpy数组,您需要知道它的大小并在创建它之前键入,这对于生成器是不可能的。如此多的numpy函数要么不能与生成器一起使用,要么在它们回退到Python内置函数时做这种事情。

但是,出于同样的原因,使用生成器通常在Numpy上下文中没用。从Numpy对象生成生成器没有什么好处,因为无论如何你必须在内存中拥有整个Numpy对象。如果您需要保留所有类型,则不应将Numpy对象包装在生成器中。

更多信息:从技术上讲,np.sum的参数应该是一个“类似数组”的对象,而不是可迭代的。类似数组的定义为in the documentation

  

数组,公开数组接口的任何对象,__array__方法返回数组的对象,或任何(嵌套)序列。

数组接口记录为here。基本上,阵列必须具有固定的形状和统一的类型。

生成器不适合此协议,因此不受支持。许多numpy函数都很好,并且会接受其他类型的对象,这些对象在技术上不符合类似数据的要求,但严格阅读文档意味着你不能依赖这种行为。这些操作可能有效,但你不能指望所有类型都能完美保存。

答案 1 :(得分:5)

如果参数是生成器,则使用Python的内置sum

您可以在numpy.sum(numpy / core / fromnumeric.py)的源代码中看到这一点:

  0     if isinstance(a, _gentype):
  1         res = _sum_(a)
  2         if out is not None:
  3             out[...] = res
  4             return out
  5         return res

_gentype只是types.GeneratorType的别名,_sum_是内置sum的别名。

如果您尝试将sum应用于genlst,您可以看到结果相同:6.0

sum的第二个参数是start,默认为 0 ,这是使您的结果为float64的部分原因。

In [1]: import numpy as np

In [2]: type(np.uint64(1) + np.uint64(2))
Out[2]: numpy.uint64

In [3]: type(np.uint64(1) + 0)
Out[3]: numpy.float64

修改: 顺便说一句,我在这个问题上找到了一张票,标注为wontfixhttp://projects.scipy.org/numpy/ticket/669