Python 如何根据运行时指定的列名比较两个巨大的CSV文件,并忽略几个列?

Python 如何根据运行时指定的列名比较两个巨大的CSV文件,并忽略几个列?,python,csv,dictionary,optimization,compare,Python,Csv,Dictionary,Optimization,Compare,我需要写一个程序,比较2个CSV文件,并在excel文件中报告差异。它根据主键和一些次键比较记录,有时忽略指定的其他列的列表。所有这些参数都是从excel中读取的。 我已经编写了一个代码,它可以实现这一点,并且对于小文件来说效果很好,但是对于大文件来说性能非常差。一些要比较的文件有超过200K行 当前逻辑使用csv.DictReader读取文件。我逐行遍历第一个文件的行,每次在第二个文件中找到对应的记录,比较主键和辅键。如果找到该记录,我将比较所有列,忽略excel中指定的列。如果任何列中存在差

我需要写一个程序,比较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

这是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)