大型csv文件的交集

时间:2015-07-20 11:17:08

标签: python csv

我有两个包含数千个条目的大型csv文件,每个文件包含以下形式的两列ID:

BRADI5G01462.1_1    NCRNA_34654_1853
BRADI5G01462.1_1    NCRNA_34398_1942
BRADI5G01462.1_1    NCRNA_2871_1959

我已经尝试了这个,但它没有给出预期的结果

import csv
files=["#Left(Brachypodium_Japonica).csv","#Right(Brachypodium_Japonica).csv"]
for i in range(len(files)):
    name=files[i][files[i].find("#")+1:files[i].find(".")]
    with open(files[i],"r",newline='') as source:
         rdr= csv.reader( source,delimiter="\t",skipinitialspace=True )
         with open("@"+name+".csv","w",newline='') as result:
              wtr= csv.writer( result,delimiter="\t",skipinitialspace=True )
              for r in rdr:
                  wtr.writerow( (r[1],r[2]) )


l1 = set(open('@Left(Brachypodium_Japonica).csv'))
l2 = set(open('@Right(Brachypodium_Japonica).csv'))
open('Intersection(Brachypodium_Japonica).csv', 'w').writelines(l1 & l2)

找到两个文件之间交集的最有效的pythonic方法是什么?!通过它,即两个文件中两列的整个匹配。

我已经问过这个问题before,但没有人费心去帮忙。

我真的陷入了困境,迫切需要得到高度赞赏的帮助。

修改
文件1(左)输入样本:

BRADI5G16060.1_36   OS08T0547100-02_5715
BRADI3G00440.1_243  OS03T0274400-01_2650
BRADI3G58610.1_438  OS01T0112500-01_899
BRADI1G73670.1_850  OS11T0481500-01_6621
BRADI1G78150.1_870  OS02T0543300-00_2055

文件2(右)输入样本:

BRADI5G16060.1_36   OS08T0547100-02_5715
BRADI4G45180.1_240  OS03T0103800-01_2473
BRADI2G12470.2_487  OS04T0470600-00_3504
BRADI1G73670.1_850  OS11T0481500-01_6621
BRADI1G78330.1_878  OS06T0155600-01_4411

Left&的交叉文件右:

BRADI5G16060.1_36   OS08T0547100-02_5715
BRADI1G73670.1_850  OS11T0481500-01_6621

4 个答案:

答案 0 :(得分:0)

当我查看您的代码时,它看起来像这样,

- >您有两个文件

- >您将它们再次写入两个文件

- >最后将它们添加到交叉点文件

让我们删除第二步

import csv
files=["#Left(Brachypodium_Japonica).csv","#Right(Brachypodium_Japonica).csv"]
for i in files:
    with open(i,"r",newline='') as source:
        rdr= csv.reader( source,delimiter="\t",skipinitialspace=True )
        with open('Intersection(Brachypodium_Japonica).csv',"aw",newline='') as result:
            wtr= csv.writer( result,delimiter="\t",skipinitialspace=True )
            for r in rdr:
                wtr.writerow( (r[0],r[1]) )

步骤:

- >读取第一个文件并将其添加到交叉点

- >阅读下一个文件并继续追加

  

尝试这个,如果不起作用,请告诉我。   我不知道你为什么使用那个换行符跳过但是如果你知道为什么,那么你可以继续使用它。   我按照你的格式以适当的方式重写了代码。

我在我的系统上尝试过,如果它不起作用,它会起作用指出追溯或错误。

答案 1 :(得分:0)

以下脚本读取两个(或更多)CSV文件,并将行条目的交集写入新的CSV文件。我的意思是,如果在input1.csv中的任何位置找到input2.csv中的row1,则该行将被写入输出,依此类推。

import csv

files = ["input1.csv", "input2.csv"]
ldata = []

for file in files:
    with open(file, "r") as f_input:
        csv_input = csv.reader(f_input, delimiter="\t", skipinitialspace=True)
        set_rows = set()
        for row in csv_input:
            set_rows.add(tuple(row))
        ldata.append(set_rows)

with open("Intersection(Brachypodium_Japonica).csv", "wb") as f_output:
    csv_output = csv.writer(f_output, delimiter="\t", skipinitialspace=True)
    csv_output.writerows(set.intersection(*ldata))

您需要添加文件名mangling。这种格式使测试更容易。使用Python 2.7进行测试。

答案 2 :(得分:0)

这里我做了一些假设,如果错误,代码会更复杂:

  • 索引将是"两个"您说的字段在数据集之间是相似的(在我的示例中,用于索引的字段是第一个在线上)
  • "索引"是一个数据集中的uniq(在left.csv中出现不超过一次,在right.csv中出现不超过一次)
  • 您希望最小化内存使用量
  • 字段
  • 中不存在分隔符(\t
import mmap

indexes = {}

left_fp = open('left.csv', 'r')
left = mmap.mmap(left_fp.fileno(), 0, access=mmap.ACCESS_READ)

while True:
        start = left.tell()
        line = left.readline()
        if not line: break
        # extract only the two columns you check
        cells = line.split('\t')[0:2]
        # store line position in left file
        indexes['\t'.join(cells)] = (start, left.tell() - start)


output = open('output.csv', 'w')

for line in open('right.csv'):
        # recreate the key
        cells = line.split('\t')[0:2]
        pos = left_indexes[key]
        if pos:
                # got the left line position
                left.seek(pos[0], 0)
                # write it
                output.write(left.read(pos[1]))
                # write right row
                output.write(line)

output.close()

答案 3 :(得分:0)

我有一个类似的问题,我需要找到两个相当大的CSV文件(74M行与450M行)的交集。基本思想是读取较小的文件并建立一个查找表,该表可在遍历较大的文件时使用。

我发现最快的方法是使用jq命令行工具。

smaller.csv

BRADI5G16060.1_36   OS08T0547100-02_5715
BRADI3G00440.1_243  OS03T0274400-01_2650
BRADI3G58610.1_438  OS01T0112500-01_899
BRADI1G73670.1_850  OS11T0481500-01_6621
BRADI1G78150.1_870  OS02T0543300-00_2055

larger.csv

BRADI5G16060.1_36   OS08T0547100-02_5715
BRADI3G00440.1_243  OS03T0274400-01_2650
BRADI3G58610.1_438  OS01T0112500-01_899
BRADI1G73670.1_850  OS11T0481500-01_6621
BRADI1G78150.1_870  OS02T0543300-00_2055
...

以json字典的形式准备 smaller.csv 的查找表,并将其写入 smaller.json

$ jq -s -R 'split("\n")|map({key:.,value:1})|from_entries' smaller.csv | tee smaller.json
{
  "BRADI5G16060.1_36   OS08T0547100-02_5715": 1,
  "BRADI3G00440.1_243  OS03T0274400-01_2650": 1,
  "BRADI3G58610.1_438  OS01T0112500-01_899": 1,
  "BRADI1G73670.1_850  OS11T0481500-01_6621": 1,
  "BRADI1G78150.1_870  OS02T0543300-00_2055": 1
}

现在迭代 larger.csv 并使用 smaller.json 作为查找表进行过滤:

$ jq -R -r --slurpfile F smaller.json 'select($F[0][.])' larger.csv | tee intersection.csv
BRADI5G16060.1_36   OS08T0547100-02_5715
BRADI1G73670.1_850  OS11T0481500-01_6621