Генератор не итератор?

У меня есть генератор (функция, которая выдает данные), но при попытке передать его gensim.Word2Vec я получаю следующую ошибку:

TypeError: вы не можете передать генератор в качестве аргумента предложения. Попробуйте итератор.

Разве генератор - это не итератор? Если нет, то как мне сделать из него итератор?

Глядя на код библиотеки, кажется, что он просто перебирает предложения вроде for x in enumerate(sentences), что отлично работает с моим генератором. Что же тогда вызывает ошибку?


person riv    schedule 08.12.2015    source источник
comment
Что ж ... Они приложили много усилий, чтобы помешать вам использовать генераторы: github.com/piskvorky/gensim/blob/   -  person mgilson    schedule 09.12.2015
comment
В этом нет никакого смысла.   -  person user2357112 supports Monica    schedule 09.12.2015
comment
@ user2357112 - Возможно, ввод нужно повторить несколько раз. Документы говорят, что список является вводом ОК. (Конечно, в этом случае iterator определенно является неправильным термином для добавления в сообщение об ошибке).   -  person mgilson    schedule 09.12.2015
comment
@riv Тогда вы можете просто изменить свой генератор на понимание списка.   -  person Tamas Hegedus    schedule 09.12.2015
comment
Я обнаружил проблему, которую должен был решить чек. Это не похоже на люди в цепочке комментариев в то время имели четкое представление о лексике. Это сообщение об ошибке обязательно следует изменить (и, возможно, им следует добавить or iter(sentences) is iter(sentences), чтобы перехватить другие типы итераторов).   -  person user2357112 supports Monica    schedule 09.12.2015


Ответы (4)


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

В частности, в своем коде они вызывают две разные функции, обе перебирают предложения (таким образом, если вы используете генератор, вторая будет работать с пустым набором)

self.build_vocab(sentences, trim_rule=trim_rule)
self.train(sentences)

Он должен работать со всем, что реализует __iter__, а не GeneratorType. Так что оберните вашу функцию в итеративный интерфейс и убедитесь, что вы можете пройти по нему несколько раз, что означает, что

sentences = your_code
for s in sentences:
  print s
for s in sentences:
  print s

напечатает вашу коллекцию дважды

person lejlot    schedule 08.12.2015
comment
После одного цикла исчерпываются все итераторы, а не только созданные генераторами. (На самом деле, постоянное повышение StopIteration при последующих вызовах до next после исчерпания является обязательным.) Сообщение об ошибке, вероятно, означало итератор вместо итератор. Некоторые итерации могут повторяться много раз, как правильно объяснено в вашем ответе. - person user4815162342; 09.12.2015
comment
Понятно, но разве итератор не будет повторяться только один раз, если он вернет self в __iter__? Я также думаю, что сообщение об ошибке означает повторение. - person riv; 09.12.2015
comment
@riv Итератор должен вернуть self в __iter__. Однако iterable не может (и делает это в случае встроенных контейнеров) возвращать новый итератор, который начинается с самого начала. - person user4815162342; 09.12.2015
comment
Я только что создал класс, который возвращает мой генератор в методе __iter__ (и не имеет других методов), и он сработал. - person riv; 09.12.2015
comment
@riv Это может выглядеть так, как будто оно работает, потому что вы больше не получаете исключение, но правильно ли оно работает? Если и build_vocab, и train повторяют итератор sentences, train встретит пустой итератор. Очень вероятно, что код вообще не тренируется. Правильное исправление объяснено Алексом Волковым, за исключением того, что его можно кратко записать как list(generator_obj). - person user4815162342; 09.12.2015

Как упоминалось в предыдущих плакатах, генератор действует аналогично итератору с двумя существенными отличиями: генераторы исчерпаны, и вы не можете их проиндексировать.

Я быстро просмотрел документацию на этой странице - https://radimrehurek.com/gensim/models/word2vec.html

В документации указано, что

gensim.models.word2vec.Word2Vec (предложения = None, size = 100, alpha = 0.025, window = 5, min_count = 5, max_vocab_size = None, sample = 0, seed = 1, worker = 1, min_alpha = 0,0001 , sg = 1, hs = 1, negative = 0, cbow_mean = 0, hashfxn =, iter = 1, null_word = 0, trim_rule = None, sorted_vocab = 1) ...

Инициализировать модель из итерации предложений. Каждое предложение представляет собой список слов (строк Unicode), которые будут использоваться для обучения.

Рискну предположить, что логика внутри функции по своей сути требует одного или нескольких свойств списка, таких как индексирование элементов, может быть явный оператор assert или оператор if, который вызывает ошибку.

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

my_iterator = [x for x in generator_obj]
person Alex Volkov    schedule 08.12.2015
comment
Обратите внимание, что список, созданный с помощью понимания в вашем ответе, является итеративным (имеет метод __iter__), но не итератором (не имеет метода next). - person user4815162342; 09.12.2015
comment
Да, вы правы, это понимание списка, а не итератор, я изменю свой ответ. - person Alex Volkov; 09.12.2015
comment
Но это означает, что вы не можете обучить word2vec на очень большом корпусе. Однако библиотека Gensim гордится своей эффективностью использования памяти. - person Sergey Orshanskiy; 03.02.2017
comment
@osa Это было быстрое решение этой конкретной проблемы. Вероятно, вам нужно будет написать что-то более сложное для вашего случая, например реализовать свой собственный итератор, который можно было бы циклически повторять несколько раз, где вы можете обменять использование памяти на ввод-вывод, перечитав файл несколько раз, см. - образец итератора stackoverflow.com/questions/19151/build-a-basic -python-iterator; см. itertools.cycle - docs.python.org/2/library/ itertools.html # itertools.cycle - person Alex Volkov; 03.02.2017

В других ответах указывалось, что Gensim требуется два прохода для построения модели Word2Vec: один раз для создания словаря (self.build_vocab), а второй - для обучения модели (self.train). Вы по-прежнему можете передать генератор методу train (например, при потоковой передаче данных), разделив методы build_vocab и train.

from gensim.models import Word2Vec

model = Word2Vec()
sentences = my_generator()  # first pass
model.build_vocab(sentences)

sentences = my_generator()  # second pass of same data
model.train(sentences2, 
            total_examples=num_sentences,  # total number of documents to process
            epochs=model.epochs)
person David C    schedule 23.08.2019

Похоже, gensim выдает вводящее в заблуждение сообщение об ошибке.

Gensim хочет перебрать ваши данные несколько раз. Большинство библиотек просто создают список из входных данных, поэтому пользователю не нужно заботиться о предоставлении многократной итеративной последовательности. Конечно, создание списка в памяти может быть очень ресурсоемким, в то время как, например, итерация по файлу может выполняться без сохранения всего файла в памяти.

В вашем случае простое изменение генератора на понимание списка должно решить проблему.

person Tamas Hegedus    schedule 08.12.2015