比较两个大型csv文件并用python

时间:2016-03-14 14:32:09

标签: python file csv numpy

我正在尝试比较两个包含化学品数据的大型csv文件。

第一个," file1"是14 Mb(不是那么重),但是第二个," file2"是3Go(47798771行)。

这里是文件1的示例(我们将关注第四列,其中包含inchikeys):

MFCD00134034    7440-42-8   B   UORVGPXVDQYIDP-UHFFFAOYSA-N
MFCD01745487    64719-89-7  B1BBBB(BBBBB1[Li])[Li]  XZXJQLAKEUKXOT-UHFFFAOYSA-N
MFCD01310566    19287-45-7  BB  QSJRRLWJRLPVID-UHFFFAOYSA-N
MFCD00011323    10035-10-6  Br  CPELXLSAUQHCOX-UHFFFAOYSA-N
        N(CCNCCCCCCCCCCNCCN(CC)CC)(CC)CC    PISAWRHWZGEVPP-UHFFFAOYSA-N
MFCD01744969    137638-86-9 O(C(=O)C(c1ccccc1)c1ccccc1)c1cc2c(C[C@H]3N(CC[C@]2(C)C3C)Cc2ccccc2)cc1  CIRJJEXKLBHURV-MAYWEXTGSA-N
        O(CCCN1CCCC1)c1ccc(NC(=Nc2ccccc2)c2ccccc2)cc1   KETUBKLQEXFJBX-UHFFFAOYSA-N
MFCD01694581    3810-31-9   S(CCN(CCSC(N)=N)CCSC(N)=N)C(N)=N    GGDUORJVTMUGNU-UHFFFAOYSA-N
MFCD06794992    60066-94-6  Brc1cc(C(=O)c2ncccc2)c(NC(=O)CNC(=O)[C@@H](N)CCCCN)cc1  NVOGGKXDMDDFEG-HNNXBMFYSA-N
MFCD06794980    60066-98-0  Brc1cc(C(=O)c2ncccc2)c(NC(=O)CNC(=O)[C@@H](N)CCCNC(N)=N)cc1 LFCYDGUHINTBOJ-AWEZNQCLSA-N

文件2:

lat_chemical_id stereo_chemical_id  source_cid  inchikey
CID100000001    CID000000001    1   RDHQFKQIGNGIED-UHFFFAOYSA-N
CID100000010    CID000000010    10  AUFGTPPARQZWDO-UHFFFAOYSA-N
CID100000100    CID000000100    100 UTIBHEBNILDQKX-UHFFFAOYSA-N
CID100001000    CID000001000    1000    ULSIYEODSMZIPX-UHFFFAOYSA-N
CID100010000    CID000010000    10000   ZPIFKCVYZBVZIV-UHFFFAOYSA-N
CID100100000    CID000100000    100000  SPTBIJLJJBZGDY-UHFFFAOYSA-N
CID101000000    CID001000000    1000000 XTNVYACQOFUTNH-UHFFFAOYSA-N
CID110000000    CID010000000    10000000    WUGPGGSZFRVGGA-UHFFFAOYSA-N
CID110000001    CID010000001    10000001    ANOUMYXLUIDQNL-UHFFFAOYSA-N

我的目标是比较两个文件中的第四行,以查看它们是否相同。然后,当它的情况下,提取所有信息(从两个文件)并写第三个。

这是我的(幼稚)代码:

#!/usr/bin/env python
#-*- coding: utf-8 -*-
######################
import numpy as np
import argparse 
import csv 
#################################


def compare(tab_data_inchik,stitch,output):
    dt = open(tab_data_inchik, 'rb')
    st = open(stitch,'rb')
    out = open(output,'wb')
    data = csv.reader(dt, delimiter = '\t')
    database = csv.reader(st, delimiter = '\t')
    result = csv.writer(out, delimiter = '\t')
    for line in data:
        for row in database:
            if line[3] == row[3]:
                result.writerow((line[0],line[1],line[2],row[0],row[1],row[2],row[3]))        

    dt.close()
    st.close()
    out.close()

##############################""
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("tsv1", help = "Pr Data")
    parser.add_argument("tsv2", help = "Database")
    parser.add_argument("output", help = "output file")
    args=parser.parse_args()

    compare(args.tsv1,args.tsv2,args.output)

看起来,程序甚至没有到达数据库循环的第二行,我猜它是因为文件很大而我的方法是机器人优化的。也许我应该使用numpy.where(),但我不知道如何。

有没有办法在没有双循环的情况下获取信息? 提前致谢。

2 个答案:

答案 0 :(得分:3)

问题出在哪里:
在你的代码中你循环了数百万行,在3GB文档中包含超过44000000行,假设每行的平均字符是68个字符,在14MB doc中假设有超过205000行。
然后第20行将执行44000000 * 205000 = 9.02 * 10 ^ 12次。

if line[3] == row[3]:

单CPU上的普通计算机每秒只能运行10 ^ 10个低级指令,并且一行python代码通常比单个指令执行要多得多。因为CPU需要花费大量时间才能完成它

Python dict数据结构(哈希表):
集合是一种数据结构,可以有效地检查单个数据是否存储在它之前或不存储在恒定数量的小CPU指令中(这是非常节省时间的)。

如果你使用这样的东西,在普通的英特尔酷睿i5或类似的东西上完成它需要不到5分钟的时间。

database_set = dict()
for row in database: #Loop on the smaller file so we store less in memory.
    database_set[row[3]] = (row[0],row[1],row[2])
for line in data:
    if line[3] in database_set:     
        row = database_set[line[3]]

        result.writerow((line[0],line[1],line[2],row[0],row[1],row[2],line[3]))

如果你想了解如何使用python集查找here
如果你想知道set如何完成它的工作,你可以找到here

答案 1 :(得分:1)

问题在于,当您第一次遍历Scanner scanner = new Scanner(input); while (true) { String letters = scanner.findWithinHorizon("\\G\\s*\\[a-zA-Z]+", 0); if (letters != null) { System.out.println("letters: " + letters.trim()); } else { String number = scanner.findWithinHorizon("\\G\\s[+-]?[0-9]+", 0); if (number != null) { System.out.println("number: " + number.trim()); } else if (scanner.findWithinHorizon("\\G\\s*\\Z", 0) != null) { System.out.println("end"); break; } else { System.out.println("unrecognized input"); break; } } } 的所有行时,databasedatabase)内的文件指针位于文件的末尾这样你就可以在没有先将其显式移回文件开头的情况下再次迭代。这可以使用st完成。

seek

更好的解决方案

根据for line in data: st.seek(0) # Resets the file back to the beginning for row in database: if line[3] == row[3]: # Write output data 的大小,由于您正在阅读database中每一行的整个文件,因此可能不会很快。您可以考虑将data加载到内存中进行比较。

database

更好的解决方案

更好的选项(因为# Load entire database in database_rows = [row for row in database] for line in data: for row in database_rows: if line[3] == row[3]: # Write output data 小于data)将加载database到内存并直接从data读取文件。为此,您可以反转循环的顺序。

database

此解决方案不需要您将data_rows = [row for row in data] for row in database: for line in data_rows: if line[3] == row[3]: # Write output data 加载到内存中。