두 파일을 공통 열과 비교한 후 각 파일의 열이 포함된 출력 파일을 얻는 방법

두 파일을 공통 열과 비교한 후 각 파일의 열이 포함된 출력 파일을 얻는 방법

두 개의 입력 파일이 있으며 둘 다 TSV 형식입니다.

File1: treated.bam.tsv 
File2: untreated.bam.tsv

두 파일 모두 아래 나열된 동일한 필드를 갖습니다. (데모 목적으로 번호를 매겼습니다.) - 각 파일에는 23개의 필드가 있습니다.

1chrom           9mismatches_pp       17C_pp
2pos             10deletions          18T
3ref             11deletions_pp       19T_pp
4reads_all       12insertions         20G
5reads_pp        13insertions_pp      21G_pp
6matches         14A                  22N
7matches_pp      15A_pp               23N_pp
8mismatches      16C

첫 번째와 두 번째 열(chrom, pos)의 값이 두 파일에서 동일하다면 레코드에서 일부 필드를 추출한 다음 아래와 같이 새 출력 파일을 생성하고 싶습니다. 출력 파일에는 15개의 필드가 있으며 아래와 같이 두 입력 파일의 데이터를 결합합니다.

From file1:
  1chrom
  2pos
  3ref
  4reads_all
  8mismatches
  10deletions
  12insertions
  pct_file1 (the values from file1: (8mismatches+10deletions+12insertions)/4reads_all)
From file2:
  3ref
  4reads_all
  8mismatches
  10deletions
  12insertions
  pct_file2 (the values from file2: (8mismatches+10deletions+12insertions)/4reads_all)
-New values from extractions.
  pct_sub  (the values from pct_file1 - pct_file2: ((8mismatches+10deletions+12insertions)/4reads_all) - ((8mismatches+10deletions+12insertions)/4reads_all))

출력 파일에서 처음 8개 열은 File1에서 가져온 것입니다 treated.bam.tsv(8번째 열은 8개의 불일치, 10개의 삭제, 12개의 삽입 및 4reads_all을 사용하여 File1에서 계산된 값입니다).

나머지는 File2에서 나오며 untreated.bam.tsv13열 역시 File2의 불일치 8개, 삭제 10개, 삽입 12개, reads_all을 기준으로 계산된 값이다.

마지막 필드는 pct_subFile1((8mismatches+10deletions+12insertions)/4reads_all) 및 File2((8mismatches+10deletions+12insertions)/4reads_all) 필드의 손상을 기반으로 계산됩니다.

출력 파일에 새 열 이름(예 pct_file1: , pct_file2, ) 을 추가하려면 어떻게 해야 합니까 pct_sub?

이것이 제가 위의 출력 파일에 대해 수행한 작업입니다. (입력 및 출력 파일 모두 TSV라는 동일한 형식을 갖습니다.)

awk 'FNR==NR{array[$1,$2]=$0;next} { if ( $1 $2 in array ) print $1, $2, array[$3], array[$4], array[$8], array[$10], array[$12], (array[$8]+array[$10]+array[$12])/array[$4], $3, $4, $8, $10, $12, ($8+$10+$12)/$4, ((array[$8]+array[$10]+array[$12])/array[$4])-(($8+$10+$12)/$4) > "awkoutput.bam.tsv" }' treated.bam.tsv untreated.bam.tsv

(Actually, $1, $2 are not a problem from File1 or File2)

파일 1( treated)

chrom pos ref reads_all reads_pp matches matches_pp mismatches mismatches_pp deletions deletions_pp insertions insertions_pp A A_pp C C_pp T T_pp G G_pp N N_pp

chrY 59363551 G 8 0 7 0 0 0 1 0 5 0 0 0 0 0 0 0 7 0 0 0
chrY 59363552 G 7 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0
chrY 59363553 T 7 0 7 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0
chrY 59363554 G 7 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0
chrY 59363555 T 7 0 7 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0

파일 2( untreated)

chrom pos ref reads_all reads_pp matches matches_pp mismatches mismatches_pp deletions deletions_pp insertions insertions_pp A A_pp C C_pp T T_pp G G_pp N N_pp
chrY 59363551 G 2 0 2 0 0 0 0 0 1 0 0 0 0 0 0 0 2 0 0 0
chrY 59363552 G 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
chrY 59363553 T 1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
chrY 59363554 G 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
chrY 59363555 T 1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0

산출

chrom pos ref reads_all mismatches deletions insertions pct_file1 ref reads_all mismatches deletions insertions pct_file2 pct_sub
chrY 59363551 G 8 0 1 5 0.75 G 2 0 0 1 0.5 0.25
chrY 59363552 G 7 0 0 0 0 G 1 0 0 0 0 0
chrY 59363553 T 7 0 0 0 0 T 1 0 0 0 0 0
chrY 59363554 G 7 0 0 0 0 G 1 0 0 0 0 0
chrY 59363555 T 7 0 0 0 0 T 1 0 0 0 0 0

답변1

생물정보학은 흥미로운 것 같습니다. awk가 아닌 솔루션에 열려 있다면 이것이 쉬울 것입니다miller:

mlr --itsv join -u -j chrom,pos --lp tr_ --rp untr_ -f treated.bam.tsv untreated.bam.tsv | # join data from treated and untreated files by fields chrom and pos
mlr put '$tr_pct=($tr_mismatches+$tr_deletions+$tr_insertions)/$tr_reads_all' | # calculate pct for treated data
mlr put '$untr_pct=($untr_mismatches+$untr_deletions+$untr_insertions)/$untr_reads_all' | # calculate pct for untreated data
mlr cut -o -f chrom,pos,tr_ref,tr_reads_all,tr_mismatches,tr_deletions,tr_insertions,tr_pct,untr_ref,untr_reads_all,untr_mismatches,untr_deletions,untr_insertions,untr_pct | # remove superfluous fields
mlr --otsv put '$pct_sub=$tr_pct-$untr_pct' # append pct subtraction field

