web-dev-qa-db-ja.com

一致するフィールドに基づいて列のペアを合計する

次の形式の大きなファイルがあります。

2 1019 0 12 
2 1019 3 0 
2 1021 0 2 
2 1021 2 0 
2 1022 4 5
2 1030 0 1 
2 1030 5 0 
2 1031 4 4

列2の値が一致する場合、両方の行のおよび4の値を合計します。それ以外の場合は、一意の行の値。

したがって、私が期待している出力は次のようになります。

2 1019 15 
2 1021 4 
2 1022 9 
2 1030 6 
2 1031 8

列2に従ってファイルをawkまたはsortでソートし、最後の列をawkで合計することができますが、個々の行に対してのみではありません列2が一致する2行。

11
TomPio

私はこれをPerlで行います:

$ Perl -lane '$k{"$F[0] $F[1]"}+=$F[2]+$F[3]; 
              END{print "$_ $k{$_}" for keys(%k) }' file 
2 1019 15
2 1021 4
2 1030 6
2 1031 8
2 1022 9

またはawk:

awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file 

2番目の列に従って出力をソートする場合は、sortにパイプするだけです。

awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file | sort -k2

どちらのソリューションにも第1列が含まれていることに注意してください。アイデアは、ハッシュ(Perl)または連想配列(awk)へのキーとして、最初と2番目の列を使用することです。各ソリューションのキーはcolumn1 column2したがって、2つの行が同じ列2で異なる列1を持つ場合、それらは別々にグループ化されます。

$ cat file
2 1019 2 3
2 1019 4 1
3 1019 2 2

$ awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file
3 1019 4
2 1019 10
12
terdon

これは役立つかもしれませんが、列1は常に2であり、結果はそれに依存しますか?

awk '{ map[$2] += $3 + $4; } END { for (i in map) { print "2", i, map[i] | "sort -t't'" } }' file

または、ソートに関するコメントで glenn jackman によって言及されています:

gawk '{ map[$2] += $3 + $4; } END { PROCINFO["sorted_in"] = "@ind_str_asc"; for (i in map) { print 2, i, map[i] } }' file
7
taliezin

データを事前にソートして、awkに詳細を処理させることができます。

sort -n infile | awk 'NR>1 && p!=$2 {print p,s} {s+=$3+$4} {p=$2}'

アキュムレータをリセットしたいかもしれません:

sort -n infile | awk 'NR>1 && p!=$2 {print p,s;s=0} {s+=$3+$4} {p=$2}'

出力:

1019 15
1021 19
1022 28
1030 34

最初の列を保持したい場合は、次のようにします。

sort -n infile | awk 'NR>1 && p!=$1FS$2 {print p,s} {s+=$3+$4} {p=$1FS$2}'

出力:

2 1019 15
2 1021 19
2 1022 28
2 1030 34

説明

p変数は、前の行の$2値、または2番目のケースでは$1FS$2を保持します。これは、前の行の{print p,s}が現在の行の$2と同じでない場合にp!=$2がトリガーされることを意味します。

4
Thor

スイスアーミーナイフユーティリティの使用 mlr

mlr --nidx   put '$5=$3+$4'   then   stats1 -g 1,2 -f 5 -a sum   infile

出力:

2   1019    15
2   1021    4
2   1022    9
2   1030    6
2   1031    8

ノート:

  • --nidxは、数値フィールド名を使用するようにmlrに指示します。

  • put '$5=$3+$4'は、新しい5番目のフィールドを作成し、フィールドの合計3および4

  • stats1関数(または "verb")は、小さなスイスアーミーナイフです
    mlrsumcountmeanなど

    stats1 -g 1,2は、データを列1および2でグループ化し、-f 5 -a sum次に、これらのグループのフィールド5を合計します。 stats1名前付きフィールドのみを出力します。

2
agc