【火炉炼AI】机器学习023-使用层次聚类算法构建模型
【火爐煉AI】機器學習023-使用層次聚類算法構建模型
(本文所使用的Python庫和版本號: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )
聚類的算法有很多種,前面我們講解了k-means算法和均值漂移算法,此處我們繼續講解層次聚類算法。
k-means是一種分散性聚類算法,以空間中K個點為中心進行聚類,將最靠近他們的樣本收歸門下。k-means的優勢在于簡單快速,對于大數據集,該算法仍然可以保持可伸縮性和高效率,對于密集型的數據集,效果非常好。缺點也很明顯:必須事先給出K值,而且對初值敏感,對于不同的初始值,可能會產生不同結果;對于非密集型數據集,比如非凸形狀的簇或者大小差別很大的簇,可能不太適用;而且k-means對噪聲和孤立點數據比較敏感。
正是因為k-means有上述優點,所以它才能夠經久不衰,也正是因為它有上述缺點,所以它才沒有一統天下。
1. 層次聚類算法簡介
層次聚類,顧名思義,就是一層一層的進行聚類,通常,我們可以把整個數據集看成一顆樹,每一個數據點就是該樹的葉子,而一個節點就是該節點下的葉子總數。故而,對這個數據集進行聚類分析,就相當于找到各種葉子對應的節點,這種尋找方式就是層次聚類算法。
一般的,層次聚類算法有兩種:自下而上的算法和自上而下的算法。在自下而上的算法中,剛開始每個數據點(即每個葉子)都被看成一個單獨的集群,然后將這些集群不斷的合并,直到所有的集群都合并成一個巨型集群,這種自下而上的合并算法也叫做凝聚層次聚類算法。
而相反的,在自上而下的算法中,剛開始所有的葉子被當做一個巨型集群,然后對這個集群進行不斷的分解,直到所有的集群都變成一個個單獨的數據點,即巨型集群被分解成單獨的葉子節點,這種自上而下的的分解算法也叫做分裂層次聚類算法。
目前應用最多的還是凝聚層次聚類算法,故而下面只對該算法進行介紹。
凝聚層次聚類算法的核心思想如上圖所示,由葉子逐步合并成根節點。
凝聚法的具體計算過程可以描述為:
1,將數據集中的所有的數據點都當做一個獨立的集群
2,計算兩兩之間的距離,找到距離最小的兩個集群,并合并這兩個集群為一個集群,認為距離越小,兩者之間的相似度越大,越有可能是一個集群。
3,重復上面的步驟2,直到聚類的數目達到設定的條件,表示聚類過程完成。
上面的計算過程看似簡單,但有一個關鍵的難點在于:數據點或集群之間的距離計算,這種集群間距離的計算方法有很多種,下面幾種比較常見的計算方法:
1,SingleLinkage: 又叫做nearest-neighbor,其本質就是取兩個集群中距離最近的兩個樣本的距離作為這兩個集群的距離。這種方式有一個缺點,會造成一種Chaning的效果,即明明兩個集群相距甚遠,但由于其中個別點的距離比較近而把他們計算成距離比較近。
2,CompleteLinkage: 這種計算方式是上面的SingleLinkage算法的反面,即取兩個集群中距離最遠的兩個點的距離作為這兩個集群的距離,所以它的缺點也和上面的算法類似。
3,AverageLinkage: 由于上面兩種算法都存在一定的問題,都會被離群點帶到溝里去,所以本算法就考慮整體的平均值,即把兩個集群中的點兩兩的距離都計算出來后求平均值,作為兩個集群的距離。有的時候,并不是計算平均值,而是取中值,其背后的邏輯也是類似的,但取中值更加能夠避免個別離群數據點對結果的干擾。
一旦我們通過上面的公式計算出來兩個集群的相似度,我們就可以對這兩個集群進行合并。
上面的部分內容來源于聚類系列-層次聚類 和Kmeans聚類與層次聚類, 聚類(2)——層次聚類,在此表示感謝。
2. 準備數據集
下面我們自己構建一個數據集,我們定義了一個函數prepare_dataset()專門用來準備數據集,此處的數據集是分布比較特殊的樣本點,如下為這個準備數據集的函數的代碼
# 準備數據集 def prepare_dataset(sample_num,data_type,noise_amplitude):'''prepare special kinds of dataset,params:sample_num: sample numbers in this prepared dataset,data_type: must be one of ['rose','spiral','hypotrochoid'],noise_amplitude: how much noise add to the dataset. normally, range from 0-0.5return:the prepared dataset in numpy.ndarray format'''def add_noise(x, y, amplitude):X = np.concatenate((x, y))X += amplitude * np.random.randn(2, X.shape[1])return X.Tdef get_spiral(t, noise_amplitude=0.5):r = tx = r * np.cos(t)y = r * np.sin(t)return add_noise(x, y, noise_amplitude)def get_rose(t, noise_amplitude=0.02):k = 5 r = np.cos(k*t) + 0.25 x = r * np.cos(t)y = r * np.sin(t)return add_noise(x, y, noise_amplitude)def get_hypotrochoid(t, noise_amplitude=0):a, b, h = 10.0, 2.0, 4.0x = (a - b) * np.cos(t) + h * np.cos((a - b) / b * t) y = (a - b) * np.sin(t) - h * np.sin((a - b) / b * t) return add_noise(x, y, 0)X=2.5*np.pi*(1+2*np.random.rand(1,sample_num))if data_type=='hypotrochoid':return get_hypotrochoid(X,noise_amplitude)elif data_type=='spiral':return get_spiral(X,noise_amplitude)else:return get_rose(X,noise_amplitude)下面我們用這個函數準備三個數據集,分別是spiral_dataset, rose_dataset, hypo_dataset,其代碼為:
spiral_dataset=prepare_dataset(600,'spiral',0.5) rose_dataset=prepare_dataset(600,'rose',0.02) hypo_dataset=prepare_dataset(600,'hypotrochoid',0)然后我們用前面文章中提到的函數visual_2D_dataset_dist()可以查看無標簽數據集的分布情況,如下圖所示為這三個數據集的二維分布情況。
########################小**********結###############################
1,此處我們自己創建了一些具有特殊分布的數據集,想用這些特殊分布的數據集來考察凝聚層次聚類算法的優虐。
2,數據集的產生是通過一些數學函數來實現的,這些函數在網上可以找到成熟的數學公式。
#################################################################
3. 使用凝聚層次聚類算法構建模型
為了更好地比較模型在不同數據集上的效果,我們將模型的構建函數和模型在不同數據集上的表現都整合到一個函數中,該函數名稱為:perform_plot_clustering(),在以后只需要調用該函數就可以分別對這三個數據集進行訓練和繪制訓練后效果圖。如下為代碼:
from sklearn.cluster import AgglomerativeClustering from sklearn.neighbors import kneighbors_graph# 建立一個函數,用來構建聚類模型,并繪圖展示聚類效果 def perform_plot_clustering(dataset,none_cluster_num=3,kneighbors_num=10):assert dataset.shape[1]==2,'only support dataset with 2 features'# 構建凝聚層次聚類模型,并用數據集對其進行訓練none_model=AgglomerativeClustering(n_clusters=none_cluster_num)none_model.fit(dataset) # 構建無connectivity的modelconnectivity = kneighbors_graph(dataset, kneighbors_num, include_self=False)conn_model=AgglomerativeClustering(n_clusters=kneighbors_num,connectivity=connectivity)conn_model.fit(dataset)# 構建kneighbors_graph connectivity的modeldef visual_2D_dataset(plt,dataset_X,dataset_y):'''將二維數據集dataset_X和對應的類別dataset_y顯示在散點圖中'''assert dataset_X.shape[1]==2,'only support dataset with 2 features'classes=list(set(dataset_y)) markers=['.',',','o','v','^','<','>','1','2','3','4','8','s','p','*','h','H','+','x','D','d','|']# colors=['b','c','g','k','m','w','r','y']colors=['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', 'tab:gray', 'tab:olive', 'tab:cyan']for class_id in classes:one_class=np.array([feature for (feature,label) in zip(dataset_X,dataset_y) if label==class_id])plt.scatter(one_class[:,0],one_class[:,1],marker=markers[class_id%len(markers)],c=colors[class_id%len(colors)],label='class_'+str(class_id))plt.legend()# 以下是繪圖def plot_model_graph(plt,model,title):labels=model.labels_# 將數據集繪制到圖表中visual_2D_dataset(plt,dataset,labels)plt.title(title)plt.xlabel('feature_0')plt.ylabel('feature_1')return pltplt.figure(12,figsize=(25,10))plt.subplot(121)plot_model_graph(plt,none_model,'none_connectivity')plt.subplot(122)plot_model_graph(plt,conn_model,'kneighbors_connectivity')plt.show()使用這個函數來查看凝聚層次聚類算法在這三個數據集上的效果,可以得到如下結果圖:
從上面這三幅圖中可以看出,在沒有使用kneighbors connectivity的圖中,凝聚層次算法傾向于把位置相近的一些點聚集到一個類別,而不考慮這些數據點之間是否連續,是否有數據之間的連接。而用kneighbors作connectivity之后,算法傾向于把有連接的一些數據劃分為一類,而沒有連接的劃分為另外一類,這樣的劃分方法更具有邏輯性。
也有人會問,是不是因為在第一幅圖中我們把類別設置為3類,所以算法在劃分時將很多距離較遠的沒有連接的樣本劃分為同一個類了?那么我們可以試一下同樣的將none_connectivity的類別設置為10,再對比以下兩者的效果,如下為結果圖:
########################小**********結###############################
1,凝聚層次聚類算法的構建和訓練比較簡單,和其他聚類算法沒有太大區別,直接構建AgglomerativeClustering對象并訓練即可。
2,在構建凝聚層次聚類算法時,有一個connectivity的參數是選擇的難點,此處我比較了不使用connectivity參數和使用kneighbors connectivity參數的區別,發現兩者在聚類時有一些不同。
3,在不使用connectivity參數時,凝聚層次算法傾向于把位置相近的一些點聚集到一個類別,而不考慮這些數據點之間是否連續,是否有數據之間的連接。
4,而用kneighbors作connectivity之后,算法傾向于把有連接的一些數據劃分為一類,而沒有連接的劃分為另外一類。在實際項目中,應該怎么使用這個connectivity參數,應該根據具體的數據集特性來選擇。
#################################################################
注:本部分代碼已經全部上傳到(我的github)上,歡迎下載。
參考資料:
1, Python機器學習經典實例,Prateek Joshi著,陶俊杰,陳小莉譯
總結
以上是生活随笔為你收集整理的【火炉炼AI】机器学习023-使用层次聚类算法构建模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我是如何零基础开始能写爬虫的?
- 下一篇: CSS修饰的浮动