集體智慧編程學習之聚類系統

來源:互聯網
上載者:User

有句話這麼說“物以類聚,人以群分”,說的很有道理,有些人就完全融入不了一些團隊,我覺得這裡面不只是氣場的問題,我也一直在苦苦思索這個問題,每個人有自己的生活習慣和思維習慣,相同生活習慣和思維習慣的人很容易聚在一起;反之則比較難了。

目標很明確,給你一堆電子書,怎麼把其中一些書歸為一類,其中另一些書歸為另一類······,我會先看書的厚度,太厚的書(超過800頁)我歸為和我沒什麼關係這一類(偶爾會有例外),下來我會按照我的愛好細分,專業類、經濟類、心理類、攝影類和其他類。如果書很多了,我一本一本的分類會很費時間和精力。

我有個朋友做資料採礦的,他給我說用貝葉斯分類,我研究了一下,貝葉斯的確是個好東東,但有個問題,需要提前建立一個模型,我有建立這個模型的時間還不如自己一本一本分類來著。有沒有不用先驗經驗就可以分類的辦法呢?我查了一下還真有:無監督學習,貝葉斯這種需要事前建立一個模型的演算法屬於監督學習。

聚類,根據什麼聚類呢?我的目的是根據書籍的內容來區分,書籍的內容怎麼描述呢?書籍無非是一些詞和片語(成語也算為片語吧?),根據詞和片語怎麼來區分書籍的分類呢?經驗是,不同分類書籍常用詞不同。什麼意思,比方說經濟類的書籍通常會出現“經濟”,“增長”,“蕭條”,“膨脹”,,,甚至“卡特爾”,“托拉斯”等等,攝影類的書籍通常會出現“光圈”,“快門”,“ISO”,“曝光”,“構圖”等等。能不能根據詞彙在書籍中出現的比例來判定這本書是那個分類的呢,好像是可以。於是有了下面的變數; 

books = {      'book1': {'word1': 2, 'word2': 3, 'word3': 3, 'word4': 12, 'word5': 13, 'word6': 12},      'book2': {'word1': 3, 'word2': 3, 'word3': 1, 'word4': 13, 'word5': 12, 'word6': 11},       'book3': {'word1': 1, 'word2': 10, 'word3': 3, 'word4': 5, 'word5': 11, 'word6': 13},      'book4': {'word1': 12, 'word2': 13, 'word3': 12, 'word4': 3, 'word5': 2, 'word6': 2},      'book5': {'word1': 13, 'word2': 12, 'word3': 11, 'word4': 1, 'word5': 3, 'word6': 3},       'book6': {'word1': 5, 'word2': 11, 'word3': 13, 'word4': 3, 'word5': 1, 'word6': 10}}  

變數的含義很明確,數字表示該book中出現該word的次數。

為了實現方便,我簡化該資料結構:

books = [      [2, 3, 3, 12, 13, 12],      [3, 3, 1, 13, 12, 11],       [1, 10, 3, 5, 11, 13],      [12, 13, 12, 3, 2, 2],      [13, 12, 11, 1, 3, 3],       [5, 11, 13, 3, 1, 10]]

下面來分類,一種叫分級分類的演算法,該演算法通過連續不斷的將最為相似的群組兩兩合并,

最終構造出一個群組的層級結構。相似性可以用上篇所說的皮爾遜相關度計算,注意的是最後一行,

皮爾遜公式計算出來的結果越相似值會越大,這裡我想讓越相似的值越小,

表示距離近,所以用1減了皮爾遜公式的傳回值;

def pearson(v1,v2):  sum1=sum(v1)  sum2=sum(v2)    sum1Sq=sum([pow(v,2) for v in v1])  sum2Sq=sum([pow(v,2) for v in v2])  pSum=sum([v1[i]*v2[i] for i in range(len(v1))])    num=pSum-(sum1*sum2/len(v1))  den=sqrt((sum1Sq-pow(sum1,2)/len(v1))*(sum2Sq-pow(sum2,2)/len(v1)))  if den==0: return 0  return 1.0-num/den

分級分類演算法先算一次所有book之間的相似性,把最相似的聚為一類,然後用他們的均值代表一個新值;

第二遍計算其他剩餘書籍和新值組成的新數組之間兩兩相似性,把最相似的聚為一類,然後用他們的他兩的均值代表一個新值;

