GMMを用いたクラスタリング

本日のテーマは「GMMを用いたクラスタリング」です。本記事では、GMMを用いたクラスタリング手法について簡単な説明をした後、scikit-learnを使って実際にプログラムを書いてみたいと思います。

 

GMMとは?

GMMとは、混合ガウスモデル(Gaussian Mixture Model)のことで、複数のガウス分布(正規分布)が重なったようなモデルのことを指します。 ガウス分布は以下のような数式で表します。

$$N(\boldsymbol{x}|\boldsymbol{\mu}, \boldsymbol{\Sigma}) = \frac{1}{(2\pi)^{D / 2}}\frac{1}{(|\boldsymbol\Sigma|)^{1 / 2}}exp\{-\frac{1}{2}(\boldsymbol{x} – \boldsymbol{\mu})^T\boldsymbol{\Sigma}^{-1}(\boldsymbol{x} – \boldsymbol{\mu})\}$$

これは1つのガウス分布の式を表しており、複数のガウス分布が重なった場合、以下のように表します。なお、ここではK個の正規分布が重なり合うと仮定しています。

$$p(\boldsymbol{x}) = \sum_{k=1}^{K}\boldsymbol{\pi}_kN(\boldsymbol{x}|\boldsymbol{\mu_k}, \boldsymbol{\Sigma_k})$$

これが混合ガウスモデルの式になります。このモデルを使って、クラスタリングをおこないます。

scikit-learnを使って教師なし学習

GMMの実装は、scikit-learnのmixtureにあります。サンプルコードは以下のようになります。

In [1]:
# -*- Coding: utf-8 -*-
import sys
sys.version
Out[1]:
'3.7.4 (default, Aug 13 2019, 15:17:50) \n[Clang 4.0.1 (tags/RELEASE_401/final)]'
In [2]:
import sklearn
print(sklearn.__version__)
0.21.3
In [3]:
import numpy as np
from sklearn.datasets import load_iris
iris = load_iris()
iris.data.shape
Out[3]:
(150, 4)
In [4]:
# 正解ラベル
iris.target
Out[4]:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
In [5]:
import sklearn.mixture
In [6]:
# gmmインスタンスを作成
gmm = sklearn.mixture.GaussianMixture(n_components=3, covariance_type="full")
In [7]:
gmm.fit(iris.data)
Out[7]:
GaussianMixture(covariance_type='full', init_params='kmeans', max_iter=100,
                means_init=None, n_components=3, n_init=1, precisions_init=None,
                random_state=None, reg_covar=1e-06, tol=0.001, verbose=0,
                verbose_interval=10, warm_start=False, weights_init=None)
In [8]:
estimate_label = gmm.fit_predict(iris.data)
estimate_label
Out[8]:
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

学習には、irisデータセットを使いました。irisデータセットは正解ラベルが存在しますが、今回は教師なし学習ですので使いません。

fit_predictメソッドを使うことで、予測を行うことができます。注意点は、fit_predictを実行すると各データ点のlabelが返ってきますが、このlabelはirisの正解ラベルとは違うものであるということです。

ちょっとした補足ですが、scikit-learnの中の実装では、EMアルゴリズムというアルゴリズムが使われています。興味がある方は是非調べてみてください。

次回は、同じmixtureの中にある、basyesian_gaussian_mixtureというものについて解説します。