繁体   English   中英

使用Python比较多个CSV文件

[英]Compare multiple CSV files with Python

我希望将多个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 ....,然后针对file3等对file2重复该步骤。 下面是我到目前为止拥有的代码,这些代码仅抓取目录中的文件,并从所有文件中以总计的价格显示价格。

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

假设所有数据都可以容纳在内存中; 如果没有,您将不得不尝试一次仅加载一些文件集,或者一次仅加载两个文件。

它进行比较,并将输出写入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个值或后N个值等。

如果文件很小,则可以执行以下基本操作

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

从那里您仍然可以进一步优化,但这应该可以助您一臂之力。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM