【问题标题】:Python - comparing columns in 2 files and returning merged outputPython - 比较 2 个文件中的列并返回合并输出
【发布时间】:2015-03-26 12:18:17
【问题描述】:

我有一个看似简单的问题,但现在卡在它上面太久了。我想比较两个文件(格式如下)

> file1
20  246057  0.28    68363   0   A
20  246058  0.28    68396   T   C
20  246059  0.28    76700   A   G
20  246060  0.28    76771   T   C
20  246061  0.28    76915   0   A

> file2
112879285   R   68303   20
200068921   M   68319   20
200257910   K   68336   20
200192457   W   68363   20
138777928   Y   68396   20

我想将 file1 的第 0 列和第 3 列与 file2 的第 2 列和第 3 列进行比较,如果它们匹配,我想输出其余信息以匹配两个文件中的行,如下所示:

> desired output
20  246057  0.28    68363   0   A   200192457   W
20  246058  0.28    68396   T   C   138777928   Y

这是我到目前为止的代码,我已经尝试了这个的几种变体以及这里的许多建议,但我仍然不知道如何从 file1 获取相应的信息。我尝试的大多数事情都会导致每次匹配都会重复 file1 中的最后一行。

#!/usr/bin/python
import csv

data2 = []
output = open("output.txt","w")

with open("file1.txt", "rb") as in_file1, open("file2.txt","rb") as in_file2:
    reader1 = csv.reader((in_file1), delimiter="\t")
    for row1 in reader1:
        y1 = row1[0], row1[3]
        data2.append(tuple(y1))
        y = row1
    reader2 = csv.reader((in_file2), delimiter="\t")
    for row2 in reader2:
        z = row2[-1], row2[2]
        if tuple(z) in data2:
            out = "\t".join(row2)
            output.write(out+"\n")

我正在努力的部分是在解析后从 file1 获取输出。所以我目前得到了下面的结果,但我还想要 file1 中这些行的相应信息:

> current output
200192457   W   68363   20
138777928   Y   68396   20

非常感谢任何帮助或建议!谢谢! (我使用的是 python 2.7)

【问题讨论】:

  • 使用带有元组键的字典?
  • 你能给我举个例子吗?对不起,我对编程很陌生
  • 是的,我给你举了一个例子。事实上,我给了你一个完整的程序版本作为例子。 :)
  • 很抱歉,我的连接速度很慢,现在会检查一下。谢谢你:)

标签: python loops for-loop multiple-columns string-matching


【解决方案1】:

这是我从头开始编写的解决方案:

f1 = file("file1.txt")
f2 = file("file2.txt")
d = {}
while True:
  line = f1.readline()
  if not line:
    break
  c0,c1,c2,c3,c4,c5 = line.split()
  d[(c0,c3)] = (c0,c1,c2,c3,c4,c5)
while True:
  line = f2.readline()
  if not line:
    break
  c0,c1,c2,c3 = line.split()
  if (c3,c2) in d:
    vals = d[(c3,c2)]
    print c3,vals[1],vals[2],vals[3],vals[4],vals[5],c0,c1

它读取第一个文件,并使用 tuple 键将值存储到 dict 中。然后它读取第二个文件,并检查字典中是否存在tuple 键。如果是这样,它会打印所有数据。

请注意,您必须记住在程序的最终工作版本中也关闭文件。为简洁起见,我省略了关闭文件的行。

【讨论】:

  • 非常感谢!它工作得很好,我从来没有想过使用带有元组键的字典。好想法!我的脚本中确实有 file.close() 但没有包含它们,感谢您的清晰说明:)
【解决方案2】:

这是 joinawkcut 的一个很好的用例:

$ join -11 -24 file1 file2 | awk '$4 == $9 { }' | cut -d' ' -f1-8

输出:

20 246057 0.28 68363 0 A 200192457 W
20 246058 0.28 68396 T C 138777928 Y

解释:

  1. 在第一个 (-11) 和第四个 (-24) 字段中加入两个文件 file1file2
  2. 仅过滤第 4 和第 9 字段相等的行 ($4 == $9);打印这些行 ({ })。
  3. 从这些行中仅打印第 1 到第 8 个字段 (-f1-8)。

【讨论】:

  • 这对我不起作用,我没有得到任何输出。你能解释一下每一位的含义吗?对不起,我对这些命令不太熟悉,但一个班轮总是一个奖励!
  • 对不起,我现在看到解释了!
  • 我不认为这对我有用,因为我想在字段 1 和 4 以及字段 4 和 3 上加入这两个文件。而当它们仅由字段 1 和 4 加入时无论如何这些都是相同的,所以我相信字段 4 和 9 中的某些匹配值不会在同一行,如果这有意义的话?
  • 这就是为什么在第二步中我使用awk 只过滤第二对字段相等的那些行。我的答案中的输出正是您在运行命令时得到的。
  • @Tichodroma 需要去掉 AWK 命令中的空大括号,否则输出将始终为空,如 user3078840 报告的那样。所以,工作命令是:join -11 -24 file1 file2 | awk '$4 == $9' | cut -d' ' -f1-8。或者,您可以避免使用最后一个 cut 命令:join -11 -24 file1 file2 | awk '$4 == $9 {$9 = $10 = ""; print}'
【解决方案3】:

尝试将您的代码修改为以下,您实际上需要将获得匹配项的 row1 存储在 file2 中:

with open("file1.txt", "rb") as in_file1, open("file2.txt","rb") as in_file2:
reader1 = csv.reader((in_file1), delimiter="\t")
for row1 in reader1:
    y1 = row1[0], row1[3]
    reader2 = csv.reader((in_file2), delimiter="\t")
    for row2 in reader2:
        z = row2[-1], row2[2]
        if tuple(z) in [tuple(y1)]:
              out = "\t".join(row1)
              output.write(out+"\n")    
              out = "\t".join(row2)
              output.write(out+"\n")

【讨论】:

  • 你有两次'out ='的地方是意味着输出row1然后输出row2写入输出文件?我更改了它,但是当有 2 个匹配时,它只将一个匹配写入输出文件。
猜你喜欢
  • 2022-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-01
  • 2022-01-03
  • 1970-01-01
  • 2011-02-06
  • 1970-01-01
相关资源
最近更新 更多