AWKを使用した合計の計算と除算

AWKを使用した合計の計算と除算

次のdata書類を見ると...

foo     10
bar     20
oof     50
rab     20

...2番目の列全体の割合で2番目の列を印刷するにはどうすればよいですか?つまり、私が欲しいのは…

foo     10    10%
bar     20    20%
oof     50    50%
rab     20    20%

...もちろん、あまり明確な数もあります。累計を簡単に作成できますが、方法がわかりません。行を印刷する前の合計の計算。私はこれをawkファイルでやっていますtotals.awk...

#!/usr/bin/awk -f
BEGIN{
        runningtotal=0
}
{
        runningtotal=runningtotal+$2
        print $1 "\t" $2 "\t" runningtotal "\t" $2/runningtotal
}

だからランは./totals.awk data戻ってきます...

foo     10      10      1
bar     20      30      0.666667
oof     50      80      0.625
rab     20      100     0.2

合計を計算するために1回、行を印刷するために1回、2回繰り返す方法はありますか? AWKでこれは可能ですか?それとも別のユーティリティを使用する必要がありますか?

答え1

単一の呼び出しでテーブルを作成するには、次の手順を実行しますawk

$ awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' data data
foo     10      10%
bar     20      20%
oof     50      50%
rab     20      20%

どのように動作しますか?

ファイルはパラメータとして2回data提供されます。awkしたがって、2回読み取られます。 1つ目は合計(変数に保存)を取得し、s2つ目は出力を印刷することです。コマンドの詳細を確認してください。

  • FNR==NR{s+=$2;next;}

    NR は読み取ったレコード (行) の総数でありawk、FNR は現在のファイルからこれまで読み取ったレコードの数です。したがって、FNR==NR私たちは最初のファイルを読んでいます。これが発生すると、変数はs2番目の列の値だけ増加します。その後、残りのコマンドをスキップして次のレコードから始めるようにnext指示します。awk

    s0に初期化する必要はありません。では、awkデフォルトではすべての数値変数がゼロに初期化されます。

  • printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s

    このコマンドに達すると、2番目のファイルを処理しています。これはs、列2の合計が保存されたことを意味します。したがって、列1、列2、およびパーセントを印刷します100*$2/s

出力フォーマットオプション

を使用すると、printf出力形式を詳細に制御できます。上記のコマンドは、%s文字列、整数、および浮動小数点数に適した書式指定子を使用します。ここで役に立つ他の3つのオプションは次のとおりです。

  • %d数値の形式を整数で指定します。数値が実際に浮動小数点の場合は整数に切り捨てられます。

  • %f数値を浮動小数点数値形式で指定します。幅と小数点以下の桁数を指定することもできます(例:)%5.2f

  • %e指数表記法を提供します。これは、いくつかの数値が特に大きいか小さい場合に便利です。

シェル関数の作成

このコマンドを複数回使用したい場合は、長いコマンドを入力するのが不便かもしれません。代わりに、コマンドを実行する関数またはスクリプトを作成してください。

という関数を生成するには、totals次のコマンドを実行します。

$ totals() { awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' "$1" "$1"; }

dataこの関数を定義したら、次のコマンドを実行して呼び出されたデータファイルの割合を確認できます。

$ totals data

定義をtotals永久に作成するには、ファイルに入れます~/.bashrc

シェルスクリプトの作成

スクリプトを好む場合は、totals.sh次の内容を含むファイルを生成してください。

#!/bin/sh
awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' "$1" "$1"

というデータファイルの割合を取得するには、次のようにdataします。

sh totals.sh data

答え2

これを行うための「簡単な」方法はawk2回呼び出すことです。 1回は合計を求め、もう1回は割合を計算します。

$ total=$(awk 'BEGIN{ total=0 } { total=total+$2 } END{ printf total }' data)
$ awk -v total=$total '{ print $1 "\t" $2 "\t" 100*$2/total "%" }' data

今、誰かが何とか気の利いたことを言うと確信しています...

答え3

awkでファイルを開く(完全性のために)

awk '{a[NR]=$0;x+=(b[NR]=$2)}END{while(++i<=NR)print a[i]"\t"100*b[i]/x"%"}' file

foo     10      10%
bar     20      20%
oof     50      50%
rab     20      20%

この方法は他の方法よりも多くのメモリを使用しますが、より高速です。

その後、行をarrayとして読み取り、aフィールド2をarrayとして読み込みますb
その後、xフィールド 2 の値だけ増加します。

最後に、1からレコード数まで繰り返して正しい行を出力し、パーセンテージを計算します。

関連情報