3

我正在努力完成以下任务,即在具有制表符分隔字段的两个文件之间比较字段的一部分(3 美元)。文件与其他字段 $1-2 逐行匹配,但 $3 略有不同。我只对 $3 的一部分感兴趣,即AF的数值。$3 中的所有子字段(?)都用分号分隔,但如您所见,AF值并不总是在该位置(有时是#2,有时是#3)。我想拔出文件之间第三个字段中AF的值不同的行。

例如,这是示例文件 1:

dmel_mitochondrion_genome       18984   AB=0.743;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19066   AB=0.684;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19074   AB=0.321;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19212   AC=8;AF=1.00;AN=8;DP=382;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19285   AC=8;AF=1.00;AN=8;DP=342;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19384   AC=8;AF=1.00;AN=8;DP=400;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19395   AC=8;AF=1.00;AN=8;DP=398;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19461   AB=0.524;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19472   AB=0.527;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19475   AC=8;AF=1.00;AN=8;BaseQRankSum=0.936;DP=$

和示例文件2:

dmel_mitochondrion_genome       18984   AB=0.730;AC=4;**AF=1.00**;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19066   AB=0.742;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19074   AB=0.345;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19212   AC=8;AF=1.00;AN=8;BaseQRankSum=1.722;DP=$
dmel_mitochondrion_genome       19285   AC=8;AF=0.50;AN=8;BaseQRankSum=1.721;DP=$
dmel_mitochondrion_genome       19384   AC=8;AF=1.00;AN=8;BaseQRankSum=1.458;DP=$
dmel_mitochondrion_genome       19395   AC=8;AF=1.00;AN=8;DP=391;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19461   AB=0.510;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19472   AB=0.526;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19475   AC=8;AF=0.50;AN=8;BaseQRankSum=-1.732;DP$

我想得到的输出是 file1 中的以下几行:

dmel_mitochondrion_genome       18984   AB=0.743;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19285   AC=8;AF=1.00;AN=8;DP=342;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19475   AC=8;AF=1.00;AN=8;BaseQRankSum=0.936;DP=$

甚至是这样的:

dmel_mitochondrion_genome       18984   AF=0.50  
dmel_mitochondrion_genome       19285   AF=1.00  
dmel_mitochondrion_genome       19475   AF=1.00

我尝试使用 awk 但我不知道如何比较部分字段而不是整个字段。我终于想出了如何使用正则表达式从一个文件的每一行中查找 AF 的值,但不知道如何捕获该值以将其与另一个文件中的另一个值进行比较。任何帮助深表感谢!

4

6 回答 6

4

以下命令应该为您提供所需格式的每个文件。然后你可以对它们做一个diif ...

awk '{s=$0; split(s, a, "AF="); split(a[1], a1); split(a[2], a2, ";"); print a1[1] " " a1[2] " AF=" a2[1]}'
于 2012-04-09T22:01:18.353 回答
2

您可以使用 AWK 数组作为哈希表来存储第一次出现的AF值,然后将其与下一次出现比较:

BEGIN { store[0] = 0 }
{
    key = $1 "-" $2
    match($3, /AF=[^;*]+/)
    val = substr($3, RSTART+3, RLENGTH-3)
    if ((key in store) && (store[key] != val))
        print $1,$2,"AF=" store[key]
    else
        store[key] = val
}

然而,filter-then-diff 解决方案似乎更优雅,因为这个解决方案有可能消耗大量内存。

于 2012-04-09T22:08:24.977 回答
2

略有不同的方法

awk '{subList=$3; 
 sub(/.*AF=/, "AF=", subList); sub(/;.*$/, "", subList)
 print $1 "\t" $2 "\t" subList}'  awkTest_20120409_1.txt > awkTest_20120409_1_cln.txt

awk '{subList=$3; 
 sub(/.*AF=/, "AF=", subList); sub(/;.*$/, "", subList)
 print $1 "\t" $2 "\t" subList}'  awkTest_20120409_2.txt > awkTest_20120409_2_cln.txt

diff awkTest_20120409_1_cln.txt awkTest_20120409_2_cln.txt | grep '^<' | sed 's/< //'

** 输出 **

dmel_mitochondrion_genome       18984   AF=0.50
dmel_mitochondrion_genome       19285   AF=1.00
dmel_mitochondrion_genome       19475   AF=1.00

当然,您需要将文件名替换为输入和输出,以及diff.

我希望这有帮助。

于 2012-04-09T22:20:59.470 回答
1

TXR:为处理糟糕文本文件的分子生物学家而创建。还有其他人。

因为文件可能很大,我们避免在内存中保留从一对行到下一行的任何内容(由:vars ()collect 子句中的确保)。

这里使用了一个技巧,使两个文件看起来像是一个流,带有交错的行。然后我们可以对该流进行模式匹配,就好像它是一个文件一样。

变量(第 3 列材料)被解析为 Lisp 关联列表,因此我们可以使用它assoc来查找感兴趣字段的值。它是按字符串比较的;如有必要,可以转换为数值,以便将 0.5 和 0.50 视为相同。

