키가 다른 파일과 일치하고 조건에 따라 파일의 값을 합산합니다.

키가 다른 파일과 일치하고 조건에 따라 파일의 값을 합산합니다.

두 개의 파일이 있습니다.

파일 1

NC_000001.11_NM_001005484.2 69270   234 69037
NC_000001.11_NM_001005484.2 69511   475 69037
NC_000001.11_NM_001005484.2 69761   725 69037
NC_000001.11_NM_001385640.1 942155  20  942136

파일 2

NC_000001.11_NM_001005484.2 65565   9
NC_000001.11_NM_001005484.2 69037   969
NC_000001.11_NM_001385640.1 924432  517
NC_000001.11_NM_001385640.1 925922  92
NC_000001.11_NM_001385640.1 930155  182
NC_000001.11_NM_001385640.1 931039  51
NC_000001.11_NM_001385640.1 935772  125
NC_000001.11_NM_001385640.1 939040  90
NC_000001.11_NM_001385640.1 939272  141
NC_000001.11_NM_001385640.1 941144  163
NC_000001.11_NM_001385640.1 942136  116
NC_000001.11_NM_001385640.1 942410  79
NC_000001.11_NM_001385640.1 942559  500
NC_000001.11_NM_001385640.1 943253  125
NC_000001.11_NM_001385640.1 943698  111
NC_000001.11_NM_001385640.1 943908  243

파일 1의 열 1이 파일 2의 열 1과 일치하고 파일 2의 열 2의 값이 파일 1의 열 4의 값보다 작은 경우 파일 2의 열 3을 일치하는 키와 일치시키려고 합니다. 그런 다음 file1의 각 줄과 file2의 해당 합계를 인쇄하고 싶습니다.

예상 출력

NC_000001.11_NM_001005484.2 69270   234 69037  9
NC_000001.11_NM_001005484.2 69511   475 69037  9
NC_000001.11_NM_001005484.2 69761   725 69037  9
NC_000001.11_NM_001385640.1 942155  20  942136 1361

나는 이 작업을 수행할 만큼 awk 또는 Python에 대한 경험이 없지만 지금은 며칠 동안 이것저것 만져보고 있습니다. 도움을 주시면 감사하겠습니다.

답변1

$4이 작업을 위해서는 행 1의 각 키( )에 대한 값을 저장해야 합니다. 아래 스크립트에서는 $1이를 위해 호출된 배열을 키와 값으로 사용합니다.keys$1$4

또한 각 실제 행을 다른 배열에 저장해야 합니다( lines행 번호를 키로 사용하고 전체 행을 이에 대한 값으로 사용하겠습니다). 이것이 큰 경우 많은 메모리를 소비할 수 있다는 점에 유의하십시오 file1. 그러나 매우 크지 않은 한 RAM이 많은 최신 시스템에서는 문제가 되지 않을 것입니다. 너무 커서 RAM에 맞지 않는 경우 배열에 저장하는 대신 첫 번째 파일을 다시 반복하도록 스크립트를 수정해야 합니다 lines.

linekeys마지막으로 각 행 번호에 해당하는 키($1)도 저장해야 합니다 . 행 번호를 인덱스로, 키를 $1값으로 사용하여 이를 위해 호출된 배열을 사용하겠습니다 . 그런데 첫 번째 파일이 너무 커서 두 번째로 처리해야 하는 경우 $1각 행을 다시 처리하면서 가져올 수 있으므로 이 배열이 필요하지 않습니다. 기술적으로 이 배열은 필요할 때 블록에서 가져올 수 있으므로 실제로는 필요하지 않지만 split()더 쉽습니다 lines[l]. 더 간단한 코드와 잠재적으로 더 빠른 런타임을 위해 더 많은 메모리 사용량을 교환하는 것입니다.END{}

awk '# process the first file
     NR==FNR {
       keys[$1] = $4;      # remember the value of $4 for the key ($1)
       lines[FNR] = $0;    # store the entire line
       linekeys[FNR] = $1; # remember the key for that line
       next
     };

     # process any remaining file(s)
     $1 in keys {
       if ($2 < keys[$1]) {
         sum[$1]+=$3
       };
     };

     # All files have been processed, so print the output
     END {
       for (l in lines) {
         print lines[l], sum[linekeys[l]]
       }
     }' file1 file2
NC_000001.11_NM_001005484.2 69270   234 69037 9
NC_000001.11_NM_001005484.2 69511   475 69037 9
NC_000001.11_NM_001005484.2 69761   725 69037 9
NC_000001.11_NM_001385640.1 942155  20  942136 1361

그런데, 이것을 두 sh스크립트 중 하나에 유지하는 것이 좋습니다( this "$@"대신 인수 로 사용하는 경우는 제외 하고 실행할 때 명령줄에서 입력 줄을 지정할 수 있습니다(예: ,awkfile1 file2bash scriptname.sh file1 file2또는awk사용할 수 있도록 awk 스크립트(명령, 작은따옴표 및 파일 이름 제거)로 저장합니다 awk -f scriptname.awk file1 file2.#!첫 번째줄을 실행하면 실행 시 명령줄에 인터프리터 이름을 입력하지 않고도 직접 실행할 수 있도록 실행 가능하게 만들 수도 있습니다.

또는 정말로 주장한다면 전체 스크립트를 한 줄로 압축할 수 있습니다. 이를 달성하려면 문 사이에 필요한 곳에 세미콜론을 남겨 두십시오. 하지만 쉘 명령줄은 이렇게 짧은 스크립트라도 편집하기에 끔찍한 장소이고 심지어 Ctrl-XCtrl-E현재 줄이나 즐겨 사용하는 편집기를 편집할 수 있는 bash 와 같은 편리한 기능도 있기 때문에 권장하지 않습니다 vi.

답변2

배열의 배열을 처리하려면 GNU awk를 사용하십시오.

$ cat tst.awk
NR==FNR {
    addends[$1][$2][$3]
    next
}
$1 in addends {
    sum = 0
    for ( val in addends[$1] ) {
        if ( val < $4 ) {
            for ( addend in addends[$1][val] ) {
                sum += addend
            }
        }
    }
    print $0, sum
}

$ awk -f tst.awk file2 file1
NC_000001.11_NM_001005484.2 69270   234 69037 9
NC_000001.11_NM_001005484.2 69511   475 69037 9
NC_000001.11_NM_001005484.2 69761   725 69037 9
NC_000001.11_NM_001385640.1 942155  20  942136 1361

위의 내용은 file1 에 나타나는 것과 동일한 순서로 단순히 file1 의 행을 출력한다는 점에 유의하세요. 메모리에 쓰는 file1대신 읽는 다른 file2솔루션은 이를 수행하지 않을 수 있습니다. 예를 들어 for (i in array)를 사용한 후에 인쇄하면 "random"으로 섞이게 됩니다. " 순서는 사용 중인 awk 버전의 내부에 따라 결정됩니다.https://www.gnu.org/software/gawk/manual/gawk.html#Scanning-an-Array, 따라서 일부 특정 예제 입력에 대해 예상되는 출력을 얻는 경우에도 모든 입력에 대해 항상 발생하는 결과에 의존하지 마십시오.

관련 정보