非階層的方法と分析の評価
(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}
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}