post Image
高次元データの次元削減および2次元プロット手法

はじめに

本記事はPython2.7, numpy 1.11, scipy 0.17, scikit-learn 0.18, matplotlib 1.5, seaborn 0.7, pandas 0.17を使用しています.
jupyter notebook上で動作確認済みです.(%matplotlib inlineは適当に修正してください)
SklearnのManifold learningの記事を参考にしています.

多様体学習と言われる手法について,sklearnのdigitsサンプルを用いて説明します.
特にt-SNEはKaggleなどでもたまに使用されている,多次元データの可視化に適した手法です.
また可視化だけでなく,元のデータと圧縮されたデータを結合することで,単純な分類問題の精度を向上することができます.

目次

  1. データの生成
  2. 線形要素に注目した次元削減
    1. Random Projection
    2. PCA
    3. Linear Discriminant Analysis
  3. 非線形成分を考慮した次元削減
    1. Isomap
    2. Locally Linear Embedding
    3. Modified Locally Linear Embedding
    4. Hessian Eigenmapping
    5. Spectral Embedding
    6. Local Tangent Space Alignment
    7. Multi-dimensional Scaling
    8. t-SNE
    9. Random Forest Embedding

1. データの生成

sklearnのサンプルデータを用います.
今回はdigits datasetを用いて,数字のクラスタリングを行います.
まずはデータのロードとチェックです.

load_digit.py
from time import time

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import offsetbox
from sklearn import (manifold, datasets, decomposition, ensemble,
                     discriminant_analysis, random_projection)

digits = datasets.load_digits(n_class=6)
X = digits.data
y = digits.target
n_samples, n_features = X.shape
n_neighbors = 30

n_img_per_row = 20
img = np.zeros((10 * n_img_per_row, 10 * n_img_per_row))
for i in range(n_img_per_row):
    ix = 10 * i + 1
    for j in range(n_img_per_row):
        iy = 10 * j + 1
        img[ix:ix + 8, iy:iy + 8] = X[i * n_img_per_row + j].reshape((8, 8))

plt.imshow(img, cmap=plt.cm.binary)
plt.xticks([])
plt.yticks([])
plt.title('A selection from the 64-dimensional digits dataset')

a

digitデータのマッピング用関数を準備します.
こちらは本記事の主題とずれるので,よくわからなければ飛ばしてください.

def plot_embedding(X, title=None):
    x_min, x_max = np.min(X, 0), np.max(X, 0)
    X = (X - x_min) / (x_max - x_min)

    plt.figure()
    ax = plt.subplot(111)
    for i in range(X.shape[0]):
        plt.text(X[i, 0], X[i, 1], str(digits.target[i]),
                 color=plt.cm.Set1(y[i] / 10.),
                 fontdict={'weight': 'bold', 'size': 9})

    if hasattr(offsetbox, 'AnnotationBbox'):
        # only print thumbnails with matplotlib > 1.0
        shown_images = np.array([[1., 1.]])  # just something big
        for i in range(digits.data.shape[0]):
            dist = np.sum((X[i] - shown_images) ** 2, 1)
            if np.min(dist) < 4e-3:
                # don't show points that are too close
                continue
            shown_images = np.r_[shown_images, [X[i]]]
            imagebox = offsetbox.AnnotationBbox(
                offsetbox.OffsetImage(digits.images[i], cmap=plt.cm.gray_r),
                X[i])
            ax.add_artist(imagebox)
    plt.xticks([]), plt.yticks([])
    if title is not None:
        plt.title(title)

2. 線形成分に着目した次元削減

ここで紹介する手法は,低計算コストかつ汎用性も高く,頻繁に使用されています.
例えば,PCAはデータの相関性を抽出できる非常に便利な手法です.
これらの手法は多くのサイトで詳しく説明されているため,軽く流していきます.

2.1. Random Projection

1にて64次元の数値データを取得しました.
このような高次元データをマッピングする最も基本的な手法は,Random Projectionです.
非常に単純な手法で,M次元のデータを,マッピング可能なN次元へと写像する行列Rの要素を乱数で設定します.
メリットとしては計算コストの小ささが挙げられます.

print("Computing random projection")
rp = random_projection.SparseRandomProjection(n_components=2, random_state=42)
X_projected = rp.fit_transform(X)
plot_embedding(X_projected, "Random Projection of the digits")
#plt.scatter(X_projected[:, 0], X_projected[:, 1])

b

2.2. PCA

一般的な次元圧縮法であるPCAでマッピングします.
変数間の相関成分を抽出します.
使用している関数はsklearnのTruncatedSVDで,PCAとの違いはインプットデータを正規化するかどうかのようです.

print("Computing PCA projection")
t0 = time()
X_pca = decomposition.TruncatedSVD(n_components=2).fit_transform(X)
plot_embedding(X_pca,
               "Principal Components projection of the digits (time %.2fs)" %
               (time() - t0))

c

2.3. Linear Discriminant Analysis

線形判別分類で次元削減を行います.各変数が多変量正規分布・同グループが同じ共分散行列をもつ,という前提のもとマハラノビス距離を用います.
PCAと似ていますが,こちらは教師あり学習です.

print("Computing Linear Discriminant Analysis projection")
X2 = X.copy()
X2.flat[::X.shape[1] + 1] += 0.01  # Make X invertible
t0 = time()
X_lda = discriminant_analysis.LinearDiscriminantAnalysis(n_components=2).fit_transform(X2, y)
plot_embedding(X_lda,
               "Linear Discriminant projection of the digits (time %.2fs)" %
               (time() - t0))

d

3. 非線形成分を考慮した次元削減

