聚類分析概念
1.1 爲什麼聚類
之所以要聚類,是因爲當今的數據量劇增(數據爆炸),導致我們檢索信息時成本增加。如果可以找到一種計數可以自動分析數據,那麼將有效節約資源。
1.2 聚類到底是什麼
聚類定義:給定一組無標籤樣本,按照各樣本間的相似度,相似的歸爲一類,不相似的歸爲另一類,這種方法稱爲聚類。
無標籤樣本:即事先並不知道該樣本的類別的樣本,與之相對應的是有標籤樣本(有標籤樣本中稱爲分類)。
例如,此時有來自全球的100人,要求按照其人種對其進行聚類或分類。
當我們知道這一百人每一個人的來歷時,對其進行上述操作就稱爲分類,每一個人的人種我們都清晰可知,我們將每一個樣本及其標籤告訴機器,機器就會訓練出相應的分類器,此時的樣本集也稱爲訓練集。
當我們用上述100人訓練出一個分類器後,接下來我們希望考察它的泛化能力(即應用能力),故我們再隨機抽取100人,此時雖然我們仍然明確地知道這100人的來歷,但這一次我們並不告訴機器他們的來歷(標籤),而只輸入相應的樣本信息,這就是無監督聚類(學習)。機器根據之前在訓練集中訓練出的分類器對新的樣本進行聚類,當輸出結果後,我們可以將輸出結果和真實情況進行對比,從而檢驗訓練效果,故此時的樣本集也稱爲檢驗集。
1.3 聚類與分類區別
類別 | 分類 | 聚類 |
---|---|---|
樣本情況 | 有標籤 | 無標籤 |
所屬大類 | 監督學習 | 非監督學習 |
目的 | 尋找數據邊界 | 尋找數據結構 |
分類(有監督)與聚類(無監督)的區別大致如上表所示。
1.4 相似性與距離聚類
相似性:模式之間有一定的相似性。
對於初學者來說,這個概念較爲抽象,下面對於此概念做以簡單的解析:
模式:模式可以理解爲每一個觀測樣本。例如,考察某學校學生的平均身高,採用抽樣的方法抽查500名同學的身高。這500名同學就是500種模式。
特徵:我們要考察的對象’身高‘就是模式的特徵,在機器學習與模式識別中,常把模式的特徵映射到向量空間中去表達,故特徵常被稱作’特徵向量‘。
特徵空間:如上所說,研究模式的特徵時,常把特徵映射到向量空間中去。而整個模式樣本集合的特徵向量可以看作某個向量空間中的一些點,這個向量空間就被稱爲特徵空間。
距離聚類:以特徵空間中點之間的距離作爲聚類依據的聚類方法叫做距離聚類。
1.5 相似性的測度
相似性測量依據:將樣本的特徵映射到特徵空間中得到特徵向量,特徵向量可以看作特徵空間中的一些點,點與點之間的距離則作爲相似性的測度。
根據相似性的測度方法,我們可以知道其本質是計算特徵向量距離,而選取特徵向量則自然牽扯到了維數的問題(即選取多少個特徵,選取什麼特徵等等),下面我們對於此問題做以簡要說明:
1.聚類分析有效性的關鍵在於特徵的選取,特徵的選取應遵循以下規則:
可分性好:同一羣樣本密集,不同羣的樣本儘可能遠。
2.特徵向量分量個數(維數)並不是越多越好。我們對於樣本特徵的選取,常常取決於我們的分類目的。對於樣本特徵過多地關注往往會造成聚類的錯誤以及計算量的負擔。比如,我們現在獲得10個水果,要求按照顏色對其進行聚類。我們的分類目的是將其顏色分開,如若我們關注不必要的特徵。例如‘形狀’,則可以會犯將橘子和西瓜分爲一類的荒謬錯誤。
3.特徵表示時要注意量綱一致。
特徵相似度測度與聚類準則
2.1 特徵相似度測度
前面以及提到相似性的測度是特徵空間中點與點之間的距離,而距離有很多表述方法,下面介紹幾種常見的距離測度:
(a) 歐氏距離
設,
在X,Y量綱一致的前提下,有:
即爲樣本間對應特徵的歐式距離
(b) 馬氏距離
馬氏距離定義如下:
其中爲協方差矩陣
對於馬氏距離,我們做以下幾點說明:
1.馬氏距離則不要求數據量綱一致,也就是說,馬氏距離與原始數據的測量單位無關(因爲單位已經被協方差矩陣消掉)。此性質相對於歐氏距離爲我們提供了很大的便捷。實際上,我們的數據來源非常廣泛,而每個人的測量習慣不同,導致其使用的測量單位也往往不一樣。而馬氏距離的構造很好地衝消了這一點的影響。
2.馬氏距離削弱了相關性過強的變量的影響,在歐式距離中,如果某兩個變量相關性過強,則會造成巨大的影響,這就屏蔽了其它變量的影響,容易對我們造成誤導。而馬氏距離則不然,對於相關性強的變量,協方差矩陣中對其協方差取倒數,一定程度上削弱了過強的影響,也可以讓我們更加全面地去考察樣本間的相關性。
3.當馬氏距離中的協方差矩陣爲單位陣時,其等於歐氏距離。
(c) 明氏距離
明氏距離定義如下:
其中,爲第i個樣本和第j的樣本的第k個分量。
當m=2時,此時的明氏距離就是歐氏距離。
當m=1時,此時的馬氏距離就是街坊距離(city block)。
(d) 角度相似性函數
角度相似性函數定義如下:
可以看到,上述公式事實上就是反應模式向量x,z間夾角的餘弦值。表徵的更多是模式間方向的相似性。關於餘弦相似度的詳解,讀者可以查看我的另一個博客“機器學習——餘弦相似度”。
(e)Tanimoto測度
定義如下:
也就是表示了x,z中共有的特徵數目佔兩者一共的特徵數目百分比。
與前不同,x,z用二分量表示。0表示不具有某種特徵,1表示具有某種特徵。
2.2 聚類準則
1.試探方法
經驗,直觀,但也易出錯。
2.聚類準則法
由於聚類是將樣本進行分類以使類別間可分離性爲最大,因此聚類準則應是反映類別間相似性或分離性的函數。而類別又由一個個樣本組成,故類別間相似性和樣本的相似性及可分離性息息相關。故可以考慮定義一個函數,其以模式樣本集{x}和模式類別S爲自變量,從而將問題轉換爲求解函數的最優化問題。此函數則稱爲聚類準則函數,表達式如下:
其中,{x}爲模式樣本集
爲模式類別
爲樣本均值向量
分級聚類法
分級聚類法基本思路:根據類內或類間的相似度測量,依次分類。
其算法步驟大致如下:
簡單說明:其中k爲初始類數,假設初始有n個樣本,則尚未開始聚類前每一個樣本都是一個類別,故第一步有k=n(n爲樣本數)。而後通過計算類間距離,將類間距離最小的兩個類合併爲一個類,如此迭代,直至滿足停止條件。
上述說明自然地引出了兩個問題:如何度量距離?如何判定是否滿足停止條件?下面我們逐一進行說明。
1.如何度量距離
對於距離,我們看到,在此算法中既有類內諸多樣本點間的距離,也有各類間的類間距離。
a) 類內距離(樣本間距離)
類內距離的度量在全面我們已經提到,即相似性測度裏的幾種距離測度,而具體選用哪種測度,須依據實際情況而定。
b)類間距離
類間距離的測量標準常有以下三種:
1.最近領域法則
即選取兩類間距離最近的樣本作爲兩類的距離,公式表達爲:
採用最近領域法則一個很明顯的缺點就是對於噪聲過於敏感。
2.最遠領域法則
與最近領域法則恰好相反,最遠領域法則選取兩類間距離最遠的樣本作爲兩類的距離,公式表達爲:
3.平均領域法則
平均領域法則即計算兩類間樣本的平均距離作爲類間距離,公式表達爲:
平均領域法則由於計算了多個樣本間距離的平均值,故其容錯性較好,對於噪聲的抵抗能力較強。但計算量相對前兩者有了明顯的增加。
我們該如何選擇類間距離測度?
這取決於我們對於數據的瞭解程度,如果我們實現知道數據的可分性非常好並且類內樣本分佈緊湊,那麼不論是哪種方法都可以得到不錯的分類結果。如果我們樣本的可分性較差,類間距離較小,那麼通常採用平均領域法則。
2.如何判定是否滿足停止條件
停止條件可以有很多種形式,滿足其中一種形式即可停止聚類,下面給出常見的幾種停止條件:
a) 給定聚類數k,即希望最後聚爲k類。
b) 給定最大允許的類間距離門限。即若
,則停止聚類。
這種思想很好理解,當類間距離過大時,有可能出現了將兩類聚爲了一類的情況。
c)當上一次聚類與這一次聚類的類間距離變化很大,即類間距離劇增時,停止聚類,此時表明有可能將原本的兩類聚爲了一類。
對分級聚類法的基礎知識有一定了解後,接下來我們給出算法的實現(基於Python):
def hcluster(rows,distance=pearson):
distances={}
currentclustid=-1
# Clusters are initially just the rows
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)
print "closest",closest
# loop through every pair looking for the smallest distance
for i in range(len(clust)):
for j in range(i+1,len(clust)):
# distances is the cache of distance calculations
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)
# calculate the average of the two clusters
mergevec=[
(clust[lowestpair[0]].vec[i]+clust[lowestpair[1]].vec[i])/2.0
for i in range(len(clust[0].vec))]
# create the new cluster
newcluster=bicluster(mergevec,left=clust[lowestpair[0]],
right=clust[lowestpair[1]],
distance=closest,id=currentclustid)
# cluster ids that weren't in the original set are negative
currentclustid-=1
del clust[lowestpair[1]]
del clust[lowestpair[0]]
clust.append(newcluster)
return clust[0]