awkを使用して複数行を1つにまとめる

awkを使用して複数行を1つにまとめる

私は次の形式の非常に大きなデータセットで作業しています。

chr1 45162 . . C T 
chr1 45162 . . C T
chr1 45162 A . . T
chr1 45162 . . C T
chr1 45257 A . . T
chr1 45257 A . . T
chr1 45413 A . . T
chr1 46844 A . C .
chr1 72434 A G . .
chr1 72434 A G . .
chr1 72434 A G . .
chr1 72434 A G . .
chr1 72515 A . C .
chr1 72515 A . . T
chr1 77689 A G . .    

私が望む出力は次のとおりです。

chr1 45162 A . C T
chr1 45257 A . . T
chr1 45413 A . . T
chr1 46844 A . C .
chr1 72434 A G . .
chr1 72515 A . C T
chr1 77689 A G . .

デフォルトでは、列2の各一意の値について別々の行に格納できるすべての属性を確認する必要があります。

だから私が持っている場合:

chr1 100 A . C .
chr1 100 . G . T

出力に必要な行は次のとおりです。

chr1 100 A G C T

私はうまく動作すると思うスクリプトがありますが、遅すぎます。awk簡単なスクリプトを使ってこれを行うより簡単な方法があるべきだと思います。

私の現在のバージョンは次のとおりです。http://ideone.com/e.js/ETBRz3 しかし、私が言ったようにawk

すべての提案を歓迎します。

(単純化している場合は、空のフィールドが「.」文字ではなく空の文字列になるようにこのファイルを生成するスクリプトを変更して変更できます。)

答え1

1つの方法は次のとおりです。

$ awk '$2!=old && NR>1 {for (i=1;i<=NF;i++) printf a[old","i]" "; print"";} {old=$2;for (i=1;i<=NF;i++) {if (a[$2","i]=="." ||  a[$2","i]=="") a[$2","i]= $i}} END{for (i=1;i<=NF;i++) printf a[old","i]" "; print"";}' file 
chr1 45162 A . C T 
chr1 45257 A . . T 
chr1 45413 A . . T 
chr1 46844 A . C . 
chr1 72434 A G . . 
chr1 72515 A . C T 
chr1 77689 A G . . 

どのように動作しますか?

  • $2!=old && NR>1 {for (i=1;i<=NF;i++) printf a[old","i]" "; print"";}

    1 行目以降の 2 列目の新しい値に出会うたびに、前の値の結果を出力します。

  • old=$2;for (i=1;i<=NF;i++) {if (a[$2","i]=="." || a[$2","i]=="") a[$2","i]= $i}

    a現在行の値で配列を更新します。

    GNUにはawk素晴らしい2次元配列があります。ただし、互換性の理由からPOSIX準拠の代替方法を使用します。

  • END{for (i=1;i<=NF;i++) printf a[old","i]" "; print"";}

    最後の行の後に情報の最後の部分を印刷します。

答え2

整列されていない行の別の変形:

awk '{
k[$2]=$1;
for(i=3;i<7;i++){
  if(l[$2,i]=="." || l[$2,i]=="")
    l[$2,i]=$i;
  }
}
END{
for(n in k){
  printf("%s %s ",k[n],n);
  for(m=3;m<7;m++)
    printf("%s ", l[n,m]);
  print "";
  }
 }' file

簡単な説明:

kファイルスクリプトを介して2つの連想配列(with field#2as indexとlwith index)を作成しますfield#2,Next_fields_number。ファイル内のすべての行が渡されると、スクリプトは2つのループを開始して最初の配列と2番目の配列のフィールドを印刷します。

答え3

一方perl通行:

$ perl -anle '
  for (2..$#F) {
    $h{join(" ",@F[0..1])}->{$_} ||= $F[$_];
    $h{join(" ",@F[0..1])}->{$_} = $F[$_] if $F[$_] ne ".";
  }
  END { print "$_ @{$h{$_}}{sort keys %{$h{$_}}}" for sort keys %h }
' file
chr1 45162 A . C T
chr1 45257 A . . T
chr1 45413 A . . T
chr1 46844 A . C .
chr1 72434 A G . .
chr1 72515 A . C T
chr1 77689 A G . .

関連情報