我有一个包含多行和多列的文件。我想选择数字 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"}
.)