【问题标题】:comparing two large csv file and writing another one with python比较两个大的 csv 文件并用 python 编写另一个
【发布时间】:2016-06-29 15:44:30
【问题描述】:

我正在尝试比较两个包含化学品数据的大型 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

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

这是我的(天真的)代码:

#!/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() 但我不知道如何使用。

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

【问题讨论】:

  • 没有尝试我的新代码??我敢打赌它会运行不到 10 分钟。
  • 刚刚尝试过(我在法国)。奇迹般有效。非常感谢
  • 欢迎您,完成需要多长时间?如果你能提供一个基准,那就太好了。
  • 花了9分钟,我错了,较小的是147 000
  • 另一种方法要运行一天以上。

标签: python file csv numpy


【解决方案1】:

问题是,当您第一次遍历database 的所有行时,database (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

更好的解决方案

更好的选择(因为datadatabase很多)是将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

此解决方案不需要您将database 加载到内存中。

【讨论】:

  • 非常感谢,它似乎可以工作(程序仍在运行),我会在它停止时给你确认。
【解决方案2】:

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

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

单 CPU 上的普通计算机每秒只能运行 10^10 条低级指令,而一行 python 代码的执行时间通常比单条指令要多得多。因为 CPU 需要很长时间才能完成它

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

如果你使用这样的东西,在普通的 Intel Core 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

【讨论】:

  • 在 writerow 中,如果我不进行双循环,计算机如何知道从哪一行提取信息?
  • @EL Walou EL Walou 很抱歉给您带来不便,我正确编辑了这段代码,将您想要的数据保存在dict的值中,当您需要时,您可以轻松找到它。
猜你喜欢
  • 2015-01-07
  • 1970-01-01
  • 2014-06-08
  • 2022-01-24
  • 1970-01-01
  • 2018-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多