选择值出现超过 x 次的列

选择值出现超过 x 次的列

我有一个包含多行和多列的文件。我想选择数字 2 出现超过 x 次的列。

我的制表符分隔文件如下所示:

Individuals  M1 M2 M3
Ind1          0 0  2
Ind2          0 2  2
Ind3          2 2  2

在此卡通示例中,假设我想要数字 2 出现两次或多次的列。我的输出是:

Individuals   M2 M3
Ind1          0  2
Ind2          2  2
Ind3          2  2

使用 R 这很容易,但由于文件太大而需要很长时间,所以我想使用 awk 或类似的东西来完成。您能告诉我如何实现这一目标吗?

答案1

BEGIN { OFS = FS = "\t" }

FNR == NR {
        for (i = 2; i <= NF; ++i)
                if ($i == 2) ++c[i]
        next
}

{
        a[nf=1] = $1
        for (i = 2; i <= NF; ++i)
                if (c[i] >= t) a[++nf] = $i

        $0 = ""
        for (i = 1; i <= nf; ++i)
                $i = a[i]

        print
}

awk程序将计算每列中该值出现的次数,2并将这些计数存储在数组中c(该数组中每列数据一个元素)。它在第一次读取输入文件时执行此操作(这是FNR == NR块)。

当第二次读取输入文件时,它使用这些计数将适当的列从输入传输到a每行读取的数组。变量的值t用作阈值来决定是否应包含该列。这是for代码最后一个块中的第一个循环。

然后它从此数组创建一个新的数据记录并打印它。

测试它(请注意,输入文件在命令行上给出两次,以便awk能够对其进行两次传递):

$ cat file
Individuals     M1      M2      M3
Ind1    0       0       2
Ind2    0       2       2
Ind3    2       2       2
$ awk -v t=1 -f script.awk file file
Individuals     M1      M2      M3
Ind1    0       0       2
Ind2    0       2       2
Ind3    2       2       2
$ awk -v t=2 -f script.awk file file
Individuals     M2      M3
Ind1    0       2
Ind2    2       2
Ind3    2       2
$ awk -v t=3 -f script.awk file file
Individuals     M3
Ind1    2
Ind2    2
Ind3    2
$ awk -v t=4 -f script.awk file file
Individuals
Ind1
Ind2
Ind3

答案2

不确定这是否快:

awk -v value=0 '
NR==FNR{for(i=2;i<=NF;i++){if($i==value){s[i]++}}}
NR!=FNR {
  printf "%s"OFS,$1
  for (i=2;i<=NF;i++){if(s[i]>1)last=i}
  for (i=2;i<=NF;i++){
    if(s[i]>1){
      if (i==last)printf "%s\n",$i
      else printf "%s"OFS,$i}
  }
}
' file file

您可能想要设置OFS为制表符 ( BEGIN{OFS="\t"}.)

相关内容