ワンライナーで少子化を体感しよう
TRANSCRIPT
スキルウェンズデーワンライナーで少子化を体感しよう
CyberZ 長尾 和真
自己紹介• 名前:長尾 和真• 言語: java• 趣味:ニコ動、カラオケ、飲み会• 好きな本:「嫌われる勇気」、「何者」
大学では何をやってたの?• 専攻:経済学• 研究室:人口論高齢化、少子化、過疎化、貧困、女性の地位、平均寿命、生涯未婚率、離婚率、出生率、死亡率、人口増加… etc
大学では何をやってたの?• 専攻:経済学• 研究室:人口論高齢化、少子化、過疎化、貧困、女性の地位、平均寿命、生涯未婚率、離婚率、出生率、死亡率、人口増加… etc
本題日本の出生率をワンライナーで計算してみましょう!
Excel でやったほうがいい
予備知識少子化合計特殊出生率が長期間に渡って 2.1 を大きく下回ること 合計特殊出生率1 人の女性が 15 歳から 49 歳までの間に何人子供を生んでいるかという水準を表す数値
n 歳の女性産んだ子供の数n 歳の女性の数Σ
n=15
45
使うコマンド一覧cat – ファイルの出力cut – フィールド単位で切り出すtr – 区切り文字の整形、特定の文字列の削除grep – 該当箇所の抽出awk – データの抽出・集計join – データの結合
cut コマンド特定のデータを切り出すコマンド今回使うオプション -d 区切り文字を指定する -f 切り出すフィールドを指定する (-c 切り出す文字のインデックスを指定する )
cut コマンド 例
tr コマンド• 文字置換、 文字削除、連続した文字を潰す今回使うオプション -d 特定の文字を消去する -s 特定の連続した文字を押しつぶす
tr コマンド例
grep コマンド行単位で検索を行うコマンド• 今回使うオプション -E 正規表現で検索する
awk コマンド行単位で様々な処理を行うコマンド
処理を行う条件 { 何か処理 } が基本 『 { } 』の中はわりと自由に書ける- 各フィールドは ${number} で参照可能 - 連想配列- for, if ,while- 便利な組み込み関数 ( gsub, toupper, substr
etc)
awk コマンド例行単位で様々な処理をするコマンド
$1 $2 $3
$0
組み込み変数NF
NR
処理している行のフィールド数処理している行番号
join コマンド2 つのファイルを結合するコマンド今回使うオプション -t 列の区切り文字を指定 -j 2 つのファイルを結合する列を指定 -1 1 つ目のファイルの結合に使う列を指定 -2 2 つ目のファイルの結合に使う列を指定
join コマンド例
方針• 総務省・厚生労働省から統計データ (Excel)をダウンロードする• txt ファイルに copy & paste ( ここまで
DONE)( women.txt, children.txt に保存してある想定 )
• コマンドを組み合わせてほしいデータを抽出• awk で計算する
理想型のデータ構造年齢別に見た女性の数( 年代 ) (15-19 歳の女性の数 ) (20-24 歳の女性の数 ) … (45-49 の女性の数 )
例1995 4172183 4853773 4336016 4012606 3876412 4478720 52900312000 3654181 4114218 4825032 4339792 4018579 3876048 44482362005 3194950 3595776 4081498 4821592 4332994 4015126 38583612010 2954128 3160193 3601978 4120486 4836227 4341490 4005147
母親の年齢別に見た出生数( 年代 ) (15-19 歳の母親が産んだ子供の数 ) (20-24) … (45-49 の母親が産んだ子供の数 )
1995 16112 193514 492714 371773 100053 12472 4142000 19772 161361 470833 396901 126409 14848 4022005 16573 128135 339328 404700 153440 19750 5982010 13546 110956 306910 384385 220101 34609 792
例
理想型のデータ構造=> 2 つのファイルを join コマンドで結合!
( 年代 ) (15-19 歳の女性の数 ) … (45-49 の女性の数 ) (15-19 歳の出産数 ) … (45-49 歳の出産数 )1995 4172183 ... 5290031 16112 … 4142000 3654181 ... 4448236 19772 ... 4022005 3194950 ... 3858361 16573 ... 5982010 2954128 ... 4005147 13546 ... 792
=> 1 行にまとめて awk で計算!
整形
とりあえず grep してみる
整形
ちょっとすっきり次は・西暦を切り出したい・年齢と女性の人口の部分を切り出したい (cut コマンド )
西暦の部分のフィールドを年齢の部分を合わせたい cut –d” ” –f1,2,5 で切り抜きたい 整形が必要 ( スペース数 )- 赤をフィールド 1,- 青をフィールド 2, - オレンジをフィール 5 に
整形
西暦を出して「〜」をスペースに変換
このままだとスペースが重なっているため、 cut コマンドでどのフィールドを切り出すべきか分かりづらい=> スペースの重なりをなくして、赤が field1 になるように
整形
大分すっきり欲しい部分が大分みえてきました
cut コマンドを走らせましょう!
整形
だいぶすっきりしかし、ファイルの下には注意書きなどいらない文字列がある=> なくすために grep で整形数字で始まり、「 ) 」 を含まないものを抽出すればよさそう同時に 「 , 」も取り除きましょう grep と tr でいける!
整形
かなり整ってきました次は該当年齢と西暦のみを抽出していきます。- 西暦と年齢の両方を出力- 今までと違って数字 ( 年齢 ) の大小を比較する必要がawk でいけそう- フィールドが 2 つ以下の場合 { フィールド 1 を出力 }- フィールドが 2 つより多い場合 && フィールド 2が 19以上 49 未満のとき { フィールド 3 を出力 }
みたいなやってみましょう
整形
必要なデータが取り出せました!!しかし困りましたあとは join するために年号 (15-19 の女性人口 ) … (45−49 の女性人口 )という形にしなければいけない。。 西暦を西暦とわかるように何かしらの文字を残しておけば tr コマンドでいけそうですね!やってみましょう
整形
西暦の前に「 _ 」を仕込んでおいてtr で改行をスペースに変換(全てスペース区切りで一行になる )tr で「 _ 」を改行に変換 年号ごとに改行される!というわけで女性の人数は出せましたね!
整形
同じようにして子供の人数を抽出します(雑) 女性のデータ : num_w.txt子供のデータ : num_c.txt
join していきます
join
西暦 女性の数 子供の数
女性の数の 7 つ後ろのフィールドに対応する子供の数がある= $i と $(i+7) で計算できる
awk で計算
でました!
でましたね!!
・・・あれ でも ワンライナーじゃなくない?
bash のプロセス置換機能を利用するコマンドを入力対象として利用出来るつまりこんな感じjoin -j1 –t” “ < ( 女性の算出コマンド ) <( 子供の算出コマンド ) | awk ‘{ 計算 }’
ワンライナーでできないこともない!
最終的なコマンド join -t " " -j1 <(cat women.txt | grep -E "〜 | 年 " | tr " 年 " "\n" | tr "〜 " " " | tr -s " " | cut -d" " -f2- | cut -d" " -f1,2,5 | grep -E "^[0-9][^\)]+"| tr -d "," | awk 'NF<=2{print "_"$1} NF>2&&$2>=19&&$2<=49{print $3}' | tr "\n" " " | tr "_" "\n") <(cat children.txt | tr -s " " | tr -d "," | awk '$3>1000000{print}' | cut -d " " -f2-10 | grep -E ^[0-9]{4} | cut -d" " -f1,3-) | awk '{ tfr = 0; for ( i = 2; i < 2 + 7; i++ ) { tfr += $(i+7) * 5 / $i; } print $1,tfr; }’
可読性のかけらもないですね
ご清聴ありがとうございました
参考文献