【シェルと遊ぼう】日本のコロナ感染者情報取得スクリプト その4(指定列項目の内訳集計)

はじめに

こちらの記事の続き。

作るもの

今回は指定列の条件でフィルタリング処理について。

  1. データベースの作成・更新と全行全項目の出力
  2. 全感染者の指定項目を取得 (列の抽出,並べ替え)
  3. 指定項目の条件でフィルタ (行の抽出)
  4. 指定項目の内訳集計 (出現回数のカウント)    <== 今回はこれ

以降では、前回同様作るスクリプト名をcovidとした前提で説明する。

実行イメージ

使い方と出力は以下みたいな感じ。

指定列項目の値と、その値の出現回数をカンマ区切りで出力する。
最終行の':TOTAL'は総数を算出して追加で出力している。
ご覧の通り、ソートは無し。外部プログラムにお任せ。

$ covid -f age          # 年代別内訳
70,1541
40,2535
90,480
不明,342
10,365
60,1803
100,10
30,2368
80,1104
50,2656
0,256
20,2594
:TOTAL,16054

-mオプションと併用できますとも。

$ covid -f area1 -m 'age<10'     # 10歳未満の感染者の受診都道府県別内訳
香川県,3
宮城県,6
新潟県,3
福島県,2
石川県,3
東京都,66
山形県,2
奈良県,3
愛媛県,2
京都府,4
北海道,14
長野県,2
三重県,4
不明,1
秋田県,1
富山県,7
群馬県,1
茨城県,2
福岡県,14
島根県,3
岐阜県,4
兵庫県,10
千葉県,7
高知県,4
山口県,1
静岡県,4
神奈川県,15
山梨県,2
埼玉県,13
愛知県,15
和歌山県,1
大阪府,30
福井県,2
滋賀県,5
:TOTAL,256

列項目について

前回も載せたけど、指定可能な列項目は以下。

項目 パラメータ 備考 出力例
ID id データの通し番号。元データの「通し」 1/2/3...
確定日 date PCR検査の陽性確定日 '2020/05/13'など
受診都道府県 area1 陽性確定時に感染者が受診していた医療機関がある都道府県。空港名もある... 東京都/沖縄県/不明など
居住地 area2 感染者の住居都道府県または居住国 東京都/沖縄県/不明など
居住地(詳細) area3 元データ項目では「キー」。居住都道府県と同じデータも多数 東京都/沖縄県那覇市/不明など
年代 age 感染者の年代。元データは100歳以上も90に含むっぽい 0/10/20/30/40/50/60/70/80/90/100/不明
性別 sex 感染者の性別 男性/女性/不明
職業 job 感染者の職業。記載がある件数が少なく同職種でも記載に統一感なし... 会社員/看護師/無職/不明(#1)など
備考 note 詳細地区や年齢やその他補足情報っぽい 足立区/100歳以上/再陽性
状態 sts 感染者の状態。元データの「ステータス」と「無症状病原体保有者」の組み合わせ 死亡/退院/退院または死亡(国内無症状)/空欄

年代については元データをスクリプトで以下のように加工して出力する。

元データ 出力 備考
0-10 0 10歳未満
90 100 備考に「100歳以上」と記載がある場合のみ
空欄 不明

コード

列内の集計に関する主要コードは以下。
コード全体はこちらを参照されたし。

引数処理

受け取った引数を変数に入れておく。

CNT_IN_FIELD=
# 〜中略〜
while getopts cf:hm:tuV OPT
do
  case $OPT in
    # 〜中略〜
    f ) CNT_IN_FIELD=$OPTARG ;;
    # 〜中略〜
  esac
done

この記事を書いてて気付いた。
この引数の項目名が正しいかチェックしてない。
なんてこった。

列項目名から列位置への置き換えと出力

下のコードで内訳集計結果を出力している。

まず、項目名からawkの列位置へ置き換えておく。

そして、ヘッダ行を削ったDBファイルのデータをawkに渡す。
awkでは、出てきた項目を配列のキーに登録して、同じキーをカウントしていく。

全行カウントが終わったら、全キーのカウント数と合計数を出力。

if [ -n "$CNT_IN_FIELD" ]; then
  CNT_IN_FIELD=`echo $CNT_IN_FIELD | $NAME_TO_POS`
  # output count each of field
  cat "$DB_FILE"    \
    | sed '1d'      \
    | awk -F"," '
      BEGIN{ OFS="," }
      '"$PICKUP_COND"'{
        count['$CNT_IN_FIELD']++
      }
      END{
        total=0
        for (field in count) {
          print field,count[field]
          total+=count[field]
        }
        print ":TOTAL",total
      }'

ちなみに、$NAME_TO_POSには出力する列項目で使っていた怠い関数が入っている。

item_name_to_pos(){
  sed -e 's/id/$1/g'    \
    -e 's/date/$2/g'    \
    -e 's/area1/$3/g'   \
    -e 's/area2/$4/g'   \
    -e 's/area3/$5/g'   \
    -e 's/age/$6/g'     \
    -e 's/sex/$7/g'     \
    -e 's/job/$8/g'     \
    -e 's/note/$9/g'    \
    -e 's/sts/$10/g'
}

もっと面倒になるかと思ったけれども、やっぱりawkスゴイ。

さいごに

最初の記事に書いたのだけども、元データのCSVの「ステータス」列は空欄が多い。
その為、今回のオプションを利用して退院数や死亡者数などを集計するのは無理だった。
数値が全く合わない。

元データのサイトさんはどうやって集計しているのかというと、
死亡者数や退院者数は別の列として用意している。
そして、出現する確定日の最終行にのみ国が公表した数値を入れてるっぽい。
以下のようなイメージ。

確定日,・・・,死亡者数累計,退院累計,・・・
 ...
2020/5/13,・・・,,,・・・
2020/5/13,・・・,,,・・・
2020/5/13,・・・,,,・・・
2020/5/13,・・・,668,20,・・・
2020/5/14,・・・,,,・・・
2020/5/14,・・・,,,・・・
2020/5/14,・・・,687,10338,・・・
2020/5/15,・・・,,,・・・
 ...

仕方がないので、これを利用して確定日別の集計表を作成しよう。

というのはまた次回。

確認環境

PC Thinkpad X1 Carbon 2nd Gen
OS FreeBSD 12.1-RELEASE-p4

参考