【问题标题】:Compare multiple CSV files with Python用 Python 比较多个 CSV 文件
【发布时间】:2012-06-25 19:53:54
【问题描述】:

我希望将多个 CSV 文件与 Python 进行比较,并输出一份报告。要比较的 CSV 文件的数量会有所不同,所以我让它从目录中提取一个列表。每个 CSV 有 2 列:第一列是区号和交易所,第二列是价格。 例如

1201007,0.006
1201032,0.0119
1201040,0.0106
1201200,0.0052
1201201,0.0345

这些文件不会都包含相同的区号和交换,所以我需要使用第一个字段作为键,而不是逐行比较。然后我需要生成一个报告,上面写着:file1 与 file2 有 200 个不匹配,比 file2 低 371 个价格,比 file2 高 562 个价格。我需要生成它以将每个文件相互比较,因此将对 file3、file4.... 重复此步骤,然后将 file2 与 files3 等重复。我认为自己是 Python 的相对菜鸟。下面是我到目前为止的代码,它只抓取目录中的文件并打印所有文件的价格,总计。

import csv
import os

count = 0
#dir containing CSV files
csvdir="tariff_compare"
dirList=os.listdir(csvdir)
#index all files for later use
for idx, fname in enumerate(dirList):
    print fname
    dic_read = csv.reader(open(fname))
    for row in dic_read:
        key = row[0]
        price = row[1]
        print price
        count += 1
print count

【问题讨论】:

    标签: python csv


    【解决方案1】:

    这假设您的所有数据都可以放入内存;如果没有,您将不得不尝试一次只加载几组文件,甚至一次只加载两个文件。

    它进行比较并将输出写入一个 summary.csv 文件,每对文件一行。

    import csv
    import glob
    import os
    import itertools
    
    def get_data(fname):
        """
        Load a .csv file
        Returns a dict of {'exchange':float(price)}
        """
        with open(fname, 'rb') as inf:
            items = (row.split() for row in csv.reader(inf))
            return {item[0]:float(item[1]) for item in items}
    
    def do_compare(a_name, a_data, b_name, b_data):
        """
        Compare two data files of {'key': float(value)}
    
        Returns a list of
          - the name of the first file
          - the name of the second file
          - the number of keys in A which are not in B
          - the number of keys in B which are not in A
          - the number of values in A less than the corresponding value in B
          - the number of values in A equal to the corresponding value in B
          - the number of values in A greater than the corresponding value in B
        """
        a_keys = set(a_data.iterkeys())
        b_keys = set(b_data.iterkeys())
    
        unique_to_a = len(a_keys - b_keys)
        unique_to_b = len(b_keys - a_keys)
    
        lt,eq,gt = 0,0,0
        pairs = ((a_data[key], b_data[key]) for key in a_keys & b_keys)
        for ai,bi in pairs:
            if ai < bi:
                lt +=1 
            elif ai == bi:
                eq += 1
            else:
                gt += 1
    
        return [a_name, b_name, unique_to_a, unique_to_b, lt, eq, gt]
    
    def main():
        os.chdir('d:/tariff_compare')
    
        # load data from csv files
        data = {}
        for fname in glob.glob("*.csv"):
            data[fname] = get_data(fname)
    
        # do comparison
        files = data.keys()
        files.sort()
        with open('summary.csv', 'wb') as outf:
            outcsv = csv.writer(outf)
            outcsv.writerow(["File A", "File B", "Unique to A", "Unique to B", "A<B", "A==B", "A>B"])
            for a,b in itertools.combinations(files, 2):
                outcsv.writerow(do_compare(a, data[a], b, data[b]))
    
    if __name__=="__main__":
        main()
    

    编辑: user1277476 说得很好;如果您通过交换对文件进行预排序(或者如果它们已经按排序顺序),则可以同时遍历所有文件,只保留内存中每个文件的当前行。

    这可以让您对每个交换条目进行更深入的比较 - 包含一个值的文件数量,或者顶部或底部 N 个值等。

    【讨论】:

    • 我会尽快尝试实现它,但它看起来正是我所需要的。谢谢!
    【解决方案2】:

    如果你的文件很小,你可以做一些基本的事情

    data = dict()
    for fname in os.listdir(csvDir):
        with open(fname, 'rb') as fin:
            data[fname] = dict((key, value) for key, value in fin.readlines())
    # All the data is now loaded into your data dictionary
    # data -> {'file1.csv': {1201007: 0.006, 1201032: 0.0119, 1201040: 0.0106}, 'file2.csv': ...}
    

    现在,您可以轻松访问所有内容,以比较数据字典中的键及其结果值。

    否则,如果您要处理更大的数据集,而这些数据集可能无法加载到内存中,您可能需要考虑一次只处理 2 个文件,其中一个文件存储在内存中。您可以使用 itertools.combinations 创建文件名组合列表,就像 combinations(filenames, 2) 一样,您可以使用唯一的组合生成 2 个文件名对。

    从那里您仍然可以进一步优化,但这应该会让您继续前进。

    【讨论】:

      【解决方案3】:

      我可能会先对文件进行排序,然后再进行比较。然后使用类似于mergesort的合并步骤的算法进行比较。

      您仍然需要考虑如何处理重复记录 - EG,如果 file1 有 1234567,0.1 两次,file2 也是如此?如果 file1 有 3 个,而 file2 有 5 个呢?反之亦然?

      http://en.literateprograms.org/Merge_sort_%28Python%29
      http://stromberg.dnsalias.org/~strombrg/sort-comparison/
      http://en.wikipedia.org/wiki/Merge_sort
      

      【讨论】:

      • 它们已经预先排序。至于重复,由于数据的类型,单个文件中绝对没有重复。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-24
      • 2015-10-30
      • 1970-01-01
      相关资源
      最近更新 更多