‌最初の列を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   

最初の列の各値について、2番目の列の最小値を持つ「すべての行」を選択し、最初の列に基づいてグループ化したいと思います。したがって、希望の出力は次のようになります。

 1   7.8e-12  
 1   7.8e-12
 2   9.3e-13
 3   3.0e-11    
 3   3.0e-11 

これを行う方法を知っていますか?

答え1

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

ファイルを2回処理します。一度は各キーの最小値を見つけ、その最小値を持つ行を出力します。

答え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

牛に似た一種の栄養awk解決策:

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

関連情報