• トップ
  • ブログ一覧
  • 「t-SNE」を用いて高次元データを可視化する
  • 「t-SNE」を用いて高次元データを可視化する

    広告メディア事業部広告メディア事業部
    2020.05.25

    IT技術

    t-SNE(ティースニー)を使い高次元データを可視化してみる

    高次元のデータを可視化するには、高次元のデータを2〜3次元のデータに変換する必要があります。

    有名な手法としては、例えば、以下のようなものがあります。

    1. 主成分分析
    2. 多次元尺度構成法
    3. Isomap
    4. LLE(Locally Linear Embedding)

    これらの方法を用いれば、高次元のデータを低次元のデータに変換し、2〜3次元のデータとして可視化することができます。

    変換にも限界がある

    しかし、これらの方法には限界があります

    まず、「主成分分析」や「多次元尺度構成法」は線形変換を前提としているため、非線形な高次元データを低次元データに上手く落とし込むことができません。

    また、「Isomap」や「LLE」は、データの局所的な構造と大局的な構造を、同時に低次元データへと表現することが難しいことが知られています。

    問題点を解消する分析手法「t-SNE」の提案

    そこで、これらの問題点を乗り越える、「t-SNE(ティースニー)」と呼ばれる分析手法が2008年に提案されました。

    2008年の提案論文の詳細は、以下の論文を参照してください。

    「Maaten Laurens van der., and Hinton Geoffrey., 2008, "Visualizing Data using t-SNE," Journal of Machine Learning Research 9: 2579-2605.」

    それでは、「t-SNE」について解説し、「MNIST」を使った分析例を見ていきたいと思います!

    「t-SNE」の概要

    「SNE」とは?

    「t-SNE」は、「SNE(Stochastic Neighbor Embedding)」をベースとしています。

    そこで、まずは「SNE」について見ていきます。

    「SNE」のポイントは、「2つ」です!

    「SNE」のポイント1

    1つ目のポイントは、高次元でのデータポイント間の距離を条件付き確率に変換することです。

    高次元において、「データポイントxix_i」から見た場合の「データポイントxjx_jとの距離pijp_{i|j}」を、「データポイントxix_i」を平均とした正規分布に従っていると仮定して、その距離(条件付き確率)を計算します。

    具体的には以下のように計算します。

    pij=exp(xixj2/2σi2)ikexp(xixk2/2σi2)p_{i|j} = \frac{exp(-||x_i - x_j||^2 / 2 \sigma_i^2)}{\sum_{i≠k} exp(-||x_i - x_k||^2 / 2 \sigma_i^2)}

    なお、正規分布の確率密度関数の12πσi2\frac{1}{\sqrt{2 \pi \sigma_i ^ 2}}部分は、分母と分子でうち消され合っていることに注意してください。

    「SNE」のポイント2

    2つ目のポイントは、上記で計算した高次元でのデータポイント間の距離(条件付き確率)と、できるだけ近い低次元でのデータポイント間の距離(条件付き確率)をとる点を見つけることです。

    まず、低次元での「データポイントyiy_i」から見た場合の「データポイントyjy_jとの距離qijq_{i|j}」を、pijp_{i|j}同様に以下のように表現します。

    ただし、標準偏差は12\frac{1}{\sqrt{2}}に固定しておきます。

    qij=exp(yiyj2)ikexp(yiyk2)q_{i|j} = \frac{exp(-||y_i - y_j||^2)}{\sum_{i≠k} exp(-||y_i - y_k||^2)}

    このように計算されたqijq_{i|j}と、上記のpijp_{i|j}を出来る限り同じにします。

    カルバック・ライブラー情報量

    両者はどちらも確率分布なので、「異なる確率分布間の距離の指標」である「カルバック・ライブラー情報量」と呼ばれる指標を用います。

    このカルバック・ライブラー情報量をコスト関数として、それを最小化する「 yy 」 を見つけます。

    こうして見つけられた「 yy 」が、高次元データxxの低次元データ変換後のデータポイントとして解釈できます。

    「t-SNE」とは「SNE」から2つのポイントを改善した分析手法

    以上が「SNE」のアイディアです。

    「t-SNE」は SNE から2つのポイントを改善した分析手法なのです!

    「t-SNE」のポイント1

    最初のポイントは、距離に対称性を持たせることです。

    SNE ではpijp_{i|j}pjip_{j|i}が、その定義から同じではありませんでした。

    そこで、高次元データ上での「データポイントxix_i」と、「データポイントxjx_j間の距離pijp_{ij}」を以下のように定義することで、その対称性を担保します。

    pij=pij+pji2np_{ij} = \frac{p_{i|j} + p_{j|i}}{2n}

    「t-SNE」のポイント2

    2つ目のポイントは、qijq_{ij}を表現する際に、正規分布ではなく自由度1の t 分布を使用することです。

    すなわち、以下のように表現します。

    qij=(1+yiyj2)1kl(1+ykyl2)1q_{ij} = \frac{(1 + ||y_i - y_j||^2)^{-1}}{\sum_{k≠l}(1 + ||y_k - y_l||^2)^{-1}}

    なぜ t 分布を用いるのか?

    なぜ正規分布ではなく t 分布を用いるかというと、t 分布は正規分布に比べて裾が長いため、近いデータはより近くに、遠いデータはより遠くに表現できるためです。

    t-SNE の「t」は、t 分布の「t」だったんですね!

    以上、2つのポイントを SNE から変更したのが「t-SNE」です。

    「t-SNE」を MNIST に適用

    それでは、「t-SNE」を実際のデータに適用して分析してみましょう!

    MNIST データの準備・確認

    今回利用するデータは、おなじみの「MNIST」です。

    「MNIST」には、訓練データが60,000枚、テストデータが10,000枚あり、1つ1つの画像には784(28×28)のデータが含まれています。

    データ量が多いと計算に時間がかかってしまいます。

    そのため、今回はテストデータ10,000枚を使用します。

    ちなみに、別の話ですが、弊社ブロブでは、こんな「MNIST」記事も書いてます。

    featureImg2020.01.23【PyTorch入門】PyTorchで手書き数字(MNIST)を学習させるPyTorchで手書き数字(MNIST)を学習させる前回は、PyTorch(パイトーチ)のインストールなどを行いました...

    中身の確認

    まずは、中身を確認しましょう。

    テストデータとそのラベルはすでにX_testy_test に格納されているとします。

    1# dataの確認
    2print(X_test.shape)
    3print(y_test.shape)
    4print(type(X_test))
    5print(type(y_test))

    出力結果

    出力結果は、こちらです。

    1(10000, 784)
    2(10000,)
    3<class 'numpy.ndarray'>
    4<class 'numpy.ndarray'>

    画像の確認

    では、先頭のデータは、どのような画像になっているのか確認してみましょう。

    1# dataの確認
    2import matplotlib.pyplot as plt
    3plt.imshow(X_test[0].reshape(28, 28))

    出力結果は、こうなりました。

    「7」という手書き文字であることが確認できます。

    print(y_test[0]) を実行し、ラベルデータで確認しておきましょう。

    予想通り、出力結果は7 となるはずです。

    「t-SNE」の適用・可視化

    それでは、「t-SNE」を適用してみましょう!

    今回は、2次元のデータに落とし込みます。

    また、それ以外のハイパーパラメータは、ライブラリのデフォルトのままにしておきます。

    下記の通りに実行すると、X_test に t-SNE を適用でき、得られた低次元データをX_tsne に格納できます。

    1# t-SNEの適用
    2from sklearn.manifold import TSNE
    3tsne = TSNE(n_components = 2) # n_componentsは低次元データの次元数
    4X_tsne = tsne.fit_transform(X_test)

    結果の可視化

    結果を可視化してみます!

    可視化のためのコードは、下記の通りです。

    2次元の散布図上に、文字を色分けしてプロットしています。

    1# 結果の可視化
    2import matplotlib.pyplot as plt
    3colors = ['red', 'blue', 'green', 'pink', 'tomato', 'purple', 'black', 'olive', 'lightblue', 'lime']
    4plt.xlim(X_tsne[:, 0].min(), X_tsne[:, 0].max() + 1)
    5plt.ylim(X_tsne[:, 1].min(), X_tsne[:, 1].max() + 1)
    6for i in range(len(X_test)):
    7    plt.text(
    8        X_tsne[i, 0],
    9        X_tsne[i, 1],
    10        str(y_test[i]),
    11        color = colors[y_test[i]]
    12        )
    13plt.xlabel('t-SNE Feature1')
    14plt.ylabel('t-SNE Feature2')

    出力結果

    出力結果です。

    これを見ると、高次元データが低次元データへと綺麗にプロットされている様子がうかがえます。

    t-SNE で出力された、この2つの特徴量を用いれば、画像分類のアルゴリズムを比較的簡単に実装できそうです。

    さらに、出力結果を確認すると互いの関係がよく分かるようになります。

    例えば、「7」(深緑色:左上)と「9」(黄緑色:左上)は互いに近くに分布しています。

    一方で、「7」(深緑色:左上)と「0」(赤色:右下)は互いに遠く分布しています。

    ここから「7」と「9」は同じような特徴があり、「7」と「0」は異なる特徴を有していることが示唆されます。

    さいごに

    今回は「t-SNE」について解説し、MNIST データに適用してみました!

    「t-SNE」は、高次元データを低次元データへと変換する比較的新しい分析手法です。

    「t-SNE」のアイディアの核は、高次元データ上でのデータ間の距離を確率として表現し、それとできるだけ同じような、低次元データ上でのデータ間の距離(確率)をとる点を探すことです。

    「t-SNE」を用いると、高次元データを低次元データへと簡単に可視化できます。

    ぜひ、「t-SNE」をご自身のデータにも適用してみてください!

    こちらの記事もオススメ!

    featureImg2020.07.28機械学習 特集知識編人工知能・機械学習でよく使われるワード徹底まとめ!機械学習の元祖「パーセプトロン」とは?【人工知能】ニューラルネ...

    featureImg2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    広告メディア事業部

    広告メディア事業部

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background