@(next :args)
@(cases)
@file1
@file2
@(or)
@  (throw error "two file names needed")
@(end)
@;
@; functional programming trick: make a bottomless lazy list which returns
@; strings, which are the lines from files f1 and f2, alternating.
@;
@(do (defun make-interleaved-lazy-stream (f1 f2)
       (let ((streams '#(,(open-file f1 "r") ,(open-file f2 "r"))))
         (let ((toggle 0) line)
           (gen (prog1
                  (set line (get-line [streams toggle]))
                  (set toggle (- 1 toggle)))
                line)))))
@(define parse-line (gen id alist))
@gen @id @(coll)@{var /[A-Z]+/}=@val;@(end)
@  (bind alist @[mapcar cons var val])
@(end)
@(next :list @(make-interleaved-lazy-stream file1 file2))
@(collect :vars ())
@  (cases)
@    (parse-line gen id alist1)
@    (parse-line gen id alist2)
@  (or)
@    (throw error `assumption violated: mismatching lines between @file1 and @file2`)
@  (end)
@  (do (let ((AF1 (cdr (assoc "AF" alist1)))
             (AF2 (cdr (assoc "AF" alist2))))
         (if (not (equal AF1 AF2))
           (put-string `@{gen 30} @{id -6}   AF1=@AF1\n`))))
@(end)

跑:

$ txr gendiff.txr file1 file2
dmel_mitochondrion_genome       18984   AF1=0.50
dmel_mitochondrion_genome       19285   AF1=1.00
dmel_mitochondrion_genome       19475   AF1=1.00
于 2012-04-09T22:25:10.727 回答
0

这可能会有所帮助 -

awk -F'[; =]' '
NR==FNR{ for (i=1;i<=NF;i++) if ($i=="AF") b[++x]=$(i+1); c[x]=$0; next } 
{for (j=1;j<=NF;j++) if ($j=="AF") d[++y]=$(j+1)} 
END {for (z=1;z<=length(b);z++) if (b[z]!=d[z]) print c[z]}' f1 f2

文件 1:

[jaypal:~/Temp] cat f1
dmel_mitochondrion_genome       18984   AB=0.743;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19066   AB=0.684;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19074   AB=0.321;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19212   AC=8;AF=1.00;AN=8;DP=382;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19285   AC=8;AF=1.00;AN=8;DP=342;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19384   AC=8;AF=1.00;AN=8;DP=400;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19395   AC=8;AF=1.00;AN=8;DP=398;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19461   AB=0.524;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19472   AB=0.527;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19475   AC=8;AF=1.00;AN=8;BaseQRankSum=0.936;DP=$

文件 2:

[jaypal:~/Temp] cat f2
dmel_mitochondrion_genome       18984   AB=0.730;AC=4;AF=1.00;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19066   AB=0.742;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19074   AB=0.345;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19212   AC=8;AF=1.00;AN=8;BaseQRankSum=1.722;DP=$
dmel_mitochondrion_genome       19285   AC=8;AF=0.50;AN=8;BaseQRankSum=1.721;DP=$
dmel_mitochondrion_genome       19384   AC=8;AF=1.00;AN=8;BaseQRankSum=1.458;DP=$
dmel_mitochondrion_genome       19395   AC=8;AF=1.00;AN=8;DP=391;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19461   AB=0.510;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19472   AB=0.526;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19475   AC=8;AF=0.50;AN=8;BaseQRankSum=-1.732;DP$

测试:

[jaypal:~/Temp] awk -F'[; =]' '
NR==FNR{ for (i=1;i<=NF;i++) if ($i=="AF") b[++x]=$(i+1); c[x]=$0; next } 
{for (j=1;j<=NF;j++) if ($j=="AF") d[++y]=$(j+1)} 
END {for (z=1;z<=length(b);z++) if (b[z]!=d[z]) print c[z]}' f1 f2
dmel_mitochondrion_genome       18984   AB=0.743;AC=4;AF=0.50;AN=8;BaseQRankSum=$
dmel_mitochondrion_genome       19285   AC=8;AF=1.00;AN=8;DP=342;DS;Dels=0.00;FS$
dmel_mitochondrion_genome       19475   AC=8;AF=1.00;AN=8;BaseQRankSum=0.936;DP=$
于 2012-04-09T23:14:46.543 回答
0

这可能对您有用:

awk -vfile2=file2 -vOFS='\t' '{sub(/.*AF=[^0-9.-]*/,"",$3);sub(/[^0-9.-]+.*/,"",$3);getline line <file2;sub(/.*AF=[^0-9.-]*/,"",line);sub(/[^0-9.-]+.*/,"",line)};$3!=line{$3="AF="$3;print}' file1

由于file1file2匹配除了AF值:

  • 读取一行file1
  • 减至价值$3_AF
  • 将一行读file2入变量line
  • 减至价值line_AF
  • 如果它们不匹配$3,则比较line和输出$0file1在前面$3加上)。AF=
于 2012-04-10T00:33:55.897 回答