我有一个类似于下面示例的文件。第一列是 SNP id。
head data
2L:647803 1 2 44.31655 -12.2373
2L:647803 1 2 43.63717 -12.302
2L:647803 1 2 43.80007 -12.3451
2L:2602906 1 2 43.39748 -11.4894
2L:2602906 1 2 44.43951 -12.3093
2L:2602906 1 2 43.80007 -12.3451
2L:3146785 1 2 44.31655 -12.2373
2L:3146785 1 2 44.43951 -12.3093
2L:3146785 1 2 43.80007 -12.3451
2L:3771395 1 2 43.39748 -11.4894
2L:3771395 1 2 43.2661 -11.6803
2L:3945568 1 2 43.63717 -12.302
2L:3945568 1 2 43.39032 -11.6099
对于每个 SNP ( 2L:647803
, 2L:2602906
, 2L:3146785
, ...),我想要 3 行。如果每个 SNP 没有 3 行,我想删除该 SNP。这是我想要的输出:(2L:3771395
并且 2L:3945568
被删除,因为每个输出只有两个实例)。
head desired
2L:647803 1 2 44.31655 -12.2373
2L:647803 1 2 43.63717 -12.302
2L:647803 1 2 43.80007 -12.3451
2L:2602906 1 2 43.39748 -11.4894
2L:2602906 1 2 44.43951 -12.3093
2L:2602906 1 2 43.80007 -12.3451
2L:3146785 1 2 44.31655 -12.2373
2L:3146785 1 2 44.43951 -12.3093
2L:3146785 1 2 43.80007 -12.3451
答案1
不优雅但实用:
$ awk 'NR==FNR {a[$1]++; next} a[$1]==3' data data
2L:647803 1 2 44.31655 -12.2373
2L:647803 1 2 43.63717 -12.302
2L:647803 1 2 43.80007 -12.3451
2L:2602906 1 2 43.39748 -11.4894
2L:2602906 1 2 44.43951 -12.3093
2L:2602906 1 2 43.80007 -12.3451
2L:3146785 1 2 44.31655 -12.2373
2L:3146785 1 2 44.43951 -12.3093
2L:3146785 1 2 43.80007 -12.3451
答案2
使用米勒(https://github.com/johnkerl/miller)并运行
mlr --nidx count-similar -g 1 then filter '$count==3' then cut -x -f count inputfile
你有
2L:647803 1 2 44.31655 -12.2373
2L:647803 1 2 43.63717 -12.302
2L:647803 1 2 43.80007 -12.3451
2L:2602906 1 2 43.39748 -11.4894
2L:2602906 1 2 44.43951 -12.3093
2L:2602906 1 2 43.80007 -12.3451
2L:3146785 1 2 44.31655 -12.2373
2L:3146785 1 2 44.43951 -12.3093
2L:3146785 1 2 43.80007 -12.3451
mlr --nidx count-similar -g 1
计算不同字段 1 的值then filter '$count==3'
仅过滤此计数 = 3 的行then cut -x -f count
删除计数列
答案3
这是另一个awk
(只不过是awk
)解决方案。
- 它假设输入是按“SNP id”整理的;即,所有 SNP id = 647 的行将在一起。
- 它不假设输入已排序;即,SNP id 647 可以出现在 2602 之前或之后。
- 它只对数据进行一次传递。
- 它不会输出出现超过 3 次的 SNP id 的任何数据。
awk '
{
if ($1 == last) {
count++
if (count <= 3) line[count] = $0
} else {
if (count == 3) { print line[1]; print line[2]; print line[3]; }
last = $1
count = 1
line[count] = $0
}
}
END { if (count == 3) { print line[1]; print line[2]; print line[3]; } }
'
它只是计算第一个字段/列 ( ) 中具有相同值的连续行,$1
并保存具有相同值的行。如果它遇到一个新值(或输入的末尾),那么,如果前一个值出现了三次,它会打印出保存的行。