NGSデータ解析まとめ

サカナ研究者の手探りNGS解析(おもに進化生物学)

FASTA形式ファイルの(一括)変換

FASTA形式の塩基配列(アミノ酸配列)ファイルをNEXUS形式やPHYLIP形式に変換したい、ということはよくあります。単一のファイルならClustalwMacCladeを使用して変換できますが、多数のFASTAファイルを扱う場合(数百〜数千遺伝子を用いた系統解析など)、一括でファイル形式を変換するスクリプトがあれば便利です。

ここでは、FASTA形式 --> NEXUS形式、またはFASTA形式 --> PHYLIP形式へ変換するPerlスクリプトを公開します。アラインメント自体は行わないので、すでにアラインメントされたFASTA形式ファイルのみが対象になります。また、配列名は9文字まで、という制約があります。

(1) fasta_to_nex.pl

#!/usr/bin/perl
# fasta_to_nex.pl
# 2015-04-07 Y Hashiguchi

# fasta format をnexus formatに変更する
# interleaveしない
# sequenceの開始位置をそろえる
# ntax, ncharをカウント

# このversionはMrBayes blockを書き加えない // 150407
# comment outはあり

## usage ##
# ./fasta_to_nex.pl [infile.fa|.aln|.fasta|.fas] > [outfile.nex]

#

use strict;
use warnings;


### Define variables ##

my $fname = $ARGV[0];

my @lines = ();		# infileの各行を入れる配列
my @seq_with_name = ();	#名前付きsequenceを入れる配列

my $ntax = 0;		# taxa数
my $nchar = 0;		# character数(gapやNも含むsequence長さ)
my $seq_data = 0;	# sequence with name
my $datatype = 'dna';	#data type (dna or protein)

my %sequence;	#sequence nameおよびsequenceを入れるhash

##

### MAIN ###
# input file (FASTA) の読み込み @linesに入れる
open (FASTA, "$fname") || die "Cannot open file:$!";
while(<FASTA>) {
	chomp;
	push(@lines, $_);
}
close(FASTA);

# taxa数をcount (= ">"の数を数える)
foreach my $line (@lines) {
	$ntax++ if($line =~ /\>/);
}

$sequence{"Name"} = shift(@lines);	#最初の1配列の名前(1行目)は$sequence{"Name"}に入れる
$sequence{"Name"} =~ s/\>//;	# ">"を除く

while ($#lines > -1) {
	my $data = shift(@lines);
	if($data =~ /\>/) {
		$nchar = length($sequence{"Sequence"});	# test
		while(length($sequence{"Name"}) < 10) {		#長さが10文字まで // ここでは、nameの長さが10文字より少ないことを仮定している
			$sequence{"Name"} .= " ";	# 後ろに" "を加える
		}
#		print $ntax, "\t", $nchar, "\n";		# test
		$seq_data = $sequence{"Name"} . $sequence{"Sequence"};	#nameとsequence統合
		push(@seq_with_name, $seq_data);	#配列 @seq_with_nameに結果入れる
#		print $sequence{"Name"}, $sequence{"Sequence"}, "\n";		# test
		$sequence{"Sequence"} = "";		# sequence中身を削除
		$sequence{"Name"} = $data;	#sequence_name代入
		$sequence{"Name"} =~ s/\>//;	# ">"を除く
	} else {
		$sequence{"Sequence"} .= $data;
	}
}

# 最後の1配列について
while(length($sequence{"Name"}) < 10) {		#長さが10文字まで 
	$sequence{"Name"} .= " ";	# 後ろに" "を加える
}
$seq_data = $sequence{"Name"} . $sequence{"Sequence"};	#nameとsequence統合
push(@seq_with_name, $seq_data);	#配列 @seq_with_nameに結果入れる

## print out as ".nex" format
print '#NEXUS', "\n\n";
print '[', "\n", 'Data from:', "\n", $ARGV[0], "\n", ']', "\n\n\n";
print 'begin data;', "\n    ", 'dimensions ntax=', $ntax,  ' nchar=', $nchar, ';', "\n";
print '    format datatype=', $datatype, ' interleave=no gap=-;', "\n";
print '    matrix', "\n";
foreach(@seq_with_name) {		# test
	print $_, "\n";
}
print '    ;', "\n";
print 'end;', "\n";

(2) fasta_to_phy.pl

#!/usr/bin/perl
# fasta_to_phy.pl
# 2015-04-07 Y Hashiguchi

