非階層的方法と分析の評価
(Press ?
for help, n
and p
for next and previous slide)
村田 昇
クラスタ分析 (cluster analysis) の目的
個体の間に隠れている 集まり=クラスタ を個体間の“距離”にもとづいて発見する方法
Figure 1: 凝集的手続きの例
観測データ : \(n\) 個の個体の組
\begin{equation} \{\boldsymbol{x}_{i}\}_{i=1}^{n} = \{(x_{i1},x_{i2},\dotsc,x_{id})^{\mathsf{T}}\}_{i=1}^{n} \end{equation}
個体とクラスタの対応 \(C\) を推定
\begin{equation} C(i) =\text{(個体 \(i\) が属するクラスタ番号)} \end{equation}
2つの個体 \(i,i'\) の 近さ=損失 を距離の二乗で評価
\begin{equation} \|\boldsymbol{x}_i-\boldsymbol{x}_{i'}\|^2 = \sum_{j=1}^{d}(x_{ij}-x_{i'j})^2 \end{equation}
損失関数 \(W(C)\) : クラスタ内の平均の近さを評価
\begin{equation} W(C) = \sum_{l=1}^k\frac{1}{n_l}\sum_{i:C(i)=l}\sum_{i':C(i')=l}\|\boldsymbol{x}_i-\boldsymbol{x}_{i'}\|^2 \end{equation}
クラスタ \(l\) に属する個体の平均
\begin{equation} \bar{\boldsymbol{x}}_l = \frac{1}{n_l}\sum_{i:C(i)=l}\boldsymbol{x}_i, \quad\text{(\(n_l\) はクラスタ \(l\) に属する個体数)} \end{equation}
損失関数 \(W(C)\) の等価な表現
\begin{equation} W(C) = 2\sum_{l=1}^k\sum_{i:C(i)=l}\|\boldsymbol{x}_i-\bar{\boldsymbol{x}}_{l}\|^2 \end{equation}
基本的な考え方 : Lloyd-Forgyのアルゴリズム
標本平均と変動の平方和の性質を利用
\begin{equation} \bar{\boldsymbol{x}}_l =\arg\min_{\mu} \sum_{i:C(i)=l}\|\boldsymbol{x}_i-\boldsymbol{\mu}\|^2 \quad \text{(クラスタ\(l\)の標本平均)} \end{equation}
各データの所属クラスタ番号 \(C(i)\) を求める
\begin{equation} C(i) = \arg\min_l\|\boldsymbol{x}_i-\boldsymbol{\mu}_l\| \end{equation}
各クラスタ中心 \(\boldsymbol{\mu}_l\;(l=1,2,\dotsc,k)\) を更新する
\begin{equation} \boldsymbol{\mu}_l = \frac{1}{n_l}\sum_{i:C(i)=l}\boldsymbol{x}_i, \quad n_l=|\{\boldsymbol{x}_i|C(i)=l\}| \end{equation}
平均の代わりにメドイド (medoid; 中心にある観測値) を用いる方法もある
\begin{equation} \boldsymbol{x}^{\mathrm{medoid}}_{l} =\arg\min_{\boldsymbol{x}_{i}} \sum_{i':C(i')=l} \|\boldsymbol{x}_{i}-\boldsymbol{x}_{i'}\|^2 \end{equation}
県名 | 梅 | 鮭 | 昆布 | 鰹 | 明太子 | 鱈子 | ツナ | その他 |
---|---|---|---|---|---|---|---|---|
北海道 | 13.86 | 27.94 | 5.58 | 5.26 | 9.26 | 15.06 | 11.61 | 11.39 |
青森県 | 14.93 | 30.79 | 7.01 | 2.43 | 10.36 | 11.58 | 11.58 | 11.28 |
岩手県 | 17.91 | 23.13 | 5.22 | 3.35 | 17.91 | 10.07 | 10.44 | 11.94 |
宮城県 | 15.16 | 29.50 | 10.00 | 1.66 | 14.83 | 8.83 | 12.83 | 7.16 |
秋田県 | 10.63 | 31.38 | 5.31 | 3.19 | 14.89 | 13.29 | 10.63 | 10.63 |
山形県 | 16.58 | 20.27 | 8.29 | 1.38 | 18.89 | 10.13 | 12.90 | 11.52 |
福島県 | 12.37 | 21.99 | 8.93 | 3.43 | 16.49 | 9.62 | 19.24 | 7.90 |
新潟県 | 21.06 | 23.03 | 3.37 | 1.12 | 19.66 | 15.16 | 7.02 | 9.55 |
富山県 | 19.41 | 21.84 | 14.56 | 4.85 | 13.59 | 7.76 | 11.16 | 6.79 |
石川県 | 23.05 | 20.00 | 19.66 | 4.06 | 13.89 | 7.11 | 10.16 | 2.03 |
福井県 | 20.58 | 20.58 | 18.62 | 4.90 | 15.68 | 6.86 | 9.80 | 2.94 |
山梨県 | 14.11 | 20.58 | 9.41 | 2.35 | 20.58 | 12.35 | 18.23 | 2.35 |
長野県 | 18.64 | 21.30 | 9.68 | 2.66 | 20.33 | 13.80 | 10.16 | 3.38 |
岐阜県 | 16.52 | 20.55 | 11.44 | 4.44 | 15.88 | 8.68 | 15.46 | 6.99 |
静岡県 | 15.96 | 27.71 | 11.86 | 4.98 | 14.30 | 9.20 | 10.75 | 5.21 |
Figure 2: 非階層的クラスタリング
Figure 3: Lloyd-Forgyのアルゴリズム (その1)
Figure 4: Lloyd-Forgyのアルゴリズム (その2)
Figure 5: Lloyd-Forgyのアルゴリズム (その3)
Figure 6: Lloyd-Forgyのアルゴリズム (その4)
Figure 7: Lloyd-Forgyのアルゴリズム (その5)
Figure 8: Lloyd-Forgyのアルゴリズム (その6)
Figure 9: クラスタリングの結果
関数 kmeans()
kmeans(x, centers, iter.max = 10, nstart = 1, algorithm = c("Hartigan-Wong", "Lloyd", "Forgy", "MacQueen"), trace = FALSE) #' x: データフレーム #' centers: クラスタ数 #' iter.max: 最大繰り返し数 #' nstart: 初期値の候補数 #' algorithm: 最適化法の指定.既定値は 'Hartigan-Wong'
関数 ggfortify::autoplot()
(ggplot 系)
autoplot(object, data = NULL, colour = "cluster", ...) #' object: stats::kmeans(), cluster::pam() などの返値 #' data: クラスタリングに用いたデータ (kmeansの場合に必要) #' 詳細は '?ggfortify::autoplot.kmeans()' を参照
cluster::clusplot()
を利用することもできる
データセット japan_social.csv
を用いて
以下を確認しなさい
js_df <- read_csv("data/japan_social.csv") |> column_to_rownames(var = "Pref") |> # 'Pref'を行名に変換 select(-Area) # 地方名は除く
kmeans()
を用いて
各変数平均0,分散1に標準化
(関数 scale()
を利用)
したデータを7クラスタに分割しなさいomusubi.csv
でも確認しなさい
関数 cluster::pam()
pam(x, k, diss = inherits(x, "dist"), metric = c("euclidean", "manhattan"), medoids = if(is.numeric(nstart)) "random", nstart = if(variant == "faster") 1 else NA, stand = FALSE, cluster.only = FALSE, do.swap = TRUE, keep.diss = !diss && !cluster.only && n < 100, keep.data = !diss && !cluster.only, variant = c("original", "o_1", "o_2", "f_3", "f_4", "f_5", "faster"), pamonce = FALSE, trace.lev = 0) #' x: データフレーム,または距離行列 #' k: クラスタの数 #' metric: 距離の指定(xがデータフレームの場合) #' stand: 標準化(平均0,絶対偏差1)
japan_social.csv
を用いて
以下を確認しなさい
pam()
を用いて
各変数平均0,絶対偏差1に標準化したデータを7クラスタに分割しなさいomusubi.csv
でも確認しなさいデータ \(\boldsymbol{x}_i\) と最初に統合されたクラスタ \(C\) の距離
\begin{equation} d_i = D({\boldsymbol{x}_i},C) \end{equation}
最後に統合された2つのクラスタ \(C',C''\) の距離
\begin{equation} D = D(C',C'') \end{equation}
凝集係数 (agglomerative coefficient)
\begin{equation} AC = \frac{1}{n}\sum_{i=1}^{n}\left(1-\frac{d_i}{D}\right) \end{equation}
定義より
\begin{equation} 0\le AC\le 1 \end{equation}
\(\boldsymbol{x}_i\) を含むクラスタ \(C^1\) と \(\boldsymbol{x}_i\) の距離
\begin{equation} d^1_i=D({\boldsymbol{x}_i},C^1\setminus{\boldsymbol{x}_i}) \end{equation}
一番近いクラスタ \(C^2\) と \(\boldsymbol{x}_i\) の距離
\begin{equation} d^2_i=D({\boldsymbol{x}_i},C^2) \end{equation}
シルエット係数 (silhouette coefficient)
\begin{equation} S_i = \frac{d^2_i-d^1_i}{\max(d^1_i,d^2_i)} \end{equation}
定義より
\begin{equation} -1\le S_i\le 1 \end{equation}
関数 cluster::agnes()
の返値の情報
object[["ac"]] # 凝集係数の取得 (object$ac でも良い) object[["height"]] # デンドログラムの高さ(結合時のクラスタ距離) object[["order.lab"]] # デンドログラムの並び順のラベル #' object: cluster::agnes() の返値
summary(object)
はこれらの情報をまとめて表示する視覚化のための関数 (graphics 系)
#' cluster::plot.agnes() 系統樹および凝集係数の表示 plot(x, ask = FALSE, which.plots = NULL, main = NULL, sub = paste("Agglomerative Coefficient = ",round(x$ac, digits = 2)), adj = 0, nmax.lab = 35, max.strlen = 5, xax.pretty = TRUE, ...) #' x: cluster::agnes() の返値 #' which.plots: 1 (banner plot), 2 (dendrogram) #' banner plot の表示には以下の cluster::bannerplot() が呼出される bannerplot(x, w = rev(x$height), fromLeft = TRUE, main=NULL, sub=NULL, xlab = "Height", adj = 0, col = c(2, 0), border = 0, axes = TRUE, frame.plot = axes, rev.xax = !fromLeft, xax.pretty = TRUE, labels = NULL, nmax.lab = 35, max.strlen = 5, yax.do = axes && length(x$order) <= nmax.lab, yaxRight = fromLeft, y.mar = 2.4 + max.strlen/2.5, ...)
japan_social.csv
を用いて
以下を検討しなさい
agnes()
を用いて階層的クラスタリングを行いなさい
関数 cluster::pam()
の返値の情報
object[["silinfo"]] # シルエット係数に関する様々な情報 object[["silinfo"]][["widths"]] # 各データのシルエット係数 object[["silinfo"]][["clus.avg.widths"]] # 各クラスタのシルエット係数の平均 object[["silinfo"]][["avg.width"]] # シルエット係数の平均 #' object: cluster::agnes() の返値
summary(object)
はこれらの情報をまとめて表示する補助的な関数
#' シルエット係数の取得 silhouette(x, ...) #' x: cluster::pam() などの返値 silhouette(x, dist, dmatrix, ...) #' x: stats::cutree() などの返値 #' dist/dmatrix: 距離行列または解離度を表す行列など
視覚化のための関数 (ggplot 系)
#' ggfortify::autoplot.silhouette() シルエット係数の表示 autoplot(object, colour = "red", linetype = "dashed", size = 0.5, bar.width = 1, ...) #' object: cluster::silhouette() の返値 #' colour/linetype/size: reference line の設定
視覚化のための関数 (graphics 系)
#' cluster::plot.partition() 2次元クラスタおよびシルエット係数の表示 plot(x, ask = FALSE, which.plots = NULL, nmax.lab = 40, max.strlen = 5, data = x$data, dist = NULL, stand = FALSE, lines = 2, shade = FALSE, color = FALSE, labels = 0, plotchar = TRUE, span = TRUE, xlim = NULL, ylim = NULL, main = NULL, ...) #' x: cluster::pam() などの返値 #' which.plots: 1 (cluster plot), 2 (silhouette plot) #' silhouette plot の表示には以下の cluster::plot.silhouette() が呼出される plot(x, nmax.lab = 40, max.strlen = 5, main = NULL, sub = NULL, xlab = expression("Silhouette width "* s[i]), col = "gray", do.col.sort = length(col) > 1, border = 0, cex.names = par("cex.axis"), do.n.k = TRUE, do.clus.stat = TRUE, ...) #' x: cluster::silhouette() の返値
omusubi.csv
を用いて
以下を検討しなさい
Hellinger距離を用いて距離行列を計算しなさい
\(\boldsymbol{p},\boldsymbol{q}\) を確率ベクトルとして 定義される確率分布の距離
\begin{equation} d_{\mathrm{hel}}(\boldsymbol{p},\boldsymbol{q}) = \frac{1}{\sqrt{2}}d_{\mathrm{euc}}(\sqrt{\boldsymbol{p}},\sqrt{\boldsymbol{q}}) \end{equation}