今年は日曜日がよく雨降るな、去年は水曜日がよく雨が降ってたななどの直感を確かめるために、気象庁データをスクレイピングして、実際に任意の年の雨が多い曜日を可視化してみます。ついでに、降水量データを用いて簡単なデータ分析をしてみます。
目次
データ分析の用意
はじめに、データ分析の際必要となる処理を行う関数を作成しておきます。
以下は、n年m月d日を曜日に変換するスクリプトです。
def get_day(year: int, month: int, date: int) -> str:
japanese_days = [
"月曜日",
"火曜日",
"水曜日",
"木曜日",
"金曜日",
"土曜日",
"日曜日",
]
_, last_day = calendar.monthrange(year, month)
weekdays = [
(f"{year}年{month}月{day}日", japanese_days[calendar.weekday(year, month, day)])
for day in range(1, last_day + 1)
]
return {str(n + 1): (day, weekday) for n, (day, weekday) in enumerate(weekdays)}[
str(date)
][1]
以下はrequestモジュールを用いて気象庁のデータベースに降水量情報を問い合わせる関数です。
データ参照元は以下のサイトになります。
https://www.data.jma.go.jp/stats/etrn/index.php
def get_precipitation_data(year: int, month: int) -> list]:
url: str = (
f"https://www.data.jma.go.jp/stats/etrn/view/daily_a1.php?prec_no=67&block_no=0683&year={year}&month={month}&day=&view="
)
content: bytes = requests.get(url).content
sp: BS = BS(content, "html.parser")
mtx_rows: list[BS] = sp.find_all("tr", class_="mtx")
prec_data = [
[cell.get_text(strip=True) for cell in row.find_all(["td", "th"])]
for row in mtx_rows
]
## header1 = ['日', '降水量', '気温', '湿度', '風向・風速', '日照時間(h)', '雪']
## header2 =['合計(mm)', '最大1時間(mm)', '最大10分間(mm)', '平均(℃)', '最高(℃)', '最低(℃)', '平均(%)', '最小(%)', '平均風速(m/s)', '最大', '最大瞬間', '最多風向', '降雪の深さの合計(cm)', '最深積雪(cm)']
return prec_data[3:]
>>>
['1', '6.5', '2.0', '1.0', '17.1', '21.0', '11.6', '87', '68', '1.0', '3.0', '南南西', '4.3', '南南西', '北東', '0.0', '///', '///']
['2', '38.0', '11.5', '3.0', '20.3', '24.6', '17.9', '91', '70', '1.6', '4.4', '北北西', '6.4', '北', '北北西', '0.0', '///', '///']
['3', '0.0', '0.0', '0.0', '19.7', '25.9', '12.2', '60', '29', '3.1', '6.4', '北北西', '11.7', '北', '北北西', '13.4', '///', '///']
['4', '0.0', '0.0', '0.0', '18.1', '25.4', '10.1', '71', '39', '1.8', '5.3', '西南西', '8.1', '西南西', '西', '5.8', '///', '///']
['5', '0.0', '0.0', '0.0', '19.0', '26.5', '12.5', '70', '32', '1.3', '3.6', '南', '5.0', '南', '西', '1.9', '///', '///']
['6', '7.5', '2.0', '1.0', '16.8', '19.1', '14.5', '89', '72', '1.4', '4.1', '南西', '6.6', '南南西', '西南西', '0.0', '///', '///']
['7', '0.0', '0.0', '0.0', '18.8', '26.3', '12.9', '83', '56', '1.3', '3.6', '西南西', '6.0', '南南東', '西北西', '6.7', '///', '///']
['8', '22.0', '6.0', '1.5', '17.2', '21.1', '14.5', '92', '71', '1.2', '5.1', '東北東', '7.0', '東北東', '西北西', '0.0', '///', '///']
['9', '0.0', '0.5', '0.0', '20.4', '26.6', '16.7', '83', '51', '1.5', '3.8', '南', '5.8', '南東', '西', '6.8', '///', '///']
['10', '1.5', '1.5', '0.5', '20.2', '25.8', '14.6', '81', '51', '1.6', '4.1', '南東', '6.4', '南東', '南', '5.4', '///', '///']
['11', '0.0', '1.5', '0.5', '21.3', '25.8', '18.1', '85', '62', '1.6', '4.4', '南東', '8.0', '南東', '西南西', '0.4', '///', '///']
['12', '0.0', '0.0', '0.0', '22.5', '27.5', '19.3', '84', '65', '1.4', '4.4', '南東', '7.2', '南東', '南南東', '2.8', '///', '///']
['13', '0.0', '0.0', '0.0', '23.0', '27.4', '19.7', '81', '63', '2.0', '4.5', '南南西', '7.1', '南', '西', '3.1', '///', '///']
['14', '12.0', '9.0', '7.0', '21.3', '24.7', '19.6', '90', '76', '1.1', '4.8', '西北西', '9.9', '西北西', '西北西', '0.0', '///', '///']
['15', '1.0', '1.0', '1.0', '20.4', '26.8', '16.3', '89', '59', '1.4', '6.2', '南西', '10.7', '南西', '北西', '2.6', '///', '///']
['16', '0.0', '0.0', '0.0', '21.3', '28.7', '14.5', '79', '47', '1.6', '4.6', '南', '7.0', '南東', '西', '9.5', '///', '///']
['17', '0.0', '0.0', '0.0', '22.7', '30.5', '15.7', '71', '34', '1.6', '4.7', '西南西', '8.2', '西南西', '西', '12.6', '///', '///']
['18', '0.0', '0.0', '0.0', '21.9', '28.7', '17.3', '76', '48', '1.2', '3.9', '南', '6.0', '南', '西', '3.7', '///', '///']
['19', '0.0', '0.0', '0.0', '23.9', '32.1', '15.8', '66', '33', '1.5', '4.6', '北北西', '9.2', '北西', '北', '13.7', '///', '///']
['20', '0.0', '0.0', '0.0', '22.8', '30.1', '16.0', '70', '43', '1.9', '4.6', '南', '7.4', '南', '西北西', '10.8', '///', '///']
['21', '9.5', '5.0', '1.5', '20.8', '22.8', '18.6', '91', '78', '1.2', '3.5', '東', '4.6', '東北東', '西北西', '0.0', '///', '///']
['22', '0.5', '0.5', '0.5', '20.9', '23.4', '19.3', '90', '80', '1.0 ]', '1.8 ]', '北北西', '2.7 ]', '北北西', '北 ]', '0.0', '///', '///']
['23', '0.0 )', '0.0 )', '0.0 )', '22.2 )', '27.7 )', '18.1 )', '82 )', '62 )', '2.2 ]', '4.0 ]', '西南西', '6.1 ]', '西', '西 ]', '3.8', '///', '///']
['24', '0.0', '0.0', '0.0', '22.3', '27.9', '17.2', '77', '52', '1.4', '3.6', '南南東', '6.0', '南東', '南', '6.8', '///', '///']
['25', '0.0', '0.0', '0.0', '23.1', '28.6', '17.4', '77', '55', '1.8', '4.8', '西南西', '8.7', '南南西', '西南西', '6.9', '///', '///']
['26', '5.0', '1.5', '0.5', '23.3', '26.7', '21.0', '91', '79', '1.3', '3.7', '西南西', '5.6', '西', '南西', '0.0', '///', '///']
['27', '0.0', '0.0', '0.0', '25.0', '29.6', '21.3', '83', '62', '1.8', '5.1', '西南西', '8.1', '西', '西南西', '2.1', '///', '///']
['28', '6.0', '5.5', '4.5', '24.0', '29.1', '21.2', '87', '64', '2.4', '5.8', '西南西', '9.6', '西', '西南西', '0.7', '///', '///']
['29', '6.0', '3.5', '1.5', '24.8', '29.0', '23.3', '89', '69', '2.3', '6.2', '南西', '9.6', '南西', '西南西', '1.9', '///', '///']
['30', '61.0', '17.0', '7.5', '23.4', '25.3', '22.0', '95', '88', '2.4', '5.3', '南南西', '9.6', '南南西', '南南西', '0.0', '///', '///']データの取得
分析毎にデータベースに問い合わせを行うと気象庁のサーバーに負荷がかかるので、あらかじめ必要なデータを抽出してローカルに保存しておきます。
import time
import json
ret = {}
for year in range(2023, 2024):
ret[year] = {}
for month in range(1, 13):
ret[year][month] = {}
time.sleep(0.5)
print(year, month)
for i in get_precipitation_data(year, month):
date = i[0]
prec = i[1]
ret[year][month][date] = prec
with open("data_2023.json", "w") as f:
json.dump(ret, f, indent=4)
データの可視化
上記のJSONデータから、2023年全ての日付の曜日ごとの降水量を抽出します。
with open("data_2023.json", "r") as f:
data = json.load(f)
days = {
"月曜日": [],
"火曜日": [],
"水曜日": [],
"木曜日": [],
"金曜日": [],
"土曜日": [],
"日曜日": [],
}
for month in range(1, 13):
for date in range(1, 32):
try:
day = get_day(2023, month, date)
prec = float(
data["2023"][str(month)][str(date)]
.replace(")", "")
.replace("(", "-")
.replace("'", "")
)
if prec > 0:
days[day].append(prec)
except KeyError:
pass
print(days)
>>>
{'月曜日': [0.5, 8.5, 10.5, 1.5, 11.5, 5.0, 24.5, 4.5, 31.0, 4.5, 3.0, 0.5, 0.5, 24.0], '火曜日': [3.0, 0.5, 1.0, 37.0, 20.5, 7.5, 0.5, 1.5, 1.0, 1.0, 5.5, 4.5, 0.5], '水曜日': [5.5, 6.0, 7.5, 26.5, 2.5, 12.0, 9.5, 6.0, 26.5, 0.5, 9.5, 5.0, 0.5, 0.5], '木曜日': [1.5, 1.0, 5.5, 26.5, 6.0, 6.5, 22.0, 1.0, 0.5, 6.0, 2.0, 0.5, 6.0, 10.0, 4.0, 3.5, 12.5, 5.0, 10.0], '金曜日': [15.5, 0.5, 7.0, 0.5, 2.0, 47.0, 12.0, 24.0, 38.0, 61.0, 9.0, 0.5, 0.5, 4.0, 0.5, 3.5, 9.0, 4.5], '土曜日': [1.0, 12.0, 8.0, 17.0, 4.5, 27.0, 28.0, 45.0, 8.5, 1.5, 80.0, 63.5, 4.5, 1.0, 3.0, 0.5], '日曜日': [3.5, 15.5, 14.0, 12.5, 4.0, 2.5, 92.0, 3.0, 81.5, 11.5, 0.5, 5.0, 0.5, 3.0]}抽出したデータから、曜日ごとの1年間の合計降水量を可視化してみます。

降水量で見ると土曜日が一番高いことがわかります。
次に、降水頻度で見てみます。
with open("data_2023.json", "r") as f:
data = json.load(f)
days = {
"月曜日": 0,
"火曜日": 0,
"水曜日": 0,
"木曜日": 0,
"金曜日": 0,
"土曜日": 0,
"日曜日": 0,
}
for month in range(1, 13):
for date in range(1, 32):
try:
day = get_day(2023, month, date)
prec = float(
data["2023"][str(month)][str(date)]
.replace(")", "")
.replace("(", "-")
.replace("'", "")
)
if prec > 0:
days[day] += 1
except KeyError:
pass
降水頻度で見ると木曜日が一番高いことがわかりました。
次に、1日ごとの降水量を可視化してみます。

このデータを元に、1LAG(日)ごとの自己相関を可視化してみます。

上図を見ると、ラグ1の自己相関が0.4付近であることから、ある日の降水量が高い場合、次の日も雨であることが多いことがわかります。

