0

我希望将多个 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 等。我认为自己是 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
4

3 回答 3

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 个值等。

于 2012-06-25T20:27:34.690 回答
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 个文件名对。

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

于 2012-06-25T20:31:12.883 回答
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
于 2012-06-25T20:55:11.227 回答