我的阵列很大
abstract class BaseDB<T extends Built<T, R> & Identifiable & Mapable, R extends Builder<T, R>> {
process(T entity) {
print(entity.id); // From Identifiable
entity.toMap(); // From Mapable
// ... etc
}
}
data = np.empty((n, k))
和n
都很大的地方。我也有很多生成器k
,每个生成器都有g
个元素,我想将每个生成器加载到k
中的一行中。我可以的:
data
或类似的内容,但这会复制data[i] = list(g)
中的数据。我可以加载一个for循环:
g
但是我想知道numpy是否已经可以做到这一点而无需在Python中复制或循环了。
我知道for j, x in enumerate(g):
data[i, j] = x
的长度为g
,并且很高兴在必要时进行一些k
子类修补。 __len__
在创建新数组时会接受类似的内容,但由于上下文的限制,如果可能的话,我宁愿加载到该已有数组中。
答案 0 :(得分:1)
如评论中所述,您无能为力。
尽管您可以考虑以下两种解决方案:
numpy.fromiter
使用data = np.empty((n, k))
和numpy.fromiter
参数代替您自己创建count
,这是在您事先知道项目数的情况下专门创建的。这样,numpy不必“猜测”大小并重新分配,直到猜测足够大为止。
使用fromiter
可以在C而不是python中运行for
循环。这可能会快一点,但是真正的瓶颈可能还是在您的生成器中。
请注意,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]])
"""
如果您可以重复使用data
并希望避免重新分配内存,则不能再使用numpy的fromiter
。恕我直言,避免python的for
循环的唯一方法是在cython中实现它。再次强调,这很可能是矫kill过正,因为您仍然必须阅读python中的生成器。
作为参考,fromiter
的C实现如下所示:https://github.com/numpy/numpy/blob/v1.18.3/numpy/core/src/multiarray/ctors.c#L4001-L4118
答案 1 :(得分:0)
没有比您描述的方法更快的方法。您必须通过迭代生成器或分配整个列表来分配numpy数组的每个元素。
答案 2 :(得分:0)
这里的事物:
1)你只能说
for whatever in g:
do_stuff
由于g是一个生成器,所以for循环了解如何从生成器中获取数据。
2)您不必一定要从生成器中“复制”(因为它不是按设计需要将整个序列加载到内存中),但是您将需要遍历它以填充您的生成器numpy数据结构。使用numpy或itertools中的工具,您也许可以挤出一些性能(因为结构很大)。
因此,由于您使用的是发电机,答案是“否”。如果您不需要一次获得所有数据,则可以使用生成器来使内存配置文件保持较小,但我对处理数据没有任何了解。