python - 替换大文本文件中的一组单词
问题描述
我有一个大的 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((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"
将正则表达式组合为一个来替换。
regexp = re.compile(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 = 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("\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 = 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 取决于字数和线分布/频率。
推荐阅读
- python - 我的 pygame 平台游戏中的碰撞系统几乎是完美的
- powershell - 如何从 Active Directory 中获取组名和 EmployeeID?
- javascript - 导航栏样式“泄漏”到我的欢迎页面?
- python - `numpy.corrcoef` 返回具有意外形状的数组
- algorithm - Little-oh 和 Little-omega 时间复杂度
- arrays - 关于数组的问题之间的区别
- ms-access-2007 - Access 2007 - 两个只读表,几个最终用户 - 设计查询
- javascript - 如何递归地将数组中的每n个元素传递给函数
- swift - 如何在 Swift 中读取结构的字节
- c# - 来自参考表的绑定 ComboBox 填充值