Kmeans學習

Kmeans學習

背景

咱們目的是將樣本分紅k個類,其實說白了就是求每一個樣例x的隱含類別y,而後利用隱含類別將x歸類。因爲咱們事先不知道類別y,那麼咱們首先能夠對每一個樣例假定一個y吧,可是怎麼知道假定的對不對呢?怎麼評價假定的好很差呢?咱們使用樣本的極大似然估計來度量,這裏是就是x和y的聯合分佈P(x,y)了。若是找到的y可以使P(x,y)最大,那麼咱們找到的y就是樣例x的最佳類別了,x順手就聚類了。可是咱們第一次指定的y不必定會讓P(x,y)最大,並且P(x,y)還依賴於其餘未知參數,固然在給定y的狀況下,咱們能夠調整其餘參數讓P(x,y)最大。可是調整完參數後,咱們發現有更好的y能夠指定,那麼咱們從新指定y,而後再計算P(x,y)最大時的參數,反覆迭代直至沒有更好的y能夠指定。css

使用

聚類的目標:python

  • 高內聚(類內距離加和儘量小!)
    • 量化指標:wcss(組內平方和,WCSS within-cluster sum of squares)
    • 尋找k個聚類中心,使得數據到聚類中心的距離最小
  • 低耦合(類與類之間的距離越大越好)!
    • 將每一個數據點分配到距離最近的聚類中心

步驟

K-means算法是將樣本聚類成k個簇(cluster),具體算法描述以下算法

  • 初始化:對每一個cluster,任意選擇空間中的一個點做爲cluster中心
  • 迭代直到收斂:
    • 分配:將每個數據點分配到距離最近的中心
    • 重調:根據新的分配從新計算聚類中心

複雜度:n*k*tapp

優勢:dom

缺點:ide

  • 對初試聚類中心依賴性強,最終效果隨機性強
  • K值很難明確
    • 所以經常使用於預處理的去重操做
    • 同類別的商品基本上類似
  • 不能發現非凸形狀的簇
  • 異或數據沒法區分
  • 結果很難保證全局最優,只是局部最優

分析

K-means面對的第一個問題是如何保證收斂,前面的算法中強調結束條件就是收斂,能夠證實的是K-means徹底能夠保證收斂性。下面咱們定性的描述一下收斂性,咱們定義畸變函數distortion function以下:函數

Kmeans學習
J函數表示每一個樣本點到其質心的距離平方和。K-means是要將J調整到最小。假設當前J沒有達到最小值,那麼首先能夠固定每一個類的質心μ,調整每一個樣例的所屬的類別c^(i)^來讓J函數減小,一樣,固定c^(i)^,調整每一個類的質心μ也可使J減少。這兩個過程就是內循環中使J單調遞減的過程。當J遞減到最小時,μ和c也同時收斂。(在理論上,能夠有多組不一樣的μ和c值可以使得J取得最小值,但這種現象實際上不多見)。學習

Kmeans學習

因爲畸變函數J是非凸函數,意味着咱們不能保證取得的最小值是全局最小值,也就是說k-means對質心初始位置的選取比較感冒,但通常狀況下k-means達到的局部最優已經知足需求。但若是你怕陷入局部最優,那麼能夠選取不一樣的初始值跑多遍k-means,而後取其中最小的J對應的μ和c輸出。3d

實現代碼

def ReAssignClass():
    did = 0
    totalDis = 0.0  # 全部的距離
    for doc in DocList:
        min = ComputeDis(doc, ClassCenterList[0])
        minIndex = 0
        for i in range(1, K):
            dis = ComputeDis(doc, ClassCenterList[i])
            if dis < min:
                min = dis
                minIndex = i
        ClassList[did] = minIndex
        did += 1
        totalDis += min
    return totalDis

注意到,K是咱們事先給定的聚類數,ComputeDis將會計算出樣例i與k個類中距離最近的那個類,其的值是1到k中的一個。質心表明咱們對屬於同一個類的樣本中心點的猜想(即μ,其實也就是咱們隨機初始化一個點),如若拿星團模型來解釋就是要將全部的星星聚成k個星團,首先隨機選取k個宇宙中的點(或者k個星星)做爲k個星團的質心,而後第一步對於每個星星計算其到k個質心中每個的距離,而後選取距離最近的那個星團記爲min,這樣通過第一步每個星星都有了所屬的星團。code

def ComputeDis(doc1, doc2):
    sum = 0.0
    for (wid, freq) in doc1.items():
        if wid in doc2:
            d = freq - doc2[wid]
            sum += d * d
        else:
            sum += freq * freq
    for (wid, freq) in doc2.items():
        if wid not in doc1:
            sum += freq * freq
    sum = math.sqrt(sum)
    return sum

第二步對於每個星團,從新計算它的質心ReComputeCentroids(對裏面全部的星星座標求平均)。重複迭代第一步和第二步直到質心不變或者變化很小。

def ReComputeCentroids():
    for i in range(K):
        ClassSizeList[i] = 0
        ClassCenterList[i] = {}
    for i in range(len(DocList)):
        classid = ClassList[i]
        ClassSizeList[classid] += 1
        AddDoc(ClassCenterList[classid], DocList[i])
    for i in range(K):
        ClassCenterList[i] = Average(i)

實踐

基於Kmeans的文章聚類(把相同的文章聚合)

準備數據

1000份已經打好標籤的文本,而且由標籤分類如bussiness,it,yule...

Kmeans學習

抽取其中一分內容已經通過文本預處理,每一個詞彙經過 分隔開

Kmeans學習

數據預處理以後經過idf爲這些詞打分

def AddIDF(DocList):
    wordDic = {}
    for doc in DocList:
        for word in doc.keys():
            if word in wordDic:
                wordDic[word] += 1
            else:
                wordDic[word] = 1
    N = len(DocList)
    for doc in DocList:
        for word in doc.keys():
            doc[word] *= math.log(N + 1 / (float)(wordDic[word]))
        Normalize(doc)

Kmeans分析

初始化K個類中心,也就是Kmeans的核心節點

def Init():
    templist = random.sample(DocList, K)
    for i in range(K):
        ClassSizeList.append(0)
        ClassCenterList.append(templist[i])

計算各個點到(類)中心的距離,固然了,這個距離是儘量的越小越好,輸出的結果就是wcss,其計算方式以下:

def ComputeDis(doc1, doc2):
    sum = 0.0
    for (wid, freq) in doc1.items():
        if wid in doc2:
            d = freq - doc2[wid]
            sum += d * d
        else:
            sum += freq * freq
    for (wid, freq) in doc2.items():
        if wid not in doc1:
            sum += freq * freq
    sum = math.sqrt(sum)
    return sum

本質上就是計算同一個簇內的距離的平方和後開方,

while math.fabs(oldWCSS - WCSS) > Threshold:
        oldWCSS = WCSS
        print "Iteration", i, "WCSS:", WCSS
        ReComputeCentroids()
        WCSS = ReAssignClass()
        i += 1
    ReComputeCentroids()
    print "Final iteration WCSS:", WCSS

重複迭代計算,直到wcss是最小,我用oldWCSS - WCSS作差,而threshold我自定義爲1,固然了能夠更加精確的,好比0.0001??

運行結果如圖所示

Kmeans學習

有5種分類方式,其中第一種的分類方式準確率是0.6,第二種是0.9,。。。。。。

相關文章
相關標籤/搜索