Python K-Means簡單實(shí)踐

機(jī)器學(xué)習(xí)算法與Python實(shí)踐這個(gè)系列主要是參考《機(jī)器學(xué)習(xí)實(shí)戰(zhàn)》這本書禁荒。因?yàn)樽约合雽W(xué)習(xí)Python猬膨,然后也想對(duì)一些機(jī)器學(xué)習(xí)算法加深下了解,所以就想通過Python來實(shí)現(xiàn)幾個(gè)比較常用的機(jī)器學(xué)習(xí)算法呛伴。恰好遇見這本同樣定位的書籍勃痴,所以就參考這本書的過程來學(xué)習(xí)了。

? ? ? ?機(jī)器學(xué)習(xí)中有兩類的大問題热康,一個(gè)是分類沛申,一個(gè)是聚類。分類是根據(jù)一些給定的已知類別標(biāo)號(hào)的樣本姐军,訓(xùn)練某種學(xué)習(xí)機(jī)器铁材,使它能夠?qū)ξ粗悇e的樣本進(jìn)行分類。這屬于supervised learning(監(jiān)督學(xué)習(xí))奕锌。而聚類指事先并不知道任何樣本的類別標(biāo)號(hào)著觉,希望通過某種算法來把一組未知類別的樣本劃分成若干類別,這在機(jī)器學(xué)習(xí)中被稱作 unsupervised learning (無監(jiān)督學(xué)習(xí))惊暴。在本文中饼丘,我們關(guān)注其中一個(gè)比較簡單的聚類算法:k-means算法。


一辽话、k-means算法

? ? ? ?通常葬毫,人們根據(jù)樣本間的某種距離或者相似性來定義聚類镇辉,即把相似的(或距離近的)樣本聚為同一類,而把不相似的(或距離遠(yuǎn)的)樣本歸在其他類贴捡。

? ? ? ?我們以一個(gè)二維的例子來說明下聚類的目的忽肛。如下圖左所示,假設(shè)我們的n個(gè)樣本點(diǎn)分布在圖中所示的二維空間烂斋。從數(shù)據(jù)點(diǎn)的大致形狀可以看出它們大致聚為三個(gè)cluster屹逛,其中兩個(gè)緊湊一些,剩下那個(gè)松散一些汛骂。我們的目的是為這些數(shù)據(jù)分組罕模,以便能區(qū)分出屬于不同的簇的數(shù)據(jù),如果按照分組給它們標(biāo)上不同的顏色帘瞭,就是像下圖右邊的圖那樣:

? ? ? ?如果人可以看到像上圖那樣的數(shù)據(jù)分布淑掌,就可以輕松進(jìn)行聚類。但我們?cè)趺唇虝?huì)計(jì)算機(jī)按照我們的思維去做同樣的事情呢蝶念?這里就介紹個(gè)集簡單和經(jīng)典于一身的k-means算法抛腕。

? ? ? ?k-means算法是一種很常見的聚類算法,它的基本思想是:通過迭代尋找k個(gè)聚類的一種劃分方案媒殉,使得用這k個(gè)聚類的均值來代表相應(yīng)各類樣本時(shí)所得的總體誤差最小担敌。

? ? ? ?k-means算法的基礎(chǔ)是最小誤差平方和準(zhǔn)則。其代價(jià)函數(shù)是:

式中廷蓉,μc(i)表示第i個(gè)聚類的均值全封。我們希望代價(jià)函數(shù)最小,直觀的來說桃犬,各類內(nèi)的樣本越相似刹悴,其與該類均值間的誤差平方越小,對(duì)所有類所得到的誤差平方求和攒暇,即可驗(yàn)證分為k類時(shí)颂跨,各聚類是否是最優(yōu)的。

? ? ? 上式的代價(jià)函數(shù)無法用解析的方法最小化扯饶,只能有迭代的方法恒削。k-means算法是將樣本聚類成 k個(gè)簇(cluster),其中k是用戶給定的尾序,其求解過程非常直觀簡單钓丰,具體算法描述如下:

1、隨機(jī)選取 k個(gè)聚類質(zhì)心點(diǎn)

