python - 将生成器中的数据加载到已分配的 numpy 数组中
问题描述
我有一个大数组
data = np.empty((n, k))
两者n
都k
很大。我也有很多生成器g
,每个都有k
元素,我想将每个生成器加载到data
. 我可以:
data[i] = list(g)
或类似的东西,但这会复制g
. 我可以使用 for 循环加载:
for j, x in enumerate(g):
data[i, j] = x
但我想知道 numpy 是否已经有办法做到这一点,而无需在 Python 中复制或循环。
我知道这有提前g
的长度,并且很乐意在必要时进行一些子类修补。在创建新数组时会接受类似的东西,但由于我的上下文的限制,如果可能的话,我宁愿加载到这个已经存在的数组中。k
__len__
np.fromiter
解决方案
正如评论中所述,您无能为力。
尽管您可以考虑以下两种解决方案:
使用numpy.fromiter
不是data = np.empty((n, k))
自己创建,而是使用numpy.fromiter
和count
参数,它是专门从这种情况下制作的,您事先知道项目的数量。这样 numpy 就不必“猜测”大小并重新分配,直到猜测足够大。使用fromiter
允许for
在 C 而不是 python 中运行循环。这可能会快一点,但真正的瓶颈可能在你的生成器中。
请注意,fromiter
仅处理平面数组,因此您需要阅读所有展平的内容(例如使用chain.from_iterable
),然后才调用reshape
:
from itertools import chain
n = 20
k = 4
generators = (
(i*j for j in range(k))
for i in range(n)
)
flat_gen = chain.from_iterable(generators)
data = numpy.fromiter(flat_gen, 'int64', count=n*k)
data = data.reshape((n, k))
"""
array([[ 0, 0, 0, 0],
[ 0, 1, 2, 3],
[ 0, 2, 4, 6],
[ 0, 3, 6, 9],
[ 0, 4, 8, 12],
[ 0, 5, 10, 15],
[ 0, 6, 12, 18],
[ 0, 7, 14, 21],
[ 0, 8, 16, 24],
[ 0, 9, 18, 27],
[ 0, 10, 20, 30],
[ 0, 11, 22, 33],
[ 0, 12, 24, 36],
[ 0, 13, 26, 39],
[ 0, 14, 28, 42],
[ 0, 15, 30, 45],
[ 0, 16, 32, 48],
[ 0, 17, 34, 51],
[ 0, 18, 36, 54],
[ 0, 19, 38, 57]])
"""
使用 cython
如果您可以重复使用data
并希望避免重新分配内存,则不能再使用 numpyfromiter
了。恕我直言,避免 pythonfor
循环的唯一方法是在 cython 中实现它。同样,这很可能是矫枉过正,因为您仍然必须阅读 python 中的生成器。
作为参考,C 实现fromiter
看起来像这样:https ://github.com/numpy/numpy/blob/v1.18.3/numpy/core/src/multiarray/ctors.c#L4001-L4118
推荐阅读
- excel - 如何使用 Excel VBA 根据标准计算 Outlook 中所有文件夹和子文件夹中的电子邮件?
- ajax - 为什么我对 JAVA-servlet 的 AJAX 调用不起作用
- java - 如何生成一个以零开头并有10位数字的随机手机号码,以零开头?
- reactjs - 我无法使用主键将对象添加到领域
- java - 如何生成通过从 Arraylist 中递归删除所有奇数索引元素创建的序列,以便我们最后只得到 1 个元素?
- nginx - IdentityServer4 中的发现文档在 Ubuntu nginx 上返回 404
- ionic4 - viewdidenter 上的离子滚动顶部特定元素
- python-2.7 - 通过使用 python pandas 删除不需要的行来读取文件
- android - 如何在应用重启之间保存和恢复 Flutter ListView 的滚动位置?
- actions-on-google - 在 Google Home 设备上,下一个 MediaObject 一秒钟后停止播放