「日本域気候予測データ - 観測地点データ」を可視化する その3- 季節・月別統計値のグラフ化

はじめに

これまで、「日本域気候予測データ - 観測地点データ」の年統計値のグラフ化について紹介しましたが、季節別及び月別に集計した値も公開されており、地球温暖化に伴う気候の変化を季節別・月別に示すことが可能です。

季節統計値、年統計値それぞれについてグラフ化してみましょう。

夏日の季節別データの読み込み・グラフ化

現在気候実験(SPA)のデータフレーム作成

現在気候再現実験(SPA)の季節集計値は/mnt/c/Users/hoge/JWP9/dias/data/csv/SPA/seasonally/に解凍されていますので、年集計値と同様に20年分の20ファイルをpythonに読み込んで1つのデータフレームにします。

# ライブラリのインポートと作業ディレクトリ変更
import os
import pathlib
import numpy as np 
import pandas as pd

os.chdir("/mnt/c/Users/hoge/JWP9/")

# ファイル名に"t2mx_ov25"を含むcsvのリストを作成します
spa_files_df = pd.DataFrame({"file_path":list(pathlib.Path("./dias/data/jmagwp/gwp9/data/csv/SPA/seasonally").glob("*t2mx_ov25*"))}) 

# 1ファイルずつ読み込み、年ー季節情報を追加した上で結合します。
spa_df = pd.DataFrame(index=[])    #入れ物のデータフレームを用意
for i,one_line in spa_files_df.iterrows():  #ファイルリストを1行ずつ処理
    tmp_df = pd.read_csv(one_line["file_path"],header=None,names=[0,1,2,3]) # 年ごとのcsvを4列のデータフレームに読み込み

    # 年ー季節情報を作成
    season_ser = tmp_df.loc[tmp_df[0] == "DATE",1]
    season_ser.index=[1,2,3,4]

    tmp_df["year-season"] = season_ser.loc[(tmp_df[0] == "DATE").cumsum()].reset_index(drop=True)  # 年ー季節情報の列を追加
    tmp_df.columns=["sfc_no","lat","lon","value","year-season"] # 列名を設定
    tmp_df = tmp_df.loc[~tmp_df["sfc_no"].isin(["DATE","sfc_no"])]  #ヘッダ情報を削除
    spa_df = pd.concat([spa_df,tmp_df],axis=0)  # 入れ物のデータフレームに追加する

# データ型を実数に変更
spa_df["value"] = spa_df["value"].astype("float")

# 年情報と季節情報を分離
ys_df = spa_df["year-season"].str.split("-",expand=True)
ys_df.columns = ["year","season"]
spa_df = pd.concat([spa_df,ys_df],axis=1)

# フラッグ列を追加(この後処理する将来予測実験のデータフレームと結合するために必要)
spa_df["MEM-FLG"] = 1

# 20年分のデータを、行方向が地点ID-季節、列方向が年のデータフレームに整形する
spa_table = spa_df.set_index(["sfc_no","season","MEM-FLG","year"])["value"].unstack(level=3)
将来気候予測実験(SFA)のデータフレーム作成

RCP2.6 シナリオについても、現在気候実験(SPA)と同様にデータフレーム化します。

# rcp26シナリオの結果のデータフレーム化

rcp26_files_df = pd.DataFrame({"file_path":list(pathlib.Path("./dias/data/jmagwp/gwp9/data/csv/SFA_rcp26_ens/seasonally").glob("*t2mx_ov25*"))}) 

rcp26_df = pd.DataFrame(index=[])    
for i,one_line in rcp26_files_df.iterrows():  
    tmp_df = pd.read_csv(one_line["file_path"],header=None,names=[0,1,2,3,4]) 

    # 年ー季節情報を作成
    season_ser = tmp_df.loc[tmp_df[0] == "DATE",1]
    season_ser.index=[1,2,3,4]

    tmp_df["year-season"] = season_ser.loc[(tmp_df[0] == "DATE").cumsum()].reset_index(drop=True)  
    tmp_df.columns=["sfc_no","lat","lon","value","MEM-FLG","year-season"] 
    tmp_df = tmp_df.loc[~tmp_df["sfc_no"].isin(["DATE","sfc_no"])] 
    rcp26_df = pd.concat([rcp26_df,tmp_df],axis=0)  

