Применить функцию numpy (np.vstack) к генератору, возвращающему 2 значения - PullRequest
0 голосов
/ 19 декабря 2018

У меня есть функция генератора, которая возвращает пакеты данных x и y.Теперь я хочу написать функцию, которая исчерпывает генератор и складывает его так, чтобы у меня был весь вход и выход моей базы данных в виде 2-х числовых массивов.

Если бы генератор был разделен, следующий кодработа:

import numpy as np
import time

def foo_gen_x(epochs):
  for _ in range(epochs):
    yield np.array([1, 2])

def foo_gen_y(epochs):
  for _ in range(epochs):
    yield np.array(["foo"])

start = time.time()
x_epoch = np.vstack(foo_gen_x(100000))
y_epoch = np.vstack(foo_gen_y(100000))
print(x_epoch)
print(y_epoch)
# output x_epoch
# [[1 2]
# ...
# [1 2]]
# output y_epoch
# [['foo']
# ...
# ['foo']]
print("time taken: {}".format(time.time() - start))
# time taken: time taken: 0.6881139278411865

Однако генератор, который у меня есть, выглядит примерно так (возвращает 2 значения):

def foo_gen_xy(epochs):
  for _ in range(epochs):
    yield np.array([1, 2]), np.array(["foo"])

Попытка 1

Поэтому я попытался что-то написатькак это:

x_epoch, y_epoch = [np.vstack(x), np.vstack(y) for x, y in foo_gen_xy(epochs=4)]
# ValueError: too many values to unpack (expected 2)

Но это дает ValueError.

Попытка 2

Затем я попробовал более явный подход:

# working but too many lines (and slower?)
start = time.time()
gen = foo_gen_xy(100000)
x_epoch, y_epoch = gen.__next__()

for x, y in gen:
    x_epoch = np.vstack((x_epoch, x))
    y_epoch = np.vstack((y_epoch, y))

print(x_epoch)
print(y_epoch)
print("time taken: {}".format(time.time() - start))
# time taken: 31.917259454727173

Это примерно в 46 раз медленнее.

Попытка 3

Я мог бы сначала просто сложить все с помощью:

epoch = np.vstack(foo_gen_xy(100000))
# output
# [[array([1, 2]) array(['foo'], dtype='<U3')]
# ...
# [array([1, 2]) array(['foo'], dtype='<U3')]]

Тем не менее, разделение на части выглядит как обходной путь, и этоВведена еще одна проблема, которая меняется dtype.

Код в блокноте Jupyter

https://colab.research.google.com/drive/1IncrTAosFuQmK65ojmzWV38F8FceL3qt

Вопрос

Что может быть более эффективным способомприменения np.vstack() к функции-генератору, которая возвращает 2 значения?

1 Ответ

0 голосов
/ 19 декабря 2018

Решение и синхронизация

Вот простой и быстрый один вкладыш:

arrs = [np.vstack(a) for a in zip(*foo_gen_xy(10000))]
#78 ms ± 48.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Вывод:

[array([[1, 2],
       [1, 2],
       [1, 2],
       ...,
       [1, 2],
       [1, 2],
       [1, 2]]), array([['foo'],
       ['foo'],
       ['foo'],
       ...,
       ['foo'],
       ['foo'],
       ['foo']], dtype='<U3')]

Примечание об инициализации большого массива из множества подмассивов

Этот вид инициализации сложного массива из большого списка подмассивов (и связанных с ними времен) обсуждался до смерти на SO много раз прежде.Вот краткая версия:

  • Генерация одного Python list из ваших массивов с последующим объединением (или суммированием, или чем-то еще) всех их одновременно, как правило, по крайней мере так же быстро, какЛюбое более изящное, более оптимизированное, кажущееся решение

  • Другой надежно быстрый метод - предварительно инициализировать один большой выходной массив (или, в вашем случае, два больших выходных массива), а затем заполнить его в цикле,Для достаточно больших подмассивов производительность этих двух методов обычно эквивалентна.

Примечание о вашей первой попытке

Исправить ValueError, который вы получаете откод в первой попытке, просто оберните элементы списка в кортеж:

x_epoch, y_epoch = [(np.vstack(x), np.vstack(y)) for x, y in foo_gen_xy(epochs=4)]

В списках, каждый «цикл» должен возвращать ровно одно значение, поэтому стандартным способом обойти это ограничение являетсявместо этого вернуть ровно одну tuple.Это все равно не даст вам желаемого результата, поскольку фактически не объединяет никакие массивы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...