我想过滤下表中的行,以便从下面的表格中筛选出来:
A 1 3 SOME_OTHER_INFO
A 1 4 SOME_OTHER_INFO2
A 2 5 SOME_OTHER_INFO3
B 1 1 SOME_OTHER_INFO4
B 2 3 SOME_OTHER_INFO4
B 2 0 SOME_OTHER_INFO4对此:
A 1 3 SOME_OTHER_INFO
A 2 5 SOME_OTHER_INFO3
B 1 1 SOME_OTHER_INFO4
B 2 0 SOME_OTHER_INFO4过滤标准是:
1)根据前2列对行进行分组。
2)然后,对于每个组,选择第三列在组内最小的行。
3)返回。
现在,在R中使用包(如使用以下命令的plyr )可以很容易地执行这样的操作:
ddply(data, .(first_col, second_col), function(x) {
min_idx = which.min(x$third_col);
return(x[min_idx])
})但是,我想知道是否有一种使用命令行上的unix工具的高效而优雅的方法。
最后,我几乎找到了使用datamash的漂亮解决方案,这是最近在GNU中发布的一个工具,但有一些小问题。
$ datamash -g 1,2 min 3 -f < file.txt | cut -f1-4
A 1 3 SOME_OTHER_INFO1
A 2 5 SOME_OTHER_INFO3
B 1 1 SOME_OTHER_INFO4
B 2 3 SOME_OTHER_INFO4 # <-- not the correct row I want to grab问题是当使用"-f“标志时,它从每个组抓取第一个项,而不是min对应的行。因此,如果您查看上面的输出,“B2 3 SOME_OTHER_INFO4”被选中,而不是“B2 0 SOME_OTHER_INFO4”。
发布于 2014-09-21 17:58:56
下面是使用perl的几个更多选项:
perl -MList::Util=min -lane'
$h{"@F[0,1]"}{$F[2]} = $_
}{
print $h{$_}{ min keys %{$h{$_}} } for sort keys %h
' file
A 1 3 SOME_OTHER_INFO
A 2 5 SOME_OTHER_INFO3
B 1 1 SOME_OTHER_INFO4
B 2 0 SOME_OTHER_INFO4min方法获取最小的外键并打印值,这是整个行。或者没有核心模块:
perl -lane'
push @{ $h{"@F[0,1]"} }, [$F[2], $_]
}{
print $_->[1] for sort map {
(sort { $a->[0] <=> $b->[0] } @$_)[0]
} values %h
' file
A 1 3 SOME_OTHER_INFO
A 2 5 SOME_OTHER_INFO3
B 1 1 SOME_OTHER_INFO4
B 2 0 SOME_OTHER_INFO4发布于 2014-09-21 10:49:30
不知道你所说的有效率还是优雅,但这似乎是你想要的:
sort -k1 -k2,3n file.txt | rev | uniq -f 2 | rev如果双rev被认为是不雅的(或者实际列数不同,在这种情况下它将无法工作),
sort -k1 -k2,3n file.txt | perl -wane'print if $.==1 || $F[0] ne $last[0] || $F[1] != $last[1]; @last=@F'发布于 2014-09-21 13:36:55
如果您能够按正确的顺序排序行,那么只打印组中的第一行的简单的Awk过滤器应该可以工作。
sort -k1 -k2n -k3n file.txt |
awk '!a[$1 $2]++'Awk脚本使用前两个字段中的键填充数组a,只有当它看到新键时才会打印。
https://stackoverflow.com/questions/25958105
复制相似问题