日々のつれづれ

不惑をむかえ戸惑いを隠せない男性の独り言

SVMの多項式カーネルとガウスカーネル

ChatGPTの練習でSVMカーネルを調べたので記録しておく

ChatGPTの回答はコードや説明文は誰かの著作権に抵触する可能性がある

調べものとして利用価値は高いが、回答をまるまる転用せず、自分の言葉、コードで残すことが肝要です

カーネルとは

サポートベクターマシンは2つのデータ点間の類似性をカーネルで計算して、最もよく分離する境界線を見つける手法。

このカーネルはこの2つのデータ点間の類似性をベクトルの内積を利用して計算する。

このとき、内積が小さいと2つのデータ点の類似度は低く、お互いが遠い。逆に内積が大きいと、類似度は高く、お互いが近い、と判断する。

カーネルはいくつか種類がある。多項式カーネルガウスカーネルが有名らしい。

多項式カーネル:低次元のデータに対して有効

  • 利点:入力データの次元を上げて、高次元データを分類する
  • 欠点:過学習しやすく、パラメーターの選択が肝

多項式カーネル関数

  • $K(x, y) = (x \cdot y + c)d$
  • xとyは2つの入力ベクトル
  • dは多項式の次数
  • cは定数項

流れ

  1. データを読み込み、スケーリングや特徴量の選択などの前処理を行う。
  2. 2つのデータ点の内積を求める。このとき、2重のforループを使い、全てのペアの内積を計算する。

R

library(Matrix)

# 2次元の5つのデータ
X <- matrix(c(0, 0, 1, 1, 2, 1, 3, 2, 3, 3), ncol = 2)

# 3次元に写像する関数
poly_kernel <- function(X, degree) {
  n <- nrow(X)
  K <- matrix(0, n, n)
  for (i in 1:n) {
    for (j in i:n) {
      K[i, j] <- (1 + crossprod(X[i,], X[j,]))^degree
      K[j, i] <- K[i, j]
    }
  }
  return(K)
}

# 3次元に写像した結果を計算
K <- poly_kernel(X, degree = 2)

Python

import numpy as np

# 2次元の5つのデータ
X = np.array([[0, 0], [1, 1], [2, 1], [3, 2], [3, 3]])

# 3次元に写像する関数
def poly_kernel(X, degree):
    n = X.shape[0]
    K = np.zeros((n, n))
    for i in range(n):
        for j in range(i, n):
            K[i, j] = (1 + np.dot(X[i], X[j]))**degree
            K[j, i] = K[i, j]
    return K

# 3次元に写像した結果を計算
K = poly_kernel(X, degree=2)

ガウスカーネル:高次元のデータに対して有効、非線形な分離を行う

  • 利点:入力データを高次元空間に写像するためのパラメーターがわかりやすく、決めやすい。また、過学習の可能性が低く、汎化性能が高い。
  • 欠点:Decison boundaryが単純になりやすく、高次元データを分類するために影響力の大きい特徴量が見逃されることがある。

ガウスカーネル関数

  • $K(x, y) = exp(-\gamma|x-y|2)$
  • xとyは元のデータの要素を表すベクトル
  • $|x-y|$はベクトル$x$と$y$のノルム(ベクトルの長さ)
  • $\gamma$はガウスカーネルのパラメータ

流れ

  1. 中心となるデータ点を決める
  2. それぞれのデータ点を中心とするガウス分布の密度を計算する、密度$=$距離となる

R

data <- matrix(c(1,2,3,4,5,6,7,8,9,10,11,12), ncol=3)
x <- c(4,5,6)
gamma <- 0.1

# 各データ点と中心との距離を計算
distances <- sqrt(rowSums((data - x)^2))

# ガウス分布の密度を計算
kernel_values <- exp(-gamma * distances^2)

Python

import numpy as np

data = [[1,2,3], [4,5,6], [7,8,9], [10,11,12]]
x = np.array([4,5,6])
gamma = 0.1

# 各データ点と中心との距離を計算
distances = np.linalg.norm(data - x, axis=1)

# ガウス分布の密度を計算
kernel_values = np.exp(-gamma * distances**2)

ガウスカーネルを使うと、なぜ、高次元のデータになるのか

ガウスカーネルを使うと、各データ点について、周囲の点との距離を計算できる。この距離はガウス分布のことで、お互いの距離が近くなると1に近づき、お互いの距離が遠くなると0に近づく。この値が新しい次元で、これを非線形な分類に利用する。