如果该行中的max-min满足特定条件,则提取行

时间:2015-01-02 05:05:08

标签: unix awk max min

我有一个制表符分隔的文件,其行如下:

chr1 1001 + KEEP 0.5 0.3 0.06 0.4 0.2 0.3 0.5
chr1 40004 + KEEP 0.93 0.2 0.6 0.25 0.8 NA NA
chr2 140004 + KEEP 0.03 0.02 0.06 0.05 0.08 NA 0.01
chr2 455235504 - KEEP NA 0.12 0.67 0.51 0.8 NA NA
chr3 5004 + KEEP 0.53 0.52 NA 0.5 NA 0.54 NA
..

我想计算第5列以后每行的最大值和最小值之间的差值,并提取此(最大 - 最小)差值等于或大于0.1的行。例如,根据上面给出的输入,我应该得到:

chr1 1001 + KEEP 0.5 0.3 0.06 0.4 0.2 0.3 0.5
chr1 40004 + KEEP 0.93 0.2 0.6 0.25 0.8 NA NA
chr2 455235504 - KEEP NA 0.12 0.67 0.51 0.8 NA NA
..

如何使用awk为每个文件大约几百万行执行此操作?

目前我正在尝试

awk '{min=max=$5; 
      for(i=5;i<=67;i++){
        if($i<min) min=$i;
        if($i>max) max=$i
      }
      print min,max}' test.txt 

4 个答案:

答案 0 :(得分:1)

主要是您错过了minmax之间的差异是否大于阈值的测试。您还应该使用NF作为for循环中的限制,而不是对67之类的数字进行硬编码。

awk '{min=max=$5; 
      for(i=6;i<=NF;i++){
        if ($i == "NA") continue;
        if (min == "NA" || $i<min) min=$i;
        if (max == "NA" || $i>max) max=$i
      }
      if ((max - min) > .1) print}' test.txt 

我还添加了对NA的检查,它会跳过这些值。

答案 1 :(得分:0)

这是一个没有额外依赖关系的Python解决方案,几乎可以在任何地方运行:

import fileinput

for line in fileinput.input():
    strings = line.rstrip().split(' ')[4:]
    numbers = [float(string) for string in strings if string != 'NA']
    if max(numbers) - min(numbers) >= 0.1:
        print line,

答案 2 :(得分:0)

另一种方式

awk '{min=max=x;for(i=5;i<=NF;i++){min=min!~/./||$i<min?$i:min;max=$i+0>max?$i:max}}
      max-min>=.1' file

在每行的开头将min和max设置为0 然后从5循环到行中的字段数 然后,如果min未设置或小于$ i,则将其设置为$ i 如果max大于$ i,请将其设置为$ i
$ i + 0将删除“NA”,然后将其设置为0 打印最大减去min大于或等于.1的行。

这个答案假定max总是高于0。

如果max可以小于0

     awk '{min=max=x
     for(i=5;i<=NF;i++){min=min!~/./||$i<min?$i:min
     $i!="NA"&&max=max!~/./||$i>max?$i:max}
     } max-min>=.1' file

答案 3 :(得分:0)

$ cat tst.awk
{
    min = max = ""
    for (i=5; i<=NF; i++) {
        if ($i == $i+0) {
            min = ( (min == "") || ($i < min) ? $i : min)
            max = ( (max == "") || ($i > max) ? $i : max)
        }
    }
}
(max - min) >= 0.1

$ awk -f tst.awk file
chr1 1001 + KEEP 0.5 0.3 0.06 0.4 0.2 0.3 0.5
chr1 40004 + KEEP 0.93 0.2 0.6 0.25 0.8 NA NA
chr2 455235504 - KEEP NA 0.12 0.67 0.51 0.8 NA NA

$i == $i+0的测试仅在$i为数字时才会生效,因此会丢弃$i"NA"或任何其他非数字值的情况。< / p>

作为一项增强功能,如果您愿意,可以轻松调整它以报告没有数值的行:

{
    min = max = ""
    for (i=5; i<=NF; i++) {
        if ($i == $i+0) {
            min = ( (min == "") || ($i < min) ? $i : min)
            max = ( (max == "") || ($i > max) ? $i : max)
        }
    }
}
min == "" { printf "ERROR[%d]: \"%s\" has no numeric values.\n", NR, $0 | "cat>&2" }
(max - min) >= 0.1