【问题标题】:Read and write large file with python用python读写大文件
【发布时间】:2017-11-17 17:32:36
【问题描述】:

我有一个包含超过 24,000,000 行的大型 .txt 文件。现在我想做一个字数统计,即计算每个单词及其对应的出现次数,并将它们记录到一个新文件中。这是我尝试运行的代码:

import gensim
class Corpus(gensim.corpora.TextCorpus): 
    def count_tokens(self):
        word_count = 0
        for text in self.get_texts():
            word_count += len(text)
        return word_count
    def get_texts(self): 
        for filename in self.input: 
            yield open(filename).read().split()

def main():
    corpus = Corpus(['somefile.txt'])
    word_count = corpus.count_tokens()
    text = open('somefile.txt').read().split()
    with open('path_to_output', 'w') as f:
        for word, _ in corpus.dictionary.token2id.items():
            num_occur = text.count(word)
            f.write('%s %d\n' % (word, num_occur))

if __name__  == '__main__':
    main()

服务器挂起...我想知道是否还有其他足够的方法可以这样做或我可以做出任何改进?如何用 python 读写非常大的文件?

【问题讨论】:

  • 使用类似系统的分词器 - 解析 char char,并检查匹配项。当模棱两可时,继续查看下一个字符以确定是否有延续
  • open(filename).read().split() 完全读取文件,然后创建一个标记化版本:同时是内存的两倍。如果您只需要计数,Uriel 方法可能是正确的方法。

标签: python file text io python-3.5


【解决方案1】:

您的get_texts() 方法是一次读取内存中的一个完整文件。有很多小文件的语料库很好,但如果你有一个巨大的文件,你需要逐行阅读。

from collections import Counter
wordcounts = Counter()

with open("file.txt") as fp:
    for line in fp:
        wordcounts.update(line.split())

【讨论】:

  • 如果文件只是一长串单词会怎样?文件足够大,这仍然是个问题
  • 天啊,这个方法几分钟就能搞定!拯救我的一天!谢谢!
  • @Uriel,每行一个单词的作用相同。如果文件中没有换行符,只会有问题。对于这种情况,您需要读取字节块,并在边缘修复损坏的单词甚至损坏的多字节字符。显然,插入可以执行此操作的库会更容易。但显然这是一个 text 文件,即换行符,所以不需要去那里。
  • @alexis 这就是我的意思,一个由空格分隔的列表。但从OP的评论来看,情况并非如此。在这种情况下很好的答案。
  • 对于没有换行符的文件,nltk 的语料库阅读器由执行我描述的“流阅读器”支持。 Gensim 也可能这样做(我不使用它),但是 OP 绕过了它的文件 i/o。无论如何,OP的问题是关于一个超过2400万行的文件。
【解决方案2】:

你的代码有很多问题:

  • 它读取内存中的文件,然后拆分单词,因此它将内存大小加倍(或三倍)
  • 它做了两次,首先计算单词的数量,然后计算每个单词的出现次数

我创建了一个简单的示例,没有您的对象和所有对象,在多个文件上使用collections.Countertext_file_list 保存文件路径列表。

import collections

c = collections.Counter()
for text_file in text_file_list:
   with open(text_file) as f:
       c.update(word for line in f for word in line.split())

循环文件,并为每个文件更新专用的Counter 字典。文件是逐行读取的,从不完整。所以需要一些时间,但不会占用太多内存。

【讨论】:

    【解决方案3】:

    我会做这样的事情:

    words = {}
    with open('somefile.txt', 'r') as textf:
        for line in textf.readlines():
            for word in line.split():
                words[word] = words.getdefault(word, 0) + 1
    

    不是很pythonic,但就是这样

    【讨论】:

    • 这无济于事,它仍然会一次读取内存中的整个文件。
    • 但是用for line in textf: 替换for line in textf.readlines(): 应该会更好。它一次只能读取 1 行,不需要进行其他更改。
    • 同时使用collections.Counter会更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多