考虑Python 2.7中的以下示例。我们有一个任意函数f()
,它返回两个1维numpy数组。请注意,通常f()
可能会返回不同大小的数组,并且大小可能取决于输入。
现在我们想在map
上调用f()
并将结果连接到两个单独的新数组中。
import numpy as np
def f(x):
return np.arange(x),np.ones(x,dtype=int)
inputs = np.arange(1,10)
result = map(f,inputs)
x = np.concatenate([i[0] for i in result])
y = np.concatenate([i[1] for i in result])
这给出了预期的结果。但是,由于结果可能占用大量内存,因此最好通过调用imap
而不是map
来使用生成器。
from itertools import imap
result = imap(f,inputs)
x = np.concatenate([i[0] for i in result])
y = np.concatenate([i[1] for i in result])
但是,这会产生错误,因为生成器在我们计算y
的位置是空的。
有没有办法只使用一次生成器并仍然创建这两个连接数组?我正在寻找没有for循环的解决方案,因为重复连接/追加数组效率相当低。
提前致谢。
答案 0 :(得分:3)
有没有办法只使用一次生成器并仍然创建这两个连接数组?
是的,可以使用tee
克隆生成器:
import itertools
a, b = itertools.tee(result)
x = np.concatenate([i[0] for i in a])
y = np.concatenate([i[1] for i in b])
但是,使用tee
对您的内存使用情况没有帮助。上述解决方案需要5 N内存才能运行:
tee
,np.concatenate
次调用中的列表推导,显然,我们可以通过放弃tee
:
x_acc = []
y_acc = []
for x_i, y_i in result:
x_acc.append(x_i)
y_acc.append(y_i)
x = np.concatenate(x_acc)
y = np.concatenate(y_acc)
这减少了一个N,留下4 N.进一步意味着删除中间列表并预先分配x
和y
。请注意,您不需要知道数组的精确大小,只需要知道上限:
x = np.empty(capacity)
y = np.empty(capacity)
right = 0
for x_i, y_i in result:
left = right
right += len(x_i) # == len(y_i)
x[left:right] = x_i
y[left:right] = y_i
x = x[:right].copy()
y = y[:right].copy()
事实上,你甚至不需要上限。只需确保x
和y
足够大,以容纳新项目:
for x_i, y_i in result:
# ...
if right >= len(x):
# It would be slightly trickier for >1D, but the idea
# remains the same: alter the 0-the dimension to fit
# the new item.
new_capacity = max(right, len(x)) * 1.5
x = x.resize(new_capacity)
y = y.resize(new_capacity)