‌如何根据第一列作为ID来选择每组中具有最小值的行?

‌如何根据第一列作为ID来选择每组中具有最小值的行?

我有一个文件如下所示:

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

相关内容