【问题标题】:append multiple files and remove duplicates using dictionaries使用字典追加多个文件并删除重复项
【发布时间】:2012-12-16 22:30:48
【问题描述】:

所以我有一些看起来像这样的文件:

snpID  Gene
rs1  ABC1
rs2  ABC1
rs3  ABC25
rs4  PT4
rs5  MTND24

在不同的文件中会有其他的 snpID 和基因对,但给定的 snpID 可能有重复,但相关的相应“基因”可能不同。例如:

snpID  Gene
rs100  URX1
rs95  KL4
rs1  ABC1
rs2  ABC1-MHT5
rs3  ABC25
rs4  PT4-FIL42

我想要做的是附加文件的所有内容,如果它们具有相同的 snpID 和基因对,则删除重复项。而如果一个 snpID 的对应基因不同,它必须进入同一行 对于上面的示例,它应该如下所示:

snpID  Gene
rs1  ABC1
rs2  ABC1, ABC1-MHT5
rs3  ABC25
rs4  PT4, PT4-FIL42
rs5  MTND2
rs100  URX1
rs95  KL4

我认为我可以通过创建字典来实现这一点。

import glob
file_list = glob.glob('annotations.*')
dict_snps_genes = {}
for filename in file_list:
    with open(filename) as fileA:
        for line in fileA:
            col0 = line.split()[0]
            col1 = line.split()[1]
            dict_snps_genes[col0] = col1 

unique_dict_snps = {}
for key,value in dict_snps_genes:
    if key not in unique_dict_snps.keys():
        unique_dict_snps_genes[key] = value

我在进一步移动之前对此进行了测试,这给了我一个错误,例如:

ValueError: too many values to unpack

PS:每个文件大约有 8000 个 snpId-Gene 对,并且文件超过 5 个

关于如何克服这个问题的想法!

【问题讨论】:

  • 除了col0 = line.split()[0]col1 = line.split()[1],您只能使用一个函数调用:col0, col1 = line.split()

标签: python dictionary merge duplicate-removal


【解决方案1】:

您正在循环键,但试图将它们分配给键和值变量:

for key,value in dict_snps_genes:

将其更改为循环 .items():

for key,value in dict_snps_genes.items():

或者更好的是,如果在 Python 2.x 上,使用 `.iteritems():

for key,value in dict_snps_genes.iteritems():

请注意,您读取文件的方式,您只存储任何给定 snpID 的最后读取基因;如果您找到该 id 的另一个条目,则覆盖前一个条目。

就个人而言,我会使用 collections.defaultdict()set 默认值:

import glob
import collections

file_list = glob.glob('annotations.*')
snps_genes = collections.defaultdict(set)
for filename in file_list:
    with open(filename) as fileA:
        for line in fileA:
            snpid, gene = line.strip().split(None, 1)
            snps_genes[snpid].add(gene)

现在snps_genes 中的值是一组基因,每个都是独一无二的。请注意,我在空格 (.split(None, 1)) 上将您的行分成 2 段,这样如果基因值中有任何空格,它将按如下方式存储:

>>> 'id gene with whitespace'.split(None, 1)
['id', 'gene with whitespace']

通过使用 `snpid,gene' 作为左手赋值表达式,Python 获取拆分的结果并将每个部分分配给单独的变量;这里有一个方便的技巧来节省一行代码。

要将其输出到新文件,只需循环生成的 snps_genes 结构即可。这是对所有内容进行排序的方法:

for id in sorted(snps_genes):
    print id, ', '.join(sorted(snps_genes[id]))

【讨论】:

  • 正如所写,我认为第二个循环没有任何作用。 unique_dict_snps 不会成为dict_snps_genes 的副本吗?
  • @DSM:我添加了一个关于如何阅读文件的部分。文件被读取的方式,无论如何都不会任何欺骗。
  • Ummm...除了我更喜欢在这种情况下使用inputfile之外,基本上是相同的答案
  • @JonClements: 我用set 开始。 :-P
  • @jules:确切地说,请参阅我的回答中对.strip() 的调用。 (全线:snpid, gene = line.strip().split(None, 1)
【解决方案2】:

我会这样写:

from glob import glob
import fileinput

infiles = glob('annotations.*')
lines = fileinput.input(infiles)
rows = (line.split() for line in lines)

from collections import defaultdict
dd = defaultdict(list)
for row in rows:
    dd[row[0]].append(row[1])

如果值是唯一的,那么:

dd = defaultdict(set)
for row in rows:
    dd[row[0]].add(row[1])

然后从那里去......

【讨论】:

  • @jules 我打错了 - 应该是 import fileinput - 抱歉 - 已编辑(这就是你直接输入 SO 得到的结果!)
【解决方案3】:

您可以将col1 = line.split()[1] 之后的行替换为:

if col0 in dict_snps_genes:
    dict_snps_genes[col0].add(col1)
else:
    dict_snps_genes[col0] = set([col1])

您可以阅读有关集合的更多信息here

【讨论】:

    【解决方案4】:

    为什么不直接做:

    import glob
    files = glob.glob('annotations.*')
    d = {}
    for f in files:
        with open(f) as f:
            for line in f:
                col0, col1 = line.split()
                if col0 not in d:
                    d[col0] = [col1]
                elif col1 not in d[col0]:
                    d[col0].append(col1)
    

    将导致:

    d = {
        "rs95": ['KL4'],
        "snpID": ['Gene'],
        "rs1": ['ABC1'],
        "rs2": ['ABC1', 'ABC1-MHT5'],
        "rs3": ['ABC25'],
        "rs4": ['PT4', 'PT4-FIL42'],
        "rs5": ['MTND24'],
        "rs100": ['URX1']
    }
    

    【讨论】:

    • 这可以完美地删除重复项,但是如何将字典中的每个键的值统一起来?我不希望再次出现相同的基因名称。
    • 同上,可以使用集合。使用您手中的列表,使用set(listname) 创建一个集合。
    • Ups,没注意到,已修复。对我来说似乎是最好的解决方案,不需要 sets 或 defaultdicts。
    猜你喜欢
    • 1970-01-01
    • 2013-05-28
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    相关资源
    最近更新 更多