在Python 3中将映射对象转换为NumPy数组

49

在Python 2中,我可以做如下操作:

import numpy as np    
f = lambda x: x**2
seq = map(f, xrange(5))
seq = np.array(seq)
print seq
# prints: [ 0  1  4  9 16]

在Python 3中它不再起作用:

import numpy as np    
f = lambda x: x**2
seq = map(f, range(5))
seq = np.array(seq)
print(seq)
# prints: <map object at 0x10341e310>

我该如何获得旧的行为(将map函数的结果转换为numpy数组)?

编辑:正如@jonrsharpe在他的答案中指出的那样,如果我首先将seq转换为列表,这个问题就可以解决:

seq = np.array(list(seq))

但我更希望避免对list进行额外的调用。


我其实知道list的解决方案,但我想要一个直接的解决方案。 - btel
不要先转换为 list。我忘了提醒。 - btel
2个回答

56

除了@jonrsharpe已经指出的有效解决方案之外,还有另一种选择,即使用np.fromiter

>>> import numpy as np    
>>> f = lambda x: x**2
>>> seq = map(f, range(5))
>>> np.fromiter(seq, dtype=np.int)
array([ 0,  1,  4,  9, 16])

fromiter 的示例基本上是这样的:np.fromiter((x*x for x in range(5)),int) - hpaulj

15
虽然你把它称为seq,但Python 3中的map对象不是一个序列(它是一个迭代器,请参见Python 3中的新内容)。numpy.array需要一个序列以便可以确定长度并保留适当数量的内存;它不会使用迭代器。例如,支持大多数序列操作的range对象可以直接传递;
seq = np.array(range(5))
print(seq)
# prints: [0 1 2 3 4]

如您所知,要恢复先前的行为,您可以明确地将 map 对象转换回序列(例如列表或元组):

seq = np.array(list(seq))  # should probably change the name!

然而,正如文档所述:

一个快速的解决方案是在map()周围包装list(),例如list(map(...)),但更好的解决方案通常是使用列表推导式(特别是当原始代码使用lambda时)

因此,另一个选项是:
seq = [f(x) for x in range(5)]

或者仅仅:

seq = [x**2 for x in range(5)]

或者,从一开始就实际使用numpy

import numpy as np    
arr = np.arange(5)
arr **= 2
print(arr)
# prints [ 0  1  4  9 16] in 2.x and 3.x

@btel 不会,np.array 不会消耗迭代器。你需要提前获得完整的列表,以便可以预留适当的内存空间。 - jonrsharpe

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