import datetime
import pathlib
import re
import subprocess
import jpholiday
import pandas as pd
import plotly.graph_objs as go
import plotly.io as pio
pio.renderers.default = "notebook" # html出力時にplotlyグラフを静的に埋め込む
# 1日ごとの時間別ファイルをawkコマンドで1ファイルにする
input_csv = pathlib.Path("/Dropbox/Contents/TEPCO/hourly/*.csv")
output_csv = pathlib.Path("/Dropbox/Contents/TEPCO/all_hourly.csv")
# 各ファイルのヘッダは削除する(全体の1行目と各ファイルの1行目以外を出力する)
command = f"awk 'NR==1 || FNR!=1' {input_csv} > {output_csv}"
result = subprocess.run(
command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True
)
# YYYY/mm/dd 24:00をYYYY/mm/dd+1 00:00に変換する
def convert_datetime(string):
# 形式はYYYY/mm/dd HH/MMのため、スラッシュとスペースとコロンで区切る
YYYY, mm, dd, HH, MM = map(int, re.split("[/ :]", string))
return datetime.datetime(YYYY, mm, dd) + datetime.timedelta(hours=HH, minutes=MM)
# コロナ禍開始日を設定する
covid19startday = datetime.datetime(2020, 3, 1)
# csvファイルを読み込む
# 対象は2019年7月~2021年6月
df = pd.read_csv(output_csv, encoding="shift_jis", usecols=["年月日", "曜日", "ご使用量"])
# 24:00データがあるため変換する
df["年月日"] = df["年月日"].apply(convert_datetime)
# 土日祝日を判定する(土日祝日の場合はTrue、平日の場合はFalse)
df["土日祝日"] = df["年月日"].apply(
lambda x: True
if x.weekday() >= 5 or jpholiday.is_holiday(x.to_pydatetime())
else False
)
# コロナ禍かどうか判定する(2020/3/1以降はコロナ禍(True)、それ以前はコロナ前(False))
df["コロナ禍"] = df["年月日"].apply(lambda x: True if x >= covid19startday else False)
# 24:00データの曜日が前日のため、曜日を設定し直す
day = {0: "月", 1: "火", 2: "水", 3: "木", 4: "金", 5: "土", 6: "日"}
df["曜日"] = df["年月日"].map(pd.Timestamp.weekday).replace(day)
# 年月日をインデックスにする
df = df.set_index("年月日")
# 年月日インデックスより各項目に分割してマルチインデックスとする
df = df.set_index(
[
df.index.year,
df.index.month,
df.index.day,
df.index.hour,
df.index.minute,
df.index.weekday,
"曜日",
"土日祝日",
"コロナ禍",
df.index.strftime("%H:%M"),
df.index,
]
)
df.index.names = ["年", "月", "日", "時", "分", "曜日", "曜日_日本", "土日祝日", "コロナ禍", "時刻", "年月日"]
df
# 平日(コロナ前)のデータフレームを作成する
df_weekdays_nocovid19 = (
df.groupby(["土日祝日", "コロナ禍"])
.get_group((False, False))
.groupby(["時", "分", "時刻"])
.mean()
)
df_weekdays_nocovid19 = df_weekdays_nocovid19.sort_index(level="時刻")
# df_weekdays_nocovid19
# 休日(コロナ前)のデータフレームを作成する
df_holidays_nocovid19 = (
df.groupby(["土日祝日", "コロナ禍"])
.get_group((True, False))
.groupby(["時", "分", "時刻"])
.mean()
)
df_holidays_nocovid19 = df_holidays_nocovid19.sort_index(level="時刻")
# df_holidays_nocovid19
# 平日(コロナ禍)のデータフレームを作成する
df_weekdays_covid19 = (
df.groupby(["土日祝日", "コロナ禍"])
.get_group((False, True))
.groupby(["時", "分", "時刻"])
.mean()
)
df_weekdays_covid19 = df_weekdays_covid19.sort_index(level="時刻")
# df_weekdays_covid19
# 休日(コロナ禍)のデータフレームを作成する
df_holidays_covid19 = (
df.groupby(["土日祝日", "コロナ禍"])
.get_group((True, True))
.groupby(["時", "分", "時刻"])
.mean()
)
df_holidays_covid19 = df_holidays_covid19.sort_index(level="時刻")
# df_holidays_covid19
# 折れ線グラフを指定する
mode = "lines+markers"
fig = go.Figure()
# 平日(コロナ前)のグラフを描写する
fig.add_trace(
go.Scatter(
x=list(df_weekdays_nocovid19.index.get_level_values("時刻").values),
y=df_weekdays_nocovid19["ご使用量"].values,
name="平日(コロナ前)",
mode=mode,
)
)
# 休日(コロナ前)のグラフを描写する
fig.add_trace(
go.Scatter(
x=list(df_holidays_nocovid19.index.get_level_values("時刻").values),
y=df_holidays_nocovid19["ご使用量"].values,
name="休日(コロナ前)",
mode=mode,
)
)
# 平日(コロナ禍)のグラフを描写する
fig.add_trace(
go.Scatter(
x=list(df_weekdays_covid19.index.get_level_values("時刻").values),
y=df_weekdays_covid19["ご使用量"].values,
name="平日(コロナ禍)",
mode=mode,
)
)
# 休日(コロナ禍)のグラフを描写する
fig.add_trace(
go.Scatter(
x=list(df_holidays_covid19.index.get_level_values("時刻").values),
y=df_holidays_covid19["ご使用量"].values,
name="休日(コロナ禍)",
mode=mode,
)
)
# グラフタイトルを設定する
fig.layout.update({"title": "時間帯別電気使用量平均"})
# x軸ラベルと表示角度を設定する
fig.layout.xaxis.update({"title": "時刻", "tickangle": 55})
# y軸ラベルと表示角度を設定する
fig.layout.yaxis.update({"title": "電気使用量[kWh]"})
# グラフを描画する
fig.show()