
使用這些基本 REST API 最佳實踐構建出色的 API
深度聚類方法主要是根據表征學習后的特征+傳統聚類算法。
kmeans聚類可以說是聚類算法中最為常見的,它是基于劃分方法聚類的,原理是先初始化k個簇類中心,基于計算樣本與中心點的距離歸納各簇類下的所屬樣本,迭代實現樣本與其歸屬的簇類中心的距離為最小的目標(如下目標函數)。
其優化算法步驟為:
1.隨機選擇 k 個樣本作為初始簇類中心(k為超參,代表簇類的個數。可以憑先驗知識、驗證法確定取值);
2.針對數據集中每個樣本 計算它到 k 個簇類中心的距離,并將其歸屬到距離最小的簇類中心所對應的類中;
3.針對每個簇類,重新計算它的簇類中心位置;
4.重復迭代上面 2 、3 兩步操作,直到達到某個中止條件(如迭代次數,簇類中心位置不變等)。
....
完整代碼可見:https://github.com/aialgorithm/Blog 或文末閱讀原文
#kmeans算法是初始化隨機k個中心點
random.seed(1)
center = [[self.data[i][r] for i in range(1, len((self.data)))]
for r in random.sample(range(len(self.data)), k)]
#最大迭代次數iters
for i in range(self.iters):
class_dict = self.count_distance() #計算距離,比較個樣本到各個中心的的出最小值,并劃分到相應的類
self.locate_center(class_dict) # 重新計算中心點
#print(self.data_dict)
print("----------------迭代%d次----------------"%i)
print(self.center_dict) #聚類結果{k:{{center:[]},{distance:{item:0.0},{classify:[]}}}}
if sorted(self.center) == sorted(self.new_center):
break
else:
self.center = self.new_center
...
可見,Kmeans 聚類的迭代算法實際上是 EM 算法,EM 算法解決的是在概率模型中含有無法觀測的隱含變量情況下的參數估計問題。
在 Kmeans 中的隱變量是每個類別所屬類別。Kmeans 算法迭代步驟中的 每次確認中心點以后重新進行標記 對應 EM 算法中的 E 步 求當前參數條件下的 Expectation 。而 根據標記重新求中心點 對應 EM 算法中的 M 步 求似然函數最大化時(損失函數最小時)對應的參數 。EM 算法的缺點是容易陷入局部極小值,這也是 Kmeans 有時會得到局部最優解的原因。
kmeans 算法是基于距離相似度計算的,以確定各樣本所屬的最近中心點,常用距離度量有曼哈頓距離和歐式距離,具體可以見文章【全面歸納距離和相似度方法(7種)】
歐幾里得距離 公式:
曼哈頓、歐幾里得距離的計算方法很簡單,就是計算兩樣本(x,y)的各個特征i間的總距離。如下圖(二維特征的情況)藍線的距離即是曼哈頓距離(想象你在曼哈頓要從一個十字路口開車到另外一個十字路口實際駕駛距離就是這個“曼哈頓距離”,也稱為城市街區距離),紅線為歐幾里得距離:
kmeans劃分k個簇,不同k的情況,算法的效果可能差異就很大。K值的確定常用:先驗法、手肘法等方法。
先驗比較簡單,就是憑借著業務知識確定k的取值。比如對于iris花數據集,我們大概知道有三種類別,可以按照k=3做聚類驗證。從下圖可看出,對比聚類預測與實際的iris種類是比較一致的。
可以知道k值越大,劃分的簇群越多,對應的各個點到簇中心的距離的平方的和(類內距離,WSS)越低,我們通過確定WSS隨著K的增加而減少的曲線拐點,作為K的取值。
手肘法的缺點在于需要人為判斷不夠自動化,還有些其他方法如:
kmeans是采用隨機初始化中心點,而不同初始化的中心點對于算法結果的影響比較大。所以,針對這點更新出了Kmeans++算法,其初始化的思路是:各個簇類中心應該互相離得越遠越好。基于各點到已有中心點的距離分量,依次隨機選取到k個元素作為中心點。離已確定的簇中心點的距離越遠,越有可能(可能性正比與距離的平方)被選擇作為另一個簇的中心點。如下代碼。
# Kmeans ++ 算法基于距離概率選擇k個中心點
# 1.隨機選擇一個點
center = []
center.append(random.choice(range(len(self.data[0]))))
# 2.根據距離的概率選擇其他中心點
for i in range(self.k - 1):
weights = [self.distance_closest(self.data[0][x], center)
for x in range(len(self.data[0])) if x not in center]
dp = [x for x in range(len(self.data[0])) if x not in center]
total = sum(weights)
#基于距離設定權重
weights = [weight/total for weight in weights]
num = random.random()
x = -1
i = 0
while i < num :
x += 1
i += weights[x]
center.append(dp[x])
center = [self.data_dict[self.data[0][center[k]]] for k in range(len(center))]
基于歐式距離的 Kmeans 假設了了各個數據簇的數據具有一樣的的先驗概率并呈現球形分布,但這種分布在實際生活中并不常見。面對非凸的數據分布形狀時我們可以引入核函數來優化,這時算法又稱為核 Kmeans 算法,是核聚類方法的一種。核聚類方法的主要思想是通過一個非線性映射,將輸入空間中的數據點映射到高位的特征空間中,并在新的特征空間中進行聚類。非線性映射增加了數據點線性可分的概率,從而在經典的聚類算法失效的情況下,通過引入核函數可以達到更為準確的聚類結果。
kmeans是面向數值型的特征,對于類別特征需要進行onehot或其他編碼方法。此外還有 K-Modes 、K-Prototypes 算法可以用于混合類型數據的聚類,對于數值特征簇類中心我們取得是各特征均值,而類別型特征中心取得是眾數,計算距離采用海明距離,一致為0否則為1。
聚類是基于特征間距離計算,計算距離時,需要關注到特征量綱差異問題,量綱越大意味這個特征權重越大。假設各樣本有年齡、工資兩個特征變量,如計算歐氏距離的時候,(年齡1-年齡2)2 的值要遠小于(工資1-工資2)2 ,這意味著在不使用特征縮放的情況下,距離會被工資變量(大的數值)主導。因此,我們需要使用特征縮放來將全部的數值統一到一個量級上來解決此問題。通常的解決方法可以對數據進行“標準化”或“歸一化”,對所有數值特征統一到標準的范圍如0~1。
歸一化后的特征是統一權重,有時我們需要針對不同特征賦予更大的權重。假設我們希望feature1的權重為1,feature2的權重為2,則進行0~1歸一化之后,在進行類似歐幾里得距離(未開根號)計算的時候,
我們將feature2的值乘根號2就可以了,這樣feature2對應的上式的計算結果會增大2倍,從而簡單快速的實現權重的賦權。如果使用的是曼哈頓距離,特征直接乘以2 權重也就是2 。
如果類別特征進行embedding之后的特征加權,比如embedding為256維,則我們對embedding的結果進行0~1歸一化之后,每個embedding維度都乘以 根號1/256,從而將這個類別全部的距離計算貢獻規約為1,避免embedding size太大使得kmeans的聚類結果非常依賴于embedding這個本質上是單一類別維度的特征。
kmeans本質上只是根據樣本特征間的距離(樣本分布)確定所屬的簇類。而不同特征的情況,就會明顯影響聚類的結果。當使用沒有代表性的特征時,結果可能就和預期大相徑庭!比如,想對銀行客戶質量進行聚類分級:交易次數、存款額度就是重要的特征,而如客戶性別、年齡情況可能就是噪音,使用了性別、年齡特征得到的是性別、年齡相仿的客戶!
對于無監督聚類的特征選擇:
本文章轉載微信公眾號@算法進階