awk를 사용하여 ID 열로 열을 압축하는 방법은 무엇입니까?

awk를 사용하여 ID 열로 열을 압축하는 방법은 무엇입니까?

일반적으로 R에서 실행되는 코드가 있는데 파일이 너무 커서 awk에서 동일한 명령을 실행하려고 합니다.

Gene한 열의 값을 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. 그런 다음 이와 관련된 새 질문을 게시하세요.

위 코드는 입력이 파일에서 오는지 파이프에서 오는지 여부에 관계없이 작동합니다.

관련 정보