첫 번째 열을 기준으로 여러 행을 병합하지만 모든 열은 독립적으로 유지되어야 합니다.

첫 번째 열을 기준으로 여러 행을 병합하지만 모든 열은 독립적으로 유지되어야 합니다.

1열의 값을 기준으로 행을 병합하고 싶습니다. 내 데이터는 다음과 같습니다(탭으로 구분된 열).

OG  FC_AG_NICO  FC_AG_ZEA   FC_AG_BRAS  FC_MB_NICO  FC_MB_ZEA   FC_MB_BRAS  FC_TN_NICO  FC_TN_ZEA   FC_TN_BRAS  FC_SL_NICO  FC_SL_ZEA   FC_SL_BRAS  FC_SE_NICFC_SE_ZEA  FC_SE_BRAS 
OG0004400   -0.787302663    -0.710790578    0.663333543                                             
OG0004400                                                   -1.659046364    -1.019969932    0.588969542
OG0004400                                       -0.373838773    0.277055943 0.481626213         
OG0004400               -0.360799687    -0.0958126  0.056722264                                 
OG0004400                           -1.77626686 -0.971114297    0.707963822                     
OG0004402   -0.304209641    -0.259080399    0.44366888                                              
OG0004402                                                   0.442748804 0.042958499 -0.316412832
OG0004402                                       -0.274550145    0.1933262   0.374095809         
OG0004402               0.253000346 0.338511357 -0.121760564

따라서 동일한 OG 번호를 공유하는 행은 하나의 행으로 병합되어야 합니다. 열당 하나의 값만 있으므로 배정밀도에는 문제가 없습니다.

여러 다른 게시물에서 비슷한 문제를 다루고 있으며 이 답변이 매우 유용하다고 생각하여 약간 편집했습니다. 그러나 여기서는 모든 값이 서로 바로 뒤에 기록됩니다. 다만, 컬럼 값은 같은 위치에 유지되는 것이 중요합니다.

awk '{if(NR!=1){a[$1]=$2"\t"a[$1]} else print $0} END {n = asorti(a, b); for (n in b) {print b[n],a[b[n]]}}'

누구든지 위 코드를 편집하는 데 도움을 줄 수 있나요?

답변1

awk 'BEGIN{FS="\t"} NR==1{print; next} {a[$1]=$1; for(i=2; i<=NF; i++){if($i!="") {f[$1,i]=$i; if(i>last[$1]){last[$1]=i}}} } END{for(j in a){printf("%s", a[j]); for(k=2; k<=last[j]; k++){printf("%s%s", FS, f[j,k])} print ""}}' file
awk 'BEGIN{FS="\t"}          # use tab as field separator
     NR==1{print; next}      # print header
     {
       a[$1]=$1              # save first column in current row
       for(i=2; i<=NF; i++){ # loop with all columns but first
         if($i!=""){         # if column not empty
           f[$1,i]=$i        # save content to array
           if(i>last[$1]){
             last[$1]=i      # save number of last element in current row
           }
         }
       }
     }
     END{
       for(j in a){
         printf("%s", a[j])           # print first element
         for(k=2; k<=last[j]; k++){   # print second to last element
           printf("%s%s", FS, f[j,k])
         }
         print ""
       }
     }' file

배열에는 a첫 번째 열이 포함되어 있습니다. 배열에는 f첫 번째 열이 없는 행이 포함되어 있습니다. 배열에는 last현재 행의 마지막 요소 위치가 포함됩니다.

아직 테스트되지 않았습니다.

답변2

한 가지 방법은 다음과 같습니다.

$ awk -F"\t" '{if(NR==1){ cols=NF; print; } else{for(i=2;i<=NF;i++){if(length($i)>0){data[$1][i]=$i}}}}END{for(id in data){ printf "%s",id; for(i=2;i<=cols;i++){printf "\t%s", data[id][i]} print ""}}' file 
OG  FC_AG_NICO  FC_AG_ZEA   FC_AG_BRAS  FC_MB_NICO  FC_MB_ZEA   FC_MB_BRAS  FC_TN_NICO  FC_TN_ZEA   FC_TN_BRAS  FC_SL_NICO  FC_SL_ZEA   FC_SL_BRAS  FC_SE_NICFC_SE_ZEA  FC_SE_BRAS 
OG0004400   -0.787302663    -0.710790578    0.663333543 -0.360799687    -0.0958126  0.056722264 -1.77626686 -0.971114297    0.707963822 -0.373838773    0.277055943 0.481626213 -1.659046364    -1.019969932
OG0004402   -0.304209641    -0.259080399    0.44366888  0.253000346 0.338511357 -0.121760564                -0.274550145    0.1933262   0.374095809 0.442748804 0.042958499

또는 읽기가 더 쉽습니다.

awk -F"\t" '{
                ## Print the headers and store the number of columns.
                if(NR==1){ 
                    cols=NF;
                    print; 
                } 
                else{
                    ## Iterate over all columns, starting from the 2nd.
                    for(i=2;i<=NF;i++){
                        ## If this one isn't empty, store it.
                        if(length($i)>0){
                            data[$1][i]=$i
                        }
                    }
                }
            }
           ## After reading everything, print.
            END{
                for(id in data){ 
                    printf "%s",id; 
                    for(i=2;i<=cols;i++){
                        printf "\t%s", data[id][i]
                    } 
                    print ""
                }
            }' file 

이는 각 ID(첫 번째 필드)에 행의 각 열에 대한 값이 있고 한 행에만 값이 있다고 가정합니다. 빈 ID가 있는 열이 있을 수 있는 경우 약간 다른 접근 방식이 필요합니다.

답변3

마친 후에는 더 많은 내용이 있을 것입니다 awk.

연관 배열을 반복하면 필드 출력이 엉망이 될지 궁금했지만 for (f in fields)최대 20개 필드까지 일부 테스트를 실행한 후에는 그렇지 않은 것 같습니다.

헤더가 행 1에 있다고 가정하면 데이터가 게시물에 따라 정렬되고 동시에 메모리에 저장하고 싶지 않은 많은 양의 데이터가 있습니다.

awk 'BEGIN{getline; split($0,out,"\t"); old=$1}
    old!=$1{for (o in out) printf "%s\t", out[o]; print""; delete out;old=$1}
    {split($0,tmp,"\t"); for (t in tmp) out[t]=(t==1)?tmp[t]:out[t]+tmp[t]}
    END{for (o in out) printf "%s\t", out[o];}' file

이 입력

head    c1  c2  c3
H1  -0.71       
H1      2   
H1          3
H2  11  12  
H2          13

주다

head    c1      c2      c3
H1      -0.71   2       3
H2      11      12      13

송곳

첫 번째 행을 잡고 첫 번째 필드를 기억하세요.old

awk 'BEGIN{getline; split($0,out,"\t"); old=$1}

다음 레코드의 첫 번째 필드가 마지막 필드(새 헤더)와 다른 경우 마지막 집계가 완료된 것이므로 인쇄하고 집계 배열을 지우고 out새 컬렉션에 있음을 확인하세요.old=$1

    old!=$1{for (o in out) printf "%s\t", out[o]; print""; delete out;old=$1}

$0배열로 분할하고 값만 가져올 때 헤더 열이 아닌 한 tmp값을 추가하여 배열을 반복합니다.tmpout

    {split($0,tmp,"\t"); for (t in tmp) out[t]=(t==1)?tmp[t]:out[t]+tmp[t]}

다음에 저장된 마지막 out기록 세트를 지웁니다.END

    END{for (o in out) printf "%s\t", out[o];}' file

관련 정보