日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

漫谈 Clustering (1): k-means

發(fā)布時間:2024/1/18 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 漫谈 Clustering (1): k-means 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

http://blog.pluskid.org/?p=17

該博主一些列的文章不錯,再次記錄

本文是“漫談 Clustering 系列”中的第 1 篇,參見本系列的其他文章。

好久沒有寫 blog 了,一來是 blog 下線一段時間,而租 DreamHost 的事情又一直沒弄好;二來是沒有太多時間,天天都跑去實驗室?,F(xiàn)在主要折騰 Machine Learning 相關(guān)的東西,因為很多東西都不懂,所以平時也找一些資料來看。按照我以前的更新速度的話,這么長時間不寫 blog 肯定是要被悶壞的,所以我也覺得還是不定期地整理一下自己了解到的東西,放在 blog 上,一來梳理總是有助于加深理解的,二來也算共享一下知識了。那么,還是從 clustering 說起吧。

Clustering?中文翻譯作“聚類”,簡單地說就是把相似的東西分到一組,同 Classification (分類)不同,對于一個 classifier ,通常需要你告訴它“這個東西被分為某某類”這樣一些例子,理想情況下,一個 classifier 會從它得到的訓(xùn)練集中進(jìn)行“學(xué)習(xí)”,從而具備對未知數(shù)據(jù)進(jìn)行分類的能力,這種提供訓(xùn)練數(shù)據(jù)的過程通常叫做?supervised learning?(監(jiān)督學(xué)習(xí)),而在聚類的時候,我們并不關(guān)心某一類是什么,我們需要實現(xiàn)的目標(biāo)只是把相似的東西聚到一起,因此,一個聚類算法通常只需要知道如何計算相似 度就可以開始工作了,因此 clustering 通常并不需要使用訓(xùn)練數(shù)據(jù)進(jìn)行學(xué)習(xí),這在 Machine Learning 中被稱作?unsupervised learning?(無監(jiān)督學(xué)習(xí))。

舉一個簡單的例子:現(xiàn)在有一群小學(xué)生,你要把他們分成幾組,讓組內(nèi)的成員之間盡量相似一些,而組之間則差別大一些。最后分出怎樣的結(jié)果,就取決于你對于“相似”的定義了,比如,你決定男生和男生是相似的,女生和女生也是相似的,而男生和女生之間則差別很大”,這樣,你實際上是用一個可能取兩個值“男”和“女”的離散變量來代表了原來的一個小學(xué)生,我們通常把這樣的變量叫做“特征”。實際上,在這種情況下,所有的小學(xué)生都被映射到了兩個點的其中一個上,已經(jīng)很自然地形成了兩個組,不需要專門再做聚類了。另一種可能是使用“身高”這個特征。我在讀小學(xué)候,每周五在操場開會訓(xùn)話的時候會按照大家住的地方的地域和距離遠(yuǎn)近來列隊,這樣結(jié)束之后就可以結(jié)隊回家了。除了讓事物映射到一個單獨的特征之外,一種常見的做法是同時提取 N 種特征,將它們放在一起組成一個 N 維向量,從而得到一個從原始數(shù)據(jù)集合到 N 維向量空間的映射——你總是需要顯式地或者隱式地完成這樣一個過程,因為許多機器學(xué)習(xí)的算法都需要工作在一個向量空間中。

那么讓我們再回到 clustering 的問題上,暫且拋開原始數(shù)據(jù)是什么形式,假設(shè)我們已經(jīng)將其映射到了一個歐幾里德空間上,為了方便展示,就使用二維空間吧,如下圖所示:

從數(shù)據(jù)點的大致形狀可以看出它們大致聚為三個 cluster ,其中兩個緊湊一些,剩下那個松散一些。我們的目的是為這些數(shù)據(jù)分組,以便能區(qū)分出屬于不同的簇的數(shù)據(jù),如果按照分組給它們標(biāo)上不同的顏色,就是這個樣子:

