awkを使用してID列に列を圧縮するには?

awkを使用してID列に列を圧縮するには?

通常、Rで実行されるコードがありますが、ファイルが大きすぎてawkで同じコマンドを実行しようとしています。

Gene1列の値をID列(または私の場合は列)でグループ化しようとしています。

私のデータは次のとおりです。

Gene       col1   col2   col3
ACE         1     0.4    BP
ACE         2     0.5    DP
RPP-I.1     1     0.01   BP
NOS2      -0.1   0.2    DP
NOS2       1.4   2.5    SP
NOS2        1      1    BP

私はそれを次のようにグループ化したいと思いますGene

Gene     col1          col2          col3
ACE      1, 2          0.4, 0.5      BP, DP
RPP-I.1  1             0.01          BP
NOS2     -0.1, 1.4, 1  0.2, 2.5, 1   BP, SP, DP

私の実際のデータは、約200列と24972316行を含む14.8GBです。最初はRのdata.tableを試しましたが、ファイルを読み取ろうとしたときにバスエラーが発生しました。

awkを使ってこれを試す方法はありますか?

答え1

GNUを使用する一般的なソリューションawkは次のとおりです。

gawk 'NR>1{ for (i=2; i<=NF; i++) {
               c[i][$1]= c[i][$1]?c[i][$1] s $i:$i;
           } next;
}1;

ENDFILE{
    for (x in c[2]) {
        printf ("%s", x);
        for (i=2;i<=NF;i++) { printf ("\t%s", c[i][x]); delete c[i][x]; };
        print "";
     };
}' s=', ' infile  |column -s $'\t' -t

上記のコマンドは、入力ファイルのほとんどすべてをメモリにロードせず、メモリに30GBのRAMがあり、ファイルサイズが15GB程度だと言ったので、少なくとも15GB以上の空きメモリが十分であればそうすることはないようです。問題が発生します。

しかし、以下は解決策ですが、最善の解決策ではありません。 bigfile.txtを小さなファイルに分割し、各ファイルに同じGeneNameを持つ次の上記のコマンドをすべてのファイルawk*.small適用し、出力を追加モードで単一のファイルに保存できます。

私は遺伝子名の分布が同じではない可能性があり、一部は少なく、一部はより多くなる可能性があるため、これは最適ではないと言います。しかし、次のようにすることができます。

  1. 最初の列で入力ファイルを小さいサイズに分割しますGene

    awk 'NR>1{ print >$1".small"; }' bigfile.txt
    
  2. awk次に、ファイルに対して上記のコマンドを実行します。*.smallbigfile.txtを分割すると既にスキップされているので、最初に条件を削除してください。NR>1

    gawk '{ ... }; ENDFILE{ ... }' s=', ' *.small >>proccedfile
    
  3. rm *.small後でファイルを削除してください。

答え2

以下は、sortファイル全体を一度だけ処理すると大容量ファイルを処理できるように設計されており、sortDemand Pagingなどを使用してファイルを処理するように設計されているため、実際に入力全体をメモリに保存する必要はありません。 awkコマンドでは、一度に現在の値のみが保存されるため、$1メモリの問題はありません。

$ cat tst.sh
#!/usr/bin/env bash

awk -v OFS='\t' '{print (NR>1), NR, $0}' "${@:--}" |
sort -k1,1n -k3,3 -k2,2n |
cut -f 3- |
awk '
    BEGIN { OFS="\t" }
    NR == 1 { $1=$1; print; next }
    $1 != prev { prt() }
    {
        for (i=2; i<=NF; i++) {
            col[i] = (i in col ? col[i] ", " : "") $i
        }
    }
    END { prt() }

    function prt(       i) {
        if ( prev != "" ) {
            printf "%s%s", prev, OFS
            for (i=2; i<=NF; i++) {
                printf "%s%s", col[i], (i<NF ? OFS : ORS)
            }
        }
        delete col
        prev = $1
    }
'

$ ./tst.sh file
Gene     col1          col2         col3
ACE      1, 2          0.4, 0.5     BP, DP
NOS2     1, 1.4, -0.1  1, 2.5, 0.2  BP, SP, DP
RPP-I.1  1             0.01         BP

上記のスクリプトの出力はタブで区切られており、簡単に他のツールを実行でき、スプレッドシートにインポートできるので便利だと思います。視覚的にソートされた列を生成するには、スクリプトの最後に追加しますが、| column -s $'\t' -t印刷する前に最大フィールド幅を計算するために出力ファイル全体をメモリに読み込む必要がある他のプログラムを導入するため、YMMVを使用することはできません。タブ区切りの出力を許可し、表形式の出力を生成するために使用することはできませんcolumn。次に、これに関連する新しい質問を投稿してください。

上記のコードは、入力がファイルから来ているかパイプから来ているかに関係なく動作します。

関連情報