在Python中优化删除大文件中的重复项
我有一个非常大的文本文件(27GB),我正试图通过删除第二个数据库中重复的行来缩小它,该数据库有几个大小更合理的文件(500MB-2GB)。我有一些功能代码,我想知道的是,有没有任何方法可以优化这些代码,使其运行得更快,人类时钟时间?目前,在使用1.5GB输入和500MB滤波器的小型测试运行中,这需要75秒才能完成 我已经经历了很多次这种想法的迭代,这一次是最适合时间的,如果有人有为过滤器制作更好的逻辑结构的想法,我很乐意听到,过去的尝试都比这一次更糟糕:将过滤器加载到一个集合中,并在输入中循环搜索重复项(大约是这一次的一半),将输入加载到一个集合中,并通过差异更新运行过滤器(速度几乎与此相同,但也与我想要的相反),然后将输入和过滤器分块加载到集合中,并执行集合差异(这是一个可怕的、可怕的想法,可能会奏效)如果我的过滤器更小,那么我也不必拆分它们。) 所以,这些都是我尝试过的。所有这些进程在CPU上都是最大的,我的最终版本运行在大约25-50%的磁盘I/O上,过滤器和输出在一个物理磁盘上,输入在另一个物理磁盘上。我正在运行一个双核,不知道这个特定的脚本是否可以线程化,以前从未做过任何多线程处理,所以如果这是一种可能性,我希望被指向正确的方向 有关数据的信息!如前所述,输入比过滤器大很多倍。我希望复制的比例很小。数据以行为单位,所有行的长度都小于20个ASCII字符。所有文件都已排序 我已经改变了三个逻辑语句的顺序,基于这样的预期:唯一的输入行将是大多数行,然后是唯一的过滤器,然后是重复的,在“最好”没有重复的情况下,这为我节省了大约10%的时间 有什么建议吗在Python中优化删除大文件中的重复项,python,optimization,duplicates,large-files,Python,Optimization,Duplicates,Large Files,我有一个非常大的文本文件(27GB),我正试图通过删除第二个数据库中重复的行来缩小它,该数据库有几个大小更合理的文件(500MB-2GB)。我有一些功能代码,我想知道的是,有没有任何方法可以优化这些代码,使其运行得更快,人类时钟时间?目前,在使用1.5GB输入和500MB滤波器的小型测试运行中,这需要75秒才能完成 我已经经历了很多次这种想法的迭代,这一次是最适合时间的,如果有人有为过滤器制作更好的逻辑结构的想法,我很乐意听到,过去的尝试都比这一次更糟糕:将过滤器加载到一个集合中,并在输入中循环
def sortedfilter(input,filter,output):
file_input = open(input,'r')
file_filter = open(filter,'r')
file_output = open(output,'w')
inline = file_input.next()
filterline = file_filter.next()
try:
while inline and filterline:
if inline < filterline:
file_output.write(inline)
inline = file_input.next()
continue
if inline > filterline:
filterline = file_filter.next()
continue
if inline == filterline:
filterline = file_filter.next()
inline = file_input.next()
except StopIteration:
file_output.writelines(file_input.readlines())
finally:
file_filter.close()
file_input.close()
file_output.close()
def分拣过滤器(输入、过滤器、输出):
文件输入=打开(输入,'r')
文件\过滤器=打开(过滤器,'r')
文件输出=打开(输出,'w')
inline=file\u input.next()
filterline=file\u filter.next()
尝试:
内联和过滤线时:
如果inline过滤器线:
filterline=file\u filter.next()
持续
如果inline==过滤器行:
filterline=file\u filter.next()
inline=file\u input.next()
除停止迭代外:
文件\u output.writelines(文件\u input.readlines())
最后:
文件_filter.close()
文件_input.close()
文件_output.close()
通过执行cmp(inline,filterline)
,每行只能执行一次字符串比较操作:
表示-1
内联
表示0
inline==filterline
表示+1
内联
while inline and filterline:
comparison = cmp(inline, filterline)
if comparison == -1:
file_output.write(inline)
inline = file_input.next()
continue
if comparison == 1:
filterline = file_filter.next()
continue
if comparison == 0:
filterline = file_filter.next()
inline = file_input.next()
看到您的输入文件已排序,下面的操作应该可以正常工作。heapq的merge从groupby操作的排序输入生成一个排序流;长度大于1的组将被丢弃。这种基于流的方法应该具有相对较低的内存需求
from itertools import groupby, repeat, izip
from heapq import merge
from operator import itemgetter
with open('input.txt', 'r') as file_input, open('filter.txt', 'r') as file_filter, open('output.txt', 'w') as file_output:
file_input_1 = izip(file_input, repeat(1))
file_filter_1 = izip(file_filter, repeat(2))
gen = merge(file_input_1, file_filter_1)
gen = ((k, list(g)) for (k, g) in groupby(gen, key=itemgetter(0)))
gen = (k for (k, g) in gen if len(g) == 1 and g[0][1] == 1)
for line in gen:
file_output.write(line)
我很想知道这两者之间的比较;它基本上只是在玩一点迭代的顺序
def sortedfilter(in_fname, filter_fname, out_fname):
with open(in_fname) as inf, open(filter_fname) as fil, open(out_fname, 'w') as outf:
ins = inf.next()
try:
for fs in fil:
while ins < fs:
outf.write(ins)
ins = inf.next()
while ins == fs:
ins = inf.next()
except StopIteration:
# reached end of inf before end of fil
pass
else:
# reached end of fil first, pass rest of inf through
file_output.writelines(file_input.readlines())
def sortedfilter(输入名称、输入名称、输出名称):
将open(in_fname)作为inf,将open(filter_fname)作为fil,将open(out_fname,'w')作为outp:
ins=inf.next()
尝试:
财政司司长:
当ins
考虑以二进制方式打开文件,这样就不需要转换为unicode:
with open(in_fname,'rb') as inf, open(filter_fname,'rb') as fil, open(out_fname, 'wb') as outf:
我喜欢这个,我对它进行了测试,结果表明,将它写入内存并读取1-3次实际上比重复计算要慢。不过,在内存更好的系统上,这可能会更快。@Briana真的吗?我很惊讶。你有没有试过用cProfile编写这段代码,看看它花了多少时间?我以前从来没有用过cProfile,所以我不确定我是否能用它收集到比这更多的数据,但这是两个结果,有cmp和没有cmp。当我试着用输入运行它时,我得到了一个错误,我以前没有玩过heapq,所以我不知道它的输入/输出是什么样子的,所以我不知道它为什么会坏。你运行的是什么版本的python?2.7,我实际上刚刚开始工作,在你最后一次编辑后再次抓取它,我不确定你是不是改变了代码,除了输入,还是我之前把事情搞砸了。我想你误解了我想做的,我不想合并文件,这样做,删除重复项,我想从一个文件中删除重复项,而另一个文件保持完整和独立。我明白了。我现在修改了代码,以确保在合并过程中不会拾取来自过滤器文件的记录。这涉及使用itertools.repeat将特定于文件的编号与输入文件中的每条记录相关联,然后根据该编号进行过滤,以确保仅将输入文件中的记录写入输出文件;记录