【问题标题】:Read and Write large text file python too slow读写大文本文件python太慢
【发布时间】:2021-04-26 13:06:13
【问题描述】:

这段代码检查了一个 5.1GB 的大文本文件,并检查是否有出现少于 100 次的单词。然后将 5.1GB 重写为输出文本文件并用 unk 替换这些单词。主要问题是 output.txt 的创建需要很长时间。 我怀疑 write_text() 方法通过打开数据集文件和输出文件的方式引起了问题。

这个脚本背后的目标:我有一个预建的词汇和一个文本。文本可能有我的词汇中没有的新词,所以我想将它们添加到我的词汇中。但我只想添加相关的新词(出现超过 100 次)。文中出现次数少于 100 次的新词是一次性的,不重要,所以我想把它们改成“unk”。


from collections import Counter

extra_words = []
new_words = []
add_words = []


def get_vocab():
    vocab = set()
    with open('vocab.txt', 'r', encoding='utf-8') as rd:
        lines = rd.readlines()

    for line in lines:
        tokens = line.split(' ')
        word = tokens[0]
        vocab.add(word)

    return vocab


def _count(text):

    vocab = get_vocab()

    with open(text, 'r', encoding='utf-8') as fd:

        for line in fd.readlines():

            for token in line.split():

                if token not in vocab:
                    extra_words.append(token)

    word_count = Counter(extra_words)

    # add del word_count[punctuation] to remove it from list

    #del word_count['"']

    for word in word_count:

        if word_count[word] < 100:
            new_words.append(word)

        else:
            add_words.append(word)

    write_text()

    #return len(new_words), word_count.most_common()[0]


def write_text():

    with open('dataset', 'r', encoding='utf-8') as fd:

        f = fd.readlines()

    with open('output.txt', 'w', encoding='utf-8') as rd:
        new_text = []
        for line in f:
            new_line = []
            for token in line.split():

                

                if token in new_words:

                    new_line.append('<unk>')

                else:

                    new_line.append(token)

            new_text.append(' '.join(new_line))
        print('\n'.join(new_text), file=rd)
            #print(' '.join(new_line), file=rd)


def add_vocab():

    ln = len(get_vocab())

    with open('vocab.txt', 'w', encoding='utf-8') as fd:

        for idx, word in add_words:

            print(f'{word} {ln + idx + 1}\n', file=fd)

    pass


print(_count('dataset'))
add_vocab()

【问题讨论】:

  • 您是否限制使用文本文件?它们可能非常慢。如果您对其他文件类型持开放态度,则可以大大提高加载和写入速度,例如泡菜文件。
  • 嗨。是的,我想只使用文本文件来解决这个问题。
  • 作为第一个措施,您可以省略对fd 的调用readlines,只使用文件对象作为生成器并以for line in fd: 遍历行
  • 多长太长?
  • 它已经运行了 5 个小时

标签: python-3.x text nlp corpus data-preprocessing


【解决方案1】:

我用莎士比亚的全集对此进行了测试。您还有大量与大小写和标点符号相关的工作要做。它在大约 15 秒内为我复制了 100 份他的作品(500meg)。如果这需要更多不可接受的时间,您可能希望查看分析您的代码。请注意,我使用了您的词汇文件的简化版本,因为我没有遵循您想要在其中看到的内容。我用的版本就是一行一行的文字。

import collections

def get_vocabulary(path):
    with open(path, 'r', encoding='utf-8') as file_in:
        tokens = [line.strip("\n") for line in file_in]
    return set(tokens)

def get_interesting_word_counts(path, vocabulary):
    word_counts = collections.Counter()
    with open(path, 'r', encoding='utf-8') as file_in:
        for line in file_in:
            word_counts.update([token for token in line.split() if token not in vocabulary])
    return word_counts

def get_cleaned_text(path, vocabulary, uncommon_words):
    with open(path, 'r', encoding='utf-8') as file_in:
        for line in file_in:
            #line_out = " ".join(["<unk>" if token in uncommon_words else token for token in line.strip("\n").split()])
            line_out = " ".join([
                token if token in vocabulary or token not in uncommon_words else "<unk>"
                for token in line.strip("\n").split()
            ])
            yield "{}\n".format(line_out)

vocabulary = get_vocabulary("vocabulary.txt")
word_counts = get_interesting_word_counts("shakespeare.txt", vocabulary)

## --------------------------------------
## Add frequent but missing words to vocabulary
## --------------------------------------
common_words = set([item[0] for item in word_counts.items() if item[1] >= 100])
with open('vocabulary.txt', 'a', encoding='utf-8') as file_out:
    for word in common_words:
        file_out.write("{}\n".format(word))
## --------------------------------------

## --------------------------------------
## Rewite the text censuring uncommon words
## --------------------------------------
uncommon_words = set([item[0] for item in word_counts.items() if item[1] < 100])
cleaned_text = get_cleaned_text("shakespeare.txt", vocabulary, uncommon_words)
with open('shakespeare_out.txt', 'w', encoding='utf-8') as file_out:
    file_out.writelines(cleaned_text)
## --------------------------------------

您可以在这里获取我使用的文字:http://www.gutenberg.org/ebooks/100

来源开始:

The Project Gutenberg eBook of The Complete Works of William Shakespeare, by William Shakespeare

生成的文件开始:

<unk> <unk> <unk> <unk> of The <unk> <unk> of <unk> <unk> by <unk> <unk>

更新的词汇文件开始:

as
run
he’s
this.
there’s
like
you.

【讨论】:

  • 您好,非常感谢您的回答。方法“get_interesting_word_counts()”中的这一行存在一个问题(word_counts.update([token for token in line.split() if token not in words]))。出现少于 100 次但在 vocab 中的单词仍在转换为 unk。应该跳过它们。
  • 我进行了更新,但如果不正确,您需要提供明确的示例输入和输出
  • 我已经重写了 get_vocabulary() 方法,现在它似乎工作正常。词汇文件包含像你这样的词汇,但每个单词旁边都有一个从 1 到 n 的数字
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 2019-04-30
  • 2017-01-13
  • 1970-01-01
  • 2017-11-17
  • 2021-02-17
  • 2016-07-14
相关资源
最近更新 更多