スポンサーリンク
スポンサーリンク

【令和最新版】固定長データをPythonで頑張ってカンマ区切りにする(震源レコード編)その2

スポンサーリンク
スポンサーリンク
スポンサーリンク
スポンサーリンク
固定長データを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()

力づくです。今回はここまで。

コメント

スポンサーリンク