Topological Data Analysisとは
Deep Learning の次は、TDA 「トポロジカル・データ・アナリシス」 の記事にもあるように、最近何かとTDAという言葉を耳にするようになった。
私はPythonをデータ分析のメイン言語として使っているので今後のことも考えてPythonでTDAを動かしたいのだが、探してみてもあまりそれに関するサンプルコードが見つからない(ぐぐるとPython Mapperとかいうのをよく見る)。
今回は色々出回っているソースのうち、kepler-mapperを使ってPythonでTDAしてみたのでサンプルソースと使い方をまとめようと思う。
とりあえず動かす
まずは先ほどのkepler-mapperからkm.pyをDLする。
適当なディレクトリに置いてこれをコールするプログラムを書いてみる。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import km
import numpy as np
import pandas as pd
train = pd.read_csv("test.csv",header = None)
train = train.dropna()
data_columns = [c for c in train.columns if c != 0]
data = np.array(train[data_columns])
y = np.array(train[0])
REDUCER = km.manifold.TSNE()
EPS = 0.3 #最低距離
MIN_SAMPLES = 3 #最低包括ログ数
NR_CUBES = 5
OVERLAP_PERC = 0.3
GRAPH_CHARGE = 50
GRAPH_GRAVITY = 0.5
FILE_NAME = "results.html"
FILE_TITLE = "test_analysis"
# mapperの初期化
mapper = km.KeplerMapper(verbose=1)
# 描写用データの生成(TSNEの場合、N次元のデータを2次元に落とす)
data = mapper.fit_transform(data,projection = REDUCER)
# ノードとリンクを返却する
complex = mapper.map(data,clusterer = km.cluster.DBSCAN(eps=EPS, min_samples=MIN_SAMPLES),nr_cubes=NR_CUBES,overlap_perc=OVERLAP_PERC)
# complexをhtmlに書き出す
mapper.visualize(complex, path_html = FILE_NAME, title=FILE_TITLE, graph_charge=-GRAPH_CHARGE, graph_gravity=GRAPH_GRAVITY, custom_tooltips=y)
最初にデータを読み込んで、正解ラベル以外のデータを
data = np.array(train[data_columns])
としてdataに代入する。
その後各種パラメータを適当に設定し
1. mapperを初期化する(verboseはデバッグモード)
2. 描画用のデータを作成する(次元削減するアルゴリズムをREDUCERに設定。値はkm.pyに設定されている値かsklearn.manifoldにある次元削減アルゴリズム
3. 描画データからノードとリンクを求める。clustererにクラスタリングのアルゴリズムを設定する(サンプルの場合DBSCAN)
4. visualizeにcomplexを渡し、htmlを作成してもらう
この4ステップでTDAっぽいhtmlファイルを生成してもらえる。
csvのフォーマットはこんな感じ。先頭行に正解ラベルを、以降1行に正解ラベルを示すデータをだーっと書いていけばいい。
正解ラベル | データ1 | データ2 |
---|---|---|
A | 1 | 2 |
B | 2 | 3 |
TDA自体は教師データは必要なく、visualizeするときのcustom_tooltipsに正解ラベルを貼り付けておくと分析がしやすいだけなので、正解ラベルについては必要に応じてつければ良い。
出力のhtmlファイルはこんな感じ、今回はmnistに対してTDAをしてみた。
この1つ1つの丸(ノード)がクラスタになっており、線(リンク)が類似度のようなものを表しているっぽい。
例えば同じ0でも線が太い0もあれば細い0もあったり、同じ0でも特徴の捉え方がより細かくわかって面白い。
TDAのパラメータを色々変えて見るとまた違ったトポロジができるので色々研究してみようと思う。
TDAとkepler-mapper
TDAに関する理論を調べているとノードやらエッジやら色々と難しい表現が出てくるのだが、今回のkepler-mapperを動かしてみた感じ要はこういうことのようだ。
- 何かしらの方法で多次元データを2次元データに落とし込む(PCA、T-SNEなど)
- 2次元データを何かしらの方法でクラスタリングし(DBSCAN、K-meansなど)、ノードとリンクを取得する
- グラフに出力する
キーになりそうなのが1と2のロジック選択で、今回はT-SNEとDBSCANを利用しているのだがこの場合は厳密にはTDAではないのかもしれない。
TDAを調べて見るとTDAは単にPCAのように次元削減をするアルゴリズムではなく、高次元データをbirthとdeathという二次元データで表現可能な状態にすること(パーシステントホモロジーっていうらしい)が目的のアルゴリズムであるようで、この1と2に関しては本来はもっと正しいやり方があるような気がする。
おそらくグラフ表現は補助的なもので、本来はパーシステントホモロジーこそがメインの話なのであろう。
とりあえず自己満足するレベルにはプログラムを動かすことに成功したので、
ここから先はTDAに関する理論を深めて正しいロジックでプログラムを動かそうと思う。