10
3

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 3 years have passed since last update.

スタンバイAdvent Calendar 2021

Day 15

気象データの細かすぎる天気概況をなんとかまとめてみる

Last updated at Posted at 2021-12-15

はじめに

この記事は スタンバイ Advent Calendar 2021 の15日目の記事です。
昨日の記事は @Nisi さんの【空冷自作PC】Ryzen7 5700G + ASRock DeskMini X300をノクチュア NH-P1でファンレスにした話でした。

概要

気象庁では、全国の観測点で記録した過去の気象データを公開しています。
一度に入手可能なデータ量に制限はありますが、
ユーザー登録無しで全国のアメダスのデータが無償で使えるのはとても素晴らしいです。

しかし、天気概況(晴、快晴、雨、大雨など)の種類が非常に細かく
(2020年東京の6時〜18時の気象概況では年間58種類使われている)
例えば、晴、雨、その中間の3分類程度で売上を比較したい、といった用途にはいささか不便です。
そこで、本記事では、気圧等の数値データに基づいて、一日の天気概況表現を再分類する方法を検討しました。

Contents

  • データの入手
  • データの概要
  • データの加工

データの入手

過去の気象データは無料で入手出来ます。以下のようなフォームが用意されているので、

  • 地点
  • 項目(気温、気圧など)
  • 期間
  • 表示オプション

を選択し、CSVファイルをダウンロードでデータ入手完了です。

image.png

なお、本記事では、以下の条件で取得したデータを使用します

  • 地点:東京
  • 項目:日平均気温、最高気温、最低気温、降水量の日合計、日照時間、日最深積雪、日平均風速、日平均現地気圧、日平均相対湿度、天気概況(昼:06時~18時)
  • 期間: 2020年1月1日〜2020年12月31日

ファイルの文字コードがShiftJISなので、必要に応じて文字コードを変換して下さい。

データの概要

早速、Pandasデータフレームに読み込んでみます。

# 必要なライブラリのインポート
import pandas as pd

# データの読み込み
df_weather = pd.read_csv('path/do/datadir/data.csv')
df_head() 

image.png

2020年はうるう年なので366行、問題なくデータを読み込めています。

次に、天気概況の分類をみてみます。

df_weather['天気概況(昼:06時〜18時)'].unique()

array(['晴', '晴一時曇', '快晴', '曇時々晴', '晴後一時曇', '曇後雨', '曇一時雨', '曇後晴', '曇後一時雨',
       '雨一時晴', '曇', '雨時々みぞれ一時雪', '曇後一時晴', '雨', '雨後曇', '晴一時雨', '晴時々曇',
       '薄曇時々晴', '薄曇後一時晴', '曇一時雨後晴', '薄曇', '雨時々曇', '晴後薄曇', '晴後一時薄曇',
       '曇時々晴後一時雨', '曇時々雨', '曇一時晴', '晴一時薄曇', '晴後一時雨', '雨後雪時々みぞれ',
       '曇一時雨後時々晴', '雨時々雪後一時曇、みぞれを伴う', '曇後雨一時晴', '晴後曇', '晴後時々曇', '大雨',
       '薄曇一時晴', '晴後曇時々雨', '晴時々薄曇', '曇後一時雨、雷を伴う', '曇時々雨、雷を伴う', '雨一時曇',
       '曇時々雨後晴', '曇時々晴一時雨、雷を伴う', '曇、雷を伴う', '曇一時雨後一時晴', '雨後時々曇', '曇時々雨一時晴',
       '曇後時々雨', '晴後曇一時雨、雷を伴う', '晴後時々曇一時雨、雷を伴う', '晴、雷を伴う', '曇時々大雨、雷を伴う',
       '晴時々曇一時雨', '曇時々雨一時晴、雷を伴う', '曇時々晴一時雨', '曇一時晴後雨', '曇後時々晴'],
      dtype=object)

「時々」、「一時」等と組み合わさって、こんな分類になるのね。

種類の数は

len(df_weather['天気概況(昼:06時〜18時)'].unique())
58

58種類も!! 細かすぎる、、、。

天気予報でよく出てくる「時々」と「一時」の定義について
時々: 断続的かつその時間が予報期間の1/2未満の場合
一時: 連続的かつその時間が予報期間の1/4未満の場合

データの加工

いよいよ天気概況を再分類します。
今回は、雨、晴、その中間の3つ程度に再分類したいと思います。
この程度の分類であれば、以下の予想をもとに、再分類を進めれそう(な気がします)。

  • 天候を左右するのは、気圧と湿度、風速ではないか
  • 似たような天気のときは、似たような値の組み合わせになるはず