2每币、重復(fù)下面過程直到收斂? {

? ? ? 對(duì)于每一個(gè)樣例 i携丁,計(jì)算其應(yīng)該屬于的類:

? ? ? 對(duì)于每一個(gè)類 j,重新計(jì)算該類的質(zhì)心:

}

? ? ? 下圖展示了對(duì)n個(gè)樣本點(diǎn)進(jìn)行K-means聚類的效果,這里k取2梦鉴。

其偽代碼如下:

********************************************************************

創(chuàng)建k個(gè)點(diǎn)作為初始的質(zhì)心點(diǎn)(隨機(jī)選擇)

當(dāng)任意一個(gè)點(diǎn)的簇分配結(jié)果發(fā)生改變時(shí)

? ? ? ?對(duì)數(shù)據(jù)集中的每一個(gè)數(shù)據(jù)點(diǎn)

? ? ? ? ? ? ? 對(duì)每一個(gè)質(zhì)心

? ? ? ? ? ? ? ? ? ? ?計(jì)算質(zhì)心與數(shù)據(jù)點(diǎn)的距離

? ? ? ? ? ? ? 將數(shù)據(jù)點(diǎn)分配到距離最近的簇

? ? ? ?對(duì)每一個(gè)簇李茫,計(jì)算簇中所有點(diǎn)的均值,并將均值作為質(zhì)心

********************************************************************



二肥橙、Python實(shí)現(xiàn)

我使用的Python是2.7.5版本的魄宏。附加的庫有Numpy和Matplotlib。具體的安裝和配置見前面的博文存筏。在代碼中已經(jīng)有了比較詳細(xì)的注釋了宠互。不知道有沒有錯(cuò)誤的地方,如果有椭坚,還望大家指正(每次的運(yùn)行結(jié)果都有可能不同)予跌。里面我寫了個(gè)可視化結(jié)果的函數(shù),但只能在二維的數(shù)據(jù)上面使用善茎。直接貼代碼:

kmeans.py?



??

from?numpy?import?*??

import?time??

import?matplotlib.pyplot?as?plt??



#?calculate?Euclidean?distance??

def?euclDistance(vector1,?vector2):??

return?sqrt(sum(power(vector2?-?vector1,?2)))??


#?init?centroids?with?random?samples??

def?initCentroids(dataSet,?k):??

????numSamples,?dim?=?dataSet.shape??

????centroids?=?zeros((k,?dim))??

for?i?in?range(k):??

index?=?int(random.uniform(0,?numSamples))??

????????centroids[i,?:]?=?dataSet[index,?:]??

return?centroids??


#?k-means?cluster??

def?kmeans(dataSet,?k):??

numSamples?=?dataSet.shape[0]??

#?first?column?stores?which?cluster?this?sample?belongs?to,??

#?second?column?stores?the?error?between?this?sample?and?its?centroid??

clusterAssment?=?mat(zeros((numSamples,2)))??

clusterChanged?=True??


##?step?1:?init?centroids??

????centroids?=?initCentroids(dataSet,?k)??


while?clusterChanged:??

clusterChanged?=False??

##?for?each?sample??

for?i?in?xrange(numSamples):??

minDist??=100000.0??

minIndex?=0??

##?for?each?centroid??

##?step?2:?find?the?centroid?who?is?closest??

for?j?in?range(k):??

????????????????distance?=?euclDistance(centroids[j,?:],?dataSet[i,?:])??

if?distance?<?minDist:??

????????????????????minDist??=?distance??

????????????????????minIndex?=?j??


##?step?3:?update?its?cluster??

if?clusterAssment[i,?0]?!=?minIndex:??

clusterChanged?=True??

clusterAssment[i,?:]?=?minIndex,?minDist**2??


##?step?4:?update?centroids??

for?j?in?range(k):??

pointsInCluster?=?dataSet[nonzero(clusterAssment[:,0].A?==?j)[0]]??

centroids[j,?:]?=?mean(pointsInCluster,?axis?=0)??


print?'Congratulations,?cluster?complete!'??

return?centroids,?clusterAssment??


#?show?your?cluster?only?available?with?2-D?data??

