笨方法學(xué)機(jī)器學(xué)習(xí)(一):聚類

聚類

  • 聚類就是對(duì)大量未知標(biāo)注的數(shù)據(jù)集,按數(shù)據(jù) 的內(nèi)在相似性將數(shù)據(jù)集劃分為多個(gè)類別坛掠,使 類別內(nèi)的數(shù)據(jù)相似度較大而類別間的數(shù)據(jù)相 似度較小
  • 無監(jiān)督

如何計(jì)算相似度/距離

  • 閔可夫斯基距離Minkowski/歐式距離 (針對(duì)坐標(biāo)點(diǎn)):
  • 杰卡德相似系數(shù)(Jaccard)(針對(duì)集合):
  • 余弦相似度(cosine similarity)(針對(duì)向量):
  • Pearson相似系數(shù)
  • 相對(duì)熵(K-L距離)(K-L距離一般不對(duì)稱):
  • Hellinger距離

余弦相似度與Pearson相關(guān)系數(shù)的區(qū)別:

  • n維向量x和y的夾角記做θ舷蒲,根據(jù)余弦定理友多,其余弦值為:


  • 這兩個(gè)向量的相關(guān)系數(shù)是:



    相關(guān)系數(shù)即將x域滥、y坐標(biāo)向量各自平移到原點(diǎn)后的夾角余弦

  • 這即解釋了為何文檔間求距離使用夾角余弦——因?yàn)檫@一物理
    量表征了文檔去均值化后的隨機(jī)向量間相關(guān)系數(shù)启绰。

聚類的基本思想:

給定一個(gè)有N個(gè)對(duì)象的數(shù)據(jù)集,構(gòu)造數(shù)據(jù)的k 個(gè)簇渊跋,k≤n着倾。滿足下列條件:

  • 每一個(gè)簇至少包含一個(gè)對(duì)象
  • 每一個(gè)對(duì)象屬于且僅屬于一個(gè)簇
  • 將滿足上述條件的k個(gè)簇稱作一個(gè)合理劃分
    基本思想:對(duì)于給定的類別數(shù)目k卡者,首先給 出初始劃分,通過迭代改變樣本和簇的隸屬 關(guān)系,使得每一次改進(jìn)之后的劃分方案都較 前一次好嗽桩。

K-means算法:

輸入:k, data[n];

  • (1) 選擇k個(gè)初始中心點(diǎn)凄敢,例如c[0]=data[0],…c[k-1]=data[k-1];
  • (2) 對(duì)于data[0]….data[n], 分別與c[0]…c[k-1]比較,假定與c[i]差值最少扑庞,就標(biāo)記為i;
  • (3) 對(duì)于所有標(biāo)記為i點(diǎn)拒逮,重新計(jì)算c[i]={ 所有標(biāo)記為i的data[j]之和}/標(biāo)記為i的個(gè)數(shù)滩援;
  • (4) 重復(fù)(2)(3),直到所有c[i]值的變化小于給定閾值。

K-means是對(duì)初值敏感的
簇近似為高斯分布的的時(shí)候,效果較好

迭代終止條件:

  • 迭代次數(shù)
  • 簇中心變化率
  • 最小平方差
import numpy as np




def kmeans(X, k, maxIt):
    '''
    :param X: 數(shù)據(jù)集,數(shù)據(jù)集的最后一列表示標(biāo)簽值(或者組號(hào))
    :param k: k個(gè)分類
    :param maxIt: 循環(huán)幾次
    :return:
    '''
    numPoints, numDim = X.shape

    dataSet = np.zeros((numPoints, numDim + 1))
    dataSet[:, :-1] = X

    # Initialize centroids randomly
    centroids = dataSet[np.random.randint(numPoints, size = k), :]
    centroids = dataSet[0:2, :]
    #Randomly assign labels to initial centorid
    centroids[:, -1] = range(1, k +1)

    # Initialize book keeping vars.
    iterations = 0
    oldCentroids = None

    # Run the main k-means algorithm
    while not shouldStop(oldCentroids, centroids, iterations, maxIt):
        print("iteration: \n", iterations)
        print ("dataSet: \n", dataSet)
        print ("centroids: \n", centroids)
        # Save old centroids for convergence test. Book keeping.
        oldCentroids = np.copy(centroids)
        iterations += 1

        # Assign labels to each datapoint based on centroids
        updateLabels(dataSet, centroids)

        # Assign centroids based on datapoint labels
        centroids = getCentroids(dataSet, k)

    # We can get the labels too by calling getLabels(dataSet, centroids)
    return dataSet