似たようなものの分類、そう、クラスター分析の出番ですね。

クラスター分析 (Try1)

今回は、k-means法を使います。分析コードは以下の通り。

# 必要なライブラリを読み込む
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

# クラスター分析に使用するカラムだけ抜き出す
df_analytics = df_weather[['平均現地気圧(hPa)','平均湿度(%)','平均風速(m/s)']]

# パラメータ間のオーダーをあわせるために値を標準化する
sc = StandardScalar()
df_analytics_std = sc.transform(df_analytics)

# k-means法によるクラスタ分析
kmeans = KMeans(init='random', n_clusters=3, random_state=0)
kmeans.fit(df_analytics_std)
labels = pd.Series(kmeans.labels_, name='cluster_number')

# 各クラスタのメンバー数を確認
print(labels.value_counts(sort=False))
1    136
2    168
0     62
Name: cluster_number, dtype: int64

# クラスター番号を結合
df_weather_lbl = pd.concat([df_weather, labels], axis=1)

各クラスターの天気概況(昼:06時〜18時)で使われている表現を見てみます。

# クラスター番号0
df_weather_class0 = df_weather_lbl[df_weather_lbl['cluster_number'] == 0]['天気概況(昼:06時〜18時)'].unique()
df_weather_class0

array(['晴後一時曇', '晴', '快晴', '曇時々晴後一時雨', '晴一時曇', '晴後一時雨', '薄曇時々晴', '曇',
       '曇時々雨', '晴一時薄曇', '晴時々薄曇', '薄曇', '雨一時曇', '曇後雨', '曇後晴', '雨時々曇',
       '晴時々曇一時雨', '曇時々雨、雷を伴う', '曇一時晴', '曇一時雨'], dtype=object)

# クラスター番号1
df_weather_class1 = df_weather_lbl[df_weather_lbl['cluster_number'] == 1]['天気概況(昼:06時〜18時)'].unique()
df_weather_class1

array(['晴', '晴一時曇', '快晴', '曇時々晴', '晴後一時曇', '曇後雨', '曇後晴', '曇', '曇後一時晴',
       '雨', '雨後曇', '晴時々曇', '薄曇時々晴', '薄曇後一時晴', '曇一時雨後晴', '曇後一時雨', '薄曇',
       '晴後薄曇', '晴後一時薄曇', '曇一時晴', '晴一時薄曇', '曇時々雨', '曇一時雨後時々晴', '晴後曇',
       '晴後時々曇', '薄曇一時晴', '曇一時晴後雨', '曇後時々晴', '雨後時々曇', '曇一時雨'], dtype=object)

# クラスター番号2
df_weather_class2 = df_weather_lbl[df_weather_lbl['cluster_number'] == 2]['天気概況(昼:06時〜18時)'].unique()
df_weather_class2

array(['曇一時雨', '曇後一時雨', '快晴', '雨一時晴', '雨時々みぞれ一時雪', '雨', '晴一時雨', '晴',
       '雨時々曇', '曇後晴', '曇時々雨', '曇一時晴', '雨後雪時々みぞれ', '晴後一時曇',
       '雨時々雪後一時曇、みぞれを伴う', '曇後雨一時晴', '大雨', '曇', '晴後曇時々雨', '曇後雨',
       '曇後一時雨、雷を伴う', '雨後曇', '曇時々晴', '曇時々雨、雷を伴う', '晴時々曇', '曇時々雨後晴', '晴一時曇',
       '薄曇', '曇時々晴一時雨、雷を伴う', '曇後一時晴', '薄曇時々晴', '曇、雷を伴う', '曇一時雨後一時晴',
       '雨一時曇', '雨後時々曇', '曇時々雨一時晴', '曇後時々雨', '晴後曇一時雨、雷を伴う',
       '晴後時々曇一時雨、雷を伴う', '晴、雷を伴う', '晴時々薄曇', '曇時々大雨、雷を伴う', '曇時々雨一時晴、雷を伴う',
       '晴後一時薄曇', '曇時々晴一時雨', '曇時々晴後一時雨', '晴後薄曇'], dtype=object)

ぱっと見た感じ、各クラスターがどのような天気概況の集団なのか、良くわからないです、、、。
ここで、分類性能を簡易的に評価するため、クラスター間の重複の数を数えてみましょう。

# 重複個数を確認
# 3クラスター重複
len(set(df_weather_class0).intersection(set(df_weather_class1), set(df_weather_class2)))
12

# クラスター0,1重複
len(set(df_weather_class0).intersection(set(df_weather_class1)))
13

# クラスター1,2重複
len(set(df_weather_class1).intersection(set(df_weather_class2)))
21

