k-means法與k-medoids法都是基於距離判別的聚類算法。本文將使用iris數據集,在R語言中實現k-means算法與k-medoids算法。
-
k-means聚類
首先刪去iris中的Species屬性,留下剩余4列數值型變量。再利用kmeans()將數據歸為3個簇
names(iris) iris2 <- iris[,-5] #刪去species一列 kmeans_result <- kmeans(iris2,3) #將數據歸為3個簇
str(kmeans_result) #查看數據結構
table(iris$Species,kmeans_result$cluster) #查看聚類結果和觀測值的對比
從聚類結果可看出,'versicolor‘類與'virginica’類之間存在小范圍的重疊。有2個versicolor被錯誤歸類為第一類,有14個'virginica’被歸為第三類。
1 plot(iris2[c('Sepal.Length','Sepal.Width')],col=kmeans_result$cluster) 2 points(kmeans_result$centers[,c('Sepal.Length','Sepal.Width')],col=1:3,pch=10,cex=3)
數據集有四個維度,而繪圖只用了前兩個維度的數據,
圖中所示的一些靠近綠色中心的黑點實際在四維空間中更靠近黑色中心
需注意的是多次運行得到的K-means聚類結果可能不同,這是因為初始的簇中心是隨機選擇的
-
k-medoids聚類
先使用fpc包中的pamk()實現K-中心聚類,優點是不要求用戶輸入K的值
2 #而是自動調用pam()或函數clara()更具最優平均陰影寬度估計的聚類簇個數來划分數據 3 library(fpc) 4 pamk.result <- pamk(iris2) 5 str(pamk.result)
1 pamk.result$nc #推薦使用兩個簇
1 table(iris$Species,pamk.result$pamobject$clustering)
layout(matrix(c(1,2),1,2)) #圖形顯示為一行兩列 plot(pamk.result$pamobject)
在 上 面 的 例 子 中 , 函 數 pamk() 生 成 了 兩 個 簇 : 一 個 是 “ setosa ” , 另 一 個 是 “ versicolor ”
和 “ virgrnica " 的 混 合 。 在 圖 6 . 2 中 , 左 邊 的 圖 像 為 兩 個 簇 的 2 維 聚 類 圖 像 ( “ clusplot " ) ,
兩 個 簇 中 間 的 直 線 表 示 距 離 ; 右 邊 的 圖 像 顯 示 了 這 兩 個 簇 的 附 影 。 當 的 值 比 較 大 時 ( 接 近
1 ) 表 明 相 應 的 觀 測 點 能 夠 准 確 地 划 分 到 相 似 性 較 大 的 簇 中 , 當 的 值 比 較 小 時 ( 接 近 0 ) 表
明 觀 測 點 位 於 這 兩 個 簇 重 疊 的 部 分 。 如 果 觀 測 點 的 鑿 值 為 負 數 , 則 說 明 觀 測 點 被 划 分 到 錯 誤
的 族 中 。 由 於 在 上 面 的 陰 影 圖 中 , 兩 個 簇 的 均 值 分 別 為 0 , 81 和 0 . 62 , 所 以 這 表 明 這 兩 個
簇 的 划 分 結 果 很 好
接下來使用cluster包中的pam()函數
library(cluster) pam.result <- pam(iris2,3) table(pam.result$clustering,iris$Species)
對 比 上 面 兩 個 聚 類 的 結 果 , 很 難 說 函 數 pamk() 和 pam() 哪 一 個 能 獲 得 更 好 的 聚 類 結 果 ,
結 果 質 量 的 好 壞 依 賴 於 目 標 問 題 以 及 領 域 知 識 和 經 驗 。 在 這 個 例 子 中 , 函 數 pam() 得 到 的 聚
類 結 果 似 乎 更 好 , 這 是 因 為 它 識 別 出 3 個 不 同 的 簇 , 分 別 對 應 於 3 個 不 同 的 種 類 。 因 此 , 使
用 啟 發 式 方 法 來 識 別 簇 個 數 的 函 數 pamk() 並 不 意 味 着 總 是 能 得 到 更 好 的 聚 類 結 果 。 還 需 要 注
意 的 是 , 由 於 事 先 已 經 知 道 Species 屬 性 確 實 只 包 含 了 3 個 種 類 , 因 此 在 使 用 函 數 pam() 時 將
設 置 為 3 也 具 有 一 定 的 投 機 性 。
-
兩種聚類算法的對比
-
層次聚類
使用iris數據集,抽取40個樣本
1 set.seed(1234) 2 idx <- sample(1:nrow(iris),40) #抽取40個數 3 iris_sample <- iris[idx,-5] #抽取40個樣本且刪去species一列
out.dist <- dist(iris_sample,method = 'euclidean')#dist()將數據轉化為兩點之間的距離
1 hc <- hclust(out.dist,method='average') #代入兩點距離(out.dist),method='ave'指使用類平均法聚類
1 plot(hc,hang=-1,labels=iris$Species[idx]) #labels:根據目測值添加標簽
1 rect.hclust(hc,k=3) #歸為三類
1 groups <- cutree(hc,k=3) #查看分類
-
基於密度的聚類
1 library(fpc) 2 iris2 <- iris[,-5] 3 ds <- dbscan(iris2,eps = 0.42,MinPts = 5) #設置可達距離和最小數目的對象點 4 table(ds$cluster,iris$Species)
‘1’-‘3’指被識別出來的三個聚類簇,‘0’表示噪聲數據或離散點,即不屬於任何簇的對象,繪制的圖中使用黑色小圓圈表示
1 plot(ds,iris2[c(1,4)]) #展示第一列和第四列的聚類結果
1 plot(ds,iris2)