【実践!CSVデータ集計スクリプト作成編】平均値の算出 〜 Awkを使った平均を計算するスクリプト


2021/04/19

CSVデータの自由でより高機能な集計操作を行うスクリプトツールを作成してみる特集の第3回目です。

Awkでも科学計算ほどの精度は無いものの、それでもかなり高度な算術計算処理をスクリプト内で実現することができます。

今回は簡単な好例として平均を計算させてみます。


はじめに

当サイトではオフィス業務のComputer-Aidedなハイブリッドな方法を模索し、より効率的なExcel業務を実現したい多忙なオフィスワーカー向けの主にAwkとSedを使うシェル講座です。

シェルスクリプトはどこでもどんなOSでも基本的に使えて、しかも一度使い方を覚えると、Excelと組み合わせて最高に効率の良いオフィスワークツールが作れることでしょう。

合同会社タコスキングダム|蛸壺の技術ブログ


CSVデータの準備

算術平均ですので、データ列のセル値は数値であることが要求されます。

今回も
前々回に引き続き、以下のCSVデータを使って平均を計算させてみます。

データ構造は左から従業員名、所属部署、勤務地、今月未清算分の立替経費、の順で並んでいるとします。

            
            $ cat << EOF > expenses.csv
山下モゲ雄,営業部,本社,7929
島田フガ子,経理部,名古屋支部,50958
岡田ピポ太,製造部,山口工場,27989
沢口モフ代,人事部,本社,28025
銭形ガメ吉,海外部,メキシコ支部,27497
上岡ムメ美,営業部,本社,17544
京谷マハ次,製造部,山口工場,25383
園田フマ由,人事部,本社,23275
田川ポゥ子,製造部,ベトナム工場,37658
満田クタ郎,営業部,本社,32259
島寺ルン大,営業部,本社,41764
香下ウル蔵,製造部,山口工場,17149
蒲田ウオ奈,海外部,メキシコ支部,25229
郷田ポポ生,営業部,名古屋支部,26683
梅岡ボル伍,経理部,本社,41615
亀川ヲル士,製造部,山口工場,18657
EOF
        
それでは以降では、2列目と3列目のカテゴリーを区別させずに選択肢を混ぜた条件で平均を求めるツールスクリプトを作成します。


ツールスクリプトの実装

早速以下に具体的なシェルスクリプトの実装例を挙げてみます。

            
            #!/bin/bash

#👇連想配列でキーからラベルを取得できるようにする
declare -A categories=(
    ['1']='営業部'
    ['2']='経理部'
    ['3']='製造部'
    ['4']='海外部'
    ['5']='本社'
    ['6']='名古屋'
    ['7']='山口'
    ['8']='ベトナム'
    ['9']='メキシコ'
)

#👇平均計算の中身
function Average() {
    #👇option : 1) 営業部 2) 経理部 3) 製造部 4) 海外部
    #           5) 本社   6) 名古屋 7) 山口   8) ベトナム 9) メキシコ
    local option="${categories[$1]}"
    local filepath="$2"
    cat "$filepath" | awk -F"," '
        #👇BEGINで該当のセル要素数のカウンタ(count)を初期化
        #  ※初期値が0の場合は省略可
        BEGIN { count = 0 }
        #👇①正規表現による集計条件(2,3列目混合)
        $2 ~ /'$option'/ || $3 ~ /'$option'/ {
            #👇avrgという配列に数値を格納&カウンタを1つ加算
            avrg[count++] = $4;
        }
        #👇平均などの計算はEND内で配列の中身で扱う
        END {
            result = 0;
            for (i = 0; i < count; i++ ) { result += avrg[i] }
            result = count > 0 ? result / count : 0;
            print "\n  '$option' (" count "人)の平均値 : " result " 円";
        }
    '
}

#👇対話型で操作を選択的に使う
function Addup() {
    local option
    printf "集計したい部署を以下 1/2/3/4 から選択してください\n"
    printf "\n  1) 営業部  2) 経理部  3) 製造部  4) 海外部"
    printf "\n  5) 本社    6) 名古屋  7) 山口    8) ベトナム  9) メキシコ\n\n"
    printf '※ 終了は q  か c を入力!\n>>>'
    read OPT
    case "$OPT" in
        [1-9]* ) Average $OPT $1; option=$OPT;;
        q | c ) echo "終了"; exit 0;;
        * ) printf "ヒント... 1から9 で入力!\n\n"; Addup $1;;
    esac
    [ -n "$option" ] && exit 1
}

Addup $1
        
このスクリプトをaverage_tool.shという名前で保存し、以下のように実行すると、

            
            $ chmod +x average_tool.sh
$ ./average_tool.sh expenses.csv
集計したい部署を以下 1/2/3/4 から選択してください

  1) 営業部  2) 経理部  3) 製造部  4) 海外部
  5) 本社    6) 名古屋  7) 山口    8) ベトナム  9) メキシコ

※ 終了は q  か c を入力!
>>>1

  営業部 (5人)の平均値 : 25235.8 円
        
というように期待通りに各キーワードごとの平均値を確認することができます。

CSVデータをシェルコマンドで平均などの計算を行うために良く理解すべき点は、先程のスクリプトでいうと自作したAverage関数内の①でマークしていた箇所の条件ブロックの使い方です。

このブロックで抜き取った配列のデータを最終的にENDブロックで色々と料理する、というプログラミングスタイルに慣れれば、平均だけなくもっと複数な算術処理も可能になります。

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。