這是我對k-means的一些想法
若有錯誤請指正謝謝,這裡拿R內建資料集iris做舉例
在所有分群演算法中,最基本的方法就是k-means分割式分群法
k-mean需要先設定集群的數量,根據該設定找出最佳的集群結構,在大量的資料中,目的為找出群中心
使得同一集群內的物件相似性最大且集群間的差異性最大,即「群內同質,群間異質」的效果
使用scale正規化是為了避免單位對數值的影響
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 3.3.2
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(useful)
iris2 <- iris[,sapply(iris, is.numeric)]
iris2 <- scale(iris2)
因為資料集的種類是3種,所以先試著取3群,看kmeans的結果與資料集本身的差異
相關細節
顯示群數、每一行的群組平均數、每一列的群別和相似度
1.between_SS / total_SS:群之間的距離平方占總體距離平方差的比率,愈大分群效果愈好,但並不表示愈容易看出資料趨勢,筆者取過10群的比率為95.2%,但是分成10群呈現在資料上反而看不出趨勢,所以如何取群數還需要研究
2.cluster:表示每個點所在的群
3.centers:每個群的群中心
4.totss:各個點的離差平方和
5.withinss:每個單一群內部的離差平方和
6.tot.withinss:所有單一群內的離差平方和的總和
7.betweenss:各個群之間的離差平方和
8.size:每個群的點個數
分成3群,重複輸出kmeans函數,會發現每次的between_SS / total_SS都不同
這是因為每次取3群kmean都需要重新分群,不同的群當然有不同的距離,多重複輸出幾次,會發現between_SS / total_SS愈來愈高,到一定比率就上不去了,就顯示出分3群的極限
kiris2 <- kmeans(iris2, 3)
kiris2
## K-means clustering with 3 clusters of sizes 96, 33, 21
##
## Cluster means:
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 0.5690971 -0.3705265 0.6888118 0.6609378
## 2 -0.8135055 1.3145538 -1.2825372 -1.2156393
## 3 -1.3232208 -0.3718921 -1.1334386 -1.1111395
##
## Clustering vector:
## [1] 2 3 3 3 2 2 2 2 3 3 2 2 3 3 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 3 3 2 2 2 3
## [36] 3 2 2 3 2 2 3 3 2 2 3 2 3 2 2 1 1 1 1 1 1 1 3 1 1 3 1 1 1 1 1 1 1 1 1
## [71] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 1 1 1 3 1 1 1 1 1 1
## [106] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [141] 1 1 1 1 1 1 1 1 1 1
##
## Within cluster sum of squares by cluster:
## [1] 149.25899 17.33362 23.15862
## (between_SS / total_SS = 68.2 %)
##
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss"
## [5] "tot.withinss" "betweenss" "size" "iter"
## [9] "ifault"
plot(kiris2, data = iris2)
根據資料本身種類用不同的標記,與上圖作比較,若顏色與形狀容易同時區別出來,表示分群效果不錯
plot(kiris2, data = iris, class = "Species")
上述群數的選擇是以資料本身種類為主,三種分成三群也是合乎常理的,但是有沒有可能有更有效的分群呢?這其實很主觀,因為群數的不同會導致群間距離差平方和的不同,群數與距離間沒有正反比或是規律性,只能找出一個平穩狀態,這裡介紹2種方法來評估群數
看出如果依照iris種類分3群的分群效果,效果挺差的,還能分成更多群,差不多到8就開始穩定了,此種方法是計算群內點之間的距離差平方和,然後觀察曲線的跌幅狀態。
x <- (nrow(iris2)-1) * sum(apply(iris2, 2, var))
for (i in 2:15) x[i] <- kmeans(iris2,centers = i)$tot.withinss
plot(x, type = "b",xlab = "Number of clusters")
此種方法是計算k個分群群內平方和與k+1個分群群內平方和的比率,把列數和群數考慮在內,比率大於10表示使用k+1個群比較好,每次執行結果都略有不同,群數大概落在7~9之間。
Hart <- FitKMeans(iris2, max.clusters = 15)
Hart
## Clusters Hartigan AddCluster
## 1 2 251.34934 TRUE
## 2 3 86.77954 TRUE
## 3 4 32.42265 TRUE
## 4 5 15.16734 TRUE
## 5 6 12.35587 TRUE
## 6 7 29.72566 TRUE
## 7 8 21.80205 TRUE
## 8 9 15.04763 TRUE
## 9 10 17.33698 TRUE
## 10 11 30.79675 TRUE
## 11 12 -50.14120 FALSE
## 12 13 74.97302 TRUE
## 13 14 31.52879 TRUE
## 14 15 -10.65285 FALSE
PlotHartigan(Hart)
畫出混淆矩陣判斷分群效果,好的分群應使圖中的對角線應該都佔有最大一比例
x <- table(iris$Species, kiris2$cluster)
plot(x,main = "Confusion Matrix",xlab = "Species",ylab = "Clusters")