# fasta format をPHYLIP formatに変更する
# fasta_to_nex.plの副産物としてできた(おまけ)
# interleaveしない
# sequenceの開始位置をそろえる
# ntax, ncharをカウント
# alignment済みのfasta file (.aln)のみ対応、これ自体はalignmentは行わない

# comment outはあり

## usage ##
# ./fasta_to_nex.pl [infile.fa|.aln|.fasta|.fas] > [outfile.phy]

#

use strict;
use warnings;


### Define variables ##

my $fname = $ARGV[0];

my @lines = ();		# infileの各行を入れる配列
my @seq_with_name = ();	#名前付きsequenceを入れる配列

my $ntax = 0;		# taxa数
my $nchar = 0;		# character数(gapやNも含むsequence長さ)
my $seq_data = 0;	# sequence with name

my %sequence;	#sequence nameおよびsequenceを入れるhash

##

### MAIN ###
# input file (FASTA) の読み込み @linesに入れる
open (FASTA, "$fname") || die "Cannot open file:$!";
while(<FASTA>) {
	chomp;
	push(@lines, $_);
}
close(FASTA);

# taxa数をcount (= ">"の数を数える)
foreach my $line (@lines) {
	$ntax++ if($line =~ /\>/);
}

$sequence{"Name"} = shift(@lines);	#最初の1配列の名前(1行目)は$sequence{"Name"}に入れる
$sequence{"Name"} =~ s/\>//;	# ">"を除く

while ($#lines > -1) {
	my $data = shift(@lines);
	if($data =~ /\>/) {
		$nchar = length($sequence{"Sequence"});	# test
		while(length($sequence{"Name"}) < 10) {		#長さが10文字まで 
			$sequence{"Name"} .= " ";	# 後ろに" "を加える
		}
#		print $ntax, "\t", $nchar, "\n";		# test
		$seq_data = $sequence{"Name"} . $sequence{"Sequence"};	#nameとsequence統合
		push(@seq_with_name, $seq_data);	#配列 @seq_with_nameに結果入れる
#		print $sequence{"Name"}, $sequence{"Sequence"}, "\n";		# test
		$sequence{"Sequence"} = "";		# sequence中身を削除
		$sequence{"Name"} = $data;	#sequence_name代入
		$sequence{"Name"} =~ s/\>//;	# ">"を除く
	} else {
		$sequence{"Sequence"} .= $data;
	}
}

# 最後の1配列について
while(length($sequence{"Name"}) < 10) {		#長さが10文字まで 
	$sequence{"Name"} .= " ";	# 後ろに" "を加える
}
$seq_data = $sequence{"Name"} . $sequence{"Sequence"};	#nameとsequence統合
push(@seq_with_name, $seq_data);	#配列 @seq_with_nameに結果入れる

#print $sequence{"Name"}, $sequence{"Sequence"}, "\n";	#最後のsequenceをprint

print $ntax, " ", $nchar, "\n";
foreach(@seq_with_name) {
	print $_, "\n";
}

複数ファイルを一括で変換する場合は、以下のshell scriptを使用して下さい。カレントディレクトリにあるすべての".aln"拡張子を持つFASTA形式のファイルを変換します(注意:clustal formatには対応していません! 拡張子.alnでも)

(1) FtoN.sh

#!/usr/bin/sh
# FtoN.sh

# FASTA -> NEXUSへのformat変換
# Current directoryに存在するすべてのfileで実行
# alignment済みのファイル (.aln)のみ、alignmentそれ自体は行わない
# mrbayes blockは追加しない
# 結果はphy_files directoryに入る

mkdir nex_files

for fname in *.aln; do

fname=`echo "$fname" | sed -E 's/\.aln//g'`		# 拡張子を除く

# .fasta(.aln) --> .nexに変換 // fasta_to_nex.pl使用
./fasta_to_nex.pl $fname.aln > $fname.nex
mv $fname.nex nex_files

done

(2) FtoP.sh

#!/usr/bin/sh
# FtoP.sh

# FASTA -> PHYLIPへのformat変換
# Current directoryに存在するすべてのfileで実行
# alignment済みのファイル (.aln)のみ、alignmentそれ自体は行わない
# mrbayes blockは追加しない
# 結果はnex_files directoryに入る

mkdir phy_files

for fname in *.aln; do

fname=`echo "$fname" | sed -E 's/\.aln//g'`		# 拡張子を除く

# .fasta(.aln) --> .phyに変換 // fasta_to_phy.pl使用
./fasta_to_phy.pl $fname.aln > $fname.phy
mv $fname.phy phy_files

done

ファイル形式の変換、一般的に、FASTAから別の形式への変換を行うことは多いですが、逆のパターンは少ない気がします。