アメダスから出てきた(らしい)データを成形してみた話

*注意* この記事はQiitaに上げられるほどの信頼性を有していないことからエピソードトークとしてnoteに上がっています
シェルスクリプトを使う準備は別で書いてます(末尾参照)

イントロ

所用で北陸三県の気温をいじる必要があったので見てみたら、10個くらいの項目がスペースで区切られたテキストで、その量は200万行overである。なんでテキストで100MB超えてるんだよ。

幸いにもテキストファイルのいなし方は最近分かってきたところ。
そう、シェルスクリプトの出番である。
とりあえず今回の戦略はこうだ。地域ごとにファイルを分割して、必要な項目だけ取り出して.csvにする。そしたらとりあえずエクセルかなんかで読めるだろう。 

1.ファイルを地域ごとに切り分ける

43999 20220832 0620 0.0 0 SE 0 1.0 0 31.2 0 22385 56
↑これは実際のデータのように見えるように作ったサンプル
こんなんが200万行ちょい続いてる。
今回はこの太字部分だけほしい

データの一列目には観測所の番号が格納されている。
55102→富山
56227→金沢
57066→福井

catとかmoreとかよくわからないのでChatGPTに一行ずつ出力する部分は書いてもらった。

#!/bin/bash

echo "filename?"
read -r origin

filename="$origin"
# ここと

while IFS= read -r line; do
# ここと

if [[ $line == 55102* ]]; then #ここと 
#  echo $lineと
  echo $line >> prm_toyama.txt

elif [[ $line == 57066* ]]; then
  echo $line >> prm_fukui.txt

else
  echo $line >> prm_kanazawa.txt
fi

done < "$filename"
# ここは書いてもらった

echo "OK!"

exit

正規表現は素晴らしい解説がすぐ見つかると思うので割愛しつつ、処理の流れとしてはChatGPTに書いてもらった部分で元テキスト.txtを一行ずつ処理に流している。
if, elif, elseで55102から始まる行なら富山、57066から始まれば福井、それ以外は金沢だと判別して、
それぞれをechoでprm_toyama.txt, prm_fukui.txt, prm_kanazawa.txtに書き込む。
スクリプト名はkodomoshiawase(元ネタわかったら教えてね)。
実行すると聞かれるんでファイル名入れてエンター。OK! って出たらOK

$ ./kodomoshiawase
filename?
(入力) <元ファイル.txt>

2.日時と気温だけ抽出する

分けたデータの列構成は変わっていないから、引き続き2列目に年月日、3行目に時分、10行目に気温が格納されている。
スクリプト名はametasにした。

#!/bin/bash

read prm

filename="$prm"

while IFS=' ' read -r line; do
  fields=($line)

  if [ ${#fields[@]} -ge 10 ]; then
    echo "${fields[1]}${fields[2]},${fields[9]}" #このへんはちょっとわかる 
  fi

done < "$filename"
exit

さっきChatGPTに書いてもらったやつを流用して一行ずつ処理していく。
どうやらスペース区切りごとに番号を振ってくれているらしい。
どうやら{fields[n]}という変数のような何かを展開するとn番目の要素が出てくるらしい。ただし人間様の1行目はBash様の0行目にあたるので注意。
てことで[1]と[2]と[9]をechoで出力している。
さらに、しれっと[2](時刻)と[9](気温)の間にコンマを差し込んでcsvファイルにしてみた。

今回からは何も聞かれないしOKも言われないので注意。>より後ろのファイル名は↓を対応するものを一つづつ入力する。
adv_toyama.csv, adv_kanazawa.csv, adv_fukui.csvができた。

$ ./ametas > adv_toyama.csv
(入力) prm_toyama.txt

$ ./ametus > adv_kanazawa.csv
(入力) prm_kanazawa.csv

$ ./ametus > adv_fukui.csv
(入力) prm_fukui.txt

3.一応、日付を山田 HH:MMにしておく

adv_で何とかなりそうな気もするけど一応。
スクリプト名はhyphen

#!/bin/bash

read adv
filename="$adv"

while IFS= read -r output_eine; do

    output_string="${output_eine:0:4}-${output_eine:4:2}-${output_eine:6:2}>    echo "$output_string"

done < "$filename"

exit

またまたさっきので一行づつ読みながらハイフンとかを足す。
一行づつoutput_eine変数に代入して、
よくわからないが{output_eine:p:q}を展開するとp文字目からq文字だけ吐き出してくれるらしい。人間様の1文字目はBashさんの0文字目であることに注意。
吐き出してる隙間に-ハイフンとか スペースとか:コロンとかをこっそり忍ばせてyyyy-mm-dd HH:MMに成形して出力する。
さっきと似た操作だなあ。

$ ./hyphen > toyama.csv
(入力) adv_toyama.csv

$ ./hyphen > kanazawa.csv
(入力) adv_kanazawa.csv

$ ./hyphen > fukui.csv
(入力) adv_fukui.csv

202307071752,28.5 (<adv_地名,csv>)
2023-07-07 17:52,28.5 (<地名.csv>)
完成品はこんな感じのがそれぞれ60万行くらい続いてる

4. 試しにExcelでグラフにする

おかしい、Excelで読むと毎日24:00の行だけ日時が五桁整数になっている。
試しに24:00を00:00に置換したら、、、いけた。」

$ cat toyama.csv | sed 's/24:00/00:00/g' > go_toyama.csv

これを各ファイルにやる。
もしくはhyphenのechoにパイプしてもいいかも。

これでいいのかわからない。読み込んだが重いのなんの。
とりあえず範囲指定して折れ線グラフを挿入。できるだけ引きでグラフを拡大するとなんとかグラフっぽくなった。


これでいいのか、、、?

おそらく三都市分いっぺんに読み込んだら比較できるよねと思う。とりあえず、グラフは見れたのでいったん良しとしませう。

(末尾)そのコマンド?みたいなのはどうやるんだよ

Windows11だったらWSLがいいかと思います
WSLは「Windows Subsystem for Linux」の略で、Windows上でLinuxを動かすための機能です。
WSLでUbuntuのインストール方法、みたいにChatGPTに聞いてみてください。

Macの方はターミナルから、どうぞ。


ツッコミ対応コーナー

Q.わけわからん変数に一回代入してから吐いたりとかcatパイプとかそんなんしてるからシェルスクリプトは遅いんだよRust使え。
A.部分的にわかる。
 どうしたら早くなるかまで調べる余裕も切迫した必要性も今回はなかった。これからがんばります。
 ただ、wsl入れるだけでスパッと使えて文法もテキスト加工やるのに助かる感じなんでシェルスクリプトが今回は総合的に最速なんじゃないかな、と思う。しらんけど

Q.文字列いじるだけなんだからコマンド1つにまとめろよ
A.わからなくもない
 けど書きながらターミナルに吐き出して確認とかが楽しいしカスタマイズしやすいからできるだけ単機能コマンドの組み合わせになるようにしてる。
 あとPOSIX中心主義にそんなんあったよね
 過度な対話形式??知らん!

この記事が気に入ったらサポートをしてみませんか?