我有一个大的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%的收益。
我建议测量和比较一些版本,并发布性能差异。这可能会导致进一步的建议变得乐观。
在所有下面的示例我换成writelines与write作为writelines可能是由汉字书写之前,您分解行字符。
任何状况之下。您想使用write您应该已经获得了大约5的加速。
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((pile(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, pile(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, pile(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"将正则表达式合并为一个替换。
regexp = pile(fr'\b({"|".join(dict_keys)})\b')
for line in corpus_input:
line = regexp.sub("\1_lorem_ipsum", line)
corpus_out.write(line)
4.a)取决于单词分布,这可能会更快:
regexp = pile(fr'\b({"|".join(dict_keys)})\b')
for line in corpus_input:
if any(word in line for word in dict_keys):
line = regexp.sub("\1_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 = pile(fr'\b({"|".join(dict_keys)})\b')
for line in corpus_input:
line = regexp.sub(repl, line)
corpus_out.write(line)
Slower than 5, whether better than 3.a depends on number of words and wird distribution / frequency.