《機器學習(周志華)》學習筆記(九)

Q:分類和聚類有什么不同?

兩者的區別可以主要從兩個方面看出。第一,它們面對的根本問題不同。分類的根本問題是判斷給定的某一個樣本屬于那一個類別;聚類的根本問題是探索給定的數據集可以分成哪幾種類別。第二,兩者使用的訓練數據集有差異。分類任務使用的訓練數據集中每個樣本除了有屬性數據外,還必須有一個標記值,用以表示該樣本屬于哪一類;聚類任務的數據集中每個樣本可以只有屬性值,沒有標記值(當然也可以有)。這也可以認為是我們常說的,監督學習與無監督學習。

Q:聚類的一般方法有哪些?

聚類算法多種多樣,但是萬變不離其宗,最基本的思想還是先提出一中衡量樣本之間相似程度的的手段,如距離、相關系數等,然后逐一計算數據集中各樣本之間的相似度,盡量把相似度高的樣本放到同一類。

一般來說聚類算法有三類:基于原型的聚類、基于密度的聚類、和基于層次的聚類。當然,還可以有更多,比如混合高斯模型也能用于聚類任務。

Q:衡量樣本間相似度的指標有那些?

所謂樣本,其數學本質就是向量。所以樣本間的相似度常用距離來表示。

最簡單的距離就是內積距離

向量x與y的內積

最直觀的距離則是歐氏距離
歐氏距離

更一般的距離有明可夫斯基距離,其中p值視情況而定
明可夫斯基距離

上面提到的距離都是適用于有序屬性的。所謂有序屬性,就是指屬性的取值有大小之分。比如西瓜的“含糖率”這個屬性,0.1就比0.9要小。無序屬性這位是指屬性取值無大小之分的屬性。比如西瓜的“顏色”屬性,取“0”表示淺綠、取“1”表示深綠,但不能說0比1小,“顏色”屬性的取值不能比較大小。此時,要更亮無序屬性的距離要用到VDM距離,即

所以,對于屬性中既含有有序屬性,又含有無序屬性的樣本,則需要統一明可夫斯基距離和VDM距離
能用于有序和無序屬性的統一距離公式

Q:k-means聚類算法的思路是怎樣的?

當我們去考察一堆數據的時候,一般會通過平均數和方差來獲取一個大致的了解。也就是說,平均數和方差可以代表一組數據。那么我們就會想,有沒有一個均值向量可以代表一組向量?

自然是有的(反正概念什么的都是人定的)。


均值向量

上式代表C_i類中所有向量的均值向量。

那么,如果有k個均值向量,就代表有k個類。可以分別計算某個向量與這k個均值向量的距離,哪個距離更短,就將該向量(樣本)歸到哪一類。這便是k-means(k均值)算法的基本思想。

實際的算法過程是一個循環。首先人為設定k值大小,即要劃分多少個類。然后第一輪在數據集中隨機挑選k個樣本作為初始的均值向量,接著計算剩下的樣本與這幾個均值向量的距離,并且聚類,可以得到k個類別,每個類別至少一個樣本。此時重新計算各個類別的均值向量,得到k個新的均值向量。下面重新計算距離,再度分類,再度重新計算均值向量,得到k個新的均值向量,如此循環往復,直到得到的k個均值向量與上一輪的均值向量一樣,也就是兩輪的聚類結果一樣的時候,循環結束。


Q:雖說聚類術語無監督學習,不需要用到樣本標記信息,但是既然存在標記信息,可不可以利用一下?

LVQ(學習向量量化)算法就是利用樣本標記信息來輔助聚類的算法。LVQ算法利用和k-means的均值向量類似的代表性向量(也可以叫原型向量),同樣也使用距離計算然后根據最短距離分類的的思想。不過LVQ算法的目的不是直接得到劃分好的幾個類,而是得到t個原型向量。也就是說,LVQ的輸出是t個原型向量。先上一張抽象的算法流程

LVQ算法

LVQ算法同樣人為設定一個t值,也就是要劃分的類別數。然后初始化t個原型向量——不是像k-means一樣隨便選,而是根據預先說好了的標記,在隨便選。比如預先說好要選3個好瓜,2個壞瓜,就從好瓜中隨便選三個,壞瓜中隨便選兩個。

選好初始原型向量后,開始和k-means一樣不斷循環計算距離,不過LVQ每次都是隨機抽取訓練數據集的一個樣本,計算抽到的樣本和各個原型向量的距離。距離最短的一個原型向量,如果其標記和抽到的標記一樣,就“使原型向量向抽到的樣本向量靠近”,如果其標記和抽到的標記不同,就“使原型向量向抽到的樣本向量遠離”——


調整原型向量

學習率,人為設定,會影響算法運行質量和時間

如此循環往復直到達到最大循環次數,或者原型向量的調整幅度已經小于某個閥值。

Q:有沒有不是基于原型向量的聚類算法?

除了基于原型向量的聚類算法,還有基于密度的聚類算法,如DBSCAN,和基于層次的聚類算法,如AGNES

