14
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

個人開発エンジニア応援 - 個人開発の成果や知見を共有しよう!-

福島県の気温データをクラスタリング分析すると、天気予報の3地方に分類できるか検証してみた

Last updated at Posted at 2023-10-09

目的

福島県の天気予報は3地方(浜通り、中通り、会津地方)に分けて提供される。
気温データをクラスタリング分析することで、うまくこの3地方に分類できるのかを検証する。

福島県は、「県内は南北方向に延びる山脈・山地によって、地形・気候・交通・歴史などの面に違いが顕れており、3地域に分けられている。」Wikipediaより引用
クラスタリング分析は、「教師なしデータ分類手法、つまり与えられたデータを外的基準なしに自動的に分類する手法。また、そのアルゴリズム。」同じくWikipediaより引用

気温データをクラスタリング分析

まず、気象庁が公開している2022年月毎の平均気温(福島県)をコピペし、fukushima_tempreture_2022.tsv としてファイル保存する。

このファイルを読み込んで表示すると、こんな感じ。

import pandas as pd
df_tempreture = pd.read_csv('fukushima_tempreture_2022.tsv',sep='\t', index_col=0)
print(df_tempreture.head())
     梁川    福島    相馬   喜多方   猪苗代   二本松    若松    船引    浪江    只見  ...    金山  \
月                                                              ...         
1   0.6   1.1   1.8  -1.7  -3.0   0.6  -0.8  -1.4   2.1  -1.4  ...  -1.3   
2   1.6   1.6   1.8  -0.9  -2.3   1.0  -0.1  -0.7   1.8  -1.3  ...  -1.2   
3   6.3   6.8   5.9   3.5   2.8   6.3   4.6   4.8   6.3   2.3  ...   2.3   
4  12.3  13.1  11.3  10.8   9.7  12.4  11.8  10.6  12.0   6.7  ...   7.9   
5  16.9  17.6  16.1  15.9  14.2  16.6  16.5  14.6  16.1  13.9  ...  14.0   

     鷲倉    川内    飯舘    桧原    茂庭    湯本   桧枝岐    玉川    山田  
月                                                        
1  -6.9  -0.8  -1.8  -5.0  -0.7  -2.9  -4.9  -0.2   2.8  
2  -6.8  -0.5  -1.9  -4.7  -0.2  -2.6  -4.5   0.0   2.7  
3  -0.9   4.8   3.7   0.2   4.1   2.3   0.7   5.6   7.3  
4   5.8  10.3  10.1   6.2  10.6   8.6   6.1  11.5  12.7  
5  10.2  14.0  14.1  11.6  14.6  12.6  11.0  15.1  16.3  

[5 rows x 30 columns]

デンドログラムで可視化するとこんな感じ。

import matplotlib.pyplot as plt
from scipy.cluster import hierarchy
import japanize_matplotlib
method = 'ward'
Z = hierarchy.linkage(df_tempreture.T, method=method)
hierarchy.dendrogram(Z, color_threshold=0,labels=df_tempreture.columns)
plt.ylabel('distance')
plt.title( '気温による分類')
plt.xticks(rotation=90)
plt.show()

なお、日本語表示ができない場合には、以下のコマンドでインストールしておく。

!pip install japanize_matplotlib

output.png

まず、都市部(平地/盆地)と山間部で2つのクラスタに分類できるようである。
都市部(平地/盆地)は、次に3地方ではなく2つに分類される。中通り中部南部の郡山/白河は会津若松/喜多方の会津地方側に、中通り北部の福島/二本松は相馬/小名浜の浜通り側に分類される。
山間部は、次に、檜原/檜枝岐の奥まった山間部と、船引/田島など山間の町村部に分類される。
うまく3地方には分類できないようだが、細かく分割すると、実態に近い分類ができそうなので、11個のクラスタに分類してみる。

from sklearn.cluster import AgglomerativeClustering
n_clusters = 11
clustering = AgglomerativeClustering(linkage=method, n_clusters=n_clusters)
clustering.fit(df_tempreture.T)
df_clustering_result = pd.DataFrame( clustering.labels_, index=df_tempreture.columns, columns=['label'])
print(df_clustering_result.head())
     label
梁川       1
福島       1
相馬       9
喜多方      0
猪苗代      7

これでは分かりにくいので、地図にプロットしてみる。

