scikit-learn

【scikit-learn】KernelPCAでカーネル主成分分析をする方法

【scikit-learn】KernelPCAでカーネル主成分分析をする方法

Pythonの機械学習ライブラリであるscikit-learnのKernelPCAを使ってカーネル主成分分析をする方法について解説します。カーネル主成分分析をして変換をすることで線形分離不可能なデータが非線形分離ができることを見ていきたいと思います。

カーネル主成分分析

主成分分析(Principal Component Analysis: PCA)は、元のデータの特徴を最もよく表すことができる主成分と呼ばれるベクトルを計算するための解析手法の一種です。scikit-learnでPCAを実行する例については「PCAで主成分分析をする方法」でまとめていますので興味があれば参考にしてください。

PCAでは、高次元の元データを寄与率が高いいくつかの主成分へ射影することで次元削減をするといったことができました。

今回紹介するカーネルPCA(KernelPCA)はデータが線形分離不可能なデータに適用し、変換をかけることで線形分離できるようなデータに変換することができます。線形分離できるようなデータに変換できれば、線形の分類器を使っても容易にデータを分類をすることができるようになります。

カーネルPCA(KernelPCA)は、Pythonの機械学習ライブラリであるscikit-learnに実装がされています。本記事では、scikit-learnのKernelPCAを使って線形分離できないデータを変換してみたいと思います。

scikit-learnのKernelPCAでカーネル主成分分析をする方法

以降では、scikit-learnを使用します。インストールがされていない場合はpipでインストールをしておいてください。

pip install scikit-learn

カーネルPCAの使い方(sklearn.decomposition.KernelPCA)

実装例(circlesデータ)

scikit-learnのデータに用意されているmake_circlesを使って生成したデータで、線形分離不可能なデータを線形分離できるように変換できることを見てみたいと思います。

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_circles
from sklearn.decomposition import KernelPCA


def main():
    """メイン関数"""
    np.random.seed(0)

    # ===== データの用意・表示
    data, label = make_circles(n_samples=1000, noise=0.1, factor=0.2)
    plt.scatter(data[label == 0, 0], data[label == 0, 1], marker="x")
    plt.scatter(data[label == 1, 0], data[label == 1, 1], marker="^")
    plt.title("circle data")

    # ===== カーネルPCAのモデル生成・学習
    k_pca = KernelPCA(n_components=2, kernel="rbf", gamma=15)
    k_pca.fit(data, label)

    # ===== 主成分軸への変換
    trans_data = k_pca.transform(data)

    # ===== 変換結果を表示
    plt.figure()
    plt.scatter(trans_data[label == 0, 0], trans_data[label == 0, 1], marker="x")
    plt.scatter(trans_data[label == 1, 0], trans_data[label == 1, 1], marker="^")
    plt.title("kernel pca")

    plt.show()


if __name__ == "__main__":
    main()

【実行結果】

circleデータ
circleデータ KernelPCA適用後

以降でプログラムの各部分について内容を説明します。

データの用意

    np.random.seed(0)

    # ===== データの用意・表示
    data, label = make_circles(n_samples=1000, noise=0.1, factor=0.2)
    plt.scatter(data[label == 0, 0], data[label == 0, 1], marker="x")
    plt.scatter(data[label == 1, 0], data[label == 1, 1], marker="^")
    plt.title("circle data")

この部分では、対象となるデータを生成して描画しています。描画結果を見てもわかりますが、内側の円と外側の円で分かれているデータとなっていることが分かります。このデータを線形分離(直線で分離)することは難しそうであるということが分かるかと思います。

カーネルPCAの実行と変換

    # ===== カーネルPCAのモデル生成・学習
    k_pca = KernelPCA(n_components=2, kernel="rbf", gamma=15)
    k_pca.fit(data, label)

    # ===== 主成分軸への変換
    trans_data = k_pca.transform(data)

カーネルPCAのモデルを生成して学習している部分です。KernelPCAのハイパーパラメータとしては以下のようなものを設定しています。

  • n_components:主成分の数を指定します。
  • kernel:カーネル関数を指定します。デフォルトは’linear’(線形)ですが、今回は’rbf’(動径基底関数)を指定しています。
  • gamma:rbfのパラメータを指定します。

モデルの学習はfitメソッドを使用し、主成分軸への変換はtransformメソッドで変換しています。

変換結果の表示

    # ===== 変換結果を表示
    plt.figure()
    plt.scatter(trans_data[label == 0, 0], trans_data[label == 0, 1], marker="x")
    plt.scatter(trans_data[label == 1, 0], trans_data[label == 1, 1], marker="^")
    plt.title("kernel pca")

    plt.show()

最後に上記の部分では、transformメソッドで変換したデータを表示しています。

元データに対して学習したモデルで変換(transform)をかけると、結果を見てもわかるようにもともと線形分離不可能であったデータが左右の二つのデータの集まりに分離されて、線形分離可能なようになっていることが分かります。

このようにKernelPCAを使った分析・変換により線形分離不可能であったデータを線形分離可能な形に変換することが可能です。

ただし、KernelPCAでデータに対して変換をかけたとしても必ず線形分離できる形に変換されるとは限りません。元のデータの特徴や、ハイパーパラメータの指定によっても変換の形は変わるためです。対象としているデータに対してハイパーパラメータを変えて色々と試してみると面白いかと思います。

実装例(moonsデータ)

scikit-learnのデータセットにmake_moonsというのがある事を知ったので試しに同じように適用してみようと思います。

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_moons
from sklearn.decomposition import KernelPCA


def main():
    """メイン関数"""
    np.random.seed(0)

    # ===== データの用意・表示
    data, label = make_moons(n_samples=100, noise=0.01)
    plt.scatter(data[label == 0, 0], data[label == 0, 1], marker="x")
    plt.scatter(data[label == 1, 0], data[label == 1, 1], marker="^")
    plt.title("moon data")

    # ===== カーネルPCAのモデル生成・学習
    k_pca = KernelPCA(n_components=2, kernel="rbf", gamma=15)
    k_pca.fit(data, label)

    # ===== 主成分軸への変換
    trans_data = k_pca.transform(data)

    # ===== 変換結果を表示
    plt.figure()
    plt.scatter(trans_data[label == 0, 0], trans_data[label == 0, 1], marker="x")
    plt.scatter(trans_data[label == 1, 0], trans_data[label == 1, 1], marker="^")
    plt.title("kernel pca")

    plt.show()


if __name__ == "__main__":
    main()

【実行結果】

moonデータ
moonデータ KernelPCA適用後

コードの構成は、circlesデータに適用した場合とほぼ同じなので説明は省略します。

結果を見てみると月形のデータで線形分離不可能なデータが線形分離可能な形になっているのが分かります。ちょっと形的に面白いなと思ったので紹介してみました。

まとめ

Pythonの機械学習ライブラリであるscikit-learnのKernelPCAを使ってカーネル主成分分析をする方法について紹介しました。

カーネル主成分分析をすること線形分離不可能なデータが非線形分離できるようになることが分かったかと思います。ただし、元データの特徴やパラメータの設定により必ずしも線形分離可能なデータに変換できるわけではないことは注意しましょう。

Note

sklearn.decomposition.KernelPCAの公式ドキュメントはこちらを参考にしてください。