私はこのようなファイルを持っています:
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のすべての値について、列2に最小値を持つ「すべての行」を選択し、列1でグループ化します。したがって、必要な出力は次のとおりです。
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
これは、科学的記数法で数値を処理する必要があります。
awk '
NR == FNR {
if (!($1 in min) || $2 < min[$1])
min[$1] = $2
next
}
$2 == min[$1]
' file file
ファイルを2回処理します。1回目は各キーのmin値を見つけ、次にそのmin値の行を出力します。
GNUツールを使用すると、値を複製する必要があるため複雑になります!
grep -F "$(datamash -W -g1 min 2 <infile | \
sed 's/\([^\.][1-9]\)e/\1.0e/')" <(sed 's/ \+/\t/' infile)
最小値のみが関係する場合は、以下でdatamash
で十分です。
datamash -W -g1 min 2 <infile
テキスト処理ベースの回答をまとめるために、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)
GNU 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