如何使用Python比较2个非常大的矩阵

时间:2010-09-21 13:14:46

标签: python django matrix data-structures

我有一个有趣的问题。

我有一个非常大的(大于300MB,文件中超过10,000,000行/行)CSV文件,里面有时间序列数据点。每个月我都会得到一个与之前文件几乎相同的新CSV文件,除了添加和/或删除了一些新行,并且可能修改了几行。

我想使用Python来比较2个文件,并确定哪些行已被添加,删除和修改。

问题是文件非常大,所以我需要一个能够处理大文件大小并在合理时间内高效执行的解决方案,越快越好。

文件及其新文件的示例:

旧文件
A,2008-01-01,23
A,2008-02-01,45
B,2008-01-01,56
B,2008-02-01,60
C,2008-01-01,3
C,2008-02-01,7
C,2008-03-01,9
etc...

新文件
A,2008-01-01,23
A,2008-02-01,45
A,2008-03-01,67 (已添加)
B,2008-01-01,56
B,2008-03-01,33 (删除并添加)
C,2008-01-01,3
C,2008-02-01,7
C,2008-03-01,22 (已修改)
etc...

基本上这2个文件可以看作是需要比较的矩阵,我已经开始考虑使用PyTable了。如何解决这个问题的任何想法将不胜感激。

2 个答案:

答案 0 :(得分:4)

喜欢这个。

步骤1.排序。

步骤2.阅读每个文件,进行逐行比较。将差异写入另一个文件。

您可以自己轻松编写。或者您可以使用difflibhttp://docs.python.org/library/difflib.html

请注意,一般解决方案非常慢,因为它会搜索差异附近的匹配行。编写自己的解决方案可以更快地运行,因为您知道文件应该如何匹配。您可以优化“resynch-after-a-diff”算法。

10,000,000行几乎不重要。它不是那么大。两个300Mb文件可轻松放入内存中。

答案 1 :(得分:1)

这是一个天真的实现,但会处理未分类的数据:

import csv

file1_dict = {}
file2_dict = {}

with open('file1.csv') as handle:
    for row in csv.reader(handle):
        file1_dict[tuple(row[:2])] = row[2:]

with open('file2.csv') as handle:
    for row in csv.reader(handle):
        file2_dict[tuple(row[:2])] = row[2:]

with open('outfile.csv', 'w') as handle:
    writer = csv.writer(handle)
    for key, val in file1_dict.iteritems():
        if key in file2_dict:
            #deal with keys that are in both
            if file2_dict[key] == val:          
                writer.writerow(key+val+('Same',))
            else:
                writer.writerow(key+file2_dict[key]+('Modified',))
            file2_dict.pop(key)
        else:
            writer.writerow(key+val+('Removed',))
    #deal with added keys!  
    for key, val in file2_dict.iteritems():
        writer.writerow(key+val+('Added',))

你可能无法“插入”这个解决方案,但它应该可以让你达到95%左右。 @ S.Lott是对的,2 300mb文件很容易适合内存......如果你的文件进入1-2gb范围,那么可能需要修改排序数据。

这样的事情很接近......虽然你可能不得不改变比较周围的添加修改有意义:

#assumming both files are sorted by columns 1 and 2
import datetime
from itertools import imap

def str2date(in):
    return datetime.date(*map(int,in.split('-')))

def convert_tups(row):
    key = (row[0], str2date(row[1]))
    val = tuple(row[2:])
    return key, val

with open('file1.csv') as handle1:
    with open('file2.csv') as handle2:
        with open('outfile.csv', 'w') as outhandle:
            writer = csv.writer(outhandle)
            gen1 = imap(convert_tups, csv.reader(handle1))
            gen2 = imap(convert_tups, csv.reader(handle2))
            gen2key, gen2val = gen2.next()      
            for gen1key, gen1val in gen1:
                if gen1key == gen2key and gen1val == gen2val:
                    writer.writerow(gen1key+gen1val+('Same',))
                    gen2key, gen2val = gen2.next()
                elif gen1key == gen2key and gen1val != gen2val:
                    writer.writerow(gen2key+gen2val+('Modified',))
                    gen2key, gen2val = gen2.next()
                elif gen1key > gen2key:
                    while gen1key>gen2key:
                        writer.writerow(gen2key+gen2val+('Added',))
                        gen2key, gen2val = gen2.next()
                else:
                    writer.writerow(gen1key+gen1val+('Removed',))