バイオインフォマティクスのエリクサー





この記事では、 GenStageライブラリ、特にFlowモジュールを使用して、バイオインフォマティクスアルゴリズムの1つを実装しようとする試みについて説明します。 過去2年間、私は炭化水素原料のメタゲノム解析( メタゲノミクス )の結果を保存および検索するための統合システムを開発してきました。 おそらく、多くの人にとって、これは中国語の手紙です。 実際、このような分析とは、たとえば油田に住んでいるすべての種類の微生物の特定を意味します。 これらの微生物の一部、主に細菌は、鋼管を腐食させ、他の多くの悪影響を引き起こす可能性があります。



メタゲノム解析の最初の段階は、炭化水素原料で見つかった数千人のゲノムの配列決定です。 シーケンスはゲノム全体を「読み取る」のではなく、個々の部分のみを「読み取る」ため、特定のサイトに属する個人を判別するのは計算上困難な作業です。



コンピューターの実装に関しては、分析は、初期データ、いわゆる窒素塩基(A、T、U、C、およびG)をプロセスチェーンに転送することにあります。 この問題を解決するための有名なプログラムの1つはQiime (「ティー」と読みます)です。 Pythonで書かれた多くの関連アプリケーションで構成されています。 最初はElixir用のストリーミングデータ処理フレームワークを開発しましたが、GenStageが登場するとすぐに、この種の研究を実施する能力を評価することに興味がありました。



GenStageに切り替え



QiimeをElixirに書き直そうとするのではなく(簡単なタスクではありません)、私は小さなことから始めることにしました。つまり、Elixirで最も単純なバイオインフォマティクスアルゴリズムを実装する方法と、GenStageの並列実行を活用する方法を見つけることです(高速に動作する可能性があります)。 この目的のために、私はCourseraのWebサイトで「DNAの隠されたメッセージを見つける(バイオインフォマティクスI)」という素晴らしいオンラインコースを受講しました。 実装には、任意のプログラミング言語を選択できます。



これらのタスクの1つは、ゲノムの重複部分の検索です。 問題の状態を定義します。 k-merはkヌクレオチドの配列です。たとえば、CTGGATは6-merです。 数百万のヌクレオチドで構成されている可能性のあるシーケンスを考えます。 繰り返し現れるkメジャーを見つける必要があります。 シーケンス全体をコーミングする代わりに、個々の部分に含まれるkメジャーに注意を払います。 特に、1,500ヌクレオチドのシーケンスでは、kメジャーは500ヌクレオチドの領域でのみ求められます。



オンラインコースの例



指定: CGGACTCGACAGATGTGAAGAACGACAATGTGAAGACTCGACACGACAGAGTGAAGAGAAGAGGAAACATTGTAA

タスク: 5ヌクレオチドを見つけ、50ヌクレオチドのプロットで少なくとも4回提示します。

ソリューション: CGACA GAAGA


このアルゴリズムは、シーケンスを反復処理して特定のセクションを分離し、次にこのセグメントを反復処理してkメジャーを分離し、その中の一意のメジャーの数をカウントします。 どちらの場合も、列挙は各窒素ベースで個別に行われます。 その結果、指定された回数発生するkメジャーを取得します。



なぜこのアルゴリズムが使用されるのですか? 事実、生体のゲノム内の特定のヌクレオチド配列は特に重要です。 たとえば、細菌では、そのような配列はDNA分子の複製の開始点と終了点を示します。



実装



そして、GenStageのFlowモジュールを使用した上記のアルゴリズムの実装です。



defmodule Bio do alias Experimental.Flow def clump(seq, k_mer_len, subseq_len, times) do |> seq |> String.to_charlist |> Stream.chunk(subseq_len, 1) |> Flow.from_enumerable |> Flow.partition |> Flow.map(fn e -> Stream.chunk(e, k_mer_len, 1) end) |> Flow.map( fn e -> Enum.reduce(e, %{}, fn w, acc -> Map.update(acc, w, 1, & &1 + 1) end) end) |> Flow.flat_map( fn e -> Enum.reject(e, fn({_, n}) -> n < times end) end) |> Flow.map(fn({seq, _}) -> seq end) |> Enum.uniq end end
      
      





完璧ではないかもしれませんが、コードは動作します。 より詳細に調べて、次のアクションを区別できます。



  1. ヌクレオチドシーケンスは、フローデータストリームに書き込まれます。
  2. 次に、kメジャーがそこに配置され、繰り返し回数が計算され、この値が[マップ]フィールドに書き込まれます。
  3. 必要な回数よりも少ない要素(kメジャー)は削除されます。
  4. 最後に、 Enum.uniq



    関数がEnum.uniq



    。これにより、繰り返し要素が削除されます(シーケンスが何回出現するかは重要ではありませんが、特定の回数発生するという事実は重要です)。


Stream.chunk/4



関数を使用していることに注意してください。 この関数はEnumおよびStreamモジュールに実装されていますが、Flowにはありません。 Flowモジュールにchunk



関数の個別の実装が必要かどうかについて混乱しているため、この質問をElixirメーリングリストに送信しました。 言語の作成者であるJose Valimが親切に答えてくれました。さらに、彼はclump



関数の実装を改善しました(以下を参照)。



彼によると、特に並列プロセスのいずれが完了して結果を返すかが正確にはわからないため、元のデータシーケンスを維持する必要がある場合は、注意してFlowを使用する必要があることに注意することが重要です。 判明したように、上記の検索アルゴリズムでは、元のデータシーケンスを保存する必要はありません。 また、JoseはFlow.partition



を呼び出す必要がないことに注意しました。このアルゴリズムではデータの分割は行われないからです。



Joseによる関数の実装:



 def clump(seq, k_mer_len, subseq_len, times) do seq |> String.to_charlist |> Stream.chunk(subseq_len, 1) |> Flow.from_enumerable |> Flow.flat_map(&find_sequences(&1, k_mer_len, times)) |> Enum.uniq end def find_sequences(subseq, k_mer_len, times) do subseq |> Stream.chunk(k_mer_len, 1) |> Enum.reduce(%{}, fn w, acc -> Map.update(acc, w, 1, & &1 + 1) end) |> Enum.reject(fn({_, n}) -> n < times end) |> Enum.map(fn({seq, _}) -> seq end) end
      
      







翻訳者からの結論



元の記事は、 GenStage and Bioinformaticsにあります。

残念ながら、ネットワーク上のロシア語のElixirに関する情報はまだ少なすぎるため、この記事が気に入ったら、プラスと再投稿でサポートし、定期的にElixirについて何か新しいことを読みたいなら、 Wunch (ロシア語圏のElixirコミュニティ)に参加してください -そして、最も興味深い記事の翻訳を受け取るためにニュースレターを購読してください!






All Articles