rcp26_df["value"] = rcp26_df["value"].astype("float")
rcp26_df["MEM-FLG"] = rcp26_df["MEM-FLG"].astype("int")

ys_df = rcp26_df["year-season"].str.split("-",expand=True)
ys_df.columns = ["year","season"]
rcp26_df = pd.concat([rcp26_df,ys_df],axis=1)

rcp26_table = rcp26_df.set_index(["sfc_no","season","MEM-FLG","year"])["value"].unstack(level=3)

# rcp85シナリオの結果のデータフレーム化
rcp85_files_df = pd.DataFrame({"file_path":list(pathlib.Path("./dias/data/jmagwp/gwp9/data/csv/SFA_rcp85_ens/seasonally").glob("*t2mx_ov25*"))}) 

rcp85_df = pd.DataFrame(index=[])    
for i,one_line in rcp85_files_df.iterrows():  
    tmp_df = pd.read_csv(one_line["file_path"],header=None,names=[0,1,2,3,4]) 

    # 年ー季節情報を作成
    season_ser = tmp_df.loc[tmp_df[0] == "DATE",1]
    season_ser.index=[1,2,3,4]

    tmp_df["year-season"] = season_ser.loc[(tmp_df[0] == "DATE").cumsum()].reset_index(drop=True)  
    tmp_df.columns=["sfc_no","lat","lon","value","MEM-FLG","year-season"] 
    tmp_df = tmp_df.loc[~tmp_df["sfc_no"].isin(["DATE","sfc_no"])] 
    rcp85_df = pd.concat([rcp85_df,tmp_df],axis=0)  

rcp85_df["value"] = rcp85_df["value"].astype("float")
rcp85_df["MEM-FLG"] = rcp85_df["MEM-FLG"].astype("int")

ys_df = rcp85_df["year-season"].str.split("-",expand=True)
ys_df.columns = ["year","season"]
rcp85_df = pd.concat([rcp85_df,ys_df],axis=1)

rcp85_table = rcp85_df.set_index(["sfc_no","season","MEM-FLG","year"])["value"].unstack(level=3)
統合データフレームの作成

3つのデータフレームを統合して保存します。

# データフレームそれぞれのインデックスにメンバー名を追加
spa_tmp = pd.concat([spa_table],keys=["spa"],names=["scenario"])
rcp26_tmp = pd.concat([rcp26_table],keys=["rcp26"],names=["scenario"])
rcp85_tmp = pd.concat([rcp85_table],keys=["rcp85"],names=["scenario"])

# カラム名を統一
spa_tmp.columns=np.arange(0,20)
rcp26_tmp.columns = np.arange(0,20)
rcp85_tmp.columns = np.arange(0,20)

# 統合して一つのデータフレームにする
t2mx_ov25_seasonal_df = pd.concat([spa_tmp,rcp26_tmp,rcp85_tmp])
t2mx_ov25_seasonal_df  = t2mx_ov25_seasonal_df.reorder_levels([1,2,0,3]).sort_index()
t2mx_ov25_seasonal_df.to_pickle("t2mx_ov25_seasonal_df.pkl")
将来変化グラフ(箱ひげ図)を作成

「北海道石狩地方 山口」地点(sfc_noが14116)のデータを切り出し、plotlyで箱ひげ図を描きます。

# ライブラリのインポート
import os
import numpy as np 
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go

os.chdir("/mnt/c/Users/hoge/JWP9/")

t2mx_ov25_seasonal_df = pd.read_pickle("t2mx_ov25_seasonal_df.pkl")

# 「北海道石狩地方 山口」地点(sfc_noが14116)のデータを切り出す。
data_df = t2mx_ov25_seasonal_df.loc[("14116",),:]

# データフレームの内容を表示
data_df.loc[(["MAM","JJA","SON","DJF"],)]

「北海道石狩地方 山口」地点の切り出しデータは次のようになっています。

ここで、インデックスの1列目は月の頭文字を合わせたもので、

  • MMA : 春(3〜5月)
  • JJA : 夏(6〜8月)
  • SON : 秋(9〜11月) 
  • DJF : 冬(12〜2月)