先ほど紹介した3つの手法は,階層構造を持つデータや非線形成分を含んだデータの次元削減という点で適していません.
ここではswiss rollのような,線形相関ではないデータの2次元プロットを紹介します.

download (2).png

3.1. Isomap

Isomapは非線形性を考慮した次元削減・クラスタリング手法の一つです.
多様体の形に沿った測地距離という距離を計算し,それを元にMulti-Dimensional Scalingを行います.
SklearnのIsomap関数で実行可能です.計測距離を計算する段階で,BallTreeを使用しています.

print("Computing Isomap embedding")
t0 = time()
X_iso = manifold.Isomap(n_neighbors, n_components=2).fit_transform(X)
print("Done.")
plot_embedding(X_iso,
               "Isomap projection of the digits (time %.2fs)" %
               (time() - t0))

3.2. Locally Linear Embedding (LLE)

全体で見れば非線形性を含んだ多様体でも.局所的に見れば線形性という直感に基づいた次元削減手法.
0ラベルが強調されているように見えますが,他のラベルはごちゃごちゃしています.

print("Computing LLE embedding")
clf = manifold.LocallyLinearEmbedding(n_neighbors, n_components=2,
                                      method='standard')
t0 = time()
X_lle = clf.fit_transform(X)
print("Done. Reconstruction error: %g" % clf.reconstruction_error_)
plot_embedding(X_lle,
               "Locally Linear Embedding of the digits (time %.2fs)" %
               (time() - t0))

3.3. Modified Locally Linear Embedding

LLEの問題点ある,正則化問題を改良したアルゴリズム.
0ラベルがはっきりと分類されました.4, 1, 5ラベルも綺麗にマッピングされているように見えます.

print("Computing modified LLE embedding")
clf = manifold.LocallyLinearEmbedding(n_neighbors, n_components=2,
                                      method='modified')
t0 = time()
X_mlle = clf.fit_transform(X)
print("Done. Reconstruction error: %g" % clf.reconstruction_error_)
plot_embedding(X_mlle,
               "Modified Locally Linear Embedding of the digits (time %.2fs)" %
               (time() - t0))

3.4. Hessian LLE Embedding

LLEの問題点ある,正則化問題を改良したアルゴリズム.
その2

print("Computing Hessian LLE embedding")
clf = manifold.LocallyLinearEmbedding(n_neighbors, n_components=2,
                                      method='hessian')
t0 = time()
X_hlle = clf.fit_transform(X)
print("Done. Reconstruction error: %g" % clf.reconstruction_error_)
plot_embedding(X_hlle,
               "Hessian Locally Linear Embedding of the digits (time %.2fs)" %
               (time() - t0))

3.5. Spectral Embedding

Laplacian Eigenmapsとも言われる圧縮手法です.
専門的な内容は調べていませんが,スペクトラルグラフ理論というのを使用しているようです.
マッピングの形はLLE, MLLE, HLLEと異なりますが,ラベルグループ間の距離や密集具合は似ているように見えます.

print("Computing Spectral embedding")
embedder = manifold.SpectralEmbedding(n_components=2, random_state=0,
                                      eigen_solver="arpack")
t0 = time()
X_se = embedder.fit_transform(X)

plot_embedding(X_se,
               "Spectral embedding of the digits (time %.2fs)" %
               (time() - t0))

3.6. Local Tangent Space Alignment

MLLE,HLLEを逆転したような結果となっています.分類結果は似た感じです.

print("Computing LTSA embedding")
clf = manifold.LocallyLinearEmbedding(n_neighbors, n_components=2,
                                      method='ltsa')
t0 = time()
X_ltsa = clf.fit_transform(X)
print("Done. Reconstruction error: %g" % clf.reconstruction_error_)
plot_embedding(X_ltsa,
               "Local Tangent Space Alignment of the digits (time %.2fs)" %
               (time() - t0))

3.7. Multi-dimensional Scaling (MDS)

多次元尺度構成法と言われる圧縮法です.
MDS自体はいくつかの手法をまとめた総称のようですが,詳細は特にまとめていません.

print("Computing MDS embedding")
clf = manifold.MDS(n_components=2, n_init=1, max_iter=100)
t0 = time()
X_mds = clf.fit_transform(X)
print("Done. Stress: %f" % clf.stress_)
plot_embedding(X_mds,
               "MDS embedding of the digits (time %.2fs)" %
               (time() - t0))

3.8. t-distributed Stochastic Neighbor Embedding (t-SNE)

各点のユークリッド距離を、類似度の代わりに条件付き確率に変換して低次元にマッピングする手法です.

精度を犠牲にして計算コストを向上させたBarnes-Hut t-SNEという方法もあります.Sklearnでは,methodをexact(精度重視)とBarnes-Hutの2つを選択可能です.デフォルトではBarnes-Hutが選択されており,同じくオプションのangleを設定することでチューニングが可能です.
Kaggleでも頻繁に取り上げられています.

print("Computing t-SNE embedding")
tsne = manifold.TSNE(n_components=2, init='pca', random_state=0)
t0 = time()
X_tsne = tsne.fit_transform(X)

plot_embedding(X_tsne,
               "t-SNE embedding of the digits (time %.2fs)" %
               (time() - t0))

3.9. Random Forest Embedding

print("Computing Totally Random Trees embedding")
hasher = ensemble.RandomTreesEmbedding(n_estimators=200, random_state=0,
                                       max_depth=5)
t0 = time()
X_transformed = hasher.fit_transform(X)
pca = decomposition.TruncatedSVD(n_components=2)
X_reduced = pca.fit_transform(X_transformed)

plot_embedding(X_reduced,
               "Random forest embedding of the digits (time %.2fs)" %
               (time() - t0))


『 機械学習 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。