DTW(Dynamic Time Warping)で台風軌道をクラスタリングする
はじめに
多次元時系列データのクラスタリングがしたいと思って探していたところ、 ちょうどこちらのブログの題材が台風軌道のクラスタリングという、多次元時系列かつ系列長の異なるデータをクラスタリングするというものだったので、理解を兼ねて同じ内容をpythonで実施してみたのが今回の内容になります。
参考資料
題材と内容を参考にさせていただいたブログ
DTWについてのわかりやすい資料
気象庁の台風データ
tsleanのドキュメント
実装
気象庁から2019年に発生した台風のデータを取得します。 下記のように、各台風に対して6時間毎の緯度経度の時系列データが存在します。
foliumで可視化するとこのような感じ。2019年は全部で29の台風がありました。
import folium map_osm = folium.Map(location=[35.6,139.7],zoom_start=3) for num in df["台風番号"].unique(): point=np.array(df[df["台風番号"]==num][["緯度","経度"]]) folium.PolyLine( locations=point, ).add_to(map_osm) map_osm
この台風軌道を3つのグループにクラスタリングします。 tslearnのドキュメントがわかりやすいですが、 系列長が同じかつある特定の時間での比較が重要である場合はユークリッド距離を用いたkmeansでもクラスタリングができますが、 例えば1期分ずれているが、全体的に動きが類似しているような時系列をクラスタリングする場合はDTW(Dynamic Time Warping)が有効になります。
DTWの考え方としては、2つの時系列データに対しすべての点の組み合わせの距離を計算し、系列同士の距離が最短となる経路を探索するものになります。 サンプルとして出てくるものは1次元のデータが多いですが、組み合わせ計算のときはユークリッド距離を使用することが多いので、多次元データにも対応できます。 今回のケースだと緯度と経度という2次元の特徴に対してDTWを用いたクラスタリングを実施する形となります。
調べるとpythonでもいくつかパッケージが見つかるのですが、tsleanというパッケージの信頼性が高そうだったので、今回はこのパッケージを用いてクラスタリング及び結果の可視化を行います。
from tslearn.clustering import TimeSeriesKMeans from tslearn.utils import to_time_series_dataset from tslearn.barycenters import dtw_barycenter_averaging points=[] for num in df["台風番号"].unique(): points.append(np.array(df[df["台風番号"]==num][["緯度","経度"]])) points = to_time_series_dataset(points) dba_km = TimeSeriesKMeans(n_clusters=3, n_init=5, metric="dtw", verbose=True, max_iter_barycenter=10, random_state=22) pred = dba_km.fit_predict(points) colors=["blue","yellow","green","red"] c0=[] c1=[] c2=[] map_osm = folium.Map(location=[35.6,139.7],zoom_start=3) for num,c in zip(df["台風番号"].unique(),pred): if c==0: c0.append(np.array(df[df["台風番号"]==num][["緯度","経度"]])) elif c==1: c1.append(np.array(df[df["台風番号"]==num][["緯度","経度"]])) else: c2.append(np.array(df[df["台風番号"]==num][["緯度","経度"]])) point=np.array(df[df["台風番号"]==num][["緯度","経度"]]) folium.PolyLine( locations=point, color=colors[c], ).add_to(map_osm) map_osm
右下の太平洋上で発生して、そこから東南アジアへ向かうもの、日本の左側を通るもの、日本の東側を通るもの、という別れ方をしているようです。 それほど別れ方に違和感はないように感じます。 元記事ではDTWを使った距離計算をした後にk-medoidsを用いてクラスタリングを行なっているのですが、 今回の手法はDTWで距離計算をした後にDBA(dtw barycenter averaging)で重心計算を行い、その重心を用いてkmeansでクラスタリングを行なっています。
各クラスタの重心点をDBAで計算したものを赤線で引いてみます。
dba_c0=dtw_barycenter_averaging(c0) dba_c1=dtw_barycenter_averaging(c1) dba_c2=dtw_barycenter_averaging(c2) folium.PolyLine( locations=dba_c0, color=colors[3], ).add_to(map_osm) folium.PolyLine( locations=dba_c1, color=colors[3], ).add_to(map_osm) folium.PolyLine( locations=dba_c2, color=colors[3], ).add_to(map_osm) map_osm
かなりガタガタしていますが、大まかな特徴を捉えるくらいには使えるでしょうか。
まとめ
DTWを用いて台風軌道のクラスタリングを行いました。 系列長が不定で多次元なデータもクラスタリングを行うことができるので、例えばgpsデータなど探せば応用できる対象が結構あるのではないかなぁと思っています。
使用したコードは下記になります。