クラスタリング結果を地図にプロット

地図にプロットするため、気象庁が公開している観測所一覧の位置情報をダウンロードし、福島県の観測所一覧(17p)をコピペし、ame_muster_fukushima.txt としてファイル保存する。

読み込んで表示すると、こんな感じ。

df_lonlat = pd.read_csv('ame_muster_fukushima.txt',encoding='shift_jis', sep=' ')
print(df_lonlat.head())
  都府県振興局  観測所番号 種類 観測所 名カタカナ名 気象情報等に表記する名称             所在地  緯度(度)  緯度(分)  \
0     福島  36056  四  茂庭    モニワ        福島市茂庭    福島市飯坂町茂庭字滑滝道     37   53.5   
1     福島  36066  四  梁川  ヤナガワ        伊達市梁川     伊達市梁川町粟野字作田     37   51.1   
2     福島  36106  四  桧原   ヒバラ       北塩原村桧原    耶麻郡北塩原村桧原字墓下     37   43.3   
3     福島  36127  官  福島   フクシマ           福島  福島市松木町 福島地方気象台     37   45.5   
4     福島  36151  四  相馬    ソウマ           相馬    相馬市成田字五郎右エ門橋     37   47.0   

   経度(度)  経度(分)  海面上の高さ(m) 風速計の高さ(m) 温度計の高さ(m)    観測開始年月日    備考1      備考2  
0    140   26.2        200       6.5         3   平4.10.23  36950    湿度を除く  
1    140   35.3         43       9.4       1.5  #昭51.12.6      −    湿度を除く  
2    140    3.5        824       9.4         4  昭53.10.26      −    湿度を除く  
3    140   28.2         67         −         −    令3.3.18  36955  気温、雨、日照  
4    140   55.5          9       6.5       1.5  #昭51.12.7      −        −  

経緯度の処理や必要な列のみを抽出し、クラスタリング結果と統合する。

# 経緯度の度分を度に変換する
df_lonlat['緯度'] = df_lonlat['緯度(度)'] + df_lonlat['緯度(分)']/60
df_lonlat['経度'] = df_lonlat['経度(度)'] + df_lonlat['経度(分)']/60
df_lonlat['高度'] = df_lonlat.loc[:,'海面上の高さ(m)']
# 必要な列のみにする
df_lonlat = df_lonlat[['観測所','緯度','経度','高度']]
print(df_lonlat.head())
# クラスタリング結果と、観測所座標を統合
df_clustering_result = pd.merge(df_clustering_result, df_lonlat, left_index=True, right_on='観測所', how='inner')
df_clustering_result = df_clustering_result.sort_values('label')
print(df_clustering_result.head())
  観測所         緯度          経度   高度
0  茂庭  37.891667  140.436667  200
1  梁川  37.851667  140.588333   43
2  桧原  37.721667  140.058333  824
3  福島  37.758333  140.470000   67
4  相馬  37.783333  140.925000    9
    label  観測所         緯度          経度   高度
5       0  喜多方  37.658333  139.863333  212
14      0   若松  37.488333  139.910000  212
9       0  西会津  37.588333  139.656667  165
1       1   梁川  37.851667  140.588333   43
3       1   福島  37.758333  140.470000   67

クラスタ別に色分けして、地図上にプロットする。

import folium
from folium.plugins import HeatMap
map = folium.Map(location=[37.4753244,140.2829286], zoom_start=9, tiles='OpenStreetMap')
color_list = ['red','blue','green','lightgray','black','pink','orange','lightblue','lightgreen','purple','darkred']
for i, rec in df_clustering_result.iterrows():
  folium.Marker(location=[rec.緯度,rec.経度],popup=rec.観測所,icon=folium.Icon(icon='ok', color=color_list[rec.label])).add_to(map)
map

output3.png

3地方より細かい地域で分割できているようではある。さらに考察するために、分類されたクラスタ毎に平均気温を可視化する。

クラスタ毎に平均気温を可視化

平均気温(度)をそのまま表示すると差が見えにくいため、県全体の平均気温との差を可視化する。

