「大人の教養・知識・気付き」を伸ばすブログ

一流の大人(ビジネスマン、政治家、リーダー…)として知っておきたい、教養・社会動向を意外なところから取り上げ学ぶことで“気付く力”を伸ばすブログです。

MENU

統計的機械学習の数理100問(10/X)

 いい加減時代の潮流に乗ろうということで機械学習を学びたいと思う。またRはともかくとしてPythonは未経験であるため、丁度良い書籍として

を用いることにする。

2. 分類

 有限個の数値を目的変数とするような分類の問題を取り扱う。

2.4. k近傍法

 訓練データ(\boldsymbol{X}_i,Y_i)\in\mathbb{R}^{p}\times A,i=1,2,\cdots,n(Aは有限集合)から規則を生成するのではなく、新しいデータX_{*}\in\mathbb{R}^{p}に最も近いk(\leq n)個の多数決によりそのデータのY_{*}\in Aを予測する方法である。
 \boldsymbol{X}\in\mathbb{R}^{n\times p},Y\in\{1,\cdots,m\}^{n}として(各Y_1,\cdots,Y_nm\geq2通りの値を取る)、\boldsymbol{X}_{*}\in\mathbb{R}^pから見て最も距離の近いk個の標本におけるY_i\in\{1,2,\cdots,m\}の頻度を調べ、そのうち最も大きいY\boldsymbol{X}_{*}に対応するY_{*}と見なす*1。すなわち

 たとえば


\begin{aligned}
\rho(\boldsymbol{X}_i,\boldsymbol{X}_j)=\sqrt{\displaystyle{\sum_{k=1}^{p}(X_{i,k}-X_{j,k})^2}}
\end{aligned}

  • 利用する標本の数k=k_0

という条件設定であれば、新たにテストデータ\boldsymbol{X}が観測されたとき以下のアルゴリズムでそのテストデータのYを決定する:

   (1) i=1,2,\cdots,nに対して距離
\begin{aligned}\rho(\boldsymbol{X}_i,\boldsymbol{X})=\sqrt{\displaystyle{\sum_{k=1}^{p}(X_{i,k}-X_{k})^2}}\end{aligned}
を計算する。
   (2) (1)で計算した各距離を昇順に並び替え、1番目からk_0番目のテストデータを選び、これらを\sigma(1),\cdots,\sigma(k_0)\in\{1,2,\cdots,n\}とする。
   (3) Y_{\sigma(1)},\cdots,Y_{\sigma(k_0)}を集計し、0,1のうち多い方をyとすれば、Y=yとする。


k近傍法のイメージ
f:id:suguru_125:20220413001649p:plain

2.4.1 Rでのスクリプト
# k近傍法
knn_1dim <- function(mt_x, vc_y, mt_z, num_k){
  # 入力の準備
  mt_x <- as.matrix(mt_x)
  num_r <- nrow(mt_x)
  num_c <- ncol(mt_x)
  vc_distance <- array(dim = num_r)
  
  # 近傍の判定
  for(i in 1:num_r){
    vc_distance[i] <- norm(x = mt_z - mt_x[i,],type = "2") # 2-norm(特異値)を距離とする
  }
  
  S <- order(vc_distance)[1:num_k] # 距離の小さいk個の添字iの集合
  vc_u <- sort(table(vc_y[S]),decreasing = T) #k個のうち最頻のmt_y[i]と頻度
  v <- names(vc_u)[1] # 最頻のmt_y[i]
  
  # タイデータがあった場合の処理
  if(length(vc_u)>1){
    w <- names(vc_u)[2]
  }
  while(length(vc_u)>1 && v==w){
    num_k <- num_k - 1
    vc_u <- vc_u[num_k]
    v <- names(vc_u)[1]
    w <- names(vc_u)[2]
  }
  
  return(v)
}

# k近傍法:判定対象が複数の場合、各対象に1dimを呼び出す
knn <- function(mt_x, vc_y, mt_z, num_k){
  num_n <- nrow(mt_z)
  vc_w <- array(dim = num_n)
  
  for(i in 1:num_n){
    vc_w[i] <- knn_1dim(mt_x, vc_y, mt_z[i,], num_k)
  }
  
  return(vc_w)
}