の集計結果を示しています。

インデックスの3列目は予測信頼度フラグで、

0:将来気候 4 メンバーの予測傾向が一致しない場合、あるいは、将来気候 4 メンバーのいずれか及び現在気候の日数/発生回数がともに 0 の場合 1:上記以外の場合 (気候予測データセット解説書第2章.P2-140より引用)

となっています。

今回切り出したデータでは、冬(12〜2月)の予測値は信頼度が低いため、使用に注意が必要であることがわかります。今回の場合、現在気候の日数/発生回数がともに 0 の場合にあたり、北海道の冬に夏日は出現しないと予測されていることがわかります。

では、切り出したデータのうち、春~秋の3シーズンについて箱ひげ図を描いてみましょう。

# 春~秋の3シーズンのデータを切り出し、plotlyに入力できる形に整形
plot_data = data_df.loc[(["MAM","JJA","SON"],),:].stack().unstack(level=1)
plot_data = plot_data.reset_index(level=0) # シーズンのラベル列を作成

# 箱ひげ図の作成
fig = go.Figure()

fig.add_trace(go.Box(
    x = plot_data["season"].values,
    y = plot_data["spa"].values,
    name = "historical",
    marker_color="black"
))

fig.add_trace(go.Box(
    x = plot_data["season"].values,
    y = plot_data["rcp26"].values,
    name = "rcp26",
    marker_color="blue"
))

fig.add_trace(go.Box(
    x = plot_data["season"].values,
    y = plot_data["rcp85"].values,
    name = "rcp85",
    marker_color="red"
))

fig.update_yaxes(title="夏日日数(日/季節)")

# レイアウトを設定します「boxmode="group"」とすることで、季節ごとにプロットすることができます。

fig.update_layout(
    width=500,height=300,
    margin=dict(t=10, b=20, l=10, r=40),
    boxmode="group",
    boxgap=0.1)

fig.show()

グラフから、このまま何もしないシナリオ(rcp8.5)の場合、

  • 夏(6〜8月)の夏日日数は、現在より30日程度増加する。
  • 秋(9〜11月)の夏日日数は、現在より15日程度増加する。

ことが読み取れます。

夏日の月別データの読み込み・グラフ化

現在気候実験(SPA)のデータフレーム作成

現在気候再現実験(SPA)の季節集計値は/mnt/c/Users/hoge/JWP9/dias/data/csv/SPA/monthly/に解凍されていますので、季節集計値と同様に20年分の20ファイルをpythonに読み込んで1つのデータフレームにします。

# ライブラリのインポートと作業ディレクトリ変更
import os
import pathlib
import numpy as np 
import pandas as pd

os.chdir("/mnt/c/Users/hoge/JWP9/")

# ファイル名に"t2mx_ov25"を含むcsvのリストを作成します
spa_files_df = pd.DataFrame({"file_path":list(pathlib.Path("./dias/data/jmagwp/gwp9/data/csv/SPA/monthly").glob("*t2mx_ov25*"))}) 

# 1ファイルずつ読み込み、年ー月情報を追加した上で結合します。
spa_df = pd.DataFrame(index=[])    #入れ物のデータフレームを用意
for i,one_line in spa_files_df.iterrows():  #ファイルリストを1行ずつ処理
    tmp_df = pd.read_csv(one_line["file_path"],header=None,names=[0,1,2,3]) # 年ごとのcsvを4列のデータフレームに読み込み

    # 年ー月情報を作成
    month_ser = tmp_df.loc[tmp_df[0] == "DATE",1]
    month_ser.index=[1,2,3,4,5,6,7,8,9,10,11,12]

    tmp_df["year-month"] = month_ser.loc[(tmp_df[0] == "DATE").cumsum()].reset_index(drop=True)  # 年ー月情報の列を追加
    tmp_df.columns=["sfc_no","lat","lon","value","year-month"] # 列名を設定
    tmp_df = tmp_df.loc[~tmp_df["sfc_no"].isin(["DATE","sfc_no"])]  #ヘッダ情報を削除
    spa_df = pd.concat([spa_df,tmp_df],axis=0)  # 入れ物のデータフレームに追加する

