首页 > 解决方案 > Gensim 中的文本流

问题描述

Gensim 使用文本流来最小化内存需求。由于无休止的磁盘 IO,这是以性能为代价的。是否有一种技巧可以将完整的文件从磁盘(一个磁盘 IO)即时复制到内存中的临时文件?我喜欢保持代码原样(不重新编码到列表结构中),但这不是调试功能的好方法

预期结果:更快的代码

关于这个问题的更多背景

原始代码位于https://github.com/skipgram/modern-nlp-in-python/blob/master/executable/Modern_NLP_in_Python.ipynb。示例代码取自短语建模部分

我正在计算单数。所有评论都在

review_txt_filepath = os.path.join(intermediate_directory,'review_text_all.txt'),

所有的unigrams都应该去

unigram_sentences_filepath = os.path.join(intermediate_directory, 'unigram_sentences_all.txt') 

关键的程序是

def punct_space(token):
    return token.is_punct or token.is_space

def line_review(filename):
    # generator function to read in reviews from the file
    with codecs.open(filename, encoding='utf_8') as f:
        for review in f:
            yield review.replace('\\n', '\n')

def lemmatized_sentence_corpus(filename):
    # generator function to use spaCy to parse reviews, lemmatize the text, and yield sentences

    for parsed_review in nlp.pipe(line_review(filename),
                              batch_size=10000, n_threads=4):
        for sent in parsed_review.sents:
            yield u' '.join([token.lemma_ for token in sent
                             if not punct_space(token)])

unigrams 计算为

with codecs.open(unigram_sentences_filepath, 'w', encoding='utf_8') as f:
    for sentence in lemmatized_sentence_corpus(review_txt_filepath):
        f.write(sentence + '\n')

为 5000 行执行此操作需要一些耐心,1 小时 30 分 ;-)

我对可迭代对象不太熟悉,但我是否正确理解我首先必须将实际文件(在磁盘上)读入变量“list_of_data”并处理它

with (review_txt_filepath, 'r', encoding='utf_8') as f:
    list_of_data = f.read()

with codecs.open(unigram_sentences_filepath, 'w', encoding='utf_8') as f:
    for sentence in lemmatized_sentence_corpus(list_of_data):
        f.write(sentence + '\n')

所以策略是

1. read all data into a list in memory
2. process the data
3. write the results to disc
4. delete the list from memory by setting list_with_data = ()

一个问题显然是 line_review 正在读取文件

标签: inputstreamgensim

解决方案


大多数 gensim 接口实际上采用可迭代序列。强调从磁盘流式传输的示例恰好使用了根据需要读取每个项目的迭代,但您可以使用内存中的列表。

本质上,如果您确实有足够的 RAM 将整个数据集保存在内存中,只需使用 IO-reading iterable 将内容一次读取到列表中。然后,将该列表提供给它期望任何可迭代序列的 gensim 类。

这不应该涉及任何“重新编码为列表结构”——但它使用 Pythonlist类型将内容保存在内存中。这是最自然的方式,也可能是最有效的方式,尤其是在对标记化文本进行多次传递的算法中。

(比方说,将整个文件加载到原始字节数组中,然后以文件样式重复读取该算法所需的单个项目的不太惯用的方法是一种笨拙的方法。它同样可以节省重复IO 成本,但可能会在重复重新解析/标记将重复处理的项目上浪费精力。如果您有内存,您需要将每个项目作为 Python 对象保存在内存中,这需要将它们放入一个列表。)

为了更具体地回答,您需要在问题中提供更多详细信息,例如您正在使用哪些特定的算法/语料库阅读样式,最好使用示例代码。


推荐阅读