1. kmeans算法簡介
待補充
2. python實現
2.1 基礎版
kmeans算法,前幾天的一道面試在線編程題目。好久不用python手法都生疏了,寫的很慢。不過后來對比了下網絡上的其他kmeans的python實現,感覺自己的實現相對簡潔美觀,代碼量少。這主要依賴於numpy包的使用。
廢話少說,直接上代碼.
對於輸入數據的說明
data是一個\(n*m\)的數組,\(data\in R^{n*m}\),\(n\)是訓練數據的樣本個數,\(m\)是feature的維數,\(k\)是設定好的聚類數
import numpy as np
def kmeans(data, n, m, k):
rarray = np.random.random(size=k)
rarray = np.floor(rarray*n)
rarray.astype(int)
end = True
cls = np.zeros([1,n],np.int)
center = np.take(data,rarray)
pcenter = np.zeros([k,m])
while end:
for i in xrange(n):
tmp = data[i] - center
tmp = np.square(tmp)
tmp = np.sum(tmp,axis=1)
cls[i] = np.argmin(tmp)
center = np.zeros([k,m])
count = np.zeros([1,k],np.int)
for i in xrange(n):
center[cls[i]]=center[cls[i]]+data[i]
count[cls[i]]= count[cls[i]]+1
if center/count == pcenter:
end = False
pcenter = center/count
2.2 修改版
說是修改版其實有點勉強,不過確實是一個很有用的修改。編程中在做數值相等判斷的時候,直接使用==
判斷並不可靠。實際上經過運算后的兩個值(浮點型)並不可能完全一致,可能會因為小數點后的些許差異導致判斷為false。
比如:
print 1e-5 == 1e-6 //這肯定是false,但是實際這兩個值可以看作近似相等。
在kmeans中判斷是否結束循環,就是判斷重新計算的聚類中心點是否和原聚類中心點一致,實際上新舊聚類中心點之間會有一個可允許的誤差。修改代碼如下:
import numpy as np
def kmeans(data, n, m, k):
rarray = np.random.random(size=k)
rarray = np.floor(rarray*n)
rarray.astype(int)
cls = np.zeros([1,n],np.int)
center = np.take(data,rarray)
pcenter = np.zeros([k,m])
end = True
while end:
for i in xrange(n):
tmp = data[i] - center
tmp = np.square(tmp)
tmp = np.sum(tmp,axis=1)
cls[i] = np.argmin(tmp)
center = np.zeros([k,m])
count = np.zeros([1,k],np.int)
for i in xrange(n):
center[cls[i]]=center[cls[i]]+data[i]
count[cls[i]]= count[cls[i]]+1
if np.sum(center/count - pcenter) <= 1e-4:
end = False
pcenter = center/count
3. 待解決的問題
由於聚類之后,開始新的迭代過程中,可能有某一類\(k'\)會產生特殊情況:訓練樣本中沒有任何一個被分到這個類。這個時候對應的count[k'] = 0
,直接做除法顯然就會報錯,這個問題暫時還沒有解決。