vcf文件的全称是variant call file,即突变识别文件,它是基因组工作流程中产生的一种文件,保存的是基因组上的突变信息。通过对vcf文件进行分析,可以得到个体的变异信息。嗯,总之,这是很重要的文件,所以怎么处理它也显得十分重要。它的文件信息如下:
文件的开头是一堆以“##”开始的注释行,包含了文件的基本信息。然后是以“#”开头的一行,共9+n个部分,前九部分标注的是后面行每部分代表的信息,相当于表头。后面部分是样本名称,可以有多个。注释行结束后是具体的突变信息,每一行分为9+n个部分,每部分之间用制表符(‘\t’)分隔。
通常处理vcf文件时,在读取,处理阶段总是会写很多重复代码,核心的任务代码很少。当然,如果仅仅是找位点的CHROM,POS,ID,REF,ALT,QUAL这几个参数时,这样做也可以。因为vcf格式规范,这几个参数的结构相对简单。但是如果处理头文件信息,或者处理INFO,FORMAT参数时,要写比较复杂的正则表达式,这样做不仅繁琐,而且容易出错。
Python的PyVCF库解决了这个问题,它通过正则表达式把vcf文件信息转换成结构化的信息,简化了vcf文件的处理过程,方便后续提取相关参数及处理。
pip install PyVCF
或者从https://github.com/jamescasbon/PyVCF网站上下载安装包,自行安装。
import vcf
PyVCF库的名字为vcf,导入之后可以使用其方法对vcf文件做处理。
>>> import vcf
>>> vcf_reader = vcf.Reader(filename=r'D:\test\example.hc.vcf.gz')
>>> for record in vcf_reader:
print record
Record(CHROM=chr1, POS=10146, REF=AC, ALT=[A])
Record(CHROM=chr1, POS=10347, REF=AACCCT, ALT=[A])
Record(CHROM=chr1, POS=10439, REF=AC, ALT=[A])
Record(CHROM=chr1, POS=10492, REF=C, ALT=[T])
Record(CHROM=chr1, POS=10583, REF=G, ALT=[A])
调用vcf.Reader类处理vcf文件,vcf文件信息就被保存到vcf_reader中了。它是一个可迭代对象,它的迭代元素都是一个_Record对象的实例,保存着非注释行的一行信息,即变异位点的具体信息。通过它,我们可以很轻易地得到位点的详细信息。
class vcf.model._Record(CHROM, POS, ID, REF, ALT, QUAL, FILTER, INFO, FORMAT, sample_indexes, samples=None)
_Record是vcf.model中的一个对象,除了它还有_Call,_AltRecord等对象。它的基本属性为CHROM,POS,ID,REF,ALT,QUAL,FILTER,INFO,FORMAT,也就是vcf中的一行位点信息。接下来对这些属性一一说明:
>>> for record in vcf_reader:
print type(record.CHROM), record.CHROM
print type(record.POS), record.POS
print type(record.ID), record.ID
print type(record.REF), record.REF
print type(record.ALT), record.ALT
print type(record.QUAL), record.QUAL
print type(record.FILTER), record.FILTER
print type(record.INFO), record.INFO
print type(record.INFO['BaseQRankSum']), record.INFO['BaseQRankSum']
print type(record.FORMAT), record.FORMAT
chr1
234481
None
T
[A]
2025.77
None
{'ExcessHet': 3.0103, 'AC': [1], 'BaseQRankSum': -2.743, 'MLEAF': [0.5], 'AF': [0.5], 'MLEAC': [1], 'AN': 2, 'FS': 2.371, 'MQ': 42.83, 'ClippingRankSum': 0.0, 'SOR': 0.972, 'MQRankSum': -2.408, 'ReadPosRankSum': 1.39, 'DP': 156, 'QD': 13.07}
-2.743
GT:AD:DP:GQ:PL
>>> for record in vcf_reader:
print record.samples, '\n', record.samples[0].sample, '\n', record.samples[0]['GT'] #按下标访问Call,按.sample访问sample,按键访问FORMAT对应信息
print record.start, record.POS, record.end
print record.REF, record.ALT, record.alleles #注意G没有引号,它是_AltRecord对象
[Call(sample=192.168.1.1, CallData(GT=0/1, AD=[39, 14], DP=53, GQ=99, PGT=0|1, PID=13116_T_G, PL=[449, 0, 2224]))]
192.168.1.1
0/1
13115 13116 13116
T [G] ['T', G]
>>> record = next(vcf_reader)
>>> record2 = next(vcf_reader)
>>> print record > record2 #按染色体名称和位置进行比较
False
>>> for i in record: #按samples列表进行迭代
print i
Call(sample=192.168.1.1, CallData(GT=0/1, AD=[18, 11], DP=29, GQ=99, PL=[280, 0, 528]))
>>> print str(record) #字符串方法
Record(CHROM=chr1, POS=10492, REF=C, ALT=[T])
>>> print record.genotype('192.168.1.1') #按sample名字进行访问
Call(sample=192.168.1.1, CallData(GT=0/1, AD=[39, 14], DP=53, GQ=99, PGT=0|1, PID=13116_T_G, PL=[449, 0, 2224]))
>>> record = next(vcf_reader)
>>> print record
Record(CHROM=chr1, POS=13118, REF=A, ALT=[G])
>>> print record.samples #只有一个sample
[Call(sample=192.168.1.1, CallData(GT=0/1, AD=[41, 13], DP=54, GQ=99, PGT=0|1, PID=13116_T_G, PL=[449, 0, 2224]))]
>>> record.num_called
1
>>> record.call_rate
1.0
>>> record.num_hom_ref
0
>>> record.aaf
[0.5]
>>> record.num_het
1
>>> record.heterozygosity
0.5
>>> record.var_type
'snp'
>>> record.var_subtype
'ts'
>>> record.is_snp
True
>>> record.is_indel
False
class Reader(fsock=None, filename=None, compressed=None, prepend_chr=False, strict_whitespace=False, encoding='ascii')
在读vcf文件时,总共有六个参数可供选择,如上图所示。
>>> vcf_reader = vcf.Reader(open('vcf/test/example-4.0.vcf', 'r')) #fsock
>>> vcf_reader = vcf.Reader(filename=r'D:\test\example.hc.vcf.gz') #filename
头文件信息主要保存在Reader对象的属性中,包括alts,contigs,filters,formats,infos,metadata。
>>> vcf_reader = vcf.Reader(filename=r'D:\test\example.hc.vcf.gz')
>>> vcf_reader.alts
OrderedDict([('NON_REF', Alt(id='NON_REF', desc='Represents any possible alternative allele at this location'))]) #字典类型
>>> vcf_reader.alts['NON_REF'].id
'NON_REF'
>>> vcf_reader.alts['NON_REF'].desc
'Represents any possible alternative allele at this location'
>>> vcf_reader = vcf.Reader(filename=r'D:\test\example.hc.vcf.gz')
>>> vcf_reader.next()
>>> record = vcf_reader.next()
>>> print record
Record(CHROM=chr1, POS=10347, REF=AACCCT, ALT=[A])
>>> for record in vcf_reader:
print record
Record(CHROM=chr1, POS=10439, REF=AC, ALT=[A])
Record(CHROM=chr1, POS=10492, REF=C, ALT=[T])
这个库还有一个Writer对象,在此就不详细介绍了,因为大部分对vcf文件的处理都可以用上面两个对象的知识搞定。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import vcf # 导入PyVCF库
filename = r'D:\test\example.hc.vcf.gz'
vcf_reader = vcf.Reader(filename=filename) # 调用Reader对象处理vcf文件
for record in vcf_reader: # 迭代Reader对象,返回的是_Record对象
# record是_Record对象
print record.CHROM, record.POS, record.ID, record.ALT
if record.is_snp:# 判断是否是snp
print "I'm a snp"
elif record.var_type != 'sv': #和 elif record.is_sv:等价
print "I'm not a sv"
if record.heterozygosity == 0.5: # 判断是否为杂合突变
print "I'm a heterozygous mutation"
...
...
这个库实现的所有功能,都可以自己写代码实现,而且实现方法比较简单。之所以要用这个库来处理vcf文件,是因为这个库考虑的东西可能比我们自己了解的更多,其实现也可能比我们自己的代码更加完备合理。