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.