セルと列の一致に基づいて行列テーブルを分割する

セルと列の一致に基づいて行列テーブルを分割する

Linuxのファイルには、タブ区切りの大きな行列があります。

Name    ID  ABC12   ABCD12  ABCD123 ABCD1234
ABC12   123456  XX  YY  ZZ  JJ
ABC12   123456  XX  YY  ZZ  JJ
ABCD12  123456  XX  YY  ZZ  JJ
ABCD12  123456  XX  YY  ZZ  JJ
ABCD123 123456  XX  YY  ZZ  JJ
ABCD123 123456  XX  YY  ZZ  JJ
ABCD1234    123456  XX  YY  ZZ  JJ
ABCD1234    123456  XX  YY  ZZ  JJ

この行列を最初の列の一致に基づいて別々のファイルに分割したいと思います。 [このファイルは容量が大きく、列数をカウントできません。]

予想出力:

ファイル1;

Name    ID  ABC12
ABC12   123456  XX
ABC12   123456  XX

ファイル2;

Name    ID  ABCD12
ABCD12  123456  YY
ABCD12  123456  YY

ファイル3;

Name    ID  ABCD123
ABCD123 123456  ZZ
ABCD123 123456  ZZ

ファイル4;

Name    ID  ABCD1234
ABCD1234    123456  JJ
ABCD1234    123456  JJ

答え1

十分アッ解決策:

awk 'NR==1{ len=split($0,a_pos); for(i=1;i<=len;i++) a_keys[a_pos[i]]=i }
     NR>1{ if(!r[$1]++) { fn="file"++c; print "Name\tID\t"$1 > fn } 
           print $1,$2,$(a_keys[$1]) > fn 
     }' OFS='\t' file
  • len=split($0,a_pos)- 最初の行を「キー」配列(整数a_posでインデックス付けされた配列)に分割します。

  • for(i=1;i<=len;i++) a_keys[a_pos[i]]=i- 文字列キーでインデックスを付ける配列に反転a_pos(追加処理のため)a_keys

  • fn="file"++c- 構成ファイル名


結果を見る:

for f in file[0-9]*; do (echo "$f"; cat "$f"; echo); done

出力(file1file2および連続file3タイプfile4):

file1
Name    ID  ABC12
ABC12   123456  XX
ABC12   123456  XX

file2
Name    ID  ABCD12
ABCD12  123456  YY
ABCD12  123456  YY

file3
Name    ID  ABCD123
ABCD123 123456  ZZ
ABCD123 123456  ZZ

file4
Name    ID  ABCD1234
ABCD1234    123456  JJ
ABCD1234    123456  JJ

答え2

あなたが使用できるawk

awk 'NR>1{if ($1!=p){N="file"++C; print "Name\tID\t"$1 >N};
             print $1,$2,$(C+2)>N}{p=$1}' infile.txt

答え3

私が考える最も簡単な方法は、最初の行を変数として保存し、残りは必要に応じて印刷することです。ただし、これを行うには、入力ファイル全体をメモリに保存する必要があります。

#!/bin/gawk -f
{
    if(NR==1){
        header[1]=$1;
        header[2]=$2;
        for(i=3;i<=NF;i++){
            header[$i]=i;
        }
    }
    else{
        data[$1][NR]=$2"\t"$(header[$1]);
    }
}
END{
    OFS="\t";
    for(i in data){
        print header[1],header[2],i > i".txt"
        for(k in data[i]){
            print i,data[i][k] >> i".txt"
        }
    }
}

スクリプトをfoo.awk実行可能ファイル(chmod a+x foo.awk)として保存し、ファイルから実行します。

foo.awk file

答え4

使用法: ./split_matrix.awk input.txt

#!/usr/bin/awk -f

BEGIN {
    cnt = 1;
}

NR == 1 { 
    for(i = 3; i <= NF; i++) {
        headers[$i] = i;            
    }   
}
NR > 1 { 
    if( ! file_names[$1]) {
        file_names[$1] = cnt++;
        printf "%s %s %s\n", "Name", "ID", $1 > "file_"file_names[$1];
    }   
    printf "%s %s %s\n", $1, $2, $headers[$1] >> "file_"file_names[$1];
}

テスト

入力する

Name    ID  ABC12   ABCD12  ABCD123 ABCD1234
ABC12   123456  XX  YY  ZZ  JJ
ABC12   123456  XX  YY  ZZ  JJ
ABCD12  123456  XX  YY  ZZ  JJ
ABCD12  123456  XX  YY  ZZ  JJ
ABCD123 123456  XX  YY  ZZ  JJ
ABCD123 123456  XX  YY  ZZ  JJ
ABCD1234    123456  XX  YY  ZZ  JJ
ABCD1234    123456  XX  YY  ZZ  JJ

出力tail -n +1 -- file*ファイル名とファイルの内容を印刷するためにこのトリックが見つかりました。ここ)

==> file_1 <==
Name ID ABC12
ABC12 123456 XX
ABC12 123456 XX

==> file_2 <==
Name ID ABCD12
ABCD12 123456 YY
ABCD12 123456 YY

==> file_3 <==
Name ID ABCD123
ABCD123 123456 ZZ
ABCD123 123456 ZZ

==> file_4 <==
Name ID ABCD1234
ABCD1234 123456 JJ
ABCD1234 123456 JJ

関連情報