行を複数の列に変換する

行を複数の列に変換する

次のような形式の 1,505,496 行の大きなテキスト ファイルがあります。

PAN     rs1  G    G 
PAB     rs1  G    G 
PAC     rs1  G    G 
PAE     rs1  G    G 
PAT     rs1  G    G 
PAN     rs2  T    T 
PAB     rs2  T    T 
PAC     rs2  T    T 
PAE     rs2  T    T 
PAT     rs2  T    T 
PAN     rs3  A    C 
PAB     rs3  A    C 
PAC     rs3  A    C 
PAE     rs3  A    C 
PAT     rs3  A    C 
. 
. 

そして、私が望む出力は次のようになります。

          Rs1   rs1       rs2   rs2       rs3   rs3      ....
PAN        G    G          T        T       A      C
PAB        G    G          T        T       A      C
PAC        G    G          T        T       A      C
PAE        G    G          T        T       A      C
PAT        G    G          T        T       A      C

'rs' 番号は 1153 個あり、各 'rs' には ref 値と alt 値があります (各 rs の場合は最初の列が ref、2 番目の列が alt)。

答え1

配列の配列用の GNU awk の場合:

$ cat tst.awk
BEGIN { OFS="\t" }
!seen[$1]++ { rowIds[++numRows] = $1 }
!seen[$2]++ { colIds[++numCols] = $2 }
{ vals[$1][$2] = $3 OFS $4 }
END {
    printf "%s%s", "", OFS
    for (colNr=1; colNr<=numCols; colNr++) {
        colId = colIds[colNr]
        printf "%s%s%s%s", colId, OFS, colId, (colNr<numCols ? OFS : ORS)
    }
    for (rowNr=1; rowNr<=numRows; rowNr++) {
        rowId = rowIds[rowNr]
        printf "%s%s", rowId, OFS
        for (colNr=1; colNr<=numCols; colNr++) {
            colId = colIds[colNr]
            printf "%s%s", vals[rowId][colId], (colNr<numCols ? OFS : ORS)
        }
    }
}

$ awk -f tst.awk file
        rs1     rs1     rs2     rs2     rs3     rs3
PAN     G       G       T       T       A       C
PAB     G       G       T       T       A       C
PAC     G       G       T       T       A       C
PAE     G       G       T       T       A       C
PAT     G       G       T       T       A       C

答え2

gawk (多次元配列機能を使用):

{
    if($2 ~ "rs[0-9]+")
    {
        idx = substr($2, 3)
        max_rs = idx > max_rs ? idx : max_rs
        a[$1][idx * 2 - 1] = $3
        a[$1][idx * 2] = $4
    }
}

END{

    # header
    printf "\t"
    for (i = 1; i <= max_rs; ++i) {
       printf "rs" i "\trs" i "\t"
    }
    printf "\n"

    # entries
    for (entry in a) {
        printf entry "\t"
        for (i = 1; i <= max_rs*2; ++i) {
            printf a[entry][i] "\t"
        }
        printf "\n"
    }
}

rs[index]これは、すべての列を および に格納しa[key][index*2-1]a[key][index*2]に出力することで機能しENDmax_rs最大rs数を格納するために使用されます。

関連情報