機器學(xué)習(xí)之K-Means算法

一、聚類算法的簡介

??聚類算法是一種典型的無監(jiān)督學(xué)習(xí)算法娶牌,主要用于將相似的樣本自動歸到一個類別中允蚣。聚類算法與分類算法最大的區(qū)別是:聚類算法是無監(jiān)督的學(xué)習(xí)算法,而分類算法屬于監(jiān)督的學(xué)習(xí)算法柏锄。

??在聚類算法中根據(jù)樣本之間的相似性,將樣本劃分到不同的類別中复亏,對于不同的相似度計算方法趾娃,會得到不同的聚類結(jié)果,常用的相似度計算方法有歐式距離法缔御。

二抬闷、K-Means算法的概述

??K-Means聚類的目的是將n個觀測值劃分為k個類,使每個類中的觀測值距離該類的中心(類均值)比距離其他類中心都近耕突。
??事先確定常數(shù)k笤成,常數(shù)k意味著最終的聚類類別數(shù),首先隨機選定初始點為質(zhì)心眷茁,并通過計算每一個樣本與質(zhì)心之間的相似度(這里為歐式距離)炕泳,將樣本點歸到最相似的類中,接著上祈,重新計算每個類的質(zhì)心(即為類中心)培遵,重復(fù)這樣的過程浙芙,知道質(zhì)心不再改變,最終就確定了每個樣本所屬的類別以及每個類的質(zhì)心籽腕。
??由于每次都要計算所有的樣本與每一個質(zhì)心之間的相似度嗡呼,故在大規(guī)模的數(shù)據(jù)集上,K-Means算法的收斂速度比較慢节仿。

三晤锥、K-Means算法的流程

1、初始化常數(shù)K廊宪,隨機選取初始點為質(zhì)心
2、重復(fù)計算一下過程女轿,直到質(zhì)心不再改變
?(1)計算樣本與每個質(zhì)心之間的相似度箭启,將樣本歸類到最相似的類中
?(2)重新計算質(zhì)心
3、輸出最終的質(zhì)心以及每個類

四蛉迹、K-Means算法的實現(xiàn)

1傅寡、K-Means算法實現(xiàn)代碼如下:
import numpy as np
import matplotlib.pyplot as plt

'''
算法思想大致為:先從樣本集中隨機選取 ?? 個樣本作為簇中心,并計算所有樣本與這 ?? 個“簇中心”的距離北救,對于每一個樣本荐操,
將其劃分到與其距離最近的“簇中心”所在的簇中,對于新的簇計算各個簇的新的“簇中心”珍策。
根據(jù)以上描述托启,我們大致可以猜測到實現(xiàn)kmeans算法的主要三點:
(1)簇個數(shù) ?? 的選擇
(2)各個樣本點到“簇中心”的距離
(3)根據(jù)新劃分的簇,更新“簇中心”
'''

def loadDataSet(filename):
    '''
    讀取數(shù)據(jù)集

    Args:
        filename: 文件名
    Returns:
        dataMat: 數(shù)據(jù)樣本矩陣
    '''
    dataMat = []
    with open(filename, 'rb') as f:
        for line in f:
            # 讀取的字節(jié)流需要先解碼成utf-8再處理
            eles = list(map(float, line.decode('utf-8').strip().split('\t')))
            dataMat.append(eles)
    return dataMat

def distEclud(vecA, vecB):
    '''
    計算兩向量的歐氏距離

    Args:
        vecA: 向量A
        vecB: 向量B
    Returns:
        歐式距離
    '''
    return np.sqrt(np.sum(np.power(vecA-vecB,2)))

def randCent(dataSet, k):
    '''
    隨機生成k個聚類中心

    Args:
        dataSet: 數(shù)據(jù)集
        k: 簇數(shù)目
    Returns:
        centroids: 聚類中心矩陣
    '''
    m, _ = dataSet.shape
    # 隨機從數(shù)據(jù)集中選幾個作為初始聚類中心
    centroids = dataSet.take(np.random.choice(80,k), axis=0)
    return centroids


def kMeans(dataSet, k, maxIter=5):
    '''
    K-Means

    Args:
        dataSet: 數(shù)據(jù)集
        k: 聚類數(shù)
    Returns:
        centroids: 聚類中心
        clusterAssment: 點分配結(jié)果
    '''
    # 隨機初始化聚類中心
    centroids = randCent(dataSet, k)
    init_centroids = centroids.copy()

    m, n = dataSet.shape

    # 點分配結(jié)果:第一列指明樣本所在的簇攘宙,第二列指明該樣本到聚類中心的距離
    clusterAssment = np.mat(np.zeros((m, 2)))

    # 標(biāo)識聚類中心是否仍在變化
    clusterChanged = True

    # 直至聚類中心不再變化
    iterCount = 0
    while clusterChanged and iterCount < maxIter:
        iterCount += 1
        clusterChanged = False
        # 分配樣本到簇
        for i in range(m):
            # 計算第i個樣本到各個聚類中心的距離
            minIndex = 0
            minDist = np.inf
            for j in range(k):
                dist = distEclud(dataSet[i, :], centroids[j, :])
                if dist < minDist:
                    minIndex = j
                    minDist = dist
            # 任何一個樣本的類簇分配發(fā)生變化則認(rèn)為變化
            if clusterAssment[i, 0] != minIndex:
                clusterChanged = True
            clusterAssment[i, :] = minIndex, minDist ** 2

        # 刷新聚類中心:移動聚類中心點到所有簇的均值位置
        for cent in range(k):
            # 通過數(shù)組過濾得到簇中的點
            # matrix.A 是將matrix-->array
            ptsInCluster = dataSet[np.nonzero(clusterAssment[:, 0].A == cent)[0]]
            if ptsInCluster.shape[0] > 0:
                # 計算均值并移動
                centroids[cent, :] = np.mean(ptsInCluster, axis=0)
    return centroids, clusterAssment, init_centroids

