原始資料:testSet2.txt
3.275154 2.957587
-3.344465 2.603513
0.355083 -3.376585
1.852435 3.547351
-2.078973 2.552013
-0.993756 -0.884433
2.682252 4.007573
-3.087776 2.878713
-1.565978 -1.256985
2.441611 0.444826
-0.659487 3.111284
-0.459601 -2.618005
2.177680 2.387793
-2.920969 2.917485
-0.028814 -4.168078
3.625746 2.119041
-3.912363 1.325108
-0.551694 -2.814223
2.855808 3.483301
-3.594448 2.856651
0.421993 -2.372646
1.650821 3.407572
-2.082902 3.384412
-0.718809 -2.492514
4.513623 3.841029
-4.822011 4.607049
-0.656297 -1.449872
1.919901 4.439368
-3.287749 3.918836
-1.576936 -2.977622
3.598143 1.975970
-3.977329 4.900932
-1.791080 -2.184517
3.914654 3.559303
-1.910108 4.166946
-1.226597 -3.317889
1.148946 3.345138
-2.113864 3.548172
0.845762 -3.589788
2.629062 3.535831
-1.640717 2.990517
-1.881012 -2.485405
4.606999 3.510312
-4.366462 4.023316
0.765015 -3.001270
3.121904 2.173988
-4.025139 4.652310
-0.559558 -3.840539
4.376754 4.863579
-1.874308 4.032237
-0.089337 -3.026809
3.997787 2.518662
-3.082978 2.884822
0.845235 -3.454465
1.327224 3.358778
-2.889949 3.596178
-0.966018 -2.839827
2.960769 3.079555
-3.275518 1.577068
0.639276 -3.412840
代碼:
from numpy import *
from math import *
'''loadDataSet(fileName)函數将文本檔案導入到一個清單中,
文本檔案每一行為tab分隔的浮點數,
每一個清單會被添加到dataMat中,最後傳回dataMat,
該傳回值是一個包含許多其他清單的清單,
這種格式可以很容易将很多值封裝到矩陣中。'''
def loadDataSet(fileName): #general function to parse tab -delimited floats
dataMat = [] #assume last column is target value
fr = open(fileName)
for line in fr.readlines():
curLine = line.strip().split('\t')
fltLine = list(map(float,curLine)) #map all elements to float()
dataMat.append(fltLine)
return dataMat
'''distEclud(vecA, vecB)函數計算兩個向量的歐式距離'''
def distEclud(vecA, vecB):
return math.sqrt(sum(power(vecA - vecB, 2))) #la.norm(vecA-vecB)
'''randCent()函數為給定資料集建構一個包含k個随機質心的集合。
随機質心必須要在整個資料集的邊界之内,這可以通過找到資料集每一維的最小值和最大值來完成。
然後生成0到1.0之間的随機數并通過取值範圍和最小值,以便確定随機點在資料的邊界之内。'''
def randCent(dataSet, k):
n = shape(dataSet)[1]
centroids = mat(zeros((k,n)))#create centroid mat
for j in range(n):#create random cluster centers, within bounds of each dimension
minJ = min(dataSet[:,j])
rangeJ = float(max(dataSet[:,j]) - minJ)
centroids[:,j] = mat(minJ + rangeJ * random.rand(k,1))
return centroids
'''
兩個必選參數:
dataSet:該參數為給定的資料集,
k:該參數為簇的數目,
兩個可選的參數:
distEclud:計算兩個向量組之間的距離,
'''def biKmeans(dataSet, k, distMeas=distEclud):
m = shape(dataSet)[0]
clusterAssment = mat(zeros((m,2)))
centroid0 = mean(dataSet, axis=0).tolist()[0]
centList =[centroid0] #create a list with one centroid
for j in range(m):#calc initial Error
clusterAssment[j,1] = distMeas(mat(centroid0), dataSet[j,:])**2
while (len(centList) < k):
lowestSSE = inf
for i in range(len(centList)):
ptsInCurrCluster = dataSet[nonzero(clusterAssment[:,0].A==i)[0],:]#get the data points currently in cluster i
centroidMat, splitClustAss = kMeans(ptsInCurrCluster, 2, distMeas)
sseSplit = sum(splitClustAss[:,1])#compare the SSE to the currrent minimum
sseNotSplit = sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1])
print("sseSplit, and notSplit: ",sseSplit,sseNotSplit)
if (sseSplit + sseNotSplit) < lowestSSE:
bestCentToSplit = i
bestNewCents = centroidMat
bestClustAss = splitClustAss.copy()
lowestSSE = sseSplit + sseNotSplit
bestClustAss[nonzero(bestClustAss[:,0].A == 1)[0],0] = len(centList) #change 1 to 3,4, or whatever
bestClustAss[nonzero(bestClustAss[:,0].A == 0)[0],0] = bestCentToSplit
print('the bestCentToSplit is: ',bestCentToSplit)
print('the len of bestClustAss is: ', len(bestClustAss))
centList[bestCentToSplit] = bestNewCents[0,:].tolist()[0]#replace a centroid with two best centroids
centList.append(bestNewCents[1,:].tolist()[0])
clusterAssment[nonzero(clusterAssment[:,0].A == bestCentToSplit)[0],:]= bestClustAss#reassign new clusters, and SSE
return mat(centList), clusterAssment
結果:
>>> import kMeans
>>> from numpy import *
>>> datMat3 = mat(kMeans.loadDataSet('testSet2.txt'))
>>> centList,myNewAssments = kMeans.biKmeans(datMat3, 3)
[[ 0.26987696 -3.28064982]
[ 3.50813038 -3.6198256 ]]
[[-1.26225285 0.68367935]
[ 3.47144757 3.00503979]]
[[-1.70351595 0.27408125]
[ 2.93386365 3.12782785]]
sseSplit, and notSplit: 541.2976292649145 0.0
the bestCentToSplit is: 0
the len of bestClustAss is: 60
[[-4.74513879 -1.43065754]
[-0.05209199 3.08915112]]
[[-0.74459109 -2.39373345]
[-2.87553522 3.53474367]]
[[-0.45965615 -2.7782156 ]
[-2.94737575 3.3263781 ]]
sseSplit, and notSplit: 67.2202000797829 39.52929868209309
[[2.01125497 0.89234622]
[3.43187479 1.67391425]]
[[1.63926033 2.382914 ]
[3.16232306 3.25928324]]
[[1.76645283 2.74857633]
[3.43418257 3.29036421]]
[[1.788374 2.990118 ]
[3.55066577 3.20197931]]
sseSplit, and notSplit: 25.194262086233078 501.7683305828214
the bestCentToSplit is: 0
the len of bestClustAss is: 40
質心為:
>>> centList
matrix([[-0.45965615, -2.7782156 ],
[ 2.93386365, 3.12782785],
[-2.94737575, 3.3263781 ]])
centList2.txt:
-0.45965615,-2.7782156
2.93386365,3.12782785
-2.94737575,3.3263781
結果可視化:
代碼:
"""
二分K-均值聚類算法
"""
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
mpl.rcParams['font.family'] = 'sans-serif'
mpl.rcParams['font.sans-serif'] = 'NSimSun,Times New Roman'
x, y = np.loadtxt('testSet2.txt', delimiter='\t', unpack=True)
m, n = np.loadtxt('centList2.txt', delimiter=',', unpack=True)
plt.plot(x, y, '.', label='Data', color='black')
plt.plot(m, n, '*', label='Center', color='red')
plt.xlabel('x')
plt.ylabel('y')
plt.title('binary k-means cluster algorithm')
plt.legend()
plt.show()
運作結果: