【问题标题】:python gensim word2vec gives typeerror TypeError: object of type 'generator' has no len() on custom dataclasspython gensim word2vec 给出 typeerror TypeError: 'generator' 类型的对象在自定义数据类上没有 len()
【发布时间】:2019-04-26 19:59:51
【问题描述】:

我正在尝试让 word2vec 在 python3 中工作,但是由于我的数据集太大而无法轻松放入内存中,我通过迭代器(从 zip 文件)加载它。但是,当我运行它时,我得到了错误

Traceback (most recent call last):
  File "WordModel.py", line 85, in <module>
    main()
  File "WordModel.py", line 15, in main
    word2vec = gensim.models.Word2Vec(data,workers=cpu_count())
  File "/home/thijser/.local/lib/python3.7/site-packages/gensim/models/word2vec.py", line 783, in __init__
    fast_version=FAST_VERSION)
  File "/home/thijser/.local/lib/python3.7/site-packages/gensim/models/base_any2vec.py", line 759, in __init__
    self.build_vocab(sentences=sentences, corpus_file=corpus_file, trim_rule=trim_rule)
  File "/home/thijser/.local/lib/python3.7/site-packages/gensim/models/base_any2vec.py", line 936, in build_vocab
    sentences=sentences, corpus_file=corpus_file, progress_per=progress_per, trim_rule=trim_rule)
  File "/home/thijser/.local/lib/python3.7/site-packages/gensim/models/word2vec.py", line 1591, in scan_vocab
    total_words, corpus_count = self._scan_vocab(sentences, progress_per, trim_rule)
  File "/home/thijser/.local/lib/python3.7/site-packages/gensim/models/word2vec.py", line 1576, in _scan_vocab
    total_words += len(sentence)
TypeError: object of type 'generator' has no len()

代码如下:

import zipfile
import os
from ast import literal_eval

from lxml import etree
import io
import gensim

from multiprocessing import cpu_count


def main():
    data = TrainingData("/media/thijser/Data/DataSets/uit2")
    print(len(data))
    word2vec = gensim.models.Word2Vec(data,workers=cpu_count())
    word2vec.save('word2vec.save')




class TrainingData:

    size=-1

    def __init__(self, dirname):
        self.data_location = dirname

    def __len__(self):
        if self.size<0: 

            for zipfile in self.get_zips_in_folder(self.data_location): 
                for text_file in self.get_files_names_from_zip(zipfile):
                    self.size=self.size+1
        return self.size            

    def __iter__(self): #might not fit in memory otherwise
        yield self.get_data()

    def get_data(self):


        for zipfile in self.get_zips_in_folder(self.data_location): 
            for text_file in self.get_files_names_from_zip(zipfile):
                yield self.preproccess_text(text_file)


    def stripXMLtags(self,text):

        tree=etree.parse(text)
        notags=etree.tostring(tree, encoding='utf8', method='text')
        return notags.decode("utf-8") 

    def remove_newline(self,text):
        text.replace("\\n"," ")
        return text

    def preproccess_text(self,text):
        text=self.stripXMLtags(text)
        text=self.remove_newline(text)

        return text




    def get_files_names_from_zip(self,zip_location):
        files=[]
        archive = zipfile.ZipFile(zip_location, 'r')

        for info in archive.infolist():
            files.append(archive.open(info.filename))

        return files

    def get_zips_in_folder(self,location):
       zip_files = []
       for root, dirs, files in os.walk(location):
            for name in files:
                if name.endswith((".zip")): 
                    filepath=root+"/"+name
                    zip_files.append(filepath)

       return zip_files

main()


for d in data:
    for dd in d :
        print(type(dd))

确实告诉我 dd 是字符串类型并且包含正确的预处理字符串(每个长度在 50 到 5000 个单词之间)。

【问题讨论】:

    标签: python machine-learning nlp gensim training-data


    【解决方案1】:

    讨论后更新:

    您的TrainingData__iter__() 函数没有提供依次返回每个文本的生成器,而是提供返回单个其他 生成器的生成器。 (yield 的级别太多了。)这不是Word2Vec 所期望的。

    __iter__() 方法的主体更改为简单...

    return self.get_data()
    

    ...所以__iter__() 是您的get_data() 的同义词,并且只返回与get_data() 相同的逐文本生成器,应该会有所帮助。

    原答案:

    您没有显示TrainingData.preproccess_text()(原文如此)方法,在get_data() 中引用,它实际上是创建Word2Vec 正在处理的数据。而且,正是这些数据产生了错误。

    Word2Vec 要求其sentences 语料库是一个可迭代序列(适合使用生成器),其中每个单独的项目都是一个字符串令牌列表时间>。

    从该错误来看,您的TrainingData 序列中的各个项目本身可能是生成器,而不是具有可读len() 的列表。

    (另外,如果您选择在那里使用生成器是因为单个文本可能非常长,请注意 gensim Word2Vec 和相关课程仅针对长度不超过 10000 个单词标记的单个文本进行训练. 任何超过第 10000 个的单词都将被忽略。如果担心,您的源文本应预先分解为 10000 个或更少的单个文本。)

    【讨论】:

    • 我添加了缺少的代码,preproccess_text 的输出类型为“str”,将 preproccess_text 中的“return text”行更改为 return [text] 将错误更改为 TypeError: unhashable type: 'list'
    • 代码,如图所示,仍然为TypeError: object of type 'generator' has no len() 提供相同的错误/堆栈,如原始问题所示? iter(data).next()[0:10] 显示什么?
    • 是的,错误仍然相同。如果我调用 data = TrainingData("/media/thijser/Data/DataSets/uit2") print(iter(data).next()[0:10]) 我得到错误文件“WordModel.py”,第 84 行,在 main() 文件“WordModel.py”,第 14 行,在 main print(iter(data).next()[0:10]) AttributeError: 'generator' object has no attribute 'next'
    • for d in data: for dd in d : print(dd) 确实给出了包含实际训练数据的字符串列表(每个字符串的长度约为 50-5000 个单词)。
    • 啊哈,在 Py3 中,它可能需要 next(iter(data)) 才能获得第一个元素 - 但我现在看到了问题 - 你对 __iter__() 的定义返回一个只能 yield 一个元素的生成器,它本身就是一个生成器。我已经预先更新了答案以提供帮助。
    猜你喜欢
    • 2015-01-21
    • 2015-08-21
    • 2021-03-03
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-01
    相关资源
    最近更新 更多