各行の一部を別々のファイルに出力

各行の一部を別々のファイルに出力

次のファイルがあります。

a   AGTACTTCCAGGAACGGTGCACTCTCC
b   ATGGATTTTTGGAGCAGGGAGATGGAATAGGAGCATGCTCCAT
c   ATATTAAATGGATTTTTGGAGCAGGGAGATGGAATAGGAGCATGCTCCATCCACTCCACAC
d   ATCAGTTTAATATCTGATACGTCCTCTATCCGAGGACAATATATTAAATGGA
e   TTTGGCTAAGATCAAGTGTAGTATCTGTTCTTATAAGTTTAATATCTGATATGTCCTCTATCTGA

a.seqシーケンスを含むファイルを作成したいですAGTACTTCCAGGAACGGTGCACTCTCC。またb.seq含まれますATGGATTTTTGGAGCAGGGAGATGGAATAGGAGCATGCTCCAT。つまり、Column1は拡張子を持つ出力ファイル名として使用する必要があり、.seqその列2の順序が必要です。 Perlスクリプトを書くことでこれを行うことができますが、コマンドラインのすべてが役に立ちます。すぐに聞きたいです。

ベストアンサー1

私の最初の反応は次のようになりました。awkしかし、多くの行(何百万もの行を話すもの)を処理する場合は、「実際の」プログラミング言語に切り替えることで実質的な利点を得ることができます。

これを念頭に置いて(そしてすでにawk答えを考慮して)、さまざまな言語でいくつかの実装を作成し、PCI-E SSDの同じ10,000行のデータセットでベンチマークしました。

me* (C)                0m1.734s
me (C++)               0m1.991s
me (Python/Pypy)       0m2.390s
me (perl)              0m3.024s
Thor+Glenn (sed|sh)    0m3.353s
me (python)            0m3.359s
jasonwryan+Thor (awk)  0m3.779s
rush (while read)      0m6.011s
Thor (sed)             1m30.947s
me (parallel)          4m9.429s

一見するとCが一番良く見えるが、そんなに早く走れば豚だ。 PypyとC ++は作成と実行が簡単です。十分何十億もの行について話さない限り。もしそうなら、RAMまたはSSDですべてのタスクを実行するようにアップグレードすることは、コードの改善よりも優れた投資かもしれません。

明らかに私がこれを見ている間、あなたはおそらく何億ものレコードを処理したでしょう。最も遅いオプションのうち。作成またはBashループしかできない場合は、awkそうして人生を続けてください。今日は間違いなく時間が多すぎると思います。

また、いくつかのマルチスレッドオプション(C ++とPythonとGNUとの混合parallel)をテストしましたが、これらの単純な操作(文字列分割、書き込み)の利点よりもスレッドのオーバーヘッドがはるかに大きかったです。

パール

awkgawkここ)は正直なところ、この種のデータをテストするための最初の呼び出しポートですが、Perlでもかなり似たようなことができます。構文は似ていますが、書き込み処理が少し優れています。

perl -ane 'open(my $fh, ">", $F[0].".seq"); print $fh $F[1]; close $fh;' infile

Python

良いPython。それは私が毎日使用している仕事の言語で、素晴らしい、信頼できる、非常に読みやすい言語です。初心者でもここで何が起こっているのか推測できます。

with open("infile", "r") as f:
    for line in f:
        id, chunk = line.split()
        with open(id + ".seq", "w") as fw:
            fw.write(chunk)

ディストリビューションのpythonバイナリがPythonの唯一の実装ではないことを覚えておく必要があります。Pypyで同じテストを実行すると、Cより速いもはやロジックの最適化は必要ありません。 Pythonを「遅い言語」と考える前にこの点に留意してください。

私は私のCPUで実際に何ができるかを知るためにこの例を始めましたが、正直に長い間Cに触れていない場合は、コーディングするのは悪夢です。これには100文字の行に制限されているという追加の欠点があり、それを拡張することは非常に簡単ですが必要ありません。

私の元のバージョンはC ++とpypyより遅かったが、ブログの後私は持っていますJulien Claudeの助け。このバージョンは、IOバッファの調整のために最も高速です。これもたくさんどんなものよりも長く深い。

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>

#define BUFLEN (8 * 1024)

int main(void) {
    FILE *fp;
    FILE *fpout;

    char line[100];
    char *id;
    char *token;
    char *buf = malloc(BUFLEN);

    fp = fopen("infile", "r");

    setvbuf ( fp , buf , _IOLBF, BUFLEN );
    while (fgets(line, 100, fp) != NULL) {
        id = strtok(line, "\t");
        token = strtok(NULL, "\t");

        char *fnout = malloc(strlen(id)+5);
        fnout = strcat(fnout, id);
        fnout = strcat(fnout, ".seq");

        fpout = fopen(fnout, "w");
        setvbuf ( fpout , NULL , _IONBF , 0 );
        fprintf(fpout, "%s", token);
        fclose(fpout);
    }
    fclose(fp);

    return 0;
}

C++

よく行動しているたくさん実際のCよりも書き込みが簡単です。役に立つすべての種類の資料があります(特に文字列と入力に関して)。これが意味するのは、実際に論理を単純化できることです。strtokCでは、文字列全体を処理し、退屈なメモリ割り当てをすべて実行する必要があるため、大きな問題です。ラベルに触れるまで線に沿ってスライドし、必要に応じてセグメントを引き出します。

#include <fstream>
#include <string>
using namespace std;

int main(void) {
    ifstream in("infile");
    ofstream out;
    string line;

    while(getline(in, line)) {
        string::size_type tab = line.find('\t', 0);
        string filename = line.substr(0, tab) + ".seq";
        out.open(filename.c_str());
        out << line.substr(tab + 1);
        out.close();
    }

    in.close();
}

GNUパラレル

(moreutilsバージョンではありません)これは簡潔な構文ですが、遅すぎます。私が間違って使用したかもしれません。

parallel --colsep '\t' echo {2} \> {1}.seq <infile

テストハーネスジェネレータ

これは100000行[ATGC]*64のデータジェネレータです。スピードは速くなく、改善は非常に歓迎されています。

cat /dev/urandom | tr -dc 'ATGC' | fold -w 64 | awk 'NR>100000{exit}{printf NR"\t"$0"\n"}' > infile

おすすめ記事