メモ:Pythonで時系列グラフの作成
時系列のデータをグラフにするとき
ハマったところをメモ
参考にしたサイト
note.nkmk.me
oku.edu.mie-u.ac.jp
元のデータはこれを使った
陽性者一覧(CSV:175KB)
csvのカラムは以下のようになっている
確定陽性者 | 性別 | 年齢 | 発病日 | 確定日 | 居住地 | 職業 | 推定感染経路 |
確定日に日付が入っているのでその数をカウントすると1日あたりの陽性者数を数えられる
それはpythonのvalue_counts()を使えばいいのだが
陽性者のいない日付もあるのでそこはNaNで埋めて日付が飛ばないようにしたい
初めは日付だけのデータフレームを作ってマージしたらよいかと思ったがうまくいかない
日付のデータフレームはDataFrame(pandas.date_range('日付1', '日付2'))を使うと
日付1から日付2の範囲の作れる
例えば次のスクリプトを実行する
from pandas import Series, DataFrame import pandas as pd import numpy as np date1 = DataFrame(pd.date_range('2020/2/1', '2020/2/7')) tmp_df = [] for i in date1.index: tmp_df.append('date1') tmp_df = DataFrame(tmp_df) date1 = pd.concat([date1, tmp_df], axis = 1) date1.columns = ['date', 'values'] date1.set_index('date', inplace = True) date1.drop(date1.index[[4, 5]], inplace = True) print(date1)
出力では5日と6日が抜けている
values date 2020-02-01 date1 2020-02-02 date1 2020-02-03 date1 2020-02-04 date1 2020-02-07 date1
更にインデックスを書き換えると
new_idx = pd.date_range(date1.index[0], date1.index[-1], freq = 'D') print(type(new_idx[0])) print(date1.index) date1 = date1.asfreq('D') print(date1)
なかった5日と6日の行にはNaNが挿入されている
values date 2020-02-01 date1 2020-02-02 date1 2020-02-03 date1 2020-02-04 date1 2020-02-05 NaN 2020-02-06 NaN 2020-02-07 date1
更に日付の範囲の異なるデータを作る
date1とdate2をpandas.concat()をつかって列で合成する
date2 = DataFrame(pd.date_range('2020/2/3', '2020/2/8')) tmp_df = [] for i in date2.index: tmp_df.append('date2') tmp_df = DataFrame(tmp_df) date2 = pd.concat([date2, tmp_df], axis = 1) date2.columns = ['date', 'values'] date2.set_index('date', inplace = True) print(date2) date = pd.concat([date1, date2], axis = 1) print(date)
結果は次の通り
values values date 2020-02-01 date1 NaN 2020-02-02 date1 NaN 2020-02-03 date1 date2 2020-02-04 date1 date2 2020-02-05 NaN date2 2020-02-06 NaN date2 2020-02-07 date1 date2 2020-02-08 NaN date2
date1とdate2それぞれにNaNの補完があって合成されている
同じようにしてvalue_counts()で日付の頻度をカウントして
日付をindexにしたらいいかと思ったが
このindexの日付とdate_range()で作った日付をconcat()で合成できない
できないというか日付の取り扱いが違っているようでうまくできない
ここまで書いてなんだが別の方法を試した
時系列データの場合、asfreq()でリサンプリングすることが可能
時系列の入ったデータフレームdf_dateを以下のようにすると
日付でデータを補完する
df_date = df_date.asfreq('D')
引数によってオフセットが変わるらしい
pandas.DataFrame.asfreq — pandas 1.5.3 documentation
Time series / date functionality — pandas 1.5.3 documentation
これを使って時系列のデータセットを作り
グラフを作るスクリプトが以下の通り
# -*- coding: utf-8 -*- import os, sys, datetime from pandas import Series, DataFrame import pandas as pd import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.dates as mdates def Count_Numbers(df_date, col_name): df_date = df_date.replace({'確認中': np.nan, '無症状': np.nan, '調査中': np.nan}) df_date = df_date.dropna() for n, i in enumerate(df_date): df_date[n] = '2020年' + df_date[n] df_date = pd.to_datetime(df_date, format = '%Y年%m月%d日') df_date = df_date.value_counts().sort_index() df_date = DataFrame(df_date) df_date = df_date.asfreq('D') df_date.columns = [col_name] return df_date if __name__ == '__main__': path = os.getcwd() path = os.chdir(os.path.dirname(os.path.abspath(__file__))) path = os.getcwd() date_today = datetime.date.today() day_save_file = str(date_today.year) + str(date_today.month) + str(date_today.day) arg = path + '\\' + 'Positives_List\\youseisyaitiran.csv' try: df = pd.read_csv(arg, index_col = 0, encoding = 'shift_jis') except Exception as e: print('cannot open file: ', arg) print(str(e)) sys.exit(1) else: print('we were able to open the file') fixed_date = Count_Numbers(df.iloc[:, 3], 'fixed_date') onset_date = Count_Numbers(df.iloc[:, 2], 'onset_date') tmp_date = pd.concat([fixed_date, onset_date], axis = 1) print(tmp_date) fig, ax = plt.subplots() locator = mdates.AutoDateLocator() formatter = mdates.ConciseDateFormatter(locator) ax.xaxis.set_major_locator(locator) ax.xaxis.set_major_formatter(formatter) ax.bar(tmp_date.index, tmp_date['fixed_date']) ax.bar(tmp_date.index, tmp_date['onset_date']) ax.legend(['fixed date', 'date of onset']) #ax.set_xticks() plt.savefig(path + '\\' + day_save_file + '_graph_bar.png') plt.close()
日付のないセルはNaNに置き換えている
グラフを作る命令はまだよくわかっていないが
このようにするといい感じのグラフができる