kuroの覚え書き

96の個人的覚え書き

vcfからSQLに流し込む

さて、データにアノテーションを付けていく作業はvcfでやるのが効率的なのだけど、これを視覚的にわかりやすく提示するにはちょっとごちゃごちゃしすぎているので、これをtext抽出してSQLに入れてやることにする。

INFOやsampleカラムには複数の情報が詰まっていて、それも行毎にすべて揃っているわけではないので単純なawkによる抽出はできない(できなくもないが結構面倒くさい)のでpythonのモジュールを使うことにする。

pyvcfというまんまなモジュールがあったのでそれを使うことにする。
https://pypi.python.org/pypi/PyVCF

先人の情報があんまりないのだけれど、基本的には csvモジュールなんかと同じようにファイルをリードでオープンしてforで行を順番に取り出す、みたいな感じで処理できるようなのでなんとかなるでしょう。

https://bi.biopapyrus.jp/python/module/pyvcf.html
こちらに出ているスクリプトを拝借して処理をしてみると

1	28499		A		0/1
1	608335		T		0/1
1	874461		GAA		1/1
1	895287		GTCA		0/1
1	911789		TA		1/1
1	1671823		A		0/1
1	1765789		A		0/1
1	2152975		A		0/1
1	2243386		T		1/1
1	2498920		T		0/1

こんな感じに出力される。
CHROM, POS, REF, ALT, GTが出力されるはずなんだけど、どうもALTが出力されてないような。

>>> import vcf
>>> vcf_reader = vcf.Reader(open('vcf/test/example-4.0.vcf', 'r'))
>>> for record in vcf_reader:
... print record
Record(CHROM=1, POS=28499, REF=A, ALT=[C])
Record(CHROM=1, POS=608335, REF=T, ALT=[G])
Record(CHROM=1, POS=874461, REF=GAA, ALT=[GAAA])
Record(CHROM=1, POS=895287, REF=GTCA, ALT=[G])
Record(CHROM=1, POS=911789, REF=TA, ALT=[TAA])
Record(CHROM=1, POS=1671823, REF=A, ALT=[T])
Record(CHROM=1, POS=1765789, REF=A, ALT=[G])
Record(CHROM=1, POS=2152975, REF=A, ALT=[T])
Record(CHROM=1, POS=2243386, REF=T, ALT=[TG])
Record(CHROM=1, POS=2498920, REF=T, ALT=[A])

こんなふうにALTはlistになっているから上のスクリプトではうまく出力できてないのだな。
なのでlistをjoinで文字列に置き換えてから引き渡せばいいのだが、listの中身がstrになってないのでまずはmapで置き換え、更にjoinすると良さそうだ。

import vcf

def format_str(x):
    '''
    Change numbers to a string, and change list to a string.
    '''
    if x is None:
        y = ''
    else:
        if isinstance(x, list):
            if not x:
                y = ';'.join(x)
            else:
                y = ''
        else:
            y = str(x)
    return y

def parse_vcf(i, o):
    with open(o, 'w') as outfh:
        vcf_fh = vcf.Reader(open(i, 'r'))
        for snp_record in vcf_fh:
            gt_list = []
            for sample in snp_record.samples:
                gt_list.append(sample['GT'])
            ALT = map(str, snp_record.ALT)
            ALT = ",".join(ALT)
            new_record = [format_str(snp_record.CHROM),
                          format_str(snp_record.POS),
                          format_str(snp_record.REF),
                          format_str(ALT)]

            new_record.extend(gt_list)

            outfh.write('\t'.join(new_record) + '\n')

parse_vcf('sample.vcf', 'gtdata.txt')

これで

1	28499	A	C	0/1
1	608335	T	G	0/1
1	874461	GAA	GAAA	1/1
1	895287	GTCA	G	0/1
1	911789	TA	TAA	1/1
1	1671823	A	T	0/1
1	1765789	A	G	0/1
1	2152975	A	T	0/1
1	2243386	T	TG	1/1
1	2498920	T	A	0/1

こうなった。

とここまでやっておきながら別の方法を発見。
snp_record.heterozygosity
を読み出すとheteroなら0.5 homoなら0が出力される。これでいいんじゃね?
更に
snp_record.num_het
だとheteroで1が出力されるし。

つぎはINFOからも抽出。ついでに入出力の引き渡しも合わせて最終的に出来上がったプログラムは以下の通り。

import vcf, sys

def format_str(x):
    '''
    Change numbers to a string, and change list to a string.
    '''
    if x is None:
        y = ''
    else:
        if isinstance(x, list):
            if not x:
                y = ';'.join(x)
            else:
                y = ''
        else:
            y = str(x)
    return y

def parse_vcf(i, o):
    with open(o, 'w') as outfh:
        vcf_fh = vcf.Reader(open(i, 'r'))
        for snp_record in vcf_fh:
            gt_list = []
            for sample in snp_record.samples:
                gt_list.append(sample['GT'])
            ALT = map(str, snp_record.ALT)
            ALT = ",".join(ALT)
            GENE = ""
            if 'GENE' in snp_record.INFO:
                GENE = snp_record.INFO['GENE']
            SNP = ""
            if 'SNP_ID' in snp_record.INFO:
                SNP = snp_record.INFO['SNP_ID']
            new_record = [format_str(snp_record.CHROM),
                          format_str(snp_record.POS),
                          format_str(snp_record.REF),
                          format_str(ALT),
                          format_str(SNP),
                          format_str(GENE),
                          format_str(snp_record.num_het)]
            # new_record.extend(gt_list)

            outfh.write('\t'.join(new_record) + '\n')

args = sys.argv
parse_vcf(args[1], args[2])