【问题标题】:Count total unique number of records based on columns from multiple VCF files根据来自多个 VCF 文件的列计算总的唯一记录数
【发布时间】:2021-08-05 12:50:37
【问题描述】:

我有大约 200 个文件,它们的标题行很长,以“#”开头,然后记录 4 列,如下所示:

file_1.vcf
##some_comments that span many lines
##some_comments that span many lines
#CRHOM    POS    REF    ALT
chr1   111    A       G
chr2   222    G       T
chrY   99999  A       C

file_2.vcf
##some_comments that span many lines
##some_comments that span many lines
#CRHOM    POS    REF    ALT
chr2   444    G       T
chr2   222    G       T
chrY   7473  C       A

对于这个只有 2 个 vcf 的简单示例,预期的记录总数为 5 条记录。

每个文件都包含一百万条左右的记录,我试图计算它们的总记录数,条件是在任何其他 vcf 文件中出现的重复记录必须只计算一次。我怎么能做到这一点,我在 Python 中尝试过,但这卡住了很长时间:

    import os
    from pathlib import Path
    import vcf

    path_gdc_data = Path(os.getcwd()+"/all_vcfs/")

    non_dup = []
    count += 1
    for i, vcf_file in enumerate(path_gdc_data.rglob("*.vcf")):
        vcf_reader = vcf.Reader(filename=str(vcf_file))
        for rec in vcf_reader:
            if (rec.CHROM,rec.POS, rec.REF, rec.ALT) not in indels_coord_uniq:
                    non_dup_records.append((rec.CHROM, rec.POS))
                    count += 1
    print(f"Total num of non dup in all vcf are {count}")

注意 1:我在我的问题中包含了 pandas 和 Dataframe 标签,看看 pandas 是否会更有效地解决这个问题。

注意2:每个单独的文件不能有重复的记录,并且每个文件都是排序的。

示例 vcf 文件:

##fileformat=VCFv4.0
##fileDate=20090805
##source=myImputationProgramV3.1
##reference=1000GenomesPilot-NCBI36
##phasing=partial
##INFO=<ID=NS,Number=1,Type=Integer,Description="Number of Samples With Data">
##INFO=<ID=DP,Number=1,Type=Integer,Description="Total Depth">
##INFO=<ID=AF,Number=.,Type=Float,Description="Allele Frequency">
##INFO=<ID=AA,Number=1,Type=String,Description="Ancestral Allele">
##INFO=<ID=DB,Number=0,Type=Flag,Description="dbSNP membership, build 129">
##INFO=<ID=H2,Number=0,Type=Flag,Description="HapMap2 membership">
##FILTER=<ID=q10,Description="Quality below 10">
##FILTER=<ID=s50,Description="Less than 50% of samples have data">
##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
##FORMAT=<ID=GQ,Number=1,Type=Integer,Description="Genotype Quality">
##FORMAT=<ID=DP,Number=1,Type=Integer,Description="Read Depth">
##FORMAT=<ID=HQ,Number=2,Type=Integer,Description="Haplotype Quality">
#CHROM POS     ID        REF ALT    QUAL FILTER INFO                              FORMAT      NA00001        NA00002        NA00003
20     14370   rs6054257 G      A       29   PASS   NS=3;DP=14;AF=0.5;DB;H2           GT:GQ:DP:HQ 0|0:48:1:51,51 1|0:48:8:51,51 1/1:43:5:.,.
20     17330   .         T      A       3    q10    NS=3;DP=11;AF=0.017               GT:GQ:DP:HQ 0|0:49:3:58,50 0|1:3:5:65,3   0/0:41:3
20     1110696 rs6040355 A      G,T     67   PASS   NS=2;DP=10;AF=0.333,0.667;AA=T;DB GT:GQ:DP:HQ 1|2:21:6:23,27 2|1:2:0:18,2   2/2:35:4
20     1230237 .         T      .       47   PASS   NS=3;DP=13;AA=T                   GT:GQ:DP:HQ 0|0:54:7:56,60 0|0:48:4:51,51 0/0:61:2
20     1234567 microsat1 GTCT   G,GTACT 50   PASS   NS=3;DP=9;AA=G                    GT:GQ:DP    0/1:35:4       0/2:17:2       1/1:40:3

非常感谢。

【问题讨论】:

  • 文件中的记录是否以某种方式排序?一个文件可以包含重复项吗?
  • 嗨@AndrejKesely,我在帖子中添加了您问题的答案,非常感谢。
  • 你能分享一些来自这两个 VCF 文件的真实样本吗?模块vcf 抱怨问题中的文件无效。
  • 我无法分享我拥有的数据,因为它们是患者数据,但我将与您分享来自internationalgenome.org/wiki/Analysis/Variant%20Call%20Format/…的 vcf 示例
  • 我使用了页面上找到的示例(稍微修改了一个文件中的2条记录以获得7条唯一记录)

标签: python-3.x pandas dataframe large-files vcf-variant-call-format


【解决方案1】:

如果 vcf 文件已排序并且一个文件中没有唯一性,您可以使用 heapq.merge 将所有文件合并在一起,然后使用 itertools.groupby 将它们分组(我假设我们要计算所有列上的唯一性)。然后计算唯一组的数量。示例