# データ型を実数に変更
spa_df["value"] = spa_df["value"].astype("float")

# 年情報と月情報を分離
ym_df = spa_df["year-month"].str.split("-",expand=True)
ym_df.columns = ["year","month"]
ym_df = ym_df.astype(int) # 整数に変更
ym_df.loc[ym_df["month"] <= 8,"year"] -= 1 # 1〜8月の年表示を前年に合わせる
spa_df = pd.concat([spa_df,ym_df],axis=1)

# フラッグ列を追加(この後処理する将来予測実験のデータフレームと結合するために必要)
spa_df["MEM-FLG"] = 1

# 20年分のデータを、行方向が地点IDー月、列方向が年のデータフレームに整形する
spa_table = spa_df.set_index(["sfc_no","month","MEM-FLG","year"])["value"].unstack(level=3)
将来気候予測実験(SFA)のデータフレーム作成

RCP2.6 シナリオについても、現在気候実験(SPA)と同様にデータフレーム化します。

# rcp26シナリオの結果のデータフレーム化

rcp26_files_df = pd.DataFrame({"file_path":list(pathlib.Path("./dias/data/jmagwp/gwp9/data/csv/SFA_rcp26_ens/monthly").glob("*t2mx_ov25*"))}) 

rcp26_df = pd.DataFrame(index=[])    
for i,one_line in rcp26_files_df.iterrows():  
    tmp_df = pd.read_csv(one_line["file_path"],header=None,names=[0,1,2,3,4]) 

    # 年ー月情報を作成
    month_ser = tmp_df.loc[tmp_df[0] == "DATE",1]
    month_ser.index=[1,2,3,4,5,6,7,8,9,10,11,12]

    tmp_df["year-month"] = month_ser.loc[(tmp_df[0] == "DATE").cumsum()].reset_index(drop=True)  
    tmp_df.columns=["sfc_no","lat","lon","value","MEM-FLG","year-month"] 
    tmp_df = tmp_df.loc[~tmp_df["sfc_no"].isin(["DATE","sfc_no"])] 
    rcp26_df = pd.concat([rcp26_df,tmp_df],axis=0)  

rcp26_df["value"] = rcp26_df["value"].astype("float")
rcp26_df["MEM-FLG"] = rcp26_df["MEM-FLG"].astype("int")

ym_df = rcp26_df["year-month"].str.split("-",expand=True)
ym_df.columns = ["year","month"]
ym_df = ym_df.astype(int) 
ym_df.loc[ym_df["month"] <= 8,"year"] -= 1 
rcp26_df = pd.concat([rcp26_df,ym_df],axis=1)

rcp26_table = rcp26_df.set_index(["sfc_no","month","MEM-FLG","year"])["value"].unstack(level=3)

# rcp85シナリオの結果のデータフレーム化
rcp85_files_df = pd.DataFrame({"file_path":list(pathlib.Path("./dias/data/jmagwp/gwp9/data/csv/SFA_rcp85_ens/monthly").glob("*t2mx_ov25*"))}) 

rcp85_df = pd.DataFrame(index=[])    
for i,one_line in rcp85_files_df.iterrows():  
    tmp_df = pd.read_csv(one_line["file_path"],header=None,names=[0,1,2,3,4]) 

    # 年ー月情報を作成
    month_ser = tmp_df.loc[tmp_df[0] == "DATE",1]
    month_ser.index=[1,2,3,4,5,6,7,8,9,10,11,12]

    tmp_df["year-month"] = month_ser.loc[(tmp_df[0] == "DATE").cumsum()].reset_index(drop=True)  
    tmp_df.columns=["sfc_no","lat","lon","value","MEM-FLG","year-month"] 
    tmp_df = tmp_df.loc[~tmp_df["sfc_no"].isin(["DATE","sfc_no"])] 
    rcp85_df = pd.concat([rcp85_df,tmp_df],axis=0)  

rcp85_df["value"] = rcp85_df["value"].astype("float")
rcp85_df["MEM-FLG"] = rcp85_df["MEM-FLG"].astype("int")

