Python 如何根据运行时指定的列名比较两个巨大的CSV文件,并忽略几个列?
我需要写一个程序,比较2个CSV文件,并在excel文件中报告差异。它根据主键和一些次键比较记录,有时忽略指定的其他列的列表。所有这些参数都是从excel中读取的。 我已经编写了一个代码,它可以实现这一点,并且对于小文件来说效果很好,但是对于大文件来说性能非常差。一些要比较的文件有超过200K行 当前逻辑使用csv.DictReader读取文件。我逐行遍历第一个文件的行,每次在第二个文件中找到对应的记录,比较主键和辅键。如果找到该记录,我将比较所有列,忽略excel中指定的列。如果任何列中存在差异,我会在excel报告中写入这两条记录,突出显示差异。 下面是我到目前为止的代码。如果有人能提供一些建议来优化这个程序或提出一种不同的方法,那将是非常感谢的Python 如何根据运行时指定的列名比较两个巨大的CSV文件,并忽略几个列?,python,csv,dictionary,optimization,compare,Python,Csv,Dictionary,Optimization,Compare,我需要写一个程序,比较2个CSV文件,并在excel文件中报告差异。它根据主键和一些次键比较记录,有时忽略指定的其他列的列表。所有这些参数都是从excel中读取的。 我已经编写了一个代码,它可以实现这一点,并且对于小文件来说效果很好,但是对于大文件来说性能非常差。一些要比较的文件有超过200K行 当前逻辑使用csv.DictReader读取文件。我逐行遍历第一个文件的行,每次在第二个文件中找到对应的记录,比较主键和辅键。如果找到该记录,我将比较所有列,忽略excel中指定的列。如果任何列中存在差
primary_key = wb['Parameters'].cell(6,2).value #Read Primary Key
secondary_keys = [] #Read Secondary Keys into a list
col = 4
while wb['Parameters'].cell(6,col).value:
secondary_keys.append(wb['Parameters'].cell(6,col).value)
col += 1
len_secondary_keys = len(secondary_keys)
ignore_col = [] #Read Columns to be ignored into a list
row = 8
while wb['Parameters'].cell(row,2).value:
ignore_col.append(wb['Parameters'].cell(row,2).value)
row += 1
with open (filename1) as csv_file_1, open (filename2) as csv_file_2:
file1_reader = csv.DictReader(filename1, delimiter='~')
for row_file1 in file1_reader:
record_found = False
file2_reader = csv.DictReader(filename2, delimiter='~')
for row_file2 in file2_reader:
if row_file2[primary_key] == row_file1[primary_key]:
for key in secondary_keys:
if row_file2[key] != row_file1[key]:
break
compare(row_file1, row_file2)
record_found = True
break
if not record_found:
report_not_found(sheet_name1, row_file1, row_no_file1)
def compare(row_file1, row_file2):
global row_diff
data_difference = False
for key in row_file1:
if key not in ignore_col:
if (row_file1[key] != row_file2[key]):
data_difference = True
break
if data_difference:
c = 1
for key in row_file1:
wb_report['DW_Diff'].cell(row = row_diff, column = c).value = row_file1[key]
wb_report['DW_Diff'].cell(row = row_diff+1, column = c).value = row_file2[key]
if (row_file1[key] != row_file2[key]):
wb_report['DW_Diff'].cell(row = row_diff+1, column = c).fill = PatternFill(patternType='solid',
fill_type='solid',
fgColor=Color('FFFF0000'))
c += 1
row_diff += 2
这是Apache Beam的一个很好的用例 groupbykey等功能将使按键匹配更加高效 使用适当的运行程序,可以有效地扩展到更大的数据集 可能没有Excel IO,但可以输出到csv、数据库等
https://beam.apache.org/documentation/
https://beam.apache.org/documentation/transforms/python/aggregation/groupbykey/
https://beam.apache.org/documentation/runners/capability-matrix/
https://beam.apache.org/documentation/io/built-in/
由于比较的结构,您遇到了速度问题。您正在使用一个嵌套循环,将一个集合中的每个项与另一个集合中的每个项进行比较,该循环处于^2慢速状态 您可以稍微修改代码的一种方法是重做接收数据的方式,而不是使用csv.DictReader为每个文件创建字典列表,而是使用主键和辅键作为字典键手动创建每个文件的单个字典。通过这种方式,您可以非常轻松地比较这两本词典中的条目,并且保持时间不变 此构造假定每个文件中都有唯一的主键/次键,这似乎是从上面假设的 这里是一个玩具的例子。在这里,我只是使用一个整数和一个动物类型作为主键和次键的元组
In [7]: file1_dict = {(1, 'dog'): [45, 22, 66], (3, 'bird'): [55, 20, 1], (15, '
...: cat'): [6, 8, 90]}
In [8]: file2_dict = {(1, 'dog'): [45, 22, 66], (3, 'bird'): [4, 20, 1]}
In [9]: file1_dict
Out[9]: {(1, 'dog'): [45, 22, 66], (3, 'bird'): [55, 20, 1], (15, 'cat'): [6, 8, 90]}
In [10]: file2_dict
Out[10]: {(1, 'dog'): [45, 22, 66], (3, 'bird'): [4, 20, 1]}
In [11]: for k in file1_dict:
...: if k in file2_dict:
...: if file1_dict[k] == file2_dict[k]:
...: print('matched %s' % str(k))
...: else:
...: print('different %s' % str(k))
...: else:
...: print('no corresponding key for %s' % str(k))
...:
matched (1, 'dog')
different (3, 'bird')
no corresponding key for (15, 'cat')
按照@Vaibhav Jadhav的建议,我可以通过熊猫图书馆通过以下步骤实现这一点: 1.将2个CSV文件导入数据帧。 e、 g: 从两个数据帧中删除不进行比较的列。 对于data1.1列中的列: 如果列在忽略列中: del data1[col] del data2[col] 将2个数据帧合并为indicator=True merged=pd.mergedata1,data2,how='outer',indicator=True 从合并的数据帧中,删除两个数据帧中可用的行。 合并=合并[合并。_merge!=“两者”] 使用键对数据帧进行排序 merged.sort_valuesby=keys,inplace=True,kind='quicksort' 迭代dataframe的行,比较前两行的键。如果键不同,则行1仅存在于2个CSV文件中的一个。如果键相同,则在各个列上迭代,并进行比较,以找到不同的列值。 尝试通过创建数据帧来使用pandas库
try:
data1 = pd.read_csv(codecs.open(filename1, 'rb', 'utf-8', errors = 'ignore'), sep = delimiter1, dtype='str', error_bad_lines=False)
print (data1[keys[0]])
except:
data1 = pd.read_csv(codecs.open(filename1, 'rb', 'utf-16', errors = 'ignore'), sep = delimiter1, dtype='str', error_bad_lines=False)