def shouldStop(oldCentroids,centroids,iterations,maxIt):
    if iterations > maxIt:
        return True
    return np.array_equal(oldCentroids,centroids)

def updateLabels(dataset,centroids):
    numPoints,numDim = dataset.shape
    #算每一行的點(diǎn)離哪個(gè)中心點(diǎn)最近
    for i in range(0,numPoints):
        dataset[i,-1] = getLabelFromClosestCentroid(dataset[i,:-1],centroids)

def getLabelFromClosestCentroid(dataRow,centroids):
    label = centroids[0,-1]
    #numpy.linalg.norm傳入任意兩個(gè)向量谨究,-為距離
    minDist = np.linalg.norm(dataRow-centroids[0,:-1])
    #找最小距離
    for i in range(1,centroids.shape[0]):
        dist = np.linalg.norm(dataRow-centroids[i,:-1])
        if dist < minDist:
            minDist = dist
            label = centroids[i,-1]
    print("minDist:"+str(minDist))
    return label
def getCentroids(dataSet,k):
    result = np.zeros((k,dataSet.shape[1]))
    for i in range(1,k+1):
        #所有求 標(biāo)簽值為i的值
        oneCluster = dataSet[dataSet[:,-1]==i,:-1]
        #axis =0 對(duì)行求平均值胶哲,axis=1 對(duì)列求平均值
        result[i-1,:-1]=np.mean(oneCluster,axis=0)
        #最后賦值標(biāo)簽
        result[i-1,-1]=i
    return result

x1 = np.array([1, 1])
x2 = np.array([2, 1])
x3 = np.array([4, 3])
x4 = np.array([5, 4])
testX = np.vstack((x1, x2, x3, x4))

result = kmeans(testX,2,10)
print("final result:\n"+str(result))

輪廓系數(shù)(Silhouette)

Silhouette系數(shù)是對(duì)聚類結(jié)果有效性的解釋跟驗(yàn)證

計(jì)算樣本i到同簇其他樣本的平均距離為ai.ai越小,說明樣本i越應(yīng)該被聚類到該簇.稱ai為樣本i的簇內(nèi)不相似度

計(jì)算樣本i到其他某簇C1的所有樣本的平均距離bil,稱為樣本i到簇c1的不相似度.bi越大,說明樣本i越不屬于其他簇

輪廓系數(shù)si:
$$S(i)=b(i)-a(i)/max{a(i),b(i)}$$

si接近1,說明樣本i聚類合理,si接近-1,則說明樣本i更應(yīng)該分類到其他簇;若si 近似于0,說明樣本i在兩個(gè)簇的邊界.

所有樣本的si的均值為聚類結(jié)果的輪廓系數(shù)

密度聚類

DBSCAN算法

若干概念:
對(duì)象的ε-領(lǐng)域,給定對(duì)象在半徑ε內(nèi)的區(qū)域
核心對(duì)象:對(duì)于給定的數(shù)目m,如果一個(gè)對(duì)象的ε-領(lǐng)域至少包含m個(gè)對(duì)象,則稱該對(duì)象為核心對(duì)象.
ε-領(lǐng)域內(nèi),而q是一個(gè)核心對(duì)象,我們說對(duì)象p從對(duì)象q出發(fā)是直接密度可達(dá)的.
密度可達(dá):如果存在一個(gè)對(duì)象煉p1p2p3pn,如果p1=q,pn=p,則pi+1是從pi 關(guān)于ε 和m直接密度可達(dá),
密度相連:如果對(duì)象集合D中存在一個(gè)對(duì)象o鸯屿,使得對(duì)象p和q 是從o關(guān)于ε和m密度可達(dá)的萎胰,那么對(duì)象p和q是關(guān)于ε和m密 度相連的技竟。
簇:一個(gè)基于密度的簇是最大的密度相連對(duì)象的集合。
噪聲:不包含在任何簇中的對(duì)象稱為噪聲熙尉。
DBSCAN算法過程:
* 如果一個(gè)點(diǎn)p的ε-鄰域包含多于m個(gè)對(duì)象搓扯,則創(chuàng)建一個(gè)p 作為核心對(duì)象的新簇;
* 尋找并合并核心對(duì)象直接密度可達(dá)的對(duì)象;
* 沒有新點(diǎn)可以更新簇時(shí),算法結(jié)束铅歼。

