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


11

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

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の値が一致する場合、両方の行の列34の値を合計します。それ以外の場合は、一意の行の値の合計のみです。

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

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

私はに従ってファイルをソートすることができる午前コラム2awksortとして、最後の列を合計awkだけで、個々のラインのためではない二行について、列2試合。


1
列1はどうですか?
グレン・ジャックマン、2015年

@glennjackman:列1は各ファイル全体で同じ値です。これはファイルの識別子として機能し(そのうちの45個あります)、いくつかのダウンストリームプロセスで使用されます。私の質問では、無視(または削除)して後で再度追加することもできます。
TomPio

または、$1 $2キーとして作る。
グレンジャックマン2015年

回答:


12

私はこれを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

7

これは役立つかもしれませんが、列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

2
GNU awkを使用している場合PROCINFO["sorted_in"] = "@ind_num_asc"は、パイピングの代わりにを使用してくださいsort。REF gnu.org/software/gawk/manual/html_node/...
グレン・ジャックマン

@taliezin:taliezinとterdonに感謝します。どちらのアプローチも魅力のように機能しました。本当にありがとうございました。
TomPio

1
@taliezin:どちらもうまくいくと言ったので、terdonの回答を「正しい」回答としてマークしました。それがあなたの意図したものだと思います。再度、感謝します。
TomPio、2015年

1
一意のキーの合計が必要な質問を理解したら、カウンターを追加して印刷できます。awk '{map [$ 2] + = $ 3 + $ 4; } END {for(i in map){print "2"、i、map [i] | "sort -t'n '"; cnt ++; } print "total unique:" cnt} 'file
taliezin

1
それはほとんど同じです:awk '{map [$ 2] + = $ 3 + $ 4; oc [$ 2] ++; } END {for(i in map){print "2"、i、map [i]、oc [i] | "sort -t'n '"; }} 'を実行すると、オカレンスのある別の列が表示されます。
taliezin

4

データを事前にソートして、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前のラインの値、または$1FS$2上記第二の場合です。これは、前の行のが現在の行のものと異なる{print p,s}場合$2にトリガーされることを意味します(p!=$2)。


最初の列に異なる値があったとしてもsort -k2、2番目の列で並べ替えるために使用できることに注意してください
gaoithe

2

スイスアーミーナイフユーティリティの使用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

ノート:

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

  • put '$5=$3+$4'新しい5番目のフィールド、フィールド34の合計を作成します。

  • stats1関数(又は「動詞」)より小さいアーミーナイフで
    の大きなアーミーナイフ内mlrといったアキュムレータ基づいて機能を、sumcountmean

    stats1 -g 1,212でデータをグループ化し、-f 5 -a sumそれらのグループのフィールドを合計します5stats1 名前付きフィールドのみを印刷します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.