ym_df = rcp85_df["year-month"].str.split("-",expand=True)
ym_df.columns = ["year","month"]
ym_df = ym_df.astype(int)
ym_df.loc[ym_df["month"] <= 8,"year"] -= 1 
rcp85_df = pd.concat([rcp85_df,ym_df],axis=1)

rcp85_table = rcp85_df.set_index(["sfc_no","month","MEM-FLG","year"])["value"].unstack(level=3)
統合データフレームの作成

3つのデータフレームを統合して保存します。

# データフレームそれぞれのインデックスにメンバー名を追加
spa_tmp = pd.concat([spa_table],keys=["spa"],names=["scenario"])
rcp26_tmp = pd.concat([rcp26_table],keys=["rcp26"],names=["scenario"])
rcp85_tmp = pd.concat([rcp85_table],keys=["rcp85"],names=["scenario"])

# カラム名を統一
spa_tmp.columns=np.arange(0,20)
rcp26_tmp.columns = np.arange(0,20)
rcp85_tmp.columns = np.arange(0,20)

# 統合して一つのデータフレームにする
t2mx_ov25_month_df = pd.concat([spa_tmp,rcp26_tmp,rcp85_tmp])
t2mx_ov25_month_df  = t2mx_ov25_month_df.reorder_levels([1,2,0,3]).sort_index()
t2mx_ov25_month_df.to_pickle("t2mx_ov25_month_df.pkl")
将来変化グラフ(箱ひげ図)を作成

「北海道石狩地方 山口」地点(sfc_noが14116)のデータを切り出し、plotlyで箱ひげ図を描きます。

# ライブラリのインポート
import os
import numpy as np 
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import calendar

os.chdir("/mnt/c/Users/hoge/JWP9/")

t2mx_ov25_month_df = pd.read_pickle("t2mx_ov25_month_df.pkl")

# 「北海道石狩地方 山口」地点(sfc_noが14116)のデータを切り出す。
data_df = t2mx_ov25_month_df.loc[("14116",),:]

# データフレームの内容を表示
data_df

「北海道石狩地方 山口」地点の切り出しデータは次のようになっています。

1〜4月、11月、12月については、夏日は出現しないと予測されていることがわかります。

では、切り出したデータのうち、5月〜10月の6ヶ月について箱ひげ図を描いてみましょう。

# 5月〜10月のデータを切り出し、plotlyに入力できる形に整形
plot_data = data_df.loc[([5,6,7,8,9,10],),:].stack().unstack(level=1)
plot_data = plot_data.reset_index(level=0)
plot_data["month_str"] = [calendar.month_abbr[m] for m in plot_data["month"].values] #英語の省略型月名のラベルを作成

# 箱ひげ図の作成
fig = go.Figure()

fig.add_trace(go.Box(
    x = plot_data["month_str"].values,
    y = plot_data["spa"].values,
    name = "historical",
    marker_color="black"
))

fig.add_trace(go.Box(
    x = plot_data["month_str"].values,
    y = plot_data["rcp26"].values,
    name = "rcp26",
    marker_color="blue"
))

fig.add_trace(go.Box(
    x = plot_data["month_str"].values,
    y = plot_data["rcp85"].values,
    name = "rcp85",
    marker_color="red"
))


fig.update_yaxes(title="夏日日数(日/月)")

# レイアウトを設定します「boxmode="group"」とすることで、月ごとにプロットすることができます。

fig.update_layout(
    width=700,height=300,
    margin=dict(t=10, b=20, l=10, r=40),
    boxmode="group",
    boxgroupgap=0.05,
    boxgap=0.2)

fig.show()

グラフから、このまま何もしないシナリオ(rcp8.5)の場合、

  • 6月と9月の夏日日数が、現在より15日程度増加する。

ことが読み取れます。

ほかの地点、ほかの統計値についても、同じ方法で箱ひげ図を作ることができます。 ぜひお近くのアメダス地点について将来予測を見える化してみてくださいね~。

※本記事では「気候予測データセット2022 ②日本域気候予測データ」を使用しました。同データセットは、気象庁気象研究所が開発した気候モデルを利用して、文部科学省気候変動リスク情報創生プログラム(RCP8.5シナリオ)及び統合的気候モデル高度化研究プログラム(RCP2.6シナリオ)において計算されたデータを元に作成されたものです。