import vcf
from heapq import merge
from itertools import groupby

filelist = ["file_1.vcf", "file_2.vcf"]  # <--- create the list from `glob()` for example
vcfs = [vcf.Reader(filename=f) for f in filelist]

uniq = sum(1 for _ in groupby(merge(*vcfs)))

print("Total number of unique records:", uniq)

打印(在我的示例中):

Total number of unique records: 7

编辑:仅计算 CHROM、POS、REF、ALT 列上的唯一性:

import vcf
from heapq import merge
from itertools import groupby

filelist = ["file_1.vcf", "file_2.vcf"]
vcfs = [
    ((row.CHROM, row.POS, row.REF, row.ALT) for row in vcf.Reader(filename=f))
    for f in filelist
]

uniq = sum(1 for _ in groupby(merge(*vcfs)))

print("Total number of unique records:", uniq)

【讨论】:

  • 感谢您的回答,仅计算列的唯一性:CHROM POS REF ALT 而不是所有列,请参阅我的示例 file_1.vcf 和 file_2.vcf
  • 谢谢,我收到以下错误:TypeError: '
  • @aBiologist 您使用的是准确的代码吗?列表vcfs 中的生成器必须返回(CHROM, POS, REF, ALT) 的元组
  • 是的,我使用的是完全相同的代码。错误指向这里的这部分“for _ in groupby(merge(*vcfs)”
  • @aBiologist 我使用的是完全相同的代码。可能是vcf 的不同版本? (我的vcf.VERSION == 0.6.8
【解决方案2】:

使用Pandas的另一种方法:

import pandas as pd
import io
from pathlib import Path

COLS = ["CRHOM", "POS", "REF", "ALT"]

def read_vcf(filepath_or_buffer, usecols=None):
    with open(filepath_or_buffer) as vcf:
        while True:
            line = vcf.readline()
            if not line.startswith("##"):
                names = line[1:].split()
                break
        return pd.read_table(vcf, sep="\t", delim_whitespace=True,
                             usecols=usecols, header=None, names=names)


# Get vcf file list and load the first to a dataframe
path_gdc_data = Path().cwd() / "all_vcfs"
vcf_files = path_gdc_data.glob("*.vcf")
# df = read_vcf(next(vcf_files), usecols=COLS)
idx = read_vcf(next(vcf_files), usecols=COLS).set_index(COLS).index


# Compare and merge other dataframes
for vcf in vcf_files:
    # df1 = read_vcf(vcf, usecols=COLS)
    idx1 = read_vcf(vcf, usecols=COLS).set_index(COLS).index
    # df = df.merge(df1, on=COLS, how="outer")
    idx = idx.union(idx1)

# print(f"Total num of non dup in all vcf are {len(df)}")
print(f"Total num of non dup in all vcf are {len(idx)}")

示例

file_1.vcf
##some_comments that span many lines
##some_comments that span many lines
#CRHOM    POS    REF    ALT
chr1   111    A       G
chr2   222    G       T
chrY   99999  A       C

file_2.vcf
##some_comments that span many lines
##some_comments that span many lines
#CRHOM    POS    REF    ALT
chr2   444    G       T
chr2   222    G       T
chrY   7473  C       A

file_3.vcf
##some_comments that span many lines
##some_comments that span many lines
#CRHOM    POS    REF    ALT
chr2   444    G       T
chr3   333    G       T
chrY   7473  C       T

在上面的代码上应用这个修改并运行:

26c26
<     df = df.merge(df1, on=COLS, how="outer")
---
>     df = df.merge(df1, on=COLS, how="outer", indicator=f"{vcf.stem}")
>>> df
  CRHOM    POS REF ALT      file_2      file_3
0  chr1    111   A   G   left_only   left_only
1  chr2    222   G   T        both   left_only
2  chrY  99999   A   C   left_only   left_only
3  chr2    444   G   T  right_only        both
4  chrY   7473   C   A  right_only   left_only
5  chr3    333   G   T         NaN  right_only
6  chrY   7473   C   T         NaN  right_only

【讨论】:

  • 出于好奇,请您试试我的回答好吗?我想知道每次使用 Pandas 是否是一个不错的选择。你能比较一下@AndrejKesely 的解决方案吗?
  • 我一定会试一试的,会告诉你进展如何。谢谢
  • 请问,与外部方法合并如何确保不重复数据?
  • 首先,主要是因为您在一个文件中没有重复条目(注2),所以我不需要删除重复项。最后,外部合并使用两个数据帧中的键并集:这是一个简单的一对一关系。
  • 我明白了,谢谢。你的方法很好,但它也像@AndrejKesely 的解决方案一样慢,有没有办法加快你的方法?我有 200 个 vcfs,每个都有数百万条记录!
猜你喜欢
  • 1970-01-01
  • 2021-07-31
  • 2014-04-08
  • 1970-01-01
  • 1970-01-01
  • 2021-05-19
  • 1970-01-01
  • 1970-01-01
  • 2021-03-14
相关资源
最近更新 更多