以前にPythonで時系列クラスタリングをするで、DTW(動的時間伸縮法)による時系列データのクラスタリングをやってみた。このときはPythonパッケージのtslearnを使ってクラスタリングをしたが、単にDTWによる時系列データ間の類似度(距離)を求めたいだけならfastdtwも使える。ただ、fastdtwではDTWの近似アルゴリズムを使用しているので、tslearnとfastdtwの結果を比べてみることにした。
Debian Buster(Dockerコンテナ)とJupyter Lab。
PythonでPDFの表からデータを抽出する(その2) で使用した帰国者・接触者相談センター(全相談件数)を使う。これは厚生労働省のホームページ地域ごとの感染状況等の公表についてからダウンロードできる「3.帰国者・接触者相談センターへの相談件数の推移(都道府県別・各日)・帰国者・接触者外来の受診者数の推移・うちPCR検査実施件数の推移(都道府県別・各日) 」のPDFに含まれるデータ。最近EXCELファイルが追加されたのでわざわざPDFからデータを抽出する必要はないのだが、ここではPythonでPDFの表からデータを抽出する(その2) の方法で作成したcsvを使う。都道府県ごとのデータがあるので、都道府県データ間の類似度をDTWで比べてみる。
PDFからcsvにしたデータをExcelで開くと次のような感じになる。
DTWを計算するためにtslearnとfastdtwをインストールする。
インストールしたライブラリのバージョン。
さらに、matplotlibのグラフで日本語表示できるように日本語フォントをインストールしておく。
PDFから抽出したデータを保存したcsv(000643758.csv)を読み込んで、このcsvに含まれる都道府県ごとの「帰国者・接触者相談センター(全相談件数)」を使う。期間は5月のひと月分。都道府県により絶対数に差があるので、0-1の範囲にデータを変換する。なお、欠損値があるとDTWによる計算でエラーになるので京都、滋賀、香川のデータは除外。
都道府県ごとのデータのプロット。
tslearnとfastdtwで都道府県データ間の距離をDTWで計算し、似ている/似ていない都道府県の組み合わせを求めてみる。
似ている都道府県の組み合わせトップ10は以下の通り。tslearnとfastdtwで違いはあるものの、最も距離が近い組み合わせの神奈川と富山はtslearnとfastdtwで同じ。
最も距離が短い神奈川と富山のプロット。ほぼ一致している。
最も距離が遠い岐阜と高知のプロット。確かにけっこう違う。
tslearnとfastdtwそれぞれで距離が短いトップ5を比較。以下のコードを上記コードのあとに追加する。
環境
Debian Buster(Dockerコンテナ)とJupyter Lab。
時系列データ
PythonでPDFの表からデータを抽出する(その2) で使用した帰国者・接触者相談センター(全相談件数)を使う。これは厚生労働省のホームページ地域ごとの感染状況等の公表についてからダウンロードできる「3.帰国者・接触者相談センターへの相談件数の推移(都道府県別・各日)・帰国者・接触者外来の受診者数の推移・うちPCR検査実施件数の推移(都道府県別・各日) 」のPDFに含まれるデータ。最近EXCELファイルが追加されたのでわざわざPDFからデータを抽出する必要はないのだが、ここではPythonでPDFの表からデータを抽出する(その2) の方法で作成したcsvを使う。都道府県ごとのデータがあるので、都道府県データ間の類似度をDTWで比べてみる。
PDFからcsvにしたデータをExcelで開くと次のような感じになる。
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjpHRY7RXqh4T5n42zLb0iHH5xM48tQZzNfNObjHEUpEqGVfEwio8Fv16UkQOp8d3qJyK4ICEx69plkUyI4-4X5F6LE3TW7SFFKpflpp4JuE6gZFwuCF49pMWngrDXG6tQa3t_294PIO4/s280/cons1.png)
ライブラリなどのインストール
DTWを計算するためにtslearnとfastdtwをインストールする。
インストールしたライブラリのバージョン。
さらに、matplotlibのグラフで日本語表示できるように日本語フォントをインストールしておく。
データの準備
PDFから抽出したデータを保存したcsv(000643758.csv)を読み込んで、このcsvに含まれる都道府県ごとの「帰国者・接触者相談センター(全相談件数)」を使う。期間は5月のひと月分。都道府県により絶対数に差があるので、0-1の範囲にデータを変換する。なお、欠損値があるとDTWによる計算でエラーになるので京都、滋賀、香川のデータは除外。
%matplotlib inline import pandas as pd from sklearn import preprocessing import matplotlib.pyplot as plt # 日本語フォントの指定 plt.rcParams['font.family'] = 'TakaoGothic' DT_FROM = '2020-05-01' DT_TO = '2020-05-30' def normalize(df): cols = df.columns idx = df.index x = df.values min_max_scaler = preprocessing.MinMaxScaler() x_scaled = min_max_scaler.fit_transform(x) return pd.DataFrame(x_scaled, index=idx, columns=cols) def _load(csvpath): df = pd.read_csv(csvpath, index_col=0, header=[0,1], parse_dates=True, encoding='shift-jis') # 全国を除く「帰国者・接触者相談センター(全相談件数)」だけを選択 df_con = df.filter(like='帰国者・接触者相談センター(全相談件数)', axis=1).drop(columns=('全国', '帰国者・接触者相談センター(全相談件数)')) # カラム名を都道府県のみにする df_con.columns = df_con.columns.droplevel(level=1) # 0-1の範囲に正規化 df_con = normalize(df_con[DT_FROM:DT_TO]) # 欠損値(NaN)があるとDTWの計算ができないので除外 # 京都、滋賀、香川のデータを除外 df_con = df_con.dropna(axis='columns') #print(df_con.info()) #display(df_con.head()) ax = df_con.plot(legend=None) plt.show() return df_con df = _load('000643758.csv')
都道府県ごとのデータのプロット。
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8OIPcYqCPZi0FD6bHCw6Zn8LW7qP2VA2_CICxR9oJHxUV-6ped9gbUkTgr49koyxZhz3LU4GB6vT1nYErzd1yPimBpWdUUuG94JqFlZOego7o4c49H6JBNTo1nRRu5hY_0xvXu88Zwd4/s280/dtw1.png)
DTWの計算
tslearnとfastdtwで都道府県データ間の距離をDTWで計算し、似ている/似ていない都道府県の組み合わせを求めてみる。
%matplotlib inline from itertools import combinations import pandas as pd from sklearn import preprocessing from fastdtw import fastdtw from tslearn.metrics import dtw import matplotlib.pyplot as plt # 日本語フォントの指定 plt.rcParams['font.family'] = 'TakaoGothic' DT_FROM = '2020-05-01' DT_TO = '2020-05-30' def calc_dtw(l_sr): dict_dtw = {} for sr1, sr2 in combinations(l_sr, 2): distance, path = fastdtw(sr1.to_numpy(), sr2.to_numpy()) dict_dtw[(sr1.name, sr2.name)] = (dtw(sr1.to_numpy(), sr2.to_numpy()), distance) return dict_dtw df = _load('000643758.csv') # Seriesのリスト l_sr = [item for l, item in df.items()] # 都道府県間のDTWを計算 dict_dtw = calc_dtw(l_sr) print('\n似ている都道府県トップ10(DTW)') display(sorted(dict_dtw.items(), key=lambda x:x[1][0])[:10]) print('\n似ている都道府県トップ10(fastDTW)') display(sorted(dict_dtw.items(), key=lambda x:x[1][1])[:10]) print('\n似ていない都道府県トップ10(DTW)') display(sorted(dict_dtw.items(), key=lambda x:x[1][0], reverse=True)[:10]) print('\n似ていない都道府県トップ10(fastDTW)') display(sorted(dict_dtw.items(), key=lambda x:x[1][1], reverse=True)[:10])
似ている都道府県の組み合わせトップ10は以下の通り。tslearnとfastdtwで違いはあるものの、最も距離が近い組み合わせの神奈川と富山はtslearnとfastdtwで同じ。
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSADTGeYNJ00hM8gyWH0GQd2rWJ-H0bcnxH7j-hGDL8Est7mcakENO9Ij2VSEt6s2saBrT5efgF5tN2n7lqMGkKkdLASDjZ6Y0RWDMGz0vRDgt3s8l98r7nOcMCOG42jIXMNfyp9niYd0/s280/result1.png)
似ていない都道府県の組み合わせトップ10は以下の通り。こちらもtslearnとfastdtwで違いはあるものの、最も距離が遠い組み合わせの岐阜と高知はtslearnとfastdtwで同じ。
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqT6-EFk91bPbUbKj5lIUE6vMzYUKOfHFaICNJQwqw_f3_O07tHH8-exqsyxCK1POHPdoGcz0LkqEOur8ukDF9Z8Tb2qVT5ugaFZmfkF0MhoqEXp12_9AklDI2Bk3uKsdZtUO_P9nEP-8/s280/result2.png)
最も距離が短い神奈川と富山のプロット。ほぼ一致している。
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPHFO9xkVTomOUu_MspMAUplA5qlbaJXDT_lWnbZLyVI7dHKw4IVW1G2-lIs-PSreT706__iob4WgPs-k75OgtawiDNwv_H1S8dTIpm3-Crz3yAflQt9PjQnWv1k_uTIaY-jwrwsWoByg/s280/dtw2.png)
最も距離が遠い岐阜と高知のプロット。確かにけっこう違う。
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUJm-4Dh_Kfyo_5-uC3X3qKx73-fawFlbpBnUxhQETDBFzCAvLOiMNElEQWPPzGeyO4e-0SJmmLyZ8pm2L5fGYZ8Fm69lIX-XDnUK45orf-FeQmBPhToKEp2SPhRCGgDnHHJz-RUaZtec/s280/dtw3.png)
tslearnとfastdtwそれぞれで距離が短いトップ5を比較。以下のコードを上記コードのあとに追加する。
(2021.12.16 グラフ作成部のコードを追加)
tslearn_top5 = sorted(dict_dtw.items(), key=lambda x:x[1][0])[:5] fastdtw_top5 = sorted(dict_dtw.items(), key=lambda x:x[1][1])[:5] for i, ((prefs1, values1), (prefs2, values2)) in enumerate(zip(tslearn_top5, fastdtw_top5)): fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10, 3)) df.loc[:, prefs1].plot(ax=axes[0]) df.loc[:, prefs2].plot(ax=axes[1]) plt.show()左がtslearnで右がfastdtw。どちらが良いのかは判断が難しい・・
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglWVQVz9tP5gdJBZUnZ7ReqbxIBpUvhJXic6lR_wzor-1ITQz8L5nVwvPRcvQYWdZQCbxJgX_zErnoBUP1geW-0b-ikRfJ0QlDdlKYh7fNagEwFHDHVF9S8RZAltmN4FCCOvbhTNEW7zc/s1600/comptop0.png)
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5NBifGfdxkdRHrpRQxtRbrPIGvBJs6B54ZWVXSPsX9Ar3azEX5dqyXPdEca2vMXzj7qqg82RwFULRl___tEgP8-R5_Ji0goWpsCbnes5mpLkkBIcmW9zH84-A4Moz2N6f4grkjap88C8/s1600/comptop1.png)
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitUgITJqRl7UIh5pLGfERa5XJO361njiBtMxv4wy7oyP8qIRSIR5CkTqeYc2HZVllhlUlOp-gNCk_eaZTn7v92MjfpjEP5Fd9B5km1mYIKzVYqceOjbHm51A7L6LvA042w1u2Wfw6lWRI/s1600/comptop2.png)
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW53n5iMfgTFxmB6OamU1OxuAQwblIg4I_2g3Wftq07_MLV4oGdsog8F3YF-GlF8eVs4sVNAgaMEBsphwG1Yo-tHjo31Lv9K759E6JyOBLipLRrLOe5oWzTjTmzbA_d77GbOLm9pnZBLk/s1600/comptop3.png)
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4F8qPYMcJwDtZo-egYkQPOp9GfjKQzAl9MGZUjwSpGCiEP-7X4hmaE4Xl63KvGjbu2ZoGOKoBjY1nt3ApYFYkhegOrVg_sXNZBkrUyt_EmiTimZ-KnHizoFUgFS62RT2Rpo3vaGGiXiE/s1600/comptop4.png)
最後のグラフの作り方についてもご教授いただけないでしょうか。
返信削除コメントを見落としていて返信遅くなりました。
削除グラフ作成箇所のコードを追記したのでご確認ください。