chrom   pos tr_ref  tr_reads_all    tr_mismatches   tr_deletions    tr_insertions   tr_pct  untr_ref    untr_reads_all  untr_mismatches untr_deletions  untr_insertions untr_pct    pct_sub
chrY    59363551    G   8   0   1   5   0.750000    G   2   0   0   1   0.500000    0.250000
chrY    59363552    G   7   0   0   0   0   G   1   0   0   0   0   0
chrY    59363553    T   7   0   0   0   0   T   1   0   0   0   0   0
chrY    59363554    G   7   0   0   0   0   G   1   0   0   0   0   0
chrY    59363555    T   7   0   0   0   0   T   1   0   0   0   0   0

실제보다 더 무서운 것 같습니다. 진짜.

답변2

  1. if ( $1 $2 in array )그것은 작동하지 않습니다; 당신은 그것을 해야 합니다 if (($1,$2) in array).
  2. array[$3]당신은 그렇게 사용할 수 없습니다 array[$4]. 귀하의 배열은 다음과 같습니다
    배열[chrY,59363551]="chrY 59363551 G 8 0 7 0 0 0 1 0 5 0 0 0 0 0 0 0 7 0 0 0"
    배열[chrY,59363552]="chrY 59363552 G 7 0 7 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0"
    array[$3]and 라고 하면 존재하지 않는 and 등을 array[$4]의미합니다 .array[G]array[2]
  3. 이를 코드에서 지정하는 기능은 여러 파일에 쓰려고 할 때 유용한 기능입니다. 단일 출력 파일만 있는 경우에는 그다지 유용하지 않습니다. 명령의 출력을 리디렉션하는 것이 어떨까요?> "filename"awkawk
  4. 긴 대기열은 좋지 않습니다. 긴 명령을 짧은 줄로 나눕니다. 변수를 재사용하여 중복을 줄입니다.
  5. 배열을 사용하지 마세요~라고 불리는 array. 이는 이라는 변수 variable, 이라는 파일 file, 이라는 사람 Person등이 있는 것과 같습니다. 설명적인 이름을 사용하십시오.

즉,

awk 'FNR==NR {file1data[$1,$2]=$0; next}
        {       if (($1,$2) in file1data) {
                        # Save desired values from file2.
                        file2arg03=$3
                        file2arg04=$4
                        file2arg08=$8
                        file2arg10=$10
                        file2arg12=$12
                        pct_file2=($8+$10+$12)/$4
                        # Get data from file1.
                        $0=file1data[$1,$2]
                        pct_file1=($8+$10+$12)/$4
                        print $1, $2, $3, $4, $8, $10, $12, pct_file1, \
                                file2arg03, file2arg04, file2arg08, file2arg10, file2arg12, \
                                pct_file2, pct_file1-pct_file2
                } else printf "(%s,%s) in file2 but not file1.%s", $1, $2, ORS
        }' treated.bam.tsv untreated.bam.tsv > awkoutput.bam.tsv

귀하의 버전과 마찬가지로 이것은 file1 데이터를 배열에 저장한 다음 file2를 읽는 동안 모든 작업/출력을 수행합니다. file2에서 행을 받은 후 해당 행의 필수 필드를 명명된 변수에 저장합니다(5개 요소 길이의 다른 배열을 사용할 수도 있음). 그런 다음file1의 해당 행에서 데이터를 복구합니다.. 전체 행을 에 할당하면 $0, , 등 $1이 원래 값으로 되돌아갑니다.$2$3$4

출력에 헤더 행을 쓰는 데 실제로 문제가 있습니까? 노력하다:

        {       if (FNR == 1) {
                        print "chrom pos ref reads_all mismatches deletions insertions pct_file1 …"
                } else if (($1,$2) in file1data ) {
                        file2arg03=$3

좋습니다. 다음은 귀하의 시도에 더 가깝고 헤더 라인을 처리하는 버전입니다.

awk 'FNR==NR {file1line[$1,$2]=$0; next}
        {       if (FNR == 1) {
                        print "chrom pos ref reads_all mismatches deletions insertions pct_file1 ref reads_all mismatches deletions insertions pct_file2 pct_sub …"
                } else if (($1,$2) in file1line ) {
                        # Get data from file1.
                        split(file1line[$1,$2], file1arg)
                        pct_file1=(file1arg[8]+file1arg[10]+file1arg[12])/file1arg[4]
                        pct_file2=($8+$10+$12)/$4
                        print $1, $2, file1arg[3], file1arg[4], file1arg[8], \
                                file1arg[10], file1arg[12], pct_file1, \
                                $3, $4, $8, $10, $12, pct_file2, pct_file1-pct_file2
                } else printf "(%s,%s) in file2 but not file1.%s", $1, $2, ORS
        }' treated.bam.tsv untreated.bam.tsv > awkoutput.bam.tsv

file1line이는 file1(from)에서 행을 검색하고 이를 전달하여 split23개의 구성 요소 값으로 나누어 array 에 저장합니다 file1arg. 그런 다음 , file1arg[3], ... 을 사용하는 것처럼 file1arg[4]사용할 수 있습니다 .array[$3]array[$4]

관련 정보