1 K-均值聚類(K-means)概述
1.1 聚類
“類”指的是具有相似性的集合。聚類是指將數據集劃分為若干類,使得類內之間的數據最為相似,各類之間的數據相似度差別盡可能大。聚類分析就是以相似性為基礎,對數據集進行聚類劃分,屬于無監督學習。
1.2 無監督學習和監督學習
和KNN所不同,K-均值聚類屬于無監督學習。那么監督學習和無監督學習的區別在哪兒呢?監督學習知道從對象(數據)中學習什么,而無監督學習無需知道所要搜尋的目標,它是根據算法得到數據的共同特征。比如用分類和聚類來說,分類事先就知道所要得到的類別,而聚類則不一樣,只是以相似度為基礎,將對象分得不同的簇。
1.3 K-means
K-means算法具有悠久的歷史,并且也是最常用的聚類算法之一。K-means算法實施起來非常簡單,因此,它非常適用于機器學習新手愛好者。
1967年,James MacQueen在他的論文《用于多變量觀測分類和分析的一些方法》中首次提出 “K-means”這一術語。1957年,貝爾實驗室也將標準算法用于脈沖編碼調制技術。1965年,E.W. Forgy發表了本質上相同的算法——Lloyd-Forgy算法。
k-means算法是一種簡單的迭代型聚類算法,采用距離作為相似性指標,從而發現給定數據集中的K個類,且每個類的中心是根據類中所有值的均值得到,每個類用聚類中心來描述。對于給定的一個包含n個d維數據點的數據集X以及要分得的類別K,選取歐式距離作為相似度指標,聚類目標是使得各類的聚類平方和最小,即最小化:
結合最小二乘法和拉格朗日原理,聚類中心為對應類別中各數據點的平均值,同時為了使得算法收斂,在迭代過程中,應使最終的聚類中心盡可能的不變。
1.4 K-Means算法的十大用例
K-means算法通常可以應用于維數、數值都很小且連續的數據集,比如:從隨機分布的事物集合中將相同事物進行分組。
1.文檔分類器
根據標簽、主題和文檔內容將文檔分為多個不同的類別。這是一個非常標準且經典的K-means算法分類問題。首先,需要對文檔進行初始化處理,將每個文檔都用矢量來表示,并使用術語頻率來識別常用術語進行文檔分類,這一步很有必要。然后對文檔向量進行聚類,識別文檔組中的相似性。 這里是用于文檔分類的K-means算法實現案例。2.物品傳輸優化
使用K-means算法的組合找到無人機最佳發射位置和遺傳算法來解決旅行商的行車路線問題,優化無人機物品傳輸過程。3.識別犯罪地點
使用城市中特定地區的相關犯罪數據,分析犯罪類別、犯罪地點以及兩者之間的關聯,可以對城市或區域中容易犯罪的地區做高質量的勘察。這是基于德里飛行情報區犯罪數據的論文。4.客戶分類
聚類能過幫助營銷人員改善他們的客戶群(在其目標區域內工作),并根據客戶的購買歷史、興趣或活動監控來對客戶類別做進一步細分。這是關于電信運營商如何將預付費客戶分為充值模式、發送短信和瀏覽網站幾個類別的白皮書。對客戶進行分類有助于公司針對特定客戶群制定特定的廣告。5.球隊狀態分析
分析球員的狀態一直都是體育界的一個關鍵要素。隨著競爭越來愈激烈,機器學習在這個領域也扮演著至關重要的角色。如果你想創建一個優秀的隊伍并且喜歡根據球員狀態來識別類似的球員,那么K-means算法是一個很好的選擇。6.保險欺詐檢測
機器學習在欺詐檢測中也扮演著一個至關重要的角色,在汽車、醫療保險和保險欺詐檢測領域中廣泛應用。利用以往欺詐性索賠的歷史數據,根據它和欺詐性模式聚類的相似性來識別新的索賠。由于保險欺詐可能會對公司造成數百萬美元的損失,因此欺詐檢測對公司來說至關重要。這是汽車保險中使用聚類來檢測欺詐的白皮書。7.乘車數據分析
面向大眾公開的Uber乘車信息的數據集,為我們提供了大量關于交通、運輸時間、高峰乘車地點等有價值的數據集。分析這些數據不僅對Uber大有好處,而且有助于我們對城市的交通模式進行深入的了解,來幫助我們做城市未來規劃。這是一篇使用單個樣本數據集來分析Uber數據過程的文章。8.網絡分析犯罪分子
網絡分析是從個人和團體中收集數據來識別二者之間的重要關系的過程。網絡分析源自于犯罪檔案,該檔案提供了調查部門的信息,以對犯罪現場的罪犯進行分類。這是一篇在學術環境中,如何根據用戶數據偏好對網絡用戶進行 cyber-profile的論文。9.呼叫記錄詳細分析
通話詳細記錄(CDR)是電信公司在對用戶的通話、短信和網絡活動信息的收集。將通話詳細記錄與客戶個人資料結合在一起,這能夠幫助電信公司對客戶需求做更多的預測。在這篇文章中,你將了解如何使用無監督K-Means聚類算法對客戶一天24小時的活動進行聚類,來了解客戶數小時內的使用情況。10.IT警報的自動化聚類
大型企業IT基礎架構技術組件(如網絡,存儲或數據庫)會生成大量的警報消息。由于警報消息可以指向具體的操作,因此必須對警報信息進行手動篩選,確保后續過程的優先級。對數據進行聚類可以對警報類別和平均修復時間做深入了解,有助于對未來故障進行預測。
1.5 應用示例
想要將一組數據,分為三類,粉色數值大,黃色數值小。
最開心先初始化,這里面選了最簡單的 3,2,1 作為各類的初始值。
剩下的數據里,每個都與三個初始值計算距離,然后歸類到離它最近的初始值所在類別。
分好類后,計算每一類的平均值,作為新一輪的中心點。
幾輪之后,分組不再變化了,就可以停止了。
1.6 算法流程
K-means是一個反復迭代的過程,算法分為四個步驟:
1) 選取數據空間中的K個對象作為初始中心,每個對象代表一個聚類中心;
2) 對于樣本中的數據對象,根據它們與這些聚類中心的歐氏距離,按距離最近的準則將它們分到距離它們最近的聚類中心(最相似)所對應的類;
3) 更新聚類中心:將每個類別中所有對象所對應的均值作為該類別的聚類中心,計算目標函數的值;
4) 判斷聚類中心和目標函數的值是否發生改變,若不變,則輸出結果,若改變,則返回2)。
用以下例子加以說明:
圖1:給定一個數據集;
圖2:根據K = 5初始化聚類中心,保證 聚類中心處于數據空間內;
圖3:根據計算類內對象和聚類中心之間的相似度指標,將數據進行劃分;
圖4:將類內之間數據的均值作為聚類中心,更新聚類中心。
最后判斷算法結束與否即可,目的是為了保證算法的收斂。
2 Python實現
2.1 計算過程
st=>start: 開始
e=>end: 結束
op1=>operation: 讀入數據
op2=>operation: 隨機初始化聚類中心
cond=>condition: 是否聚類是否變化
op3=>operation: 尋找最近的點加入聚類
op4=>operation: 更新聚類中心
op5=>operation: 輸出結果
st->op1->op2->op3->op4->cond
cond(yes)->op3
cond(no)->op5->e
2.2 輸入樣例
15.55,28.65
14.9,27.55
14.45,28.35
14.15,28.8
13.75,28.05
13.35,28.45
13,29.15
13.45,27.5
13.6,26.5
12.8,27.35
2.3 代碼實現
__author__ = 'Bobby'
from numpy import *
import matplotlib.pyplot as plt
import time
INF = 9999999.0
def loadDataSet(fileName, splitChar='\t'):
"""
輸入:文件名
輸出:數據集
描述:從文件讀入數據集
"""
dataSet = []
with open(fileName) as fr:
for line in fr.readlines():
curline = line.strip().split(splitChar)
fltline = list(map(float, curline))
dataSet.append(fltline)
return dataSet
def createDataSet():
"""
輸出:數據集
描述:生成數據集
"""
dataSet = [[0.0, 2.0],
[0.0, 0.0],
[1.5, 0.0],
[5.0, 0.0],
[5.0, 2.0]]
return dataSet
def distEclud(vecA, vecB):
"""
輸入:向量A, 向量B
輸出:兩個向量的歐式距離
"""
return sqrt(sum(power(vecA - vecB, 2)))
def randCent(dataSet, k):
"""
輸入:數據集, 聚類個數
輸出:k個隨機質心的矩陣
"""
n = shape(dataSet)[1]
centroids = mat(zeros((k, n)))
for j in range(n):
minJ = min(dataSet[:, j])
rangeJ = float(max(dataSet[:, j]) - minJ)
centroids[:, j] = minJ + rangeJ * random.rand(k, 1)
return centroids
def kMeans(dataSet, k, distMeans=distEclud, createCent=randCent):
"""
輸入:數據集, 聚類個數, 距離計算函數, 生成隨機質心函數
輸出:質心矩陣, 簇分配和距離矩陣
"""
m = shape(dataSet)[0]
clusterAssment = mat(zeros((m, 2)))
centroids = createCent(dataSet, k)
clusterChanged = True
while clusterChanged:
clusterChanged = False
for i in range(m): # 尋找最近的質心
minDist = INF
minIndex = -1
for j in range(k):
distJI = distMeans(centroids[j, :], dataSet[i, :])
if distJI < minDist:
minDist = distJI
minIndex = j
if clusterAssment[i, 0] != minIndex:
clusterChanged = True
clusterAssment[i, :] = minIndex, minDist**2
for cent in range(k): # 更新質心的位置
ptsInClust = dataSet[nonzero(clusterAssment[:, 0].A == cent)[0]]
centroids[cent, :] = mean(ptsInClust, axis=0)
return centroids, clusterAssment
def plotFeature(dataSet, centroids, clusterAssment):
m = shape(centroids)[0]
fig = plt.figure()
scatterMarkers = ['s', 'o', '^', '8', 'p', 'd', 'v', 'h', '>', '<']
scatterColors = ['blue', 'green', 'yellow', 'purple', 'orange', 'black', 'brown']
ax = fig.add_subplot(111)
for i in range(m):
ptsInCurCluster = dataSet[nonzero(clusterAssment[:, 0].A == i)[0], :]
markerStyle = scatterMarkers[i % len(scatterMarkers)]
colorSytle = scatterColors[i % len(scatterColors)]
ax.scatter(ptsInCurCluster[:, 0].flatten().A[0], ptsInCurCluster[:, 1].flatten().A[0], marker=markerStyle, c=colorSytle, s=90)
ax.scatter(centroids[:, 0].flatten().A[0], centroids[:, 1].flatten().A[0], marker='+', c='red', s=300)
def main():
#dataSet = loadDataSet('testSet2.txt')
dataSet = loadDataSet('788points.txt', splitChar=',')
#dataSet = createDataSet()
dataSet = mat(dataSet)
resultCentroids, clustAssing = kMeans(dataSet, 6)
print('*******************')
print(resultCentroids)
print('*******************')
plotFeature(dataSet, resultCentroids, clustAssing)
if __name__ == '__main__':
start = time.clock()
main()
end = time.clock()
print('finish all in %s' % str(end - start))
plt.show()
2.4 輸出樣例
*******************
[[32.69453125 22.13789062]
[33.14278846 8.79375 ]
[21.16041667 22.89895833]
[ 9.25928144 22.98113772]
[ 9.81847826 7.59311594]
[19.0637931 7.06551724]]
*******************
finish all in 2.270720974