if __name__ == '__main__':
    dataMat = np.mat(loadDataSet('./testSet.txt'))
    m, n = np.shape(dataMat)
    set_k = 4
    centroids, clusterAssment, init_centroids = kMeans(dataMat, set_k)

    clusterCount = np.shape(centroids)[0]

    # 我們這里只設(shè)定了最多四個簇的樣式屯耸,所以前面如果set_k設(shè)置超過了4,后面就會出現(xiàn)index error
    patterns = ['o', 'D', '^', 's']
    colors = ['b', 'g', 'y', 'black']

    fig = plt.figure()
    title = 'kmeans with k={}'.format(set_k)
    ax = fig.add_subplot(111, title=title)
    for k in range(clusterCount):
        # 繪制聚類中心
        ax.scatter(centroids[k, 0], centroids[k, 1], color='r', marker='+', linewidth=20)
        # 繪制初始聚類中心
        ax.scatter(init_centroids[k, 0], init_centroids[k, 1], color='purple', marker='*', linewidth=10)
        for i in range(m):
            # 繪制屬于該聚類中心的樣本
            ptsInCluster = dataMat[np.nonzero(clusterAssment[:, 0].A == k)[0]]
            ax.scatter(ptsInCluster[:, 0].flatten().A[0], ptsInCluster[:, 1].flatten().A[0], color=colors[k],
                       marker=patterns[k])

    plt.show()

效果圖.png
2蹭劈、sklearn中K-Means算法實現(xiàn)代碼如下:
from sklearn.cluster import KMeans
import numpy as np
import matplotlib.pyplot as plt

def loadDataSet(filename):
    '''
    讀取數(shù)據(jù)集

    Args:
        filename: 文件名
    Returns:
        dataMat: 數(shù)據(jù)樣本矩陣
    '''
    dataMat = []
    with open(filename, 'rb') as f:
        for line in f:
            # 讀取的字節(jié)流需要先解碼成utf-8再處理
            eles = list(map(float, line.decode('utf-8').strip().split('\t')))
            dataMat.append(eles)
    return dataMat

dataMat = np.mat(loadDataSet('./testSet.txt'))
kmeans = KMeans(init='random', n_clusters=4, random_state=0).fit(dataMat)
centroids = kmeans.cluster_centers_
clusterAssment = kmeans.labels_

m, n = np.shape(dataMat)
set_k = 4
clusterCount = np.shape(centroids)[0]

# 我們這里只設(shè)定了最多四個簇的樣式疗绣,所以前面如果set_k設(shè)置超過了4,后面就會出現(xiàn)index error
patterns = ['o', 'D', '^', 's']
colors = ['b', 'g', 'y', 'black']


fig = plt.figure()
title = 'kmeans with k={}'.format(set_k)
ax = fig.add_subplot(111, title=title)
for k in range(clusterCount):
    # 繪制聚類中心
    ax.scatter(centroids[k, 0], centroids[k, 1], color='r', marker='+', linewidth=20)

    for i in range(m):
        # 繪制屬于該聚類中心的樣本
        ptsInCluster = dataMat[np.nonzero(clusterAssment == k)[0]]
        ax.scatter(ptsInCluster[:, 0].flatten().A[0], ptsInCluster[:, 1].flatten().A[0], color=colors[k],
                   marker=patterns[k])

plt.show()

分類效果圖.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末铺韧,一起剝皮案震驚了整個濱河市多矮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哈打,老刑警劉巖塔逃,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異前酿,居然都是意外死亡患雏,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門罢维,熙熙樓的掌柜王于貴愁眉苦臉地迎上來淹仑,“玉大人丙挽,你說我怎么就攤上這事≡冉瑁” “怎么了颜阐?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吓肋。 經(jīng)常有香客問我凳怨,道長,這世上最難降的妖魔是什么是鬼? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任肤舞,我火速辦了婚禮,結(jié)果婚禮上均蜜,老公的妹妹穿的比我還像新娘李剖。我一直安慰自己,他們只是感情好囤耳,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布篙顺。 她就那樣靜靜地躺著,像睡著了一般充择。 火紅的嫁衣襯著肌膚如雪德玫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天椎麦,我揣著相機與錄音宰僧,去河邊找鬼。 笑死铃剔,一個胖子當(dāng)著我的面吹牛撒桨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播键兜,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼凤类,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了普气?” 一聲冷哼從身側(cè)響起谜疤,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎现诀,沒想到半個月后夷磕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡仔沿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年坐桩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片封锉。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡绵跷,死狀恐怖膘螟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碾局,我是刑警寧澤荆残,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站净当,受9級特大地震影響内斯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜像啼,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一俘闯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧忽冻,春花似錦备徐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秀菱。三九已至振诬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間衍菱,已是汗流浹背赶么。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脊串,地道東北人辫呻。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像琼锋,于是被迫代替她去往敵國和親放闺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

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