Pythonによる4種の次元削減と可視化
以下4つの次元削減アルゴリズムをPythonで実行し、それぞれで2次元のグラフを作成してみます。
- PCA(Principal Component Analysis:主成分分析)
- SVD(Singular Value Decomposition:特異値分解)
- t-SNE(t-distributed Stochastic Neighbor Embedding)
- UMAP(Uniform Manifold Approximation and Projection)
次元削減についての説明やこれらの使い分けについてはこちらの記事に纏めています。
ファイルの読み込み
今回は、以下のような15名のエンジニアのスキルレベルを10段階で評価したデータを仮定します。
まずはこのCSVを以下のようにデータフレームに読み込みます。
1 2 3 4 5 |
import pandas as pd import numpy as np #ファイル読み込み df = pd.read_csv("skill_level.csv",index_col=0) |
さて、それでは全社員のスキルの傾向や分布はどうなっているのか。
どの社員とどの社員が近いのか。
そういった事をパッと視覚的に分かりやすくするために、次元削減で可視化してみましょう。
Pythonによる次元削減の実行
PCA
scikit-learnのPCAクラスを使います。
1 2 3 |
from sklearn.decomposition import PCA model_pca = PCA(n_components=2) vecs_list = model_pca.fit_transform(df) |
vecs_listに、2次元に圧縮された15名のデータが格納されています。
なので、最終的にはこの圧縮された15個の点を座標状にプロットしてあげればOKです。
(この散布図の書き方は次の章で記します。)
また、PCAではどれほど元の情報が残ったかの「寄与度」を簡単に計算する事ができます。
1 |
print(pca.explained_variance_ratio_) |
1 |
[0.71235597 0.21434312] |
第1主成分だけで約71%、第2主成分だけで約21%です。
累積寄与率は約93%という高い値なので、次元を2にしても、元の情報は殆ど保持されていると考えて良いでしょう。
SVD
scikit-learnのTruncatedSVDクラスを使います。
1 2 3 |
from sklearn.decomposition import TruncatedSVD model_svd = TruncatedSVD(n_components=2) vecs_list = model_svd.fit_transform(df) |
結果を見ると、ほぼPCAが左右反転しただけのようです。
細かい計算の理論は違うのですが、このようにほぼPCAとSVDは同じ結果が得られます。
t-SNE
scikit-learnのTSNEクラスを使用します。
(bhtsneライブラリを使用する方法もあります。)
1 2 3 |
from sklearn.manifold import TSNE model_tsne = TSNE(n_components=2, perplexity=2) vecs_list = model_tsne.fit_transform(df) |
PCAやSVDよりも綺麗にクラスタが出来ているのが分かるかと思います。
一般的に、PCA/SVDよりもt-SNEを用いた方が明確にクラスタが見て取れるような結果が得られます。
しかし、その分、「データ間の距離」にはあまり意味がなくなっていますのでご注意ください。
また、t-SNEは、パラメータ調整で結果が大きく変わります。
パラメータにも色々ありますが、とりわけ重要なのはperplexityという引数です。
この値によって結果は大きく変わります。
データによってどの値が優れるかは変わりますので、幾つか実験してみる必要があります。
例えば2,5,10,50,100あたりにひとまず設定してみるのが良いかと思います。
ちなみに、今回のデータでperplexity=100とすると、以下の結果が得られます。
綺麗ですが、特に何の特徴も読み取れない結果となってしまいました。このように、perplexityの値で結果が大きく変わるので注意が必要です。
UMAP
umapライブラリのUMAPクラスを使います。
1 2 3 4 5 |
import umap.umap_ as umap from scipy.sparse.csgraph import connected_components model_umap = umap.UMAP(n_components=2,n_neighbors=3) vecs_list = model_umap.fit_transform(df) |
こちらも、綺麗にクラスタができています。
UMAPもt-SNE同様パラメータ調整が必要で、特に重要なのがn_neighborsです。
今回のデータでは3にしましたが、適切な値はデータによって異なりますので、t-SNE同様に幾つか数値を入れてみて、上手く次元削減できていそうなところをご自身で選ぶようにしてください。
グラフの描画ソース
seabornライブラリのscatterplotを用いて、上記の散布図を作成するソースです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import seaborn as sns import matplotlib.pyplot as plt X = vecs_list[:,0] Y = vecs_list[:,1] sns.set(font="Hiragino Maru Gothic Pro") plt.figure(figsize=(8, 8)) sns.scatterplot(x=X,y=Y) for i,(x_name,y_name) in enumerate(zip(X,Y)): plt.annotate(df.index[i],(x_name,y_name)) plt.show() |
vecs_listに圧縮された値が入っているので、そのXとYを与えてやるだけです。
plt.annotateで、点の上にデータ名を付与しています。
以上、Pythonによる次元削減でした。