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

kin*_*182 2 linux awk text-processing

我比较新,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
Run Code Online (Sandbox Code Playgroud)

我想将第 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
Run Code Online (Sandbox Code Playgroud)

我只知道如何在 R 中做到这一点,但我想学习如何在awk. 谢谢!

jas*_*jas 5

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

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

$ awk '{$11 = $9 / $10}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
Run Code Online (Sandbox Code Playgroud)

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

$ awk -v OFS='\t' '{$11 = $9 / $10}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
Run Code Online (Sandbox Code Playgroud)

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

$ awk -v OFS='\t' '{$11 = sprintf("%.3f", $9 / $10)}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
Run Code Online (Sandbox Code Playgroud)

更新

正如 Ed Morton 在他的回答中所示,三元运算符?:可用于防止被零除。在这里,我在第 11 列中放置了“UND”以表示“未定义”,但当然您可以将其留空或放置一些不同的值。

$ awk -v OFS='\t' '{$11 = ($10 != 0) ? sprintf("%.3f", $9 / $10) : "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
Run Code Online (Sandbox Code Playgroud)

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

$ cat div.awk file 

BEGIN { OFS="\t"}

{
    if ($10 != 0) {
        quotient = $9 / $10
        $11 = sprintf("%.3f", quotient)
    }
    else {
        $11 = "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
Run Code Online (Sandbox Code Playgroud)