df_mean = df_tempreture.mean(axis=1)  # 県全体の平均気温
fig_size_x = 8
fig_size_y = 5
fig = plt.figure(figsize=(fig_size_x, fig_size_y))
# クラスタ毎に処理
for i in range(n_clusters):
  df_work = pd.DataFrame()
  name_list = ''
  for j, rec in df_clustering_result.iterrows():
    # 対象クラスタに分類された結果のみ抽出
    if rec.label==i:
      name = rec.観測所
      name_list += name
      df_work[name] = df_tempreture[name]
  # クラスタ毎の平均と県全体の平均の差をプロット
  plt.plot(df_work.mean(axis=1)-df_mean,c=color_list[i],label=f'#{i}{name_list}')
plt.grid(axis='y')
plt.xlabel('')
plt.xticks(range(1,13))
plt.ylabel('県全体の平均気温との差(度)')
plt.title( 'クラスタ毎の県全体の平均気温との差')
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0, fontsize=18)
plt.show()

output4.png

考察

各クラスタ

1月(冬場)の暖かい順に考察する。

  • ピンク:浜通り南部(小名浜など)
    冬場は一番暖かいが、夏は涼しくなってくる。
  • 紫:浜通り北部(相馬など)
    浜通り南部に次いで冬暖かい。年間通して、浜通り南部より1度程度低いが、8月だけは、浜通り南部と同じく暑い。
  • 青:中通り北部(福島など)
    上記浜通り(南部/北部)の次に冬暖かいが、夏場になると、浜通りより暑い。(県内で一番夏が暑い。)
  • 黄色:中通り中部/南部(郡山/白河など)
    中通り北部と同じ傾向だが、年間通して、中通り北部より1度ほど低い。
  • 赤:会津中北部(会津若松など)
    冬は県平均だが、夏場が急激に暑くなり、中通り中部/南部を抜いて、県内で二番目に夏が暑くなる。
  • 茶色:阿武隈高地(船引など)
    冬は会津中北部と同じく県平均だが、夏場は暑くならない。年間通して県平均。
  • 灰色:会津南西部(只見など)
    会津地方としては会津中北部に次いで冬暖かいが、3、4月は残冬が厳しく、田島より寒い。5、6月に回復し県平均となり、阿武隈高地より暑くなる。
  • 水色:猪苗代、飯館(ここだけ地域として特定できず)
    年間を通して、県平均から1~2度低い。
  • 緑色:会津南部(田島など)
    年間を通して、県平均から2度ほど低い。
  • 黒:会津山間部(檜枝岐など)
    年間を通して、県平均から4度ほど低い。
  • 黄緑:中通り山間部(鷲倉)
    観光有料山岳道路の頂点(浄土平)で、標高高い場所にある(通常、人は住まない)。ここだけ別格で格別に寒い。秋(10,11月)だけは会津山間部と同じ気温となる。

全体

  • 浜通りが冬暖かいことには納得だが、夏はそれほど涼しくないことに驚き。(浜通り南部を上回る暑さは、中通り北部と会津中北部のみ。中通り中南部と同程度の暑さ)
  • 夏冬の寒暖差が最も激しいのは会津中北部であることに納得。(住むのは大変だが、美味しい米どころたる所以)
  • 中通り北部と中通り中部/南部では平均気温の差がある(北部の方が暖かい/暑い)ので、北部は気温の高い浜通りへ、中部/南部は気温の低い会津へ分類された(デンドログラムにて)と推察される。クラスタリング分析では2つずつ分割していくのでそのようになったが、3つに分割する手法であれば、3地域になるのだろうか?
  • 中通り中部と中通り南部は気温の傾向が似ているため、温度データだけでは分割されにくい。
  • 船引などの阿武隈高地が年間を通して県平均を維持していることに驚き。(気温的には県の中心のようです。)
  • 最高の避暑地となるのは、檜枝岐、檜原(裏磐梯)であり、県内有数の観光地(保養地)であることに納得。
  • 会津南西部の残冬(3、4月)が厳しく、鷲倉(浄土平)の秋(10、11月)がそれほど寒くならないのが謎。(知見ある方いらっしゃれば教えてください。)

まとめ

気温データだけから分類したこともあり、3地方というよりは、都市部と山間部で分割されたが、より細かい地域で分割すると、そこそこうまく分類できたと思う。降水量や日照時間なども含めると、うまく3地方で分類できたかもしれないが、、、
皆さんのお住まいの都道府県でも分析してみてはいかがでしょうか?

14
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?