首页 > 解决方案 > 如何根据运行时指定的列名并忽略几列来比较 2 个巨大的 CSV 文件?

问题描述

我需要编写一个程序来比较 2 个 CSV 文件并报告 excel 文件中的差异。它基于主键(有时是几个辅助键)比较记录,忽略指定的其他列的列表。所有这些参数都是从 Excel 中读取的。我已经编写了一个代码,它适用于小文件,但对于大文件来说性能很差(一些要比较的文件有超过 200K 的行)。

当前逻辑使用 csv.DictReader 读取文件。我逐行遍历第一个文件的行,每次都在第二个文件中找到相应的记录(比较主键和辅助键)。如果找到记录,我会比较所有列,忽略 Excel 中指定的列。如果任何列有差异,我会在 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

标签: pythoncsvdictionaryoptimizationcompare

解决方案


我可以使用 @Vaibhav Jadhav 建议的 Pandas 库来实现这一点,使用以下步骤: 1. 将 2 个 CSV 文件导入数据帧。例如:

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)
  1. 从两个数据框中删除不比较的列。

for col in data1.columns: if col in ignore_col: del data1[col] del data2[col]

  1. 将 2 个数据框与indicator=True

merged = pd.merge(data1, data2, how='outer', indicator=True)

  1. 从合并的数据框中,删除两个数据框中可用的行。

merged = merged[merged._merge != 'both']

  1. 使用键对数据框进行排序

merged.sort_values(by = keys, inplace = True, kind = 'quicksort')

  1. 迭代数据帧的行,比较前 2 行的键。如果键不同,则 row1 仅存在于 2 个 CSV 文件之一中。如果键相同,则遍历各个列并进行比较以找出不同的列值。

推荐阅读