# データ
data(iris)

num_n <- 150

# 訓練データ数は全体の3割
vc_train <- sample(1:num_n, round(0.3 * num_n,digits = 0), replace = F)
vc_test <- setdiff(1:num_n, vc_train)

# 入力の準備
mt_x <- as.matrix(iris[vc_train,1:4])
vc_y <- as.vector(iris[vc_train,5])
mt_z <- as.matrix(iris[vc_test,1:4])
vc_ans <- as.vector(iris[vc_test,5])

# k近傍法
w <- knn(mt_x = mt_x, vc_y = vc_y, mt_z = mt_z, num_k = 3)

table(w,vc_ans)
2.4.2 Pythonによるスクリプト*2
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split

# アヤメデータセット読み込み
from sklearn.datasets import load_iris
iris = load_iris()

# 特徴量
X = iris.data
# 目的変数
Y = iris.target

# データ表示(特徴量)
print("データ数 = %d  特徴量 = %d" % (X.shape[0], X.shape[1]))
pd.DataFrame(X, columns=iris.feature_names).head()

# トレーニング・テストデータ分割
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, random_state=0)

#
# K-近傍法
#
from sklearn.neighbors import KNeighborsClassifier

list_nn = []
list_score = []

for k in range(1, 101): 
  # KNeighborsClassifier
  knc = KNeighborsClassifier(n_neighbors=k)
  knc.fit(X_train, Y_train)

  # 予測
  Y_pred = knc.predict(X_test)

  # 評価 R^2
  score = knc.score(X_test, Y_test)
  print("[%d] score: {:.2f}".format(score) % k)

  list_nn.append(k)
  list_score.append(score)

# プロット
plt.ylim(0.5, 1.0)
plt.xlabel("n_neighbors")
plt.ylabel("score")
plt.plot(list_nn, list_score)



kを変えたときの決定係数の推移
f:id:suguru_125:20220413011152p:plain

2.5 ROC曲線

 分類問題に当たっては事後確率最大化、すなわち誤り率最小という意味で妥当ではある。しかし問題によっては敢えて別の面での性能を向上させたい場合がある。
 たとえば2値問題において、一方に誤判断する方がもう一方に誤判断するよりも深刻な損害が出る場合がある。たとえば致命的な病気の診断において、実際にはそれに罹患しているのに罹患していないと誤判断することの方が生命の危機という観点で被害が大きいと考えられる。この場合、

      病気である 病気でない
   病気だと診断 真陽性(True Positive) 偽陽性(False Positive)
   病気でないと診断 偽陰性(False Negative) 真陰性(True Negative)

というパターンが存在する。
 X,Yをそれぞれ病気に罹患しているか否か(罹患している=1,罹患していない=0)、診断で陽性と出る(=1)か陰性と出るか(=0)を表す確率変数だとする。このときFalse Positiveとする誤りを第1種の誤り、False Negativeとする誤りを第2種の誤りとし、それらの確率を


\begin{aligned}
P\{Y=1|X=0\}&=\alpha,\\
P\{Y=0|X=1\}&=\beta,
\end{aligned}

とする。このとき


\begin{aligned}
検出力&=\displaystyle{\frac{真陽性の数}{真陽性の数+真陰性の数}}=1-\beta,\\
偽陽性率&=\displaystyle{\frac{偽陽性の数}{真陽性の数+真陰性の数}}=\alpha
\end{aligned}

と定義する。
 偽陽性率を与えたときに、検出力を最大化するように分類を設計することを考える*3。このとき、その分類の良さを検証するのに、偽陽性率を横軸、各偽陽性率に対応する検出力を縦軸として曲線を描くことが良く行われる。これを\mathrm{ROC}曲線という。x軸と\mathrm{ROC}曲線とが囲む部分の面積が1に近いほど良い検査を行っているものだと考えられる。


\mathrm{ROC}曲線のイメージ
f:id:suguru_125:20220413014604p:plain

*1:距離にはユークリッド距離やマハラノビス距離を用いる。

*2:機械学習 〜 K−近傍法 〜 - Qiitaを拝見しました。

*3:Neyman-Pearsonの基準という。

プライバシーポリシー お問い合わせ