密度最大值聚類

局部密度:


dc是一個(gè)截?cái)嗑嚯x, ρi即到對(duì)象i的距離小于dc的對(duì)象的個(gè) 數(shù)椎椰。由于該算法只對(duì)ρi的相對(duì)值敏感, 所以對(duì)dc的選擇是 穩(wěn)健的沾鳄,一種推薦做法是選擇dc,使得平均每個(gè)點(diǎn)的鄰 居數(shù)為所有點(diǎn)的1%-2%
高局部密度點(diǎn)距離:

簡(jiǎn)單的,就是:在密度高于對(duì)象i的所有對(duì)象中瓤的,到對(duì)象i最近 的距離圈膏,即高局部密度點(diǎn)距離.
#####簇中心的識(shí)別:
那些有著比較大的局部密度ρi和很大的高密 距離δi的點(diǎn)被認(rèn)為是簇的中心;
高密距離δi較大但局部密度ρi較小的點(diǎn)是 異常點(diǎn);
####密度最大值的分類過程:

###譜與譜矩陣
方陣作為線性算子,它所有的特征值的全體統(tǒng) 成為方陣的譜.
* 方陣的譜半徑為最大的特征值
* 矩陣A的譜半徑:(ATA)的最大特征值
#####譜分析過程:
給定一組數(shù)據(jù)x1,x2,...xn本辐,記任意兩個(gè)點(diǎn)之間 的相似度(“距離”的減函數(shù))為sij=<xi,xj>,形 成相似度圖(similarity graph):G=(V,E) 老虫。如 果xi和xj之間的相似度sij大于一定的閾值茫多,那 么,兩個(gè)點(diǎn)是連接的夺欲,權(quán)值記做sij今膊。
相似度圖G的建立:
* 全連接圖:
高斯相似度函數(shù):距離越大斑唬,相似度越小

* ε近鄰圖
小于ε的邊裁掉
ε的選定:
圖G的權(quán)值的均值
圖G的最小生成樹的最大邊
* k近鄰圖(k-nearest neighbor graph)
直接選K個(gè)最近的
###拉普拉斯矩陣:
計(jì)算點(diǎn)之間的鄰接相似度矩陣W
若兩個(gè)點(diǎn)的相似度值越大恕刘,表示這兩個(gè)點(diǎn)越相似;
同時(shí),定義wij=0表示vi,vj兩個(gè)點(diǎn)沒有任何相似性(無窮遠(yuǎn))

W的第i行元素的和為vi的度,形成了頂點(diǎn)度對(duì)角陣D
dii表示第i個(gè)點(diǎn)的度
除主對(duì)角線元素坷澡,D其他位置為0
未正則的拉普拉斯矩陣:$$L=D-W$$

對(duì)稱拉普拉斯矩陣:

隨機(jī)游走拉普拉斯矩陣:

未正則拉普拉斯矩陣譜聚類算法:
輸入:n個(gè)點(diǎn){pi}频敛,簇的數(shù)目k
計(jì)算n×n的相似度矩陣W和度矩陣D;
計(jì)算拉普拉斯矩陣L=D-W;
計(jì)算L的前k個(gè)特征向量u1,u2,...,uk(從小到大);特征值的意義:降維處理

將k個(gè)列向量u1,u2,...,uk組成矩陣U馅扣,U∈Rn×k;
對(duì)于i=1,2,...,n,令yi∈Rk是U的第i行的向量;
使用k-means算法將點(diǎn)(yi)i=1,2,...,n聚類成簇 C1,C2,...Ck;
輸出簇A1,A2,...Ak岂嗓,其中鹊碍,Ai={j|yj∈Ci}

hierarchical clustering 層次聚類

假如有N個(gè)待聚類的樣本,步驟:

  • (初始化)把每個(gè)樣本歸為一類,計(jì)算類之間的距離,(樣本之間的相似度)
  • 尋找各個(gè)類之間最近的兩個(gè)類,把它們歸為一類
  • 重新計(jì)算新生產(chǎn)的這個(gè)類與各個(gè)舊類之間的相識(shí)度;
  • 重復(fù)2,3,直到所有的樣本點(diǎn)都?xì)w為一類.

距離的選擇:

  • SingleLinkage(nearest-neighbor)兩個(gè)類中距離最近的兩個(gè)點(diǎn)的距離作為兩個(gè)類的距離.
  • CompleteLinkage 正好相反.兩個(gè)集合中距離最遠(yuǎn)的兩個(gè)點(diǎn)的距離作為集合距離
  • AverageLinkage 兩個(gè)集合中點(diǎn)兩兩距離全部放在一起求均值

代碼:

import  numpy as np
class cluster_node(object):
   def __init__(self,vec,left = None,right = None,distance = 0.0,id = None,count =1):
       self.left = left
       self.right = right
       self.vec = vec
       self.id = id
       self.distance = distance
       self.count = count
def L2dist(v1,v2):
   return  np.sqrt(np.sum((v1-v2)**2))

def L1dist(v1,v2):
   return np.sum(np.abs(v1-v2))

def hcluster(features,distance = L2dist):
   distances = {}
   currentclustid = 1
   clust = [cluster_node(np.array(features[i]),id=i) for i in range(len(features))]


   ##聚類過程
   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)
       ##兩個(gè)類的合并
       mergevec = [(clust[lowestpair[0]].vec[i] + clust[lowestpair[1]].vec[i]) /2.0 \
                   for i in range(len(clust[0].vec))]

       newcluster = cluster_node(np.array(mergevec),left=clust[lowestpair[0]],
                                 right=clust[lowestpair[1]],distance=closest,id=currentclustid)

       currentclustid = -1

       del clust[lowestpair[0]]
       del clust[lowestpair[1]]
       clust.append(newcluster)
   return clust[0]
def extract_clusters(clust,dist):
   clusters = {}
   if clust.distance < dist:
       return [clust]

   if clust.left != None:
       cl = extract_clusters(clust.left,dist = dist)
   if clust.right != None:
       cr =extract_clusters(clust.right,dist = dist)

def get_cluster_elements(clust):
   # return ids for elements in a cluster sub-tree
   if clust.id>=0:
       # positive id means that this is a leaf
       return [clust.id]
   else:
       # check the right and left branches
       cl = []
       cr = []
       if clust.left!=None:
           cl = get_cluster_elements(clust.left)
       if clust.right!=None:
           cr = get_cluster_elements(clust.right)
       return cl+cr


def printclust(clust, labels=None, n=0):
   # indent to make a hierarchy layout
   for i in range(n): print
   (' '),
   if clust.id < 0:
       # negative id means that this is branch
       print
       ('-')
   else:
       # positive id means that this is an endpoint
       if labels == None:
           print (clust.id)
       else:
           print(labels[clust.id])

   # now print the right and left branches
   if clust.left != None: printclust(clust.left, labels=labels, n=n + 1)
   if clust.right != None: printclust(clust.right, labels=labels, n=n + 1)


def getheight(clust):
   # Is this an endpoint? Then the height is just 1
   if clust.left == None and clust.right == None: return 1

   # Otherwise the height is the same of the heights of
   # each branch
   return getheight(clust.left) + getheight(clust.right)


def getdepth(clust):
   # The distance of an endpoint is 0.0
   if clust.left == None and clust.right == None: return 0

   # The distance of a branch is the greater of its two sides
   # plus its own distance
   return max(getdepth(clust.left), getdepth(clust.right)) + clust.distance

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市楼眷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌掌腰,老刑警劉巖张吉,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肮蛹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡伦忠,警方通過查閱死者的電腦和手機(jī)昆码,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笔刹,“玉大人冬耿,你說我怎么就攤上這事亦镶。” “怎么了缤骨?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵绊起,是天一觀的道長(zhǎng)虱歪。 經(jīng)常有香客問我,道長(zhǎng)笋鄙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任践美,我火速辦了婚禮陨倡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘矛缨。我一直安慰自己帖旨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布落竹。 她就那樣靜靜地躺著述召,像睡著了一般蟹地。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上怪与,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天夺刑,我揣著相機(jī)與錄音,去河邊找鬼分别。 笑死遍愿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的耘斩。 我是一名探鬼主播沼填,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼括授!你這毒婦竟也來了坞笙?” 一聲冷哼從身側(cè)響起荚虚,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤薛夜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后曲管,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體却邓,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡硕糊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年院水,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了腊徙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡檬某,死狀恐怖撬腾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情恢恼,我是刑警寧澤民傻,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站场斑,受9級(jí)特大地震影響漓踢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜漏隐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一喧半、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧青责,春花似錦挺据、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至产阱,卻和暖如春婉称,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背心墅。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工酿矢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人怎燥。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓瘫筐,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親铐姚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子策肝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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