def?showCluster(dataSet,?k,?centroids,?clusterAssment):??

????numSamples,?dim?=?dataSet.shape??

if?dim?!=?2:??

print?"Sorry!?I?can?not?draw?because?the?dimension?of?your?data?is?not?2!"??

return?1??


mark?=?['or',?'ob',?'og',?'ok',?'^r',?'+r',?'sr',?'dr',?'

if?k?>?len(mark):??

print?"Sorry!?Your?k?is?too?large!?please?contact?Zouxy"??

return?1??


#?draw?all?samples??

for?i?in?xrange(numSamples):??

markIndex?=?int(clusterAssment[i,0])??

plt.plot(dataSet[i,0],?dataSet[i,?1],?mark[markIndex])??


mark?=?['Dr',?'Db',?'Dg',?'Dk',?'^b',?'+b',?'sb',?'db',?'

#?draw?the?centroids??

for?i?in?range(k):??

plt.plot(centroids[i,0],?centroids[i,?1],?mark[i],?markersize?=?12)??


????plt.show()?



三券册、測(cè)試結(jié)果

? ? ? 測(cè)試數(shù)據(jù)是二維的,共80個(gè)樣本垂涯。有4個(gè)類烁焙。如下:

testSet.txt

1.658985????4.285136??

-3.453687???3.424321??

4.838138????-1.151539??

-5.379713???-3.362104??

0.972564????2.924086??

-3.567919???1.531611??

0.450614????-3.302219??

-3.487105???-1.724432??

2.668759????1.594842??

-3.156485???3.191137??

3.165506????-3.999838??

-2.786837???-3.099354??

4.208187????2.984927??

-2.123337???2.943366??

0.704199????-0.479481??

-0.392370???-3.963704??

2.831667????1.574018??

-0.790153???3.343144??

2.943496????-3.357075??

-3.195883???-2.283926??

2.336445????2.875106??

-1.786345???2.554248??

2.190101????-1.906020??

-3.403367???-2.778288??

1.778124????3.880832??

-1.688346???2.230267??

2.592976????-2.054368??

-4.007257???-3.207066??

2.257734????3.387564??

-2.679011???0.785119??

0.939512????-4.023563??

-3.674424???-2.261084??

2.046259????2.735279??

-3.189470???1.780269??

4.372646????-0.822248??

-2.579316???-3.497576??

1.889034????5.190400??

-0.798747???2.185588??

2.836520????-2.658556??

-3.837877???-3.253815??

2.096701????3.886007??

-2.709034???2.923887??

3.367037????-3.184789??

-2.121479???-4.232586??

2.329546????3.179764??

-3.284816???3.273099??

3.091414????-3.815232??

-3.762093???-2.432191??

3.542056????2.778832??

-1.736822???4.241041??

2.127073????-2.983680??

-4.323818???-3.938116??

3.792121????5.135768??

-4.786473???3.358547??

2.624081????-3.260715??

-4.009299???-2.978115??

2.493525????1.963710??

-2.513661???2.642162??

1.864375????-3.176309??

-3.171184???-3.572452??

2.894220????2.489128??

-2.562539???2.884438??

3.491078????-3.947487??

-2.565729???-2.012114??

3.332948????3.983102??

-1.616805???3.573188??

2.280615????-2.559444??

-2.651229???-3.103198??

2.321395????3.154987??

-1.685703???2.939697??

3.031012????-3.620252??

-4.599622???-2.185829??

4.196223????1.126677??

-2.133863???3.093686??

4.668892????-2.562705??

-2.793241???-2.149706??

2.884105????3.043438??

-2.967647???2.848696??

4.479332????-1.764772??

-4.905566???-2.911070?


測(cè)試代碼:

test_kmeans.py

from?numpy?import?*??

import?time??

import?matplotlib.pyplot?as?plt??


##?step?1:?load?data??

print?"step?1:?load?data..."??

dataSet?=?[]??

fileIn?=?open('E:/Python/Machine?Learning?in?Action/testSet.txt')??

for?line?in?fileIn.readlines():??

lineArr?=?line.strip().split('\t')??

dataSet.append([float(lineArr[0]),?float(lineArr[1])])??


##?step?2:?clustering...??

print?"step?2:?clustering..."??

dataSet?=?mat(dataSet)??

k?=4??

centroids,?clusterAssment?=?kmeans(dataSet,?k)??


##?step?3:?show?the?result??

print?"step?3:?show?the?result..."??

showCluster(dataSet,?k,?centroids,?clusterAssment)??


運(yùn)行的前后結(jié)果是:

不同的類用不同的顏色來表示,其中的大菱形是對(duì)應(yīng)類的均值質(zhì)心點(diǎn)集币。


四考阱、算法分析

? ? ? ?k-means算法比較簡單翠忠,但也有幾個(gè)比較大的缺點(diǎn):

(1)k值的選擇是用戶指定的鞠苟,不同的k得到的結(jié)果會(huì)有挺大的不同,如下圖所示秽之,左邊是k=3的結(jié)果当娱,這個(gè)就太稀疏了,藍(lán)色的那個(gè)簇其實(shí)是可以再劃分成兩個(gè)簇的考榨。而右圖是k=5的結(jié)果跨细,可以看到紅色菱形和藍(lán)色菱形這兩個(gè)簇應(yīng)該是可以合并成一個(gè)簇的:

(2)對(duì)k個(gè)初始質(zhì)心的選擇比較敏感,容易陷入局部最小值河质。例如冀惭,我們上面的算法運(yùn)行的時(shí)候,有可能會(huì)得到不同的結(jié)果掀鹅,如下面這兩種情況散休。K-means也是收斂了,只是收斂到了局部最小值:

(3)存在局限性乐尊,如下面這種非球狀的數(shù)據(jù)分布就搞不定了:

(4)數(shù)據(jù)庫比較大的時(shí)候戚丸,收斂會(huì)比較慢。

? ? ? ?k-means老早就出現(xiàn)在江湖了扔嵌。所以以上的這些不足也被世人的目光敏銳的捕捉到限府,并融入世人的智慧進(jìn)行了某種程度上的改良夺颤。例如問題(1)對(duì)k的選擇可以先用一些算法分析數(shù)據(jù)的分布,如重心和密度等胁勺,然后選擇合適的k世澜。而對(duì)問題(2),有人提出了另一個(gè)成為二分k均值(bisecting k-means)算法姻几,它對(duì)初始的k個(gè)質(zhì)心的選擇就不太敏感宜狐,這個(gè)算法我們下一個(gè)博文再分析和實(shí)現(xiàn)。


五蛇捌、參考文獻(xiàn)

[1]?K-means聚類算法

[2]?漫談 Clustering (1): k-means


原文參考:http://blog.csdn.net/zouxy09/article/details/17589329

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末抚恒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子络拌,更是在濱河造成了極大的恐慌俭驮,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件春贸,死亡現(xiàn)場離奇詭異混萝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)萍恕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門逸嘀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人允粤,你說我怎么就攤上這事崭倘。” “怎么了类垫?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵慈省,是天一觀的道長仔掸。 經(jīng)常有香客問我责鳍,道長挡鞍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任售躁,我火速辦了婚禮坞淮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘陪捷。我一直安慰自己回窘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布揩局。 她就那樣靜靜地躺著毫玖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上付枫,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天烹玉,我揣著相機(jī)與錄音,去河邊找鬼阐滩。 笑死二打,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掂榔。 我是一名探鬼主播继效,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼装获!你這毒婦竟也來了瑞信?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤穴豫,失蹤者是張志新(化名)和其女友劉穎凡简,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體精肃,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡秤涩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了司抱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筐眷。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖习柠,靈堂內(nèi)的尸體忽然破棺而出匀谣,到底是詐尸還是另有隱情,我是刑警寧澤津畸,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布振定,位于F島的核電站必怜,受9級(jí)特大地震影響肉拓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜梳庆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一暖途、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧膏执,春花似錦驻售、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春迟几,著一層夾襖步出監(jiān)牢的瞬間消请,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來泰國打工类腮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留臊泰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓蚜枢,卻偏偏與公主長得像缸逃,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厂抽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

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