44

在我目前的工作中,我经常使用 Numpy 和列表​​推导,为了获得最佳性能,我有以下问题:

如果我按如下方式创建 Numpy 数组,幕后实际上会发生什么?

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

我的猜测是python首先创建一个包含值的普通列表,然后使用列表大小分配一个numpy数组,然后将值复制到这个新数组中。这是正确的,还是解释器足够聪明地意识到列表只是中介,而是直接复制值?

同样,如果我希望使用以下命令从列表理解创建一个 numpy 数组numpy.fromiter()

a = numpy.fromiter( [ x for x in xrange(0,4) ], int )

这会导致在输入之前创建一个中间值列表fromiter()吗?

4

3 回答 3

45

我相信您正在寻找的答案是generator expressionsnumpy.fromiter一起使用。

numpy.fromiter((<some_func>(x) for x in <something>),<dtype>,<size of something>)

生成器表达式是惰性的 - 当您遍历它们时,它们会评估表达式。

使用列表推导生成列表,然后将其输入 numpy,而生成器表达式将一次生成一个。

像大多数语言(如果不是全部)一样,Python 评估内部 -> 外部的事物,因此 using[<something> for <something_else> in <something_different>]将创建列表,然后对其进行迭代。

于 2013-01-17T05:31:27.457 回答
8

您可以创建自己的列表并进行试验以了解情况......

>>> class my_list(list):
...     def __init__(self, arg):
...         print 'spam'
...         super(my_list, self).__init__(arg)
...   def __len__(self):
...       print 'eggs'
...       return super(my_list, self).__len__()
... 
>>> x = my_list([0,1,2,3])
spam
>>> len(x)
eggs
4
>>> import numpy as np
>>> np.array(x)
eggs
eggs
eggs
eggs
array([0, 1, 2, 3])
>>> np.fromiter(x, int)
array([0, 1, 2, 3])
>>> np.array(my_list([0,1,2,3]))
spam
eggs
eggs
eggs
eggs
array([0, 1, 2, 3])
于 2013-01-17T05:33:21.050 回答
0

对于标题中的问题,现在有一个名为 numba 的包,它支持numpy 数组理解,它直接构造 numpy 数组而无需中间 python 列表。与 不同numpy.fromiter的是,它还支持嵌套推导。但是,请记住,如果您不熟悉 numba,它会有一些限制和性能怪癖。

也就是说,它可以非常快速和高效,但是如果你可以使用 numpy 的向量操作来编写它,那么让它更简单可能会更好。

>>> from timeit import timeit
>>> # using list comprehension
>>> timeit("np.array([i*i for i in range(1000)])", "import numpy as np", number=1000)
2.544344299999999
>>> # using numpy operations
>>> timeit("np.arange(1000) ** 2", "import numpy as np", number=1000)
0.05207519999999022
>>> # using numpy.fromiter
>>> timeit("np.fromiter((i*i for i in range(1000)), dtype=int, count=1000)",
...        "import numpy as np",
...        number=1000)
1.087984500000175
>>> # using numba array comprehension
>>> timeit("squares(1000)",
... """
... import numpy as np
... import numba as nb
... 
... @nb.njit
... def squares(n):
...     return np.array([i*i for i in range(n)])
... 
... 'compile the function'
... squares(10)
... """,
... number=1000)
0.03716940000003888
于 2021-03-19T15:09:01.000 回答