(數據科學學習手札13)K-medoids聚類算法原理簡介&Python與R的實現


前幾篇我們較為詳細地介紹了K-means聚類法的實現方法和具體實戰,這種方法雖然快速高效,是大規模數據聚類分析中首選的方法,但是它也有一些短板,比如在數據集中有臟數據時,由於其對每一個類的准則函數為平方誤差,當樣本數據中出現了不合理的極端值,會導致最終聚類結果產生一定的誤差,而本篇將要介紹的K-medoids(中心點)聚類法在削弱異常值的影響上就有着其過人之處。

與K-means算法類似,區別在於中心點的選取,K-means中選取的中心點為當前類中所有點的重心,而K-medoids法選取的中心點為當前cluster中存在的一點,准則函數是當前cluster中所有其他點到該中心點的距離之和最小,這就在一定程度上削弱了異常值的影響,但缺點是計算較為復雜,耗費的計算機時間比K-means多。

具體的算法流程如下:

  1.在總體n個樣本點中任意選取k個點作為medoids

  2.按照與medoids最近的原則,將剩余的n-k個點分配到當前最佳的medoids代表的類中

  3.對於第i個類中除對應medoids點外的所有其他點,按順序計算當其為新的medoids時,准則函數的值,遍歷所有可能,選取准則函數最小時對應的點作為新的medoids

  4.重復2-3的過程,直到所有的medoids點不再發生變化或已達到設定的最大迭代次數

  5.產出最終確定的k個類

而在R中有內置的pam()函數來進行K-medoids聚類,下面我們對人為添加臟數據的樣本數據集分別利用K-medoids和K-means進行聚類,以各自的代價函數變化情況作為評判結果質量的標准:

rm(list=ls())
library(Rtsne)
library(cluster)
library(RColorBrewer)
data1 <- matrix(rnorm(10000,mean=0,sd=0.7),ncol=10,nrow=1000)
data2 <- matrix(rnorm(10000,mean=8,sd=0.7),ncol=10,nrow=1000)
data3 <- matrix(rnorm(10000,mean=16,sd=0.7),ncol=10,nrow=1000)
data4 <- matrix(rnorm(200,mean=100,sd=0.5),ncol=10,nrow=20)
data <- rbind(data1,data2,data3,data4)

#數據降維
tsne <- Rtsne(data,check_duplicates = FALSE)
cols <- sample(brewer.pal(n=7,name='Set1'),7)

#自定義代價函數計算函數
Mycost <- function(data,medoids){
  l <- length(data[,1])
  d <- matrix(0,nrow=l,ncol=length(medoids[,1]))
  for(i in 1:l){
    for(j in 1:length(medoids[,1])){
      dist <- 0
      for(k in 1:length(medoids[1,])){
        dist <- dist + (data[i,k]-medoids[j,k])^2
      }
      d[i,j] <- dist
    }
  }
  return(sum(apply(d,1,min)))
}

par(mfrow=c(2,3))
#進行K-medoids聚類
cost <- c()
for(i in 2:7){
  cl <- pam(data,k=i)
  plot(tsne$Y,col=cols[cl$clustering])
  title(paste(paste('K-medoids Cluster of',as.character(i)),'Clusters'))
  cost[i-1] <- Mycost(data,cl$medoids)
}

par(mfrow=c(1,1))
plot(2:7,cost,type='o',xlab='k',ylab='Cost')
title('Cost Change of K-medoids')


#進行K-means聚類
cost <- c()
par(mfrow=c(2,3))
for(i in 2:7){
  cl <- kmeans(data,centers=i)
  plot(tsne$Y,col=cols[cl$cluster])
  title(paste(paste('K-means Cluster of',as.character(i)),'Clusters'))
  cost[i-1] <- Mycost(data,cl$centers)
}
par(mfrow=c(1,1))
plot(2:7,cost,type='o',xlab='k',ylab='Cost')
title('Cost Change of K-means')

K-medoids的聚類結果(基於不同的k值):

 

K-medoids過程的代價函數變化情況:

K-means的聚類結果(基於不同的k值):

K-means的代價函數變化情況:

 可以看出,K-medoids在應付含有臟數據的數據集時有着更為穩定的性能表現。

 

Python

 在Python中關於K-medoids的第三方算法實在是夠冷門,經過筆者一番查找,終於在一個久無人維護的第三方模塊pyclust中找到了對應的方法KMedoids(),若要對制定的數據進行聚類,使用格式如下:
KMedoids(n_clusters=n).fit_predict(data),其中data即為將要預測的樣本集,下面以具體示例進行展示:

from pyclust import KMedoids
import numpy as np
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt

'''構造示例數據集(加入少量臟數據)'''
data1 = np.random.normal(0,0.9,(1000,10))
data2 = np.random.normal(1,0.9,(1000,10))
data3 = np.random.normal(2,0.9,(1000,10))
data4 = np.random.normal(3,0.9,(1000,10))
data5 = np.random.normal(50,0.9,(50,10))

data = np.concatenate((data1,data2,data3,data4,data5))

'''准備可視化需要的降維數據'''
data_TSNE = TSNE(learning_rate=100).fit_transform(data)

'''對不同的k進行試探性K-medoids聚類並可視化'''
plt.figure(figsize=(12,8))
for i in range(2,6):
    k = KMedoids(n_clusters=i,distance='euclidean',max_iter=1000).fit_predict(data)
    colors = ([['red','blue','black','yellow','green'][i] for i in k])
    plt.subplot(219+i)
    plt.scatter(data_TSNE[:,0],data_TSNE[:,1],c=colors,s=10)
    plt.title('K-medoids Resul of '.format(str(i)))

 

以上就是關於K-medoids算法的基本知識,如有錯誤之處望指出。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM