将数据从生成器加载到已分配的numpy数组中

时间:2019-04-30 16:02:38

标签: python numpy

我的阵列很大

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__在创建新数组时会接受类似的内容,但由于上下文的限制,如果可能的话,我宁愿加载到该已有数组中。

3 个答案:

答案 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]])
"""

使用cython

如果您可以重复使用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中的工具,您也许可以挤出一些性能(因为结构很大)。

因此,由于您使用的是发电机,答案是“否”。如果您不需要一次获得所有数据,则可以使用生成器来使内存配置文件保持较小,但我对处理数据没有任何了解。