使用Python比较多个CSV文件

时间:2012-06-25 19:53:55

标签: python csv

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

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对文件3等重复。我认为自己是Python的相对noob。下面是我到目前为止的代码,它只是抓取目录中的文件并打印所有文件的总价格。

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

3 个答案:

答案 0 :(得分:0)

这假设您的所有数据都适合内存;如果没有,你将不得不尝试一次只加载一些文件集,或者一次只加载两个文件。

进行比较并将输出写入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值等。

答案 1 :(得分:0)

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

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个文件名对。

从那里你仍然可以进一步优化,但这应该让你去。

答案 2 :(得分:0)

我可能会在比较之前对文件进行排序。然后使用类似于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