任意の文字数のシーケンスを全パターン出力するプログラムについて考えてみます。ブルートフォースアタックをするわけではないので、使う文字列はA,C,G,Tの4文字とします。
目次
パターン数
参考までに、以下に生成する文字数によってどれだけのパターンがあるのかをみてみます。
4文字の場合
具体例として4文字の場合を考えてみると、
$4^4=256(通り)$の塩基配列ができることになります。
n文字の場合
一般に、n文字の塩基配列の全パターン数は、
$4^n$ とすることができます。
列挙アルゴリズム
今回の目的は、パターン数を調べることではなく全パターンを列挙することなので、ここではそのアルゴリズムについて考えてみます。
先ほどのように、まずは文字数4の具体例から考えます。
4文字の場合
4文字の場合、以下のようにforをネストさせることでかろうじて256個の配列全てをターミナルに出力することができます。
n = 4
nucleotides = ["A","C","G","T"]
for i in range(n):
for j in range(n):
for k in range(n):
for l in range(n):
print(nucleotides[i] + nucleotides[j] + nucleotides[k]+ nucleotides[l])
n文字の場合
n=4の時は、ループ構造を4回ネストすることで4文字の組み合わせを網羅的に出力できましたが、nが変数である以上、ネストの回数まで可変的にする必要が出てきます。
こうなるとネストが深くなり、可読性も著しく下がってしまいます。
この対策としてpythonが用意しているitertoolsモジュールを利用します。
import itertools
n = input()
nucleotides = ["A","C","G","T"]
print ("\n".join(["".join(nucleotide) for nucleotide in itertools.product(nucleotides,repeat=n)]))
一気に描きすぎたので、一段階噛み砕いたものを下に書きます。
import itertools
n = input()
seq_list = []
nucleotides = ["A","C","G","T"]
for nucleotide in itertools.product(nucleotides, repeat=n):
print(nucleotide)
seq_list.append(nucleotide)
これで無事、n文字における全パターンを出力できるようになりましたが、実はもう一つ問題があります。
上記のコードは、全パターンを順にターミナルに出力する仕様になっていますが、ターミナルの表示行数には限りがあります。そこで、取得した文字列を順に新しいファイル’seq_all.txt’を作成して記述するところまでを行います。
txtへの書き込み
txt形式のファイルにpythonから直接書き込みを行う場合、open関数を使用します。
open関数には3つのモードw,a,xがありますが、一からファイルを作成する場合はどれを選んでも良いです。今回は最新の結果のみ欲しいのでモード(w)を使用します。
以下に、アルゴリズムの実行から書き込みまでの一連の操作を一気に記述します。
import itertools
seq_all = open('seq_all.txt', 'w')
#第一引数にファイル名、第二引数にモードを指定します。
n = input()
seq_list = []
nucleotides = ["A","C","G","T"]
for nucleotide in itertools.product(nucleotides, repeat=n):
print(nucleotide)
seq_list.append(nucleotide)
for seq in range(len(seq_list)):
seq_all.write(''.join(seq_list[seq]))
seq_all.write('\n')
#配列が全てつながってしまわないように改行しておきます。
seq_all.close()
writeメソッドは改行まではしてくれないため、改行コードを書かないといけないことに注意してください。
以上で、任意の文字数の全配列パターンを取得することができるようになりました。今のところ、どこでこんなのを使うのかは検討もつきませんが、、、
せめてn=1000くらいで何かしらの作業には役に立ちそうですが、今回は一連の操作をpythonで行ったためnが10を超えたあたりからパソコンが発熱し出します。