基本KMeans和二分Kmeans的python實現(xiàn)

基本Kmeans算法

import numpy as np
import random

def calc_dist(vec1, vec2):
    """計算兩個向量的歐氏距離"""
    return np.sqrt(sum(np.power(vec1-vec2, 2)))

def rand_cent(dataSet, k):
    """取k個隨機質(zhì)心午磁,質(zhì)心的每個特征的值是在數(shù)據(jù)上下界中隨機選取
    不一定是數(shù)據(jù)中包含的值"""
    n = shape(dataSet)[1]
    centroids = np.mat(np.zeros((k, n)))
    for j in range(n):
        min_val = min(dataSet[:, j])
        range_val = max(dataSet[:, j]) - min_val
        centroids[j] = min_val + range_val * random.rand(k, 1)
    return centroids
def Kmeans(dataSet, k, dist_eval = calc_dist, create_cent = rand_cent):
    """
    創(chuàng)建隨機的K個點作為起始質(zhì)心
    當(dāng)任意一個點的簇分配結(jié)果發(fā)生改變時:
        對數(shù)據(jù)中的每個數(shù)據(jù)點:
            對每個質(zhì)心:
                計算質(zhì)心與數(shù)據(jù)點之間的距離
            將數(shù)據(jù)點分配到距其最近的簇
        對每個簇拦止,計算簇中所有點的均值并將其作為質(zhì)心
    """
    m = shape(dataSet)[0]
    cluster_assign = np.mat(np.zeros((m, 2)))  #樣本屬于哪個簇和距離
    centroids = create_cent(dataSet, k)  #隨機創(chuàng)建質(zhì)心
    
    cluster_change = True  #程序終止條件
    while cluster_change:
        cluster_change = False
        
        #更新每個樣本的所在簇
        for i in range(m):
            min_dist = np.inf
            min_index = -1
            for j in range(k):
                dist = dist_eval(dataSet[i, :], centroids[j, :])
                if dist < min_dist:
                    min_dist = dist
                    min_index = j
            if min_index != cluster_assign[i]:
                cluster_change = True
                cluster_assign[i] = [min_index, min_dist]
        
        if not cluster_change:
            break
        
        #更新每個簇
        for cent in range(k):
            cluster_sample = dataSet[np.nonzero(cluster_assign[:, 0].A == cent)[0]]
            centroids[cent, :] = np.mean(cluster_sample, axis = 0)
    
    return centroids, cluster_assign

二分KMeans算法

def bin_Kmeans(dataSet, k, dist_eval = calc_dist):
    """
    Kmeans容易收斂到局部最小值窍霞,為克服饥追,有二分Kmeans:
    1. 將所有點看成一個簇
    2. 當(dāng)簇數(shù)目小于k時繼續(xù)劃分:
           對于每一個簇:
               計算總誤差
               在給定的簇上面進(jìn)行2Means聚類
               計算將該簇一分為2之后的誤差 + 其他簇類的誤差作為新的總誤差
           選擇使得總誤差最小的的分割
    """
    m = shape(dataSet)[0]
    cluster_assign = np.mat(np.zeros((m, 2)))  #第一列保存所屬簇id咕痛, 第二列保存距離
    
    centroid0 = np.mean(dataSet, axis = 0).tolist()[0]  #初始簇為全數(shù)據(jù)集的中心
    cent_list = [centroid0]
    
    for i in range(m):
        cluster_assign[i, 1] = dist_eval(np.mat(centroid0), dataSet[i, :]) ** 2  #用歐式距離的平方颠印,更重視那些遠(yuǎn)離中心的點
        
    while len(cent_list) < k:
        lowest_sse = np.inf  # sum of squared error
        
        #選擇最優(yōu)分割簇瘤载,使總誤差最小
        for i in range(len(cent_list)):  
            cluster_samples = dataSet[np.nonzero(cluster_assign[:, 0].A == i)[0], :]  #這個簇的所有樣本
            centroids, clusters = Kmeans(cluster_samples, 2, dist_eval)  #對這個簇的樣本一分為2
            sse_other_cluster = sum(cluster_assign[np.nonzero(cluster_assign[:, 0].A != i)[0], 1])  #其他簇類的誤差
            sse_split = sum(clusters[:, 1])  #劃分部分的誤差
            
            if sse_split + sse_other_cluster < lowest_sse:
                lowest_sse = sse_split + sse_other_cluster
                best_new_cnets = centroids
                best_clusters = clusters
                best_split_cent = i
        
        #更新簇的分配結(jié)果
        best_clusters[np.nonzero(best_clusters[:, 0].A == 1)[0], 0] = len(cent_list)  #新的簇id
        best_clusters[np.nonzero(best_clusters[:, 0].A == 0)[0], 0] = best_split_cent  #被分割的簇id
        
        cent_list[best_split_cent] = best_new_cnets[0:]  #更新簇的特征值
        cent_list.append(best_new_cnets[1:])
        
        cluster_assign[np.nonzero(cluster_assign[:, 0].A == best_split_cent)[0], :] = best_clusters  #更新總的樣本所屬簇記錄
        
    return np.mat(cent_list), cluster_assign
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末晓淀,一起剝皮案震驚了整個濱河市想诅,隨后出現(xiàn)的幾起案子王悍,更是在濱河造成了極大的恐慌,老刑警劉巖题画,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件默辨,死亡現(xiàn)場離奇詭異,居然都是意外死亡苍息,警方通過查閱死者的電腦和手機缩幸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來竞思,“玉大人表谊,你說我怎么就攤上這事「桥纾” “怎么了爆办?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長课梳。 經(jīng)常有香客問我距辆,道長,這世上最難降的妖魔是什么暮刃? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任跨算,我火速辦了婚禮,結(jié)果婚禮上椭懊,老公的妹妹穿的比我還像新娘诸蚕。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布背犯。 她就那樣靜靜地躺著坏瘩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪漠魏。 梳的紋絲不亂的頭發(fā)上桑腮,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音蛉幸,去河邊找鬼破讨。 笑死,一個胖子當(dāng)著我的面吹牛奕纫,可吹牛的內(nèi)容都是我干的提陶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼匹层,長吁一口氣:“原來是場噩夢啊……” “哼隙笆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起升筏,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤撑柔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后您访,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體铅忿,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年灵汪,在試婚紗的時候發(fā)現(xiàn)自己被綠了檀训。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡享言,死狀恐怖峻凫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情览露,我是刑警寧澤荧琼,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站差牛,受9級特大地震影響命锄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜多糠,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一累舷、第九天 我趴在偏房一處隱蔽的房頂上張望浩考。 院中可真熱鬧夹孔,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至怜俐,卻和暖如春身堡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拍鲤。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工贴谎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人季稳。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓擅这,卻偏偏與公主長得像,于是被迫代替她去往敵國和親景鼠。 傳聞我的和親對象是個殘疾皇子仲翎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容