在了解什么是基于密度的算法前,先參考一下人際社交的生活經驗。“物以類聚,人以群分”,人群中會自發地誕生多個人際關系圈子。圈子中的核心人物一般來說往往是人脈最豐富的,或者直接說認識人最多的,這些人暫且稱為社交領袖。一個人一般來說可以很迅速地和自己的朋友建立聯系。只要兩個人處于同一個圈子之中,或者說他們處于不同的圈子,但是兩個圈子的人有交集,那么即使他們不認識,也可以通過朋友的朋友的朋友······建立聯系。弱兩個人分屬不同的圈子,且兩個圈子沒有交集,但是兩個圈子都和第三個圈子有交集,那么這兩個人同樣可以通過朋友的朋友的朋友······建立聯系。

根據上面這個例子,我們可以建立一個樣本密度模型



DBSCAN算法中的簇類比于交際關系里的圈子,鄰域類比于一個人的朋友圈,核心對象類比于社交領袖,密度直達、可達、相連分別類比于三種人與人知啊今建立聯系的方式。DBSCAN算法中的一個簇是指所有可以相互之間密度直達、可達、相連的樣本的集合。

而DBSCAN算法的原理也就很簡單了,首先確定數據集中所有核心對象,然后隨機從一個核心對象出發找出所有與之密度可達的樣本,找完以后這些樣本就是一個簇了,然后再隨機選一個不在現有的簇范圍內的核心對象,繼續上面的步驟,知道所有核心對象都被分到某個簇中。

DBSCAN算法最后可能會產生幾個不在任何簇里的樣本,他們被稱為噪聲,同時也可以視為異常數據

基于層次的聚類算法試圖用自頂向下或者自底向上的方式在不同層次上對數據進行劃分。AGNES算法是一中自底向上的算法。算法的基本思想是在一開始把所有樣本都看作一個簇類。那么有n個樣本的數據集就有n個初始簇。接下來兩兩計算簇間距離,距離最小的兩個簇合并為一個簇(有點像霍夫曼樹的子樹合并),直到所有的簇合并為一個簇為止。各種簇間距離計算公式如下,視情況挑選



AGNES算法最終得到的結果如下圖



我們可以通過選擇簇間距離來確定到底分幾個簇。簇間距離越大,得到的簇越少,簇間距離越小,得到的簇越多。

Talk is cheap, show me the code!

下面是一個KMeans模型的簡單實現

"""
K-means clustering model

:file: supervised.py
:author: Richy Zhu
:email: rickyzhu@foxmail.com
"""
import numpy as np

class MyKMeans:
    def __init__(self, k=3):
        '''
        K-means clustering model

        :k: int, number of clusters
        '''
        self.k = k
        self.X = None
        self.labels = None
        self.cluster_centers = None
    
    def fit(self, X):
        '''
        Train the K-means clustering model

        Parameters
        ----------
        X: ndarray of shape (m, n)
            sample data where row represent sample and column represent feature

        Returns
        -------
        self
            trained model
        '''
        ran_index = np.random.choice(np.arange(0,len(X)), self.k)
        centres = [X[i] for i in ran_index]
        prev_labels = np.zeros(len(X))
        i = 0
        while True:
            labels = []
            for x in X:
                labels.append(np.argmin([np.linalg.norm(x - c) for c in centres]))
            if np.array_equal(prev_labels, labels):
                break
            prev_labels = labels
            for i in range(len(centres)):
                centres[i] = np.mean(X[np.array(labels)==i], axis=0)
            i += 0
        self.labels = np.array(labels)
        self.cluster_centers = np.array(centres)
        return self
    
    def predict(self, X):
        '''
        Make prediction by the trained model.

        Parameters
        ----------
        X: ndarray of shape (m, n)
            data to be predicted, the same shape as trainning data

        Returns
        -------
        C: ndarray of shape (m,)
            Predicted class label per sample.
        '''
        labels = []
        for x in X:
            labels.append(np.argmin([
                np.linalg.norm(x - c) for c in self.cluster_centers
            ]))
        return np.array(labels)

測試代碼如下

import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

from unsupervised import *

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y)

print('\nK-means clustering')
print('---------------------------------------------------------------------')
mykm = MyKMeans(k=3)
mykm.fit(X_train)
print('My KMeans:')
print(mykm.cluster_centers)
print(mykm.predict(X_test))
print()

from sklearn.cluster import KMeans
skkm = KMeans(n_clusters=3)
skkm.fit(X_train)
print('Sk KMeans:')
print(skkm.cluster_centers_)
print(skkm.predict(X_test))

測試結果為

$ python unsupervised_examples.py
K-means clustering
---------------------------------------------------------------------
[[4.78333333 3.11666667 1.50555556 0.26666667]
 [6.24       2.87866667 4.90133333 1.66933333]
 [5.25789474 3.74210526 1.49473684 0.26315789]]
[2 1 2 1 2 1 2 1 1 0 1 1 1 1 0 1 1 1 0 0 0 1 0 1 1 0 2 1 1 2 1 1 1 0 0 1 1
 0]

Sk KMeans:
[[5.025      3.46388889 1.45833333 0.24166667]
 [6.78888889 3.08888889 5.72962963 2.08888889]
 [5.91428571 2.75510204 4.40612245 1.42653061]]
[0 1 0 1 0 2 0 2 2 0 1 1 2 2 0 1 1 2 0 0 0 2 0 1 1 2 0 2 1 0 1 2 2 2 0 2 1
 0]

更多代碼請參考https://github.com/qige96/programming-practice/tree/master/machine-learning


本作品首發于簡書博客園平臺,采用知識共享署名 4.0 國際許可協議進行許可。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

推薦閱讀更多精彩內容