如何将一列的值除以另一列并在新列中打印结果?

How to divide values from one column by another and print results in a new column?

我对 awk 比较陌生,所以我有一个关于除法的简单问题,并在新列中打印结果。例如:

head data

1   13273      .  G   C   563  5  .  25    128
1   202259     .  G   T   675  8  .  12    130
1   598934     .  C   C   756  9  .  17    231
1   634112     .  T   C   125  1  .  32    89
1   779762     .  G   A   675  5  .  28    187

我想将第 9 列除以第 10 列并将结果打印在新的第 11 列中,最好将新结果从高到低排序。例如:

1   634112     .  T   C   125  1  .  32    89    0.360
1   13273      .  G   C   563  5  .  25    128   0.195
1   779762     .  G   A   675  5  .  28    187   0.150
1   202259     .  G   T   675  8  .  12    130   0.092
1   598934     .  C   C   756  9  .  17    231   0.074

我只知道如何在 R 中实现,但我想了解我们如何在 awk 中实现。谢谢!

Awk 对于第一个要求非常有表现力。如果你想要第 11 列,你可以发明它并将其设置为等于第 9 列除以第 10 列的结果。

可以在 awk 中进行排序,但是通过管道进行排序有点麻烦,所以更容易。 column命令让它更漂亮,仅此而已

$ awk '{ =  / }1' file | sort -nr -k 11 | column -t
1  634112  .  T  C  125  1  .  32  89   0.359551
1  13273   .  G  C  563  5  .  25  128  0.195312
1  779762  .  G  A  675  5  .  28  187  0.149733
1  202259  .  G  T  675  8  .  12  130  0.0923077
1  598934  .  C  C  756  9  .  17  231  0.0735931

如果您的输出需要制表符分隔,您可以设置 OFS 变量(忘记列命令):

$ awk -v OFS='\t' '{ =  / }1' file | sort -nr -k 11 
1   634112  .   T   C   125 1   .   32  89  0.359551
1   13273   .   G   C   563 5   .   25  128 0.195312
1   779762  .   G   A   675 5   .   28  187 0.149733
1   202259  .   G   T   675 8   .   12  130 0.0923077
1   598934  .   C   C   756 9   .   17  231 0.0735931

最后,您可以使用 sprintf 格式化最后一列,如示例输出中所示:

$ awk -v OFS='\t' '{ = sprintf("%.3f",  / )}1' file | sort -nr -k 11
1   634112  .   T   C   125 1   .   32  89  0.360
1   13273   .   G   C   563 5   .   25  128 0.195
1   779762  .   G   A   675 5   .   28  187 0.150
1   202259  .   G   T   675 8   .   12  130 0.092
1   598934  .   C   C   756 9   .   17  231 0.074

更新:

正如 Ed Morton 在他的回答中所展示的那样,三元运算符 ?: 可用于防止被零除。这里我在第 11 列中放置了 "UND" 以表示 "undefined",当然您可以将其留空或输入其他值。

$ awk -v OFS='\t' '{ = ( != 0) ? sprintf("%.3f",  / ) : "UND"}1' file | sort -nr -k 11
1   634112  .   T   C   125 1   .   32  89  0.360
1   13273   .   G   C   563 5   .   25  128 0.195
1   779762  .   G   A   675 5   .   28  187 0.150
1   202259  .   G   T   675 8   .   12  130 0.092
1   598934  .   C   C   756 9   .   17  0   UND

在某些时候,您可能会认为 awk 程序变得足够复杂,因此最好将其放在自己的文件中,更强调可读性而不是紧凑性。

$ cat div.awk file 

BEGIN { OFS="\t"}

{
    if ( != 0) {
        quotient =  / 
         = sprintf("%.3f", quotient)
    }
    else {
         = "UND"
    }
    print
}


$ awk -f div.awk file  | sort -nr -k 11
1   634112  .   T   C   125 1   .   32  89  0.360
1   13273   .   G   C   563 5   .   25  128 0.195
1   779762  .   G   A   675 5   .   28  187 0.150
1   202259  .   G   T   675 8   .   12  130 0.092
1   598934  .   C   C   756 9   .   17  0   UND

使用 GNU awk sorted_in:

$ cat tst.awk
{ a[NR]=[=10=]; v[NR]=/ }
END {
    PROCINFO["sorted_in"]="@val_num_desc"
    for (i in v) {
        print a[i] "\t" v[i]
    }
}

$ awk -f tst.awk file
1   634112     .  T   C   125  1  .  32    89   0.359551
1   13273      .  G   C   563  5  .  25    128  0.195312
1   779762     .  G   A   675  5  .  28    187  0.149733
1   202259     .  G   T   675  8  .  12    130  0.0923077
1   598934     .  C   C   756  9  .  17    231  0.0735931

v[NR]=/ 更改为 v[NR]=(==0 ? 0 : /) 或类似内容以防止 $10 可以为零时被零除。