# RefSeq転写産物の3'UTRの範囲をBEDに書き出す
### 目的
* GGGenomeでRefSeq転写産物の3'UTRを検索したい。
* GGGenomeは検索結果をBED形式で出力できるので、3'UTRの範囲を記載したBEDファイルを用意しておけば、`bedtools intersect` で3'UTRに対するヒットのみを得ることができる。
### RefSeq転写産物のgbffを入手
ftp://ftp.ncbi.nlm.nih.gov/refseq/release/complete/
から `complete.*.rna.gbff.gz` をダウンロード。
* `complete` は全生物種を含む
* `rna` が転写産物(ほかに `genomic`, `protein` がある)
* `gbff` はGenBank形式(配列+アノテーション)
RefSeq 215 では、圧縮された状態で合計 71GB ある。
### gbffのパースの準備
#### コマンド
```
zcat complete.*.rna.gbff.gz \
| egrep '^(LOCUS|VERSION|SOURCE|\s+CDS|//)' \
```
(メモ)gbffは大きいため、最初に `egrep` で必要な行だけを抜き出すことにより処理の時間を短縮。行末の `\` に続けて下記コマンドを順次実行。
```
| perl -ne 'BEGIN{ $/ = "\n//\n" }
my $length = /^LOCUS\ .*?(\d+)\ *bp/m ? $1 : "" ;
my $version = /^VERSION\ +(\S*)/m ? $1 : "" ;
my $source = /^SOURCE\ +(.*?)\ *$/m ? $1 : "" ;
my ($cds1, $cds2) = /^\ {5}CDS\ +(\d+)\.\.(\d+)/m ? ($1, $2) : () ;
print $source . "\t" .
$version . "\t" .
$cds1 . "\t" .
$cds2 . "\t" .
$length . "\n"' \
```
(メモ)gbffでは各エントリが `//` で区切られているので、perlの行セパレータを `//` に変更して、1エントリをまるごと「1行」として読み込んで高速化。1エントリごとに、配列の長さ、生物種、version、CDS の start と end を抽出していく。
```
| grep '^Homo sapiens (human)' \
| cut -f 2- \
```
(メモ)ヒト `Homo sapiens (human)` のみ抽出。
```
| grep -v '^X'
```
(メモ)predictedな転写産物 `XM_`, `XR_` を除外。
#### パースの途中の状態
gbff から必要な行だけ抜き出したもの。
```
LOCUS NM_001387374 4051 bp mRNA linear PRI 21-APR-2022
VERSION NM_001387374.1
SOURCE Homo sapiens (human)
CDS 167..2026
//
LOCUS NM_001387375 4027 bp mRNA linear PRI 21-APR-2022
VERSION NM_001387375.1
SOURCE Homo sapiens (human)
CDS 167..2002
//
LOCUS NM_001387376 3973 bp mRNA linear PRI 21-APR-2022
VERSION NM_001387376.1
SOURCE Homo sapiens (human)
CDS 167..1948
//
[...]
```
最終的な出力。
```
NM_001387562.1 221 2017 4790
NM_001387563.1 221 1219 1358
NR_073515.3 1315
NR_170667.1 6439
NR_047672.2 488
NR_038873.1 2636
NM_001141920.2 236 781 2901
NM_001363651.3 171 1949 2081
NM_001365041.3 510 1526 3569
NM_175569.3 236 778 2898
NM_001367912.2 39 1844 1986
NM_001387759.1 243 2255 2923
NM_001387772.1 160 2079 2747
[...]
```
BED形式のように見えるが開始位置が 0-based start でない点には注意。
`NM_` で始まるものは mRNA なので CDS の記載あり。
`NR_` で始まるものは ncRNA なので CDS の記載なし。
#### (2023/08/22追記)
OAZ1, OAZ2, OAZ3, PEG10 遺伝子は ribosomal frameshift が起こるため、
```
CDS join(480..1436,1436..2605)
```
のように記載されている。そのような場合にも対応できるよう下記のように修正。
```
| perl -ne 'BEGIN{ $/ = "\n//\n" }
my $length = /^LOCUS\ .*?(\d+)\ *bp/m ? $1 : "" ;
my $version = /^VERSION\ +(\S*)/m ? $1 : "" ;
my $source = /^SOURCE\ +(.*?)\ *$/m ? $1 : "" ;
my ($cds1, $cds2) = /^\ {5}CDS\ +(\d+)\.\.(\d+)/m ? ($1, $2) :
/^\ {5}CDS\ +join\((\d+)\.\.\d+,\d+\.\.(\d+)\)/m ? ($1, $2) :
() ;
print $source . "\t" .
$version . "\t" .
$cds1 . "\t" .
$cds2 . "\t" .
$length . "\n"' \
```
### (並列化)
そのまま実行すると時間がかかるため、並列化する方法もメモ。
下記を `/tmp/parse.sh` に保存して `chmod 755` しておく。
```
egrep '^(LOCUS|VERSION|SOURCE|\s+CDS|//)' \
| perl -ne 'BEGIN{ $/ = "\n//\n" }
my $length = /^LOCUS\ .*?(\d+)\ *bp/m ? $1 : "" ;
my $version = /^VERSION\ +(\S*)/m ? $1 : "" ;
my $source = /^SOURCE\ +(.*?)\ *$/m ? $1 : "" ;
my ($cds1, $cds2) = /^\ {5}CDS\ +(\d+)\.\.(\d+)/m ? ($1, $2) :
/^\ {5}CDS\ +join\((\d+)\.\.\d+,\d+\.\.(\d+)\)/m ? ($1, $2) :
() ;
print $source . "\t" .
$version . "\t" .
$cds1 . "\t" .
$cds2 . "\t" .
$length . "\n"' \
| grep '^Homo sapiens (human)' \
| cut -f 2- \
| grep -v '^X'
```
下記を実行。
```
/bin/ls *gbff* \
| awk '{print "zcat "$1" | /tmp/parse.sh > /tmp/refseq215/"$1".txt" }' \
| /backup/bin/parallel.pl -12
```
(メモ)[parallel.pl](https://github.com/meso-cacase/parallel/blob/master/parallel.pl) は並列化を支援する自作スクリプト。
終了したら、
```
setopt numeric_glob_sort
cat /tmp/refseq215/* > /tmp/hs_refseq215_cds.txt
```
でマージ完了。
### 3'UTRの範囲の抽出 → BED化
* CDS end の値をそのまま 3'UTR start とする。
* 0-based start のBEDにするため。
* length の値を 3'UTR end とする。
* 出力の対象を mRNA `MN_` のみとする。
`/tmp/parse.sh` を下記のように修正して同様に実行。
```
egrep '^(LOCUS|VERSION|SOURCE|\s+CDS|//)' \
| perl -ne 'BEGIN{ $/ = "\n//\n" }
my $length = /^LOCUS\ .*?(\d+)\ *bp/m ? $1 : "" ;
my $version = /^VERSION\ +(\S*)/m ? $1 : "" ;
my $source = /^SOURCE\ +(.*?)\ *$/m ? $1 : "" ;
my ($cds1, $cds2) = /^\ {5}CDS\ +(\d+)\.\.(\d+)/m ? ($1, $2) :
/^\ {5}CDS\ +join\((\d+)\.\.\d+,\d+\.\.(\d+)\)/m ? ($1, $2) :
() ;
print $source . "\t" .
$version . "\t" .
$cds2 . "\t" .
$length . "\n"' \
| grep '^Homo sapiens (human)' \
| cut -f 2- \
| grep '^NM_'
```
```
/bin/ls *gbff* \
| awk '{print "zcat "$1" | /tmp/parse.sh > /tmp/refseq215/"$1".txt" }' \
| /backup/bin/parallel.pl -12
```
並列処理が終了したら、
```
cat /tmp/refseq215/* \
| /backup/bin/sort_refseq_id.pl \
> /tmp/hs_refseq215_3utr.bed
```
でマージ完了。
(メモ)[sort_refseq_id.pl](https://gist.github.com/meso-cacase/7a287171a6b364b5b487bdb55c66b251) はテキストを RefSeq ID の順番にソートする自作スクリプト。
### 結果
[hs_refseq215_3utr.bed](https://gist.github.com/meso-cacase/97301382511db5e5dd61366991dda8d7) (66,326行)
```
NM_000014.6 4495 4610
NM_000015.3 943 1285
NM_000016.6 1345 2261
NM_000017.4 1299 1859
NM_000018.4 2015 2184
[...]
```
* BED形式なので 0-based start である点に注意。
* CDSしか登録されていないエントリがある。
* その場合は start = end になっている。
### 完了