计算两个 csv 文件之间差异的更快方法
Posted
技术标签:
【中文标题】计算两个 csv 文件之间差异的更快方法【英文标题】:Faster way to compute difference between two csv files 【发布时间】:2018-04-30 19:43:19 【问题描述】:我正在尝试计算两个大型 csv 文件(约 4GB)之间的差异,以获得新添加的行并将它们写入输出 csv 文件。通过使用以下代码,我可以为相对较小的文件(~50MB)获得此功能。
input_file1 = "data.csv"
input_file2 = "data_1.csv"
output_path = "out.csv"
with open(input_file1, 'r') as t1, open(input_file2, 'r') as t2:
fileone = t1.readlines()
filetwo = t2.readlines()
with open(output_path, 'w') as outFile:
for line in filetwo:
if line not in fileone:
outFile.write(line)
但是,对于较大的文件,上述代码要么太慢(运行大约半小时),要么因内存空间不足而崩溃。
有没有更快的方法来获取大型 csv 文件的差异?
【问题讨论】:
也许将数据转储到数据库中并进行重复数据删除?对于这种处理繁重的任务,4 GB 是一个巨大的文件。至少在数据库中,引擎应该能够稍微优雅地处理内存管理...... 尝试阅读这个答案:***.com/questions/44447107/… @Sneha,第二个 CSV 文件是否总是将新数据添加到文件的基础中?还是以不同的方式分类到数据中? 如果 .csv 文件都已排序,您可以使用类似整理器的合并排序。这具有 O(N+M) 的复杂性,其中你的双循环是 O(N*M) Plus:它只需要在内存中存储一个 M + 一个 N 记录。 @Grant - 第二个 csv 文件会将新数据添加到文件的底部。 【参考方案1】:您不必完全阅读第二个文件,只需逐行阅读即可。
为了速度,只需从第一个文件中创建一个set
(快速查找,如果有重复的行可以节省内存)。为此,您必须在编写结果时保持第二个文件处于打开状态:
input_file1 = "data.csv"
input_file2 = "data_1.csv"
output_path = "out.csv"
with open(input_file1, 'r') as t1:
fileone = set(t1)
with open(input_file2, 'r') as t2, open(output_path, 'w') as outFile:
for line in t2:
if line not in fileone:
outFile.write(line)
for line in t2
逐行读取文件(尽可能避免使用readlines()
),因此即使文件很大,内存占用也很小。
fileone
确实需要一些内存,但希望如果它更小和/或有重复的行,则不会那么多,当然比readlines()
少
if line not in fileone
可能看起来和以前一样,但它具有平均 O(1)
复杂度,这使得程序更快
【讨论】:
【参考方案2】:您可以使用数据库或排序合并。我会给你基本算法(而不是python代码)
排序合并说明
这个想法是将 2 个文件排序为相同的顺序。然后依次读取2个文件
如果两个文件中的记录相等 --> 在两个文件中 如果旧文件记录 > 新文件记录 --> 记录已插入 如果旧文件记录 记录已被删除排序合并算法
Sort the 2 files to new SortedFiles using the Operating Systems sort
(use the whole record as sort key)
Open/Read SortedOldFile
Open/Read SortedNewFile
while (not end-of-file-SortedOldFile) and (not end-of-file-SortedOldFile):
if SortedOldFile.record < SortedNewFile.record:
## Deleted processing goes here
read SortedOldFile
elseif SortedOldFile.record > SortedNewFile.record:
## Insert processing goes here
read SortedNewFile
else
read SortedOldFile
read SortedNewFile
while (not end-of-file-SortedOldFile):
## Deleted processing
read SortedOldFile
while (not end-of-file-SortedNewFile):
## Insert processing
read SortedNewFile
优点:
使用最少的内存 它可以扩展到绝对庞大的文件 应该足够快,操作系统排序非常高效缺点:
使用额外的磁盘空间(现在磁盘空间很便宜) 代码取决于操作系统【讨论】:
【参考方案3】:您可以对行进行散列以压缩较小的集合,然后进行比较。 或者使用更高级的算法来查找指纹
https://en.wikipedia.org/wiki/Fingerprint_(computing)
import hashlib
input_file1 = "data.csv"
input_file2 = "data_1.csv"
output_path = "out.csv"
def get_data(file_):
res =
m = hashlib.md5()
for i, line in file_:
hashed_line = m.update(line).hexdigest()
if hashed_line not in res:
res[hashed_line ] = []
res[hashed_line ].append(i)
with open(input_file1, 'r') as t1, open(input_file2, 'r') as t2:
file1_data = get_data(t1)
file2_data = get_data(t2)
file2_raw = t2.readlines()
with open(output_path, 'w') as outFile:
for line in file2_data:
if line not in file1_data:
outFile.write(file2_raw[file2_data[line]])
【讨论】:
oopsfor line in file2_data: if line not in file2_data:
再次 :) 是时候测试您的代码了 :) 我会谨慎使用哈希值。甚至 md5 也不是双射的。如果哈希不匹配,那么好吧,它是不同的,但我认为如果哈希匹配你必须测试值......
散列的东西很有趣,但它不会节省内存,因为您仍然需要原始数据来写回文件。此外,如果哈希匹配,您仍然需要比较实际的字符串值。所以不确定你是否能赢得时间。
@Jean-FrançoisFabre 它没有比较字符串。它比较字典中的散列字符串,所以它是 O(1) 速度。对于内存使用,它应该小于 op 的
@Jean-FrançoisFabre 字典中的散列字符串应小于内存中的字符串散列(集)
是的,但我的意思是你可以使用md5.hexdigest(s1) == md5.hexdigest(s2)
和s1 != s2
。不太可能,但有可能。以上是关于计算两个 csv 文件之间差异的更快方法的主要内容,如果未能解决你的问题,请参考以下文章