聚類分析概念
聚類分析(cluster analysis ):是一組將研究對象分爲相對同質的羣組(clusters)的統計分析技術。聚類分析也叫分類分析,或者數值分類。聚類的輸入是一組未被標記的樣本,聚類根據數據自身的距離或者相似度將其劃分成若干個組,劃分的原則是組內距離最小化而組間(外部)距離最大化。聚類和分類的不同在於:聚類所要求劃分的類是未知的。
距離量度
不同的距離量度會對距離的結果產生影響,常見的距離量度如下所示:
聚類研究分析的方法
1.層次的方法(hierarchical method)
2.劃分方法(partitioning method)
3.基於密度的方法(density-based method)DBSCAN
4.基於網格的方法(grid-based method)
5.基於模型的方法(model-based method)
K-means算法
K-means算法是經典的聚類分析劃分方法之一。其優缺點如下:
優點:
原理簡單
速度快
對大數據集有比較好的伸縮性
缺點:
需要指定聚類 數量K
對異常值敏感
對初始值敏感
受離羣點的影響較大,由於其迭代每次的中心點到全部樣本點的距離和的平均值。
以歐式距離來衡量距離大小,使用誤差平方和(Sum of the Squared Error,SSE)作爲聚類的目標函數:
k表示k個聚類中心,ci表示第幾個中心,dist表示的是歐幾里得距離。該公式表示求每個點到自己所屬聚類中心的距離之和。即先把每個點到自己聚類中心的距離求出來,然後將所有距離相加。要讓SSE最小,需每個點到自己聚類中心的距離最短。
由上可以看出,簇的最佳質心是簇中各點的均值。
K-means算法思想如下:
任選k個初始點作爲質心
repeat :
數據集中每一個數據點
每一個初始質心
計算數據點與質心的距離
將數據點分配到距離最近的簇
對每個簇計算簇的均值,將均值作爲簇的新的質心
until:
任一數據點的簇分配結果沒有發生改變,或者達到最大迭代次數
具體實現代碼如下:
(光看代碼沒用,可將下面代碼直接copy到IDE中跑下,看看效果。也可通過IDE單步運行功能看看程序的具體的走向)
#-*- coding: utf-8 -*-
#python實現聚類
#import numpy as np
from numpy import *
#加載數據集
def loadDataSet(fileName):
dataMat = []
fr = open(fileName)
for line in fr.readlines():
"""
strip()將line行開頭和結尾的空白符號刪掉。split('\t') 函數以‘\t’爲切分符號對每行切分
split函數返回的結果是一個列表,賦值給curLine
"""
curLine = line.strip().split('\t')
"""#map()是 Python 內置的高階函數,它接收一個函數 f 和一個 list,
並通過把函數 f 依次作用在 list 的每個元素上,得到一個新的 list 並返回。"""
fltLine = map(float, curLine)
dataMat.append(fltLine)
return dataMat
#計算歐式距離的函數
def countDist(vecA,vecB):
return sqrt(sum(power(vecA-vecB,2)))
#測試countDist
# vecA,vecB = np.array([1,2]),np.array([3,4])
# x = countDist(vecA,vecB)
# print(x)
#隨機設置k個質心
def randCent(dataSet,k):
n = shape(dataSet)[1]
#初始化一個k行n列的二維數組,數組初始值全部爲0,然後用mat函數將其轉化爲矩陣
centroids = mat(zeros([k,n]))
for j in range(n):
minj = min(dataSet[:,j])
rangej = float(max(dataSet[:,j])-minj)
centroids[:, j] = mat(minj + rangej * random.rand(k, 1))
return centroids
#k-Means算法核心部分
def kMeans(dataSet, k, distMeas=countDist, createCent=randCent):
#將函數distEclud和randCent作爲參數傳進來,可以更好的封裝kMeans函數
m = shape(dataSet)[0]
""" clusterAssment是一個m行2列的矩陣,第一列存放每個樣本所屬聚類中心的下標,
第二列存放該樣本與該聚類中心的距離
"""
clusterAssment = mat(zeros((m,2)))
centroids = createCent(dataSet, k)
clusterChanged = True
while clusterChanged:
clusterChanged = False
#下面兩個for循環計算每一個樣本到每一個聚類中心的距離
for i in range(m): #遍歷樣本
minDist = inf #inf表示無窮大,-inf表示負無窮
minIndex = -1
for j in range(k): #遍歷聚類中心
distJI = distMeas(centroids[j,:],dataSet[i,:])
if distJI < minDist:
minDist = distJI; minIndex = j
if clusterAssment[i,0] != minIndex:
clusterChanged = True
clusterAssment[i,:] = minIndex,minDist**2
print(centroids)
for cent in range(k): #重新計算聚類中心,cent從0遍歷到k
ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]] #nonzero函數:返回不爲0元素的行列下標組成的元組
""" #clusterAssment[:,0]:取得clusterAssment中第0列元素。
#clusterAssment[:,0].A:轉置成一個1行m列的行矩陣
#clusterAssment[:,0].A==cent :將行矩陣中每一個元素與
cent進行比較,得到一個1行m列、元素取值爲True和false
的矩陣,元素爲true表示該樣本是第cent個聚類中心的點
#nonzero(clusterAssment[:,0].A==cent)[0]:獲得元素值爲
True的元素下標,這些下標集合即爲所有屬於cent類的樣 本下標
#整句含義:取得數據集中屬於第cent個簇的樣本集
"""
centroids[cent,:] = mean(ptsInClust, axis=0)
return centroids, clusterAssment
#顯示結果
def show(dataSet, k, centroids, clusterAssment):
from matplotlib import pyplot as plt
numSamples, dim = dataSet.shape #dataSet.shape返回兩個值,分別賦給numSamples和dim
mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr'] #樣本集的顯#示樣式
for i in range(numSamples):
markIndex = int(clusterAssment[i, 0])
plt.plot(dataSet[i, 0], dataSet[i, 1], mark[markIndex])
mark = ['Dr', 'Db', 'Dg', 'Dk', '^b', '+b', 'sb', 'db', '<b', 'pb'] #聚類中#心的顯示樣式
for i in range(k):
plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize = 12)
plt.show()
def main():
#dataMat = mat(loadDataSet('testSet.txt')) #加載數據集。若沒有源數據,可用下面兩句隨機生成數據
dataMat = random.rand(100,2) #隨機生成100行2列的數據
dataMat = mat(dataMat)
myCentroids, clustAssing = kMeans(dataMat,4)
print(myCentroids)
show(dataMat, 4, myCentroids, clustAssing)
if __name__ == '__main__':
""" python代碼按照順序從頭到尾執行,不執行def開頭的函數,def函數只有被調用時才執行。
本句意思是:判斷正在執行的程序是否有主函數,若有,則不執行下面這行語句;若沒有,則調用main函數"""
main()