那么計算機要如何來完成這個任務(wù)呢?當(dāng)然,計算機還沒有高級到能夠“通過形狀大致看出來”,不過,對于這樣的 N 維歐氏空間中的點進(jìn)行聚類,有一個非常簡單的經(jīng)典算法,也就是本文標(biāo)題中提到的 k-means 。在介紹 k-means 的具體步驟之前,讓我們先來看看它對于需要進(jìn)行聚類的數(shù)據(jù)的一個基本假設(shè)吧:對于每一個 cluster ,我們可以選出一個中心點 (center) ,使得該 cluster 中的所有的點到該中心點的距離小于到其他 cluster 的中心的距離。雖然實際情況中得到的數(shù)據(jù)并不能保證總是滿足這樣的約束,但這通常已經(jīng)是我們所能達(dá)到的最好的結(jié)果,而那些誤差通常是固有存在的或者問題本身的不可分性造成的。例如下圖所示的兩個高斯分布,從兩個分布中隨機地抽取一些數(shù)據(jù)點出來,混雜到一起,現(xiàn)在要讓你將這些混雜在一起的數(shù)據(jù)點按照它們被生成的那個分布分開來:

由于這兩個分布本身有很大一部分重疊在一起了,例如,對于數(shù)據(jù)點 2.5 來說,它由兩個分布產(chǎn)生的概率都是相等的,你所做的只能是一個猜測;稍微好一點的情況是 2 ,通常我們會將它歸類為左邊的那個分布,因為概率大一些,然而此時它由右邊的分布生成的概率仍然是比較大的,我們?nèi)匀挥胁恍〉膸茁蕰洛e。而整個陰影部分是我們所能達(dá)到的最小的猜錯的概率,這來自于問題本身的不可分性,無法避免。因此,我們將 k-means 所依賴的這個假設(shè)看作是合理的。

基于這樣一個假設(shè),我們再來導(dǎo)出 k-means 所要優(yōu)化的目標(biāo)函數(shù):設(shè)我們一共有 N 個數(shù)據(jù)點需要分為 K 個 cluster ,k-means 要做的就是最小化

這個函數(shù),其中??在數(shù)據(jù)點 n 被歸類到 cluster k 的時候為 1 ,否則為 0 。直接尋找??和??來最小化??并不容易,不過我們可以采取迭代的辦法:先固定??,選擇最優(yōu)的??,很容易看出,只要將數(shù)據(jù)點歸類到離他最近的那個中心就能保證??最小。下一步則固定?,再求最優(yōu)的?。將??對??求導(dǎo)并令導(dǎo)數(shù)等于零,很容易得到??最小的時候??應(yīng)該滿足:

亦即??的值應(yīng)當(dāng)是所有 cluster k 中的數(shù)據(jù)點的平均值。由于每一次迭代都是取到??的最小值,因此??只會不斷地減小(或者不變),而不會增加,這保證了 k-means 最終會到達(dá)一個極小值。雖然 k-means 并不能保證總是能得到全局最優(yōu)解,但是對于這樣的問題,像 k-means 這種復(fù)雜度的算法,這樣的結(jié)果已經(jīng)是很不錯的了。

下面我們來總結(jié)一下 k-means 算法的具體步驟:

  • 選定 K 個中心??的初值。這個過程通常是針對具體的問題有一些啟發(fā)式的選取方法,或者大多數(shù)情況下采用隨機選取的辦法。因為前面說過 k-means 并不能保證全局最優(yōu),而是否能收斂到全局最優(yōu)解其實和初值的選取有很大的關(guān)系,所以有時候我們會多次選取初值跑 k-means ,并取其中最好的一次結(jié)果。
  • 將每個數(shù)據(jù)點歸類到離它最近的那個中心點所代表的 cluster 中。
  • 用公式??計算出每個 cluster 的新的中心點。
  • 重復(fù)第二步,一直到迭代了最大的步數(shù)或者前后的??的值相差小于一個閾值為止。
  • 按照這個步驟寫一個 k-means 實現(xiàn)其實相當(dāng)容易了,在?SciPy?或者 Matlab 中都已經(jīng)包含了內(nèi)置的 k-means 實現(xiàn),不過為了看看 k-means 每次迭代的具體效果,我們不妨自己來實現(xiàn)一下,代碼如下(需要安裝?SciPy?和?matplotlib) :

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 #!/usr/bin/pythonfrom __future__ import with_statement import cPickle as pickle from matplotlib import pyplot from numpy import zeros, array, tile from scipy.linalg import norm import numpy.matlib as ml import randomdef kmeans(X, k, observer=None, threshold=1e-15, maxiter=300):N = len(X)labels = zeros(N, dtype=int)centers = array(random.sample(X, k))iter = 0def calc_J():sum = 0for i in xrange(N):sum += norm(X[i]-centers[labels[i]])return sumdef distmat(X, Y):n = len(X)m = len(Y)xx = ml.sum(X*X, axis=1)yy = ml.sum(Y*Y, axis=1)xy = ml.dot(X, Y.T)return tile(xx, (m, 1)).T+tile(yy, (n, 1)) - 2*xyJprev = calc_J()while True:# notify the observerif observer is not None:observer(iter, labels, centers)# calculate distance from x to each center# distance_matrix is only available in scipy newer than 0.7# dist = distance_matrix(X, centers)dist = distmat(X, centers)# assign x to nearst centerlabels = dist.argmin(axis=1)# re-calculate each centerfor j in range(k):idx_j = (labels == j).nonzero()centers[j] = X[idx_j].mean(axis=0)J = calc_J()iter += 1if Jprev-J < threshold:breakJprev = Jif iter >= maxiter:break# final notificationif observer is not None:observer(iter, labels, centers)if __name__ == '__main__':# load previously generated pointswith open('cluster.pkl') as inf:samples = pickle.load(inf)N = 0for smp in samples:N += len(smp[0])X = zeros((N, 2))idxfrm = 0for i in range(len(samples)):idxto = idxfrm + len(samples[i][0])X[idxfrm:idxto, 0] = samples[i][0]X[idxfrm:idxto, 1] = samples[i][1]idxfrm = idxtodef observer(iter, labels, centers):print "iter %d." % itercolors = array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])pyplot.plot(hold=False) # clear previous plotpyplot.hold(True)# draw pointsdata_colors=[colors[lbl] for lbl in labels]pyplot.scatter(X[:, 0], X[:, 1], c=data_colors, alpha=0.5)# draw centerspyplot.scatter(centers[:, 0], centers[:, 1], s=200, c=colors)pyplot.savefig('kmeans/iter_%02d.png' % iter, format='png')kmeans(X, 3, observer=observer)

    代碼有些長,不過因為用 Python 來做這個事情確實不如 Matlab 方便,實際的 k-means 的代碼只是 41 到 47 行。首先 3 個中心點被隨機初始化,所有的數(shù)據(jù)點都還沒有進(jìn)行聚類,默認(rèn)全部都標(biāo)記為紅色,如下圖所示:

    然后進(jìn)入第一次迭代:按照初始的中心點位置為每個數(shù)據(jù)點著上顏色,這是代碼中第 41 到 43 行所做的工作,然后 45 到 47 行重新計算 3 個中心點,結(jié)果如下圖所示:

    可以看到,由于初始的中心點是隨機選的,這樣得出來的結(jié)果并不是很好,接下來是下一次迭代的結(jié)果:

    可以看到大致形狀已經(jīng)出來了。再經(jīng)過兩次迭代之后,基本上就收斂了,最終結(jié)果如下:

    不過正如前面所說的那樣 k-means 也并不是萬能的,雖然許多時候都能收斂到一個比較好的結(jié)果,但是也有運氣不好的時候會收斂到一個讓人不滿意的局部最優(yōu)解,例如選用下面這幾個初始中心點:

    最終會收斂到這樣的結(jié)果:

    不得不承認(rèn)這并不是很好的結(jié)果。不過其實大多數(shù)情況下 k-means 給出的結(jié)果都還是很令人滿意的,算是一種簡單高效應(yīng)用廣泛的 clustering 方法。

    Update 2010.04.25: 很多人都問我要 cluster.pkl ,我干脆把它上傳上來吧,其實是很容易自己生成的,點擊這里下載。


    總結(jié)

    以上是生活随笔為你收集整理的漫谈 Clustering (1): k-means的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。