「機械学習理論入門」第6章 k平均法:教師なし学習モデルの基礎
##今回やること
- k平均法の概要
- k平均法の数学的根拠
- 画像データへの応用
- サンプルコードの解説
- k近傍法の紹介
##k平均法の概要
教師なし学習によるクラスタリングの基礎
類似のデータをグループ化するシンプルなアルゴリズム
画像の色のグループ化や文書データのグループ化に用いる
教師あり学習と教師なし学習の違い
学習 | 特長 |
---|---|
教師あり学習 | すでに目的変数がわかっているデータを分析することで 未知のデータに対して目的変数の値を推測するルールを導き出す |
教師なし学習 | 与えられたデータを明示的に分類する目的変数がわからない 状態でデータ間の類似性を発見していく |
今回は**図6.1(a)**の例
を二つのグループに分類する
##いつもの3ステップ
- 1.パラメータを含むモデル(数式)を設定する
- 2.パラメータを評価する基準を定める
- 3.最良の評価を与えるパラメータを決定する
しかし今回はパラメトリックモデルではないため2ステップになる
- 1.評価する基準を定める
- 2.最良の評価を与える分類を決定する
##1.評価する基準を定める
k平均法では「二乗歪み」という値を定義しておき、これをなるべく小さくするグループ分けを見つけ出す。
J = \sum_{n=1}^{N}\sum_{k=1}^{K}r_{nk}||X_n-μ_k||^2
##2.最良の評価を与える分類を決定する
k平均法のアルゴリズムでは、分類するクラスターの数は、事前に指定する必要がある
今回は二つのクラスターに分類するので、平面上の適当な2点を代表点として設定する(図6.1b)
続いて、トレーニングセットの各点について、「どちらの代表点に属するか」を決定する
ここでは代表点との距離||xn-μk||を計算して、距離が短い方の代表点に所属すると決める(図6.1c)
ここで、それぞれの点がどちらの代表点に所属するかを示す変数rnkを定義しておく
r_{nk} = 1 : X_nがk番目の代表点に属する場合 \\
r_{nk} = 0 : それ以外の場合 \tag{6.1}
この分類は最初に決めた代表点に依存するため、最適な分類ではない
そこで、次にそれぞれのクラスターの「重心」を新たな代表点とする
μ_k = \frac{\sum{X_n}}{N_k} (k = 1,2) \tag{6.2}
ここでNkはk番目の代表点に所属する点の個数で
Σはk番目の代表点に所属する点についてのみ加える
(6.2)を変数rnkを用いて書くと
μ_k = \frac{\sum_{n=1}^{N}{r_{nk}X_n}}{\sum_{n=1}^{N}{r_{nk}}} \tag{6.3}
図6.1dには各クラスターの重心として決まった代表点を示している
そして、新たな代表点を元にして、どちらの代表点に所属するか決め直す
先ほどと、同様、距離が短い方の代表点に所属するとする
すると、図6.1eの様に適切な分類が行われることがわかる
ここで二乗歪みを計算し変化が十分小さくなるまで手続きを繰り返す
そして図6.1fの状態になった後はそれぞれのクラスターに所属する点は変化しなくなる
最終的に得られた代表点がそれぞれのクラスターを代表することになる
※最終的に得られる代表点は最初に選んだ点によって異なる
##画像データへの応用
今回はk平均法のアルゴリズムを用いて画像ファイルの減色処理に取り組む。
図6.2の画像ファイルから代表色を抽出する
画像ファイルに含まれるピクセルの色をデータとみなしてk平均法を適用すれば、代表色が得られる
各ピクセルの色をデータ化するのに、今回はRGBを三つの値で表現してそれを三次元空間の点とみなす
たとえば表表6.1は各種webサービスのブランドカラーをRGBで表現したものとなる
同様に、先ほどの画像ファイルをRGB空間に配置すると図6.4の様になる
これを点を分類し、各ピクセルの代表色「もっとも近い代表色」で置き換える事で画像の減色処理を行う
##サンプルコードの解説
# -*- coding: utf-8 -*-
#
# k平均法による画像の減色処理
#
# 2015/04/24 ver1.0
#
import numpy as np
from numpy.random import randint
from PIL import Image
#------------#
# Parameters #
#------------#
Colors = [2, 3, 5, 16] # 減色後の色数(任意の個数の色数を指定できます)
# k平均法による減色処理
def run_kmeans(pixels, k):
cls = [0] * len(pixels)#ピクセル数
# 代表色の初期値をランダムに設定
center = []
for i in range(k):
center.append(np.array([randint(256), randint(256), randint(256)]))#最初の代表点をランダムを設定
#randint(256):0~256の整数をランダムに出力する
print("Initial centers:",)
print(map(lambda x: x.tolist(), center))#無名関数
print("========================")
distortion = 0.0
# 最大50回のIterationを実施
for iter_num in range(50):
center_new = []
for i in range(k):
center_new.append(np.array([0,0,0]))
num_points = [0] * k
distortion_new = 0.0
# E Phase: 各データが属するグループ(代表色)を計算
for pix, point in enumerate(pixels):#point=[R,G,B]
min_dist = 256*256*3
point = np.array(point)
for i in range(k):
d = sum([x*x for x in point-center[i]])#(6,4)Σ^(k)rnk(||Xn-μk||)^2
if d < min_dist:#RGBをかけたものの最小値
min_dist = d
cls[pix] = i
center_new[cls[pix]] += point#(6,3)の分子Σ^(N)rnkXn
num_points[cls[pix]] += 1#(6,3)の分母Σ^(N)rnk
distortion_new += min_dist#(6,4)J
# M Phase: 新しい代表色を計算
for i in range(k):
center_new[i] = center_new[i] / num_points[i]#(6,3)
center = center_new#代表色を計算して代入
print(map(lambda x: x.tolist(), center))
print("Distortion: J=%d" % distortion_new)
# Distortion(J)の変化が0.1%未満になったら終了
if iter_num > 0 and distortion - distortion_new < distortion * 0.001:
break
distortion = distortion_new
# 画像データの各ピクセルを代表色で置き換え
for pix, point in enumerate(pixels):
pixels[pix] = tuple(center[cls[pix]])
return pixels
# Main
if __name__ == '__main__':
for k in Colors:
print("")
print("========================")
print("Number of clusters: K=%d" % k)
# 画像ファイルの読み込み
im = Image.open("photo.jpg")
pixels = list(im.convert('RGB').getdata())
# k平均法による減色処理
result = run_kmeans(pixels, k)
########################################################
#【追記】2系と3系の違い?でこれを書かないとエラーになる
#resultがfloatで入ってるのをintに変換
test = []
for val in result:
intest = []
for v in val:
intest.append(int(v))
test.append(tuple(intest))
########################################################
# 画像データの更新とファイル出力
im.putdata(test) # Update image
im.save("output%02d.bmp" % k, "BMP")
それぞれの画像で減色処理が行われている
クラスター数kの値を増やすほど元画像に近づいて行っている
##k近傍法の紹介
k近傍法はk平均法の「教師有ver」
新たなデータ(x,y)が得られた際に、その周りのデータを見て、自分の近くにあるデータの目的変数
の値から自分自身の目的変数を推定する
具体的には、自分の周りのk個分のデータを見てその中で個数が多いものを採用する
つまり、自分の周りのデータで「多数決」を取る
K=1の場合は、示したように単独で存在するデータの周りに離れ小島ができる
k=3の場合は、多数決に負けなくなる。また、より滑らかで自然な文分類となる
##k近傍法の問題点
k近傍法には二つ問題がある
1.新たなデータの分類を判定するのに時間がかかる
2.分析のモデルが明確でない
モデルがないと、「なぜそれでうまくいったのか」という説明ができない