![如何根据第一列作为ID来选择每组中具有最小值的行?](https://linux22.com/image/126800/%E2%80%8C%E5%A6%82%E4%BD%95%E6%A0%B9%E6%8D%AE%E7%AC%AC%E4%B8%80%E5%88%97%E4%BD%9C%E4%B8%BAID%E6%9D%A5%E9%80%89%E6%8B%A9%E6%AF%8F%E7%BB%84%E4%B8%AD%E5%85%B7%E6%9C%89%E6%9C%80%E5%B0%8F%E5%80%BC%E7%9A%84%E8%A1%8C%EF%BC%9F.png)
我有一个文件如下所示:
1 7.8e-12
1 7.8e-12
1 1.0e-11
2 9.3e-13
2 3.5e-12
2 3.5e-10
2 3.1e-9
3 3.0e-11
3 3.0e-11
3 1.7e-08
对于第一列中的每个值,我想选择第二列中具有最小值的“所有行”并按第一列分组。所以期望的输出是:
1 7.8e-12
1 7.8e-12
2 9.3e-13
3 3.0e-11
3 3.0e-11
知道如何做到这一点吗?
答案1
一种方法是按升序排序,然后记下每个 col1 的第一个 col2 值,并打印当前 col2 值是否等于它:
sort -k1,1n -k2,2g file | awk '!a[$1] {a[$1] = $2} $2 == a[$1]'
1 7.8e-12
1 7.8e-12
2 9.3e-13
3 3.0e-11
3 3.0e-11
答案2
这应该处理科学记数法中的数字:
awk '
NR == FNR {
if (!($1 in min) || $2 < min[$1])
min[$1] = $2
next
}
$2 == min[$1]
' file file
我们处理该文件两次:一次查找每个键的最小值,然后输出具有该最小值的行。
答案3
为了完善基于文本处理的答案,以下是使用 PostgreSQL 执行此操作的方法:
首先,预处理文件以将其转换为 CSV 以便于导入:
awk -v OFS=, '$1=$1' file.txt > file.csv
然后在 PostgreSQL 中创建一个临时表,如下所示:
create temp table x (id int, bignum float);
将 CSV 复制到其中:
\copy x from file.csv with (format csv)
并查询临时表以获得您想要的结果:
select id, bignum
from (
select
*,
rank() over (partition by id order by bignum)
as rank
from x
) as sqlrequiresthisalias
where rank = 1;
结果:
id | bignum
----+---------
1 | 7.8e-12
1 | 7.8e-12
2 | 9.3e-13
3 | 3e-11
3 | 3e-11
(5 rows)
答案4
GNUawk
解决方案:
awk 'BEGIN{ PROCINFO["sorted_in"] = "@val_num_asc" }
{ a[$1][++c] = $2 }
END{
for (i in a) {
prev = 0;
for (j in a[i]) {
v = a[i][j]; if (prev && v != prev) continue;
print i, v; prev = v
}
}
}' file
输出:
1 7.8e-12
1 7.8e-12
2 9.3e-13
3 3.0e-11
3 3.0e-11