Numpy Fromiter с генератором списка

import numpy as np
def gen_c():
    c = np.ones(5, dtype=int)
    j = 0
    t = 10
    while j < t:
        c[0] = j
        yield c.tolist()
        j += 1 

# What I did:
# res = np.array(list(gen_c())) <-- useless allocation of memory

# this line is what I'd like to do and it's killing me
res = np.fromiter(gen_c(), dtype=int) # dtype=list ?

Ошибка сказала ValueError: setting an array element with a sequence.

Это очень глупый кусок кода. Я хотел бы создать массив списка (наконец, 2D-массив) из генератора...

Хотя я искал везде, я все еще не могу понять, как заставить это работать.

2 ответа

Решение

Вы можете использовать только numpy.fromiter() создавать 1-мерные массивы (не 2-мерные), как указано в документации numpy.fromiter -

numpy.fromiter (повторяемый, dtype, count=-1)

Создайте новый одномерный массив из повторяемого объекта.

Одна вещь, которую вы можете сделать, это преобразовать функцию генератора, чтобы выдавать отдельные значения из c а затем создать 1D массив из него, а затем изменить его (-1,5), Пример -

import numpy as np
def gen_c():
    c = np.ones(5, dtype=int)
    j = 0
    t = 10
    while j < t:
        c[0] = j
        for i in c:
            yield i
        j += 1

np.fromiter(gen_c(),dtype=int).reshape((-1,5))

Демо -

In [5]: %paste
import numpy as np
def gen_c():
    c = np.ones(5, dtype=int)
    j = 0
    t = 10
    while j < t:
        c[0] = j
        for i in c:
            yield i
        j += 1

np.fromiter(gen_c(),dtype=int).reshape((-1,5))

## -- End pasted text --
Out[5]:
array([[0, 1, 1, 1, 1],
       [1, 1, 1, 1, 1],
       [2, 1, 1, 1, 1],
       [3, 1, 1, 1, 1],
       [4, 1, 1, 1, 1],
       [5, 1, 1, 1, 1],
       [6, 1, 1, 1, 1],
       [7, 1, 1, 1, 1],
       [8, 1, 1, 1, 1],
       [9, 1, 1, 1, 1]])

Как и предполагалось в документах, np.fromiter() принимает только одномерные итерации. Ты можешь использовать itertools.chain.from_iterable() сплющить итерируемое первым и np.reshape() это позже:

import itertools
import numpy as np

def fromiter2d(it, dtype):

    # clone the iterator to get its length
    it, it2 = itertools.tee(it)
    length = sum(1 for _ in it2)

    flattened = itertools.chain.from_iterable(it)
    array_1d = np.fromiter(flattened, dtype)
    array_2d = np.reshape(array_1d, (length, -1))
    return array_2d

Демо-версия:

>>> iter2d = (range(i, i + 4) for i in range(0, 12, 4))

>>> from_2d_iter(iter2d, int)
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

Проверено только на Python 3.6, но также должно работать с Python 2.

Другие вопросы по тегам