# クラスター2,0重複
len(set(df_weather_class2).intersection(set(df_weather_class0)))
17

どのクラスターも半分以上他のクラスターと重複しており、うまく分類出来ているとは言い難いです。
改良の余地がありそうです。

クラスター分析 (Try2)

気圧、湿度、風速の値だけで分類が難しい、であれば、パラメータを増やしてみることにします。
試しに、降水量の合計、日照時間を加えてみます。

# クラスター分析に使用するカラムだけ抜き出す
df_analytics = df_weather[['降水量の合計(mm)','日照時間(時間)','平均現地気圧(hPa)','平均湿度(%)','平均風速(m/s)']]

# 先程と同様

# 各クラスタのメンバー数を確認
print(labels.value_counts(sort=False))
0    181
1    149
2     36
Name: cluster_number, dtype: int64

再び、各クラスターの天気概況(昼:06時〜18時)で使われている表現を見てみます。

# クラスター番号0
df_weather_class0 = df_weather_lbl[df_weather_lbl['cluster_number'] == 0]['天気概況(昼:06時〜18時)'].unique()
df_weather_class0

array(['晴', '晴一時曇', '快晴', '曇時々晴', '晴後一時曇', '曇', '晴時々曇', '薄曇時々晴', '薄曇後一時晴',
       '曇一時雨後晴', '晴後薄曇', '薄曇', '晴後一時薄曇', '曇時々晴後一時雨', '曇一時晴', '晴一時薄曇',
       '晴後一時雨', '晴後曇', '晴後時々曇', '薄曇一時晴', '晴時々薄曇', '曇後晴', '晴、雷を伴う',
       '曇後一時晴', '晴一時雨', '曇後時々晴'], dtype=object)

# クラスター番号1
df_weather_class1 = df_weather_lbl[df_weather_lbl['cluster_number'] == 1]['天気概況(昼:06時〜18時)'].unique()
df_weather_class1

array(['曇後雨', '曇一時雨', '曇後晴', '曇後一時雨', '雨一時晴', '雨時々みぞれ一時雪', '曇後一時晴', '雨',
       '曇', '雨後曇', '薄曇', '雨時々曇', '曇時々雨', '曇一時晴', '曇一時雨後時々晴', '曇後雨一時晴',
       '晴後曇時々雨', '曇後一時雨、雷を伴う', '曇時々雨、雷を伴う', '曇時々雨後晴', '曇時々晴一時雨、雷を伴う',
       '曇、雷を伴う', '曇一時雨後一時晴', '晴一時曇', '曇後時々雨', '晴', '晴時々曇', '晴後曇一時雨、雷を伴う',
       '晴後時々曇一時雨、雷を伴う', '曇時々晴', '晴時々曇一時雨', '曇時々晴一時雨', '晴一時雨', '曇一時晴後雨',
       '曇時々晴後一時雨', '雨後時々曇', '晴後薄曇', '薄曇一時晴'], dtype=object)

# クラスター番号2
df_weather_class2 = df_weather_lbl[df_weather_lbl['cluster_number'] == 2]['天気概況(昼:06時〜18時)'].unique()
df_weather_class2

array(['雨', '晴一時雨', '雨時々曇', '雨後雪時々みぞれ', '曇時々雨', '雨時々雪後一時曇、みぞれを伴う', '大雨',
       '雨一時曇', '曇後雨', '雨後曇', '雨後時々曇', '曇時々雨一時晴', '曇時々大雨、雷を伴う',
       '曇時々雨一時晴、雷を伴う', '曇時々雨、雷を伴う', '曇'], dtype=object)

ぱっと見た感じ、おおよそ

  • クラスター番号0 : 晴
  • クラスター番号2 : 雨
  • クラスター番号1 : 中間

のように再分類出来ていそうです。
先程と同じように、クラスター間の重複をカウントしてみます。

# 重複個数を確認
# 3クラスター重複
len(set(df_weather_class0).intersection(set(df_weather_class1), set(df_weather_class2)))
2

# クラスター0,1重複
len(set(df_weather_class0).intersection(set(df_weather_class1)))
13

# クラスター1,2重複
len(set(df_weather_class1).intersection(set(df_weather_class2)))
9

# クラスター2,0重複
len(set(df_weather_class2).intersection(set(df_weather_class0)))
2

先程と比較してだいぶクラスター間の重複を減らせたのではないかと思います。

まとめ

  • 降水量合計、日照時間、平均現地気圧、平均風速、平均湿度をもとに、天気概況を3分類程度に分けられそう。
  • 他の地域でも試してみたい。(例えば、北海道など)
10
3
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
10
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?