替换大型文本文件中的一组单词

Replacing a set of words in a large text file

我有一个很大的 txt 文件(大约 20GB),我想从这个大文件中替换单词列表的所有实例。我正在努力寻找优化此代码的方法。这导致我处理这个文件很长时间。

我可以改进什么?

    corpus_input =  open(corpus_in,"rt")
    corpus_out = open(corpus_out,"wt")
    for line in corpus_input:
        temp_str=line
        for word in dict_keys:
            if word in line:
                new_word = word+"_lauren_ipsum"
                temp_str = re.sub(fr'\b{word}\b',new_word,temp_str)

            else:
                continue
        
        corpus_out.writelines(temp_str)

     corpus_input.close()
     corpus_out.close()

优化最重要的是了解,究竟是什么表现不佳。 然后就可以看到有什么可以优化了。

例如,如果读取和写入占用了 99% 的时间,那么优化数据处理就不值得了。 即使你可以将处理速度提高 10,如果读写消耗 99%

,你也只会获得 0.9%

我建议测量和比较一些版本并 post 性能差异。 这可能会导致潜在的进一步优化建议。

在下面的所有示例中,我将 writelines 替换为 write,因为 writelines 可能会在写入之前逐个字符地分解您的行。

无论如何。你想使用 write 您应该已经获得了大约 5 的加速比。[​​=23=]

1.) 只是读写

with open(corpus_in,"rt") as corpus_input, open(corpus_out,"wt")
 as corpus_out:
   for line in corpus_input:
       corpus_out.write(line)

2.) 只是读写 有更大的缓冲区

import io

BUF_SIZE = 50 * io.DEFAULT_BUFFER_SIZE # try other buffer sizes if you see an impact
with open(corpus_in,"rt", BUF_SIZE) as corpus_input, open(corpus_out,"wt", BUF_SIZE)
 as corpus_out:
   for line in corpus_input:
corpus_out.write(line)

对我来说,这会提高几个百分点的性能

3.) 将搜索正则表达式和替换生成移出循环。

   rules = []
   for word in dict_keys:
       rules.append((re.compile(fr'\b{word}\b'), word + "_lorem_ipsum"))

   for line in corpus_input:
       for regexp, new_word in rules: 
           line = regexp.sub(new_word, line)
       corpus_out.write(line)

在我的机器上,我的频率是包含单词的行,这个解决方案实际上比包含 if word in line

行的解决方案慢

所以也许试试: 3.a) 将搜索正则表达式和替换生成移出循环。

   rules = []
   for word in dict_keys:
       rules.append((word, re.compile(fr'\b{word}\b'), word + "_lorem_ipsum"))

   for line in corpus_input:
       for word, regexp, new_word in rules: 
           if word in line:
               line = regexp.sub(new_word, line)
       corpus_out.write(line)

3.b) 如果所有替换字符串都比初始字符串长,那么这会快一点。

   rules = []
   for word in dict_keys:
       rules.append((word, re.compile(fr'\b{word}\b'), word + "_lorem_ipsum"))

   for line in corpus_input:
       temp_line = line
       for word, regexp, new_word in rules: 
           if word in line:
               temp_line = regexp.sub(new_word, temp_line)
       corpus_out.write(temp_line)

4.) 如果你真的用 word + "_lorem_ipsum" 替换 always 将正则表达式合二为一。

   regexp = re.compile(fr'\b({"|".join(dict_keys)})\b')

   for line in corpus_input:
       line = regexp.sub("_lorem_ipsum", line)
       corpus_out.write(line)

4.a) 根据单词分布,这可能会更快:

   regexp = re.compile(fr'\b({"|".join(dict_keys)})\b')

   for line in corpus_input:
       if any(word in line for word in dict_keys):
           line = regexp.sub("_lorem_ipsum", line)
       corpus_out.write(line)

这是否更有效可能取决于要搜索和替换的单词数量以及这些单词的出现频率。 我没有那个日期。

对于 5 个单词,我的分发比 3.a

5) 如果要替换的词不同,您仍然可以尝试组合正则表达式并使用函数来替换

   replace_table = {
      "word1": "word1_laram_apsam",
      "word2": "word2_lerem_epsem",
      "word3": "word3_lorom_opsom",

   }

   def repl(match):
      return replace_table[match.group(1)]

   regexp = re.compile(fr'\b({"|".join(dict_keys)})\b')

   for line in corpus_input:
       line = regexp.sub(repl, line)
       corpus_out.write(line)

慢于5,是否优于3.a取决于字数和线分布/频率。