固定長データをPythonで頑張ってカンマ区切りにする(震源レコード編)その1
気象庁一元化震源データをカンマ区切りにする方法を模索しています
気象庁|震源レコードフォーマット
気象庁が提供するページです
前回作成したスクリプトは、バグまみれ…と言いますか可読性が悪かったです。
そして今や、Github Copilotという相棒もいますので、スクリプトを書き直してみました。
とはいえ、この記事は試行錯誤中の段階かつナンセンスなコードです。自己責任でお願いします。
目的(再掲載)
- 固定長データは扱いずらい
- どうにかCSVに持っていきたい
- というか気象庁は公式でUSGSみたいにカンマ区切りに早くしてほしい。
おことわり
震源を決定するにあたっての初期条件等
不明の場合は空白
1: 深さフリー
2: 深さ刻み条件(深さを一定の幅で変化させて計算)で最適解を求めた
3: 深さ固定等、人の判断による
4: Depth Phaseを用いた
5: S-Pを用いた
7: 参考(2016年3月まで)
8: 決定不能または不採用
9: 震源固定(最も早い相の情報を検測した観測点の緯度、経度)
M: Matched Filter法を用いた
変換する際に立ちはだかる「震源評価」ですが、これが9だと面倒なことになるのは前にも書きましたが、7でも面倒なことが分かったので、今回は、1,2,3,Mのみを対象として変換することとします。
また、USGS決定の地震(1文字目がUの地震)は面倒なので省きます)
分割プロセス
以下のことに気を付けて分割します。
- 深さフリー・Matched Filterは深さはF4.2(小数含む)
- 深さ刻み・固定はI3(整数のみ)
- マグニチュードの1桁目が数値でない("-"や"A")時点で、負のマグニチュードになる
というわけで、場合分けのオンパレードです。
固定長を分割
これは前回と同じです
import pandas as pd
input = "./h2022"
colspecs = [(0,1),(1,5),(5,7),(7,9),(9,11),(11,13),(13,17),(17,21),(21,24),(24,28),(28,32),(32,36),(36,40),(40,44),(44,49),(49,52),(52,53),(53,54), (54,55),(55,57),(57,58),(58,59),(59,60),(60,61),(61,62),(62,63),(63,64),(64,65),(65,68),(68,92),(92,95),(95,96)]
df = pd.read_fwf(input, colspecs=colspecs, header=None)
深さ条件の場合分け
場合分けの一発目です。愚直にやりましょう。
# 1列目がJかつ、深さフリーのデータを抽出
df_temp = df[(df[0]=='J')]
df_hypofree = df_temp[(df_temp[22]=="1") | (df_temp[22]=="M")]
# 1列目がJかつ、深さ刻みまたは固定のデータを抽出
df_depthkotei = df_temp[(df_temp[22]=="2") | (df_temp[22]=="3")]
深さフリーの分割
愚直に…。
発震時・緯度・経度の分割
# df_hypofreeの処理
# 発震時の整理 -> 7列目に0.01を掛ける
df_hypofree[6] = df_hypofree[6] * 0.01
# 緯度の整理 -> 10列目の値に0.01を掛けて60で除算する
df_hypofree[9] = df_hypofree[9] * 0.01 / 60
# 8列目をfloat型に変換
df_hypofree[8] = df_hypofree[8].astype(float)
# 8列目の値に9列目の値を加える。
df_hypofree[8] = df_hypofree[8] + df_hypofree[9]
# 9列目を削除
df_hypofree = df_hypofree.drop(9, axis=1)
# 経度の整理 -> 13列目の値に0.01を掛けて60で除算する
df_hypofree[12] = df_hypofree[12] * 0.01 / 60
# 12列目をfloat型に変換
df_hypofree[11] = df_hypofree[11].astype(float)
# 12列目の値に13列目の値を加える。
df_hypofree[11] = df_hypofree[11] + df_hypofree[12]
# 13列目を削除
df_hypofree = df_hypofree.drop(12, axis=1)
# 深さの整理
# 15列目の値に0.01を掛ける
df_hypofree[14] = df_hypofree[14] * 0.01
マグニチュードの場合分け
17列目が"-"だったり"A"である場合は隔離して置換します。
長いですが、やってることは大したことではないです。
# マグニチュードの整理
# 17列目が"-"もしくは"A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"のいずれかでない行を抽出 -> df_hypofree_positive
df_hypofree_positive = df_hypofree[~df_hypofree[16].isin(['-', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'])]
# 16行目に17行目の値を加える
df_hypofree_positive[17] = df_hypofree_positive[17] * 0.1
df_hypofree_positive[16] = df_hypofree_positive[16].astype(float)
df_hypofree_positive[16] = df_hypofree_positive[16] + df_hypofree_positive[17]
# 17行目を削除
df_hypofree_positive = df_hypofree_positive.drop(17, axis=1)
# 17列目が"-"もしくは"A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"のいずれかである行を抽出 -> df_hypofree_negative
df_hypofree_negative = df_hypofree[df_hypofree[16].isin(['-', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'])]
# 17列目の値に-1を掛ける
df_hypofree_negative[17] = df_hypofree_negative[17].astype(float)
df_hypofree_negative[17] = df_hypofree_negative[17] * -0.1
# 16列目が"-"の場合、16列目を0にする
df_hypofree_negative.loc[df_hypofree_negative[16] == '-', 16] = 0
# 16列目がAの場合、16列目を-1にする。Bの場合は-2にする。Zの場合は-26にする。(E以降は省略)
df_hypofree_negative.loc[df_hypofree_negative[16] == 'A', 16] = -1
df_hypofree_negative.loc[df_hypofree_negative[16] == 'B', 16] = -2
df_hypofree_negative.loc[df_hypofree_negative[16] == 'C', 16] = -3
df_hypofree_negative.loc[df_hypofree_negative[16] == 'D', 16] = -4
# 16列目の値に17列目の値を加える
df_hypofree_negative[16] = df_hypofree_negative[16] + df_hypofree_negative[17]
# 17列目を削除
df_hypofree_negative = df_hypofree_negative.drop(17, axis=1)
深さ刻み・深さ固定の分割
実は上記が完成していれば、意識するのは震源の深さだけです。
# df_depthkoteiの処理
# 発震時の整理
# 7列目に0.01を掛ける
df_depthkotei[6] = df_depthkotei[6] * 0.01
# 緯度の整理
# 10列目の値に0.01を掛ける
df_depthkotei[9] = df_depthkotei[9] * 0.01 / 60
# 8列目をfloat型に変換
df_depthkotei[8] = df_depthkotei[8].astype(float)
# 8列目の値に9列目の値を加える。
df_depthkotei[8] = df_depthkotei[8] + df_depthkotei[9]
# 9列目を削除
df_depthkotei = df_depthkotei.drop(9, axis=1)
# 経度の整理
# 13列目の値に0.01を掛ける
df_depthkotei[12] = df_depthkotei[12] * 0.01 / 60
# 12列目をfloat型に変換
df_depthkotei[11] = df_depthkotei[11].astype(float)
# 12列目の値に13列目の値を加える。
df_depthkotei[11] = df_depthkotei[11] + df_depthkotei[12]
# 13列目を削除
df_depthkotei = df_depthkotei.drop(12, axis=1)
# **深さの整理はしない**(整数なので)
# マグニチュードの整理
# 17列目が"-"もしくは"A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"のいずれかでない行を抽出 -> df_depthkotei_positive
df_depthkotei_positive = df_depthkotei[~df_depthkotei[16].isin(['-', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y','Z'])]
# 16行目に17行目の値を加える
df_depthkotei_positive[17] = df_depthkotei_positive[17] * 0.1
df_depthkotei_positive[16] = df_depthkotei_positive[16].astype(float)
df_depthkotei_positive[16] = df_depthkotei_positive[16] + df_depthkotei_positive[17]
# 17行目を削除
df_depthkotei_positive = df_depthkotei_positive.drop(17, axis=1)
# 23列目が1以外の行を抽出 -> df_depthkotei_positive_unnatural
df_depthkotei_positive_unnatural = df_depthkotei_positive[df_depthkotei_positive[23]!="1"]
df_depthkotei_positive_unnatural = df_depthkotei_positive_unnatural.round(4)
df_depthkotei_positive_unnatural.to_csv('./df_depthkotei_positive_unnatural.csv')
# 17列目が"-"もしくは"A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"のいずれかである行を抽出 -> df_depthkotei_negative
df_depthkotei_negative = df_depthkotei[df_depthkotei[16].isin(['-', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O','P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y','Z'])]
# 17列目の値に-1を掛ける
df_depthkotei_negative[17] = df_depthkotei_negative[17].astype(float)
df_depthkotei_negative[17] = df_depthkotei_negative[17] * -0.1
# 16列目が"-"の場合、16列目を0にする
df_depthkotei_negative.loc[df_depthkotei_negative[16] == '-', 16] = 0
# 16列目がAの場合、16列目を-1にする。Bの場合は-2にする。Zの場合は-26にする。(E以降は省略)
df_depthkotei_negative.loc[df_depthkotei_negative[16] == 'A', 16] = -1
df_depthkotei_negative.loc[df_depthkotei_negative[16] == 'B', 16] = -2
df_depthkotei_negative.loc[df_depthkotei_negative[16] == 'C', 16] = -3
df_depthkotei_negative.loc[df_depthkotei_negative[16] == 'D', 16] = -4
# 16列目の値に17列目の値を加える
df_depthkotei_negative[16] = df_depthkotei_negative[16].astype(float)
df_depthkotei_negative[16] = df_depthkotei_negative[16] + df_depthkotei_negative[17]
# 17列目を削除
df_depthkotei_negative = df_depthkotei_negative.drop(17, axis=1)
# df_depthkotei_positiveとdf_depthkotei_negativeを結合
df_depthkotei_result = pd.concat([df_depthkotei_positive, df_depthkotei_negative])
まとめ
あとはconcatなどで、がっちゃんこすれば終わりです。
import pandas as pd
import sys
def main():
# 引数にファイル名を指定
input = sys.argv[1]
# ファイルを読み込む
colspecs = [(0,1),(1,5),(5,7),(7,9),(9,11),(11,13),(13,17),(17,21),(21,24),(24,28),(28,32),(32,36),(36,40),(40,44),(44,49),(49,52),(52,53),(53,54), (54,55),(55,57),(57,58),(58,59),(59,60),(60,61),(61,62),(62,63),(63,64),(64,65),(65,68),(68,92),(92,95),(95,96)]
df = pd.read_fwf(input, colspecs=colspecs, header=None)
# 1列目がJかつ、震源固定ではない・深さフリーのデータを抽出
df_temp = df[(df[0]=='J')]
# df_temp[22]をString型に変換
df_temp[22] = df_temp[22].astype(str)
df_hypofree = df_temp[(df_temp[22]=="1") | (df_temp[22]=="M")]
# 1列目がJかつ、震源固定ではない・深さ刻みまたは固定のデータを抽出
df_depthkotei = df_temp[(df_temp[22]=="2") | (df_temp[22]=="3")]
#
# df_hypofreeの処理
# 発震時の整理
# 7列目に0.01を掛ける
df_hypofree[6] = df_hypofree[6] * 0.01
# 緯度の整理
# 10列目の値に0.01を掛ける
df_hypofree[9] = df_hypofree[9] * 0.01 / 60
# 8列目をfloat型に変換
df_hypofree[8] = df_hypofree[8].astype(float)
# 8列目の値に9列目の値を加える。
df_hypofree[8] = df_hypofree[8] + df_hypofree[9]
# 9列目を削除
df_hypofree = df_hypofree.drop(9, axis=1)
# 経度の整理
# 13列目の値に0.01を掛ける
df_hypofree[12] = df_hypofree[12] * 0.01 / 60
# 12列目をfloat型に変換
df_hypofree[11] = df_hypofree[11].astype(float)
# 12列目の値に13列目の値を加える。
df_hypofree[11] = df_hypofree[11] + df_hypofree[12]
# 13列目を削除
df_hypofree = df_hypofree.drop(12, axis=1)
# 深さの整理
# 15列目の値に0.01を掛ける
df_hypofree[14] = df_hypofree[14] * 0.01
# マグニチュードの整理
# 17列目が"-"もしくは"A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"のいずれかでない行を抽出 -> df_hypofree_positive
df_hypofree_positive = df_hypofree[~df_hypofree[16].isin(['-', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'])]
# 16行目に17行目の値を加える
df_hypofree_positive[17] = df_hypofree_positive[17] * 0.1
df_hypofree_positive[16] = df_hypofree_positive[16].astype(float)
df_hypofree_positive[16] = df_hypofree_positive[16] + df_hypofree_positive[17]
# 17行目を削除
df_hypofree_positive = df_hypofree_positive.drop(17, axis=1)
# 17列目が"-"もしくは"A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"のいずれかである行を抽出 -> df_hypofree_negative
df_hypofree_negative = df_hypofree[df_hypofree[16].isin(['-', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'])]
# 17列目の値に-1を掛ける
df_hypofree_negative[17] = df_hypofree_negative[17].astype(float)
df_hypofree_negative[17] = df_hypofree_negative[17] * -0.1
# 16列目が"-"の場合、16列目を0にする
df_hypofree_negative.loc[df_hypofree_negative[16] == '-', 16] = 0
# 16列目がAの場合、16列目を-1にする。Bの場合は-2にする。Zの場合は-26にする。(E以降は省略)
df_hypofree_negative.loc[df_hypofree_negative[16] == 'A', 16] = -1
df_hypofree_negative.loc[df_hypofree_negative[16] == 'B', 16] = -2
df_hypofree_negative.loc[df_hypofree_negative[16] == 'C', 16] = -3
df_hypofree_negative.loc[df_hypofree_negative[16] == 'D', 16] = -4
# 16列目の値に17列目の値を加える
df_hypofree_negative[16] = df_hypofree_negative[16] + df_hypofree_negative[17]
# 17列目を削除
df_hypofree_negative = df_hypofree_negative.drop(17, axis=1)
# df_hypofree_positiveとdf_hypofree_negativeを結合
df_hypofree_result = pd.concat([df_hypofree_positive, df_hypofree_negative])
names = ['recode','year','month','day','hour','minute','second','time_SE_x','latitude','lat_SD_x','longitude','lon_SD_x','depth','dep_SD_x','mag1','mag1_type','mag2_x','mag2_type_x','used_traveltime','hypo_judge','hypo_type','max_coefficient','scale_victim','tsunami_victim','region_main','region_sub','hypo_locale','obs_number','determination_way']
df_hypofree_result.columns = names
df_hypofree_result = df_hypofree_result.round(4)
df_hypofree_result.to_csv('./df_hypofree_result.csv',index=False)
#
# df_depthkoteiの処理
# 発震時の整理
# 7列目に0.01を掛ける
df_depthkotei[6] = df_depthkotei[6] * 0.01
# 緯度の整理
# 10列目の値に0.01を掛ける
df_depthkotei[9] = df_depthkotei[9] * 0.01 / 60
# 8列目をfloat型に変換
df_depthkotei[8] = df_depthkotei[8].astype(float)
# 8列目の値に9列目の値を加える。
df_depthkotei[8] = df_depthkotei[8] + df_depthkotei[9]
# 9列目を削除
df_depthkotei = df_depthkotei.drop(9, axis=1)
# 経度の整理
# 13列目の値に0.01を掛ける
df_depthkotei[12] = df_depthkotei[12] * 0.01 / 60
# 12列目をfloat型に変換
df_depthkotei[11] = df_depthkotei[11].astype(float)
# 12列目の値に13列目の値を加える。
df_depthkotei[11] = df_depthkotei[11] + df_depthkotei[12]
# 13列目を削除
df_depthkotei = df_depthkotei.drop(12, axis=1)
# 深さの整理はしない(整数なので)
# マグニチュードの整理
# 17列目が"-"もしくは"A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"のいずれかでない行を抽出 -> df_depthkotei_positive
df_depthkotei_positive = df_depthkotei[~df_depthkotei[16].isin(['-', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y','Z'])]
# 16行目に17行目の値を加える
df_depthkotei_positive[17] = df_depthkotei_positive[17] * 0.1
df_depthkotei_positive[16] = df_depthkotei_positive[16].astype(float)
df_depthkotei_positive[16] = df_depthkotei_positive[16] + df_depthkotei_positive[17]
# 17行目を削除
df_depthkotei_positive = df_depthkotei_positive.drop(17, axis=1)
# 17列目が"-"もしくは"A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"のいずれかである行を抽出 -> df_depthkotei_negative
df_depthkotei_negative = df_depthkotei[df_depthkotei[16].isin(['-', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O','P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y','Z'])]
# 17列目の値に-1を掛ける
df_depthkotei_negative[17] = df_depthkotei_negative[17].astype(float)
df_depthkotei_negative[17] = df_depthkotei_negative[17] * -0.1
# 16列目が"-"の場合、16列目を0にする
df_depthkotei_negative.loc[df_depthkotei_negative[16] == '-', 16] = 0
# 16列目がAの場合、16列目を-1にする。Bの場合は-2にする。Zの場合は-26にする。(E以降は省略)
df_depthkotei_negative.loc[df_depthkotei_negative[16] == 'A', 16] = -1
df_depthkotei_negative.loc[df_depthkotei_negative[16] == 'B', 16] = -2
df_depthkotei_negative.loc[df_depthkotei_negative[16] == 'C', 16] = -3
df_depthkotei_negative.loc[df_depthkotei_negative[16] == 'D', 16] = -4
# 16列目の値に17列目の値を加える
df_depthkotei_negative[16] = df_depthkotei_negative[16].astype(float)
df_depthkotei_negative[16] = df_depthkotei_negative[16] + df_depthkotei_negative[17]
# 17列目を削除
df_depthkotei_negative = df_depthkotei_negative.drop(17, axis=1)
# df_depthkotei_positiveとdf_depthkotei_negativeを結合
df_depthkotei_result = pd.concat([df_depthkotei_positive, df_depthkotei_negative])
names = ['recode','year','month','day','hour','minute','second','time_SE_x','latitude','lat_SD_x','longitude','lon_SD_x','depth','dep_SD_x','mag1','mag1_type','mag2_x','mag2_type_x','used_traveltime','hypo_judge','hypo_type','max_coefficient','scale_victim','tsunami_victim','region_main','region_sub','hypo_locale','obs_number','determination_way']
df_depthkotei_result.columns = names
# df_depthkotei_result = df_depthkotei_result.round(4)
# df_depthkotei_result.to_csv('./df_depthkotei_result.csv',index=False)
# df_hypofree_resultとdf_depthkotei_resultを結合
df_result = pd.concat([df_hypofree_result, df_depthkotei_result])
# mag1の列の型をfloatにする
df_result['mag1'] = df_result['mag1'].astype(float)
df_result = df_result.round(4)
df_result.to_csv('./df_result.csv',index=False)
# "hypo_type"の列の値が1以外の行を抽出
df_result_unnatual = df_result[df_result['hypo_type'] != 1]
df_result_unnatual.to_csv('./df_result_unnatual.csv',index=False)
if __name__ == "__main__":
args = sys.argv
# 引数にファイル名を指定されているか確認する
if len(sys.argv) != 2:
print("Usage: python jma_cut_2024.py [input]")
sys.exit()
main()
力づくです。今回はここまで。
コメント