。。。

直到最後就剩下一個元素,結束。

這裡面有個可以最佳化的地方,我們看第一遍計算了所有元素之間的相似性,在第二遍時還要再計算,

所以我們可以把中間結果值緩衝下來,來減少中間的計算。

我們先定義一個資料結構,代表聚類的一條資料:

class bicluster:  def __init__(self,vec,left=None,right=None,distance=0.0,id=None):    self.left=left    self.right=right    self.vec=vec    self.id=id    self.distance=distance

下面來看看分級分類演算法的實現:

def hcluster(rows,distance=pearson):  distances={}  currentclustid=-1  clust=[bicluster(rows[i],id=i) for i in range(len(rows))]  while len(clust)>1:    lowestpair=(0,1)    closest=distance(clust[0].vec,clust[1].vec)    for i in range(len(clust)):      for j in range(i+1,len(clust)):        if (clust[i].id,clust[j].id) not in distances:           distances[(clust[i].id,clust[j].id)]=distance(clust[i].vec,clust[j].vec)        d=distances[(clust[i].id,clust[j].id)]        if d<closest:          closest=d          lowestpair=(i,j)    mergevec=[    (clust[lowestpair[0]].vec[i]+clust[lowestpair[1]].vec[i])/2.0     for i in range(len(clust[0].vec))]    newcluster=bicluster(mergevec,left=clust[lowestpair[0]],                         right=clust[lowestpair[1]],                         distance=closest,id=currentclustid)    currentclustid-=1    del clust[lowestpair[1]]    del clust[lowestpair[0]]    clust.append(newcluster)    print len(clust)  return clust[0]

中間的del只是刪除了clust數組中的元素,也就是只刪除了指標,實際元素並沒有被刪除。

這個演算法好像沒有解決我得問題,最後都聚為一類的,並沒有我想要的聚為幾類。

並且這個演算法的計算量很驚人,因為我們必須計算每兩個配對項之間的關係,

並且在合并項之後,這些關係還得重新再計算。


還有一種K-均值聚類的演算法好像可以滿足我的要求:

K-均值聚類演算法首先會隨即確定K個中心位置,然後將各個資料項目分配給最接近的中心點。

分配完成後,聚類中心會移動到分配給該聚類的所有節點的平均位置處。然後整個分配過程重新開始。

這一過程會一直重複下去,直到分配過程不再產生變化為止。

下面代碼執行個體:

import randomdef kcluster(rows,distance=pearson,k=4):  ranges=[(min([row[i] for row in rows]),max([row[i] for row in rows]))   for i in range(len(rows[0]))]  clusters=[[random.random()*(ranges[i][1]-ranges[i][0])+ranges[i][0]   for i in range(len(rows[0]))] for j in range(k)]    lastmatches=None  for t in range(100):    print 'Iteration %d' % t    bestmatches=[[] for i in range(k)]        for j in range(len(rows)):      row=rows[j]      bestmatch=0      for i in range(k):        d=distance(clusters[i],row)        if d<distance(clusters[bestmatch],row): bestmatch=i      bestmatches[bestmatch].append(j)    if bestmatches==lastmatches: break    lastmatches=bestmatches        for i in range(k):      avgs=[0.0]*len(rows[0])      if len(bestmatches[i])>0:        for rowid in bestmatches[i]:          for m in range(len(rows[rowid])):            avgs[m]+=rows[rowid][m]        for j in range(len(avgs)):          avgs[j]/=len(bestmatches[i])        clusters[i]=avgs        return bestmatches

對代碼進行點解釋:

ranges變數儲存第一次隨機產生中心點的值範圍,也就是word出現頻率的上下限

clusters變數就是隨機產生的K個中心點

迴圈100次:

        定義bestmatches存放聚類到K個中心點的數組 

        對每一行:

                 計算每一行到K個中心點的距離,將改行放入最近中心點的數組bestmatches中

        如果本次計算結果和上次計算結果相同,說明聚類完成,退出

        重新計算聚類中心,每個聚類中心為聚到該類的行的平均值

來看看我機器上的結果,效果還算不錯吧

>>> clust = clusters.kcluster(books,clusters.pearson,2)Iteration 0Iteration 1>>> print clust[[3, 4, 5], [0, 1, 2]]


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.