以《简单易懂》的语言带你搞懂无监督学习算法【附Python代码详解】机器学习系列之K-Means篇
大家早上好,本人姓吳,如果覺得文章寫得還行的話也可以叫我吳老師。歡迎大家跟我一起走進數據分析的世界,一起學習!
感興趣的朋友可以關注我或者我的數據分析專欄,里面有許多優質的文章跟大家分享哦。
目錄
- 必看前言
- 無監督學習算法
- 1 聚類與分類
- 2 K-Means算法
- 2.1 K-Means的基本原理
- 2.1.1 K-Means 是如何工作的?
- 2.1.2 簇內誤差平方和的定義
- 2.2 K-Means算法的python實現
- 2.2.1 導入數據集
- 2.2.2 編寫距離計算函數
- 2.2.3 編寫隨機生成質心函數
- 2.2.4 編寫 K-Means 聚類函數
- 2.2.5 算法驗證
- 結束語
必看前言
今天這一篇文章,將跟大家分享一下無監督學習算法。
而本文將試圖用簡單易懂的語言來講說到底什么是無監督學習算法,同時主要會以KMeans算法為例,跟大家詳細地說明。
無監督學習算法
決策樹、線性和邏輯回歸都是比較常用的機器學習算法,他們雖然有著不同的功能,但卻都屬于“有監督學習” 的?部分,即是說,模型在訓練的時候,即需要特征矩陣X,也需要真實標簽y。機器學習當中,還有相當?部分算法屬于 “無監督學習” ,無監督的算法在訓練的時候只需要特征矩陣X,不需要標簽。無監督學習的代表算法有聚類算法、降維算法。
聚類算法又叫做“無監督分類”,其目的是將數據劃分成有意義或有用的組(或簇)。這種劃分可以基于我們的業務需求或建模需求來完成,也可以單純地幫助我們探索數據的自然結構和分布。
比如在商業中,如果我們手頭有大量的當前和潛在客戶的信息,我們可以使用聚類將客戶劃分為若干組,以便進一步分析和開展營銷活動,最有名的客戶價值判斷模型RFM(Recency Frequency Monetary),就常常和聚類分析共同使用。再比如,聚類可以用于降維和矢量量化(vectorquantization),可以將高維特征壓縮到一列當中,常常用于圖像,聲音,視頻等非結構化數據,可以大幅度壓縮數據量。
1 聚類與分類
| 核心 | 將數據分成多個組,探索每個組的數據是否有聯系 | 從已經分組的數據中去學習,把新數據放到已經分好的組中 |
| 學習類型 | 無監督,無需標簽進行訓練 | 有監督,需要標簽進行訓練 |
| 典型算法 | K-Means, DBSCAN, 層次聚類,光譜聚類 | 決策樹,貝葉斯,邏輯回歸 |
| 算法輸出 | 聚類結果是不確定的,不一定總是能夠反映數據的真實分類,同樣的分類根據不同的業務需求可能是好結果也可能是壞結果 | 分類結果是確定的,分類的優劣是客觀的,不是根據業務或算法需求來決定的 |
聚類算法是無監督類機器學習算法中最常用的?類,其目的是將數據劃分成有意義或有用的組(也被稱為簇)。這種劃分可以基于我們的業務需求或建模需求來完成,也可以單純地幫助我們探索數據的自然結構和分布。如果目標是劃分成有意義的組,則簇應當捕獲數據的自然結構。然而,在某種意義下,聚類分析只是解決其他問題(如數據匯總)的起點。無論是旨在理解還是應用,聚類分析都在廣泛的領域扮演著重要角色。這些領域包括:心理學和其他社會科學、生物學、統計學、模式識別、信息檢索、機器學習和數據挖掘。
那么接下來,我會詳細講解無監督學習算法中的K-Means算法,來借此幫助大家了解K-Means算法。
2 K-Means算法
2.1 K-Means的基本原理
2.1.1 K-Means 是如何工作的?
- 關鍵概念:簇和質心
KMeans 算法將一組 N 個樣本的特征矩陣 X 劃分為 K 個無交集的簇,直觀上來看是簇是一組一組聚集在一起的數據,在一個簇中的數據就認為是同一類。簇就是聚類的結果表現。
簇中所有數據的均值通常被稱為這個簇的“質心”(centroids)。在一個二維平面中,一簇數據點的質心的橫坐標就是這一簇數據點的橫坐標的均值,質心的縱坐標就是這一簇數據點的縱坐標的均值。同理可推廣至高維空間。
在 KMeans 算法中,簇的個數 K 是一個超參數,需要我們人為輸入來確定。KMeans 的核心任務就是根據我們設定好的 K,找出 K 個最優的質心,并將離這些質心最近的數據分別分配到這些質心代表的簇中去。
具體過程可以總結如下:
? 計算質心與數據點之間的距離
? 將數據點分配到據其最近的簇
那什么情況下,質心的位置會不再變化呢?
當我們找到一個質心,在每次迭代中被分配到這個質心上的樣本都是一致的,即每次新生成的簇都是一致的,所有的樣本點都不會再從一個簇轉移到另一個簇,質心就不會變化了。
下面我們可以看到例題:
我們先來看下思路(其實也就是上面提到的):
然后看下解題過程:
總之,我感覺K-Means這一整個流程還是非常容易理解和實現的。
那接下來,我們來講一下聚類算法聚出的類有什么含義。
2.1.2 簇內誤差平方和的定義
聚類算法聚出的類有什么含義?這些類有什么樣的性質?我們認為,被分在同一個簇中的數據是有相似性的,而不同簇中的數據是不同的,當聚類完畢之后,我們就要分別去研究每個簇中的樣本都有什么樣的性質,從而根據業務需求制定不同的商業或者科技策略。
聚類算法的目的就是追求“簇內差異小,簇外差異大”(圈起來,下次要考)。而這個“差異“,由樣本點到其所在簇的質心的距離來衡量。
對于一個簇來說,所有樣本點到質心的距離之和越小,我們就認為這個簇中的樣本越相似,簇內差異就越小。而距離的衡量方法有多種,令:
? x 表示簇中的一個樣本點;
? μ表示該簇中的質心;
? n 表示每個樣本點中的特征數目;
? i 表示組成點 x 的每個特征編號;
則該樣本點到質心的距離可以由以下距離來度量:
- 歐幾里得距離:d(x,u)=∑i=1n(xi?ui)2d(x,u)=\sqrt{}{\sum^{n}_{i=1}{(x_i-u_i)^2}}d(x,u)=?∑i=1n?(xi??ui?)2
- 曼哈頓距離:d(x,u)=∑i=1n(∣xi?ui∣)d(x,u)=\sum^{n}_{i=1}{(|x_i- u_i|)}d(x,u)=∑i=1n?(∣xi??ui?∣)
- 余弦距離:cosθ=∑1n(i?u)∑1n(xi)2?∑1n(ui)2cos\theta=\frac{\sum^n_1(_i*u)}{\sqrt{}{\sum^n_1(x_i)^2}*\sqrt{}{\sum^n_1(u_i)^2}}cosθ=?∑1n?(xi?)2??∑1n?(ui?)2∑1n?(i??u)?
如我們采用歐幾里得距離,則一個簇中所有樣本點到質心的距離的平方和為:ClusterSumofSquare(CSS)=∑j=0m∑i=1n(xi?ui)2Cluster \, Sum \, of \, Square(CSS)=\sum^{m}_{j=0}\sum^{n}_{i=1}{(x_i-u_i)^2}ClusterSumofSquare(CSS)=j=0∑m?i=1∑n?(xi??ui?)2? 其中,m 為一個簇中樣本的個數;
? j 是每個樣本的編號;
這個公式被稱為簇內平方和(cluster Sum of Square),又叫做 Inertia。
而將一個數據集中的所有簇的簇內平方和相加,就得到了整體平方和(Total Cluster Sum of
Square),又叫做total inertia:TotalClusterSumofSquare=∑i=1kCSSlTotal \, Cluster \, Sum \, of \, Square=\sum^{k}_{i=1}{CSS_l}TotalClusterSumofSquare=i=1∑k?CSSl?Total Inertia 越小,代表著每個簇內樣本越相似,聚類的效果就越好。(記住,后期會考!)
因此 KMeans 追求的是,求解能夠讓 Inertia 最小化的質心。
實際上,在質心不斷變化不斷迭代的過程中,總體平方和是越來越小的。當整體平方和最小的時候,質心就不再發生變化了。
大家可以發現,我們的 Inertia 是基于歐幾里得距離的計算公式得來的。實際上,我們也可以使用其他距離,每個距離都有自己對應的 Inertia。在過去的經驗中,我們總結出不同距離所對應的質心選擇方法和 Inertia,在Kmeans 中,只要使用了正確的質心和距離組合,無論使用什么樣的距離,都可以達到不錯的聚類效果:
| 歐幾里得距離 | 均值 | 最小化每個樣本點到之心的歐氏距離之和 |
| 曼哈頓距離 | 中位值 | 最小化每個樣本點到之心的曼哈頓距離之和 |
| 余弦距離 | 均值 | 最小化每個樣本點到之心的余弦之和 |
而這些組合,都可以由嚴格的數學證明來推導。在實際中我們往往都使用歐式距離,因此我們也無需去擔憂這些距離所搭配的質心選擇是如何得來的了。
2.2 K-Means算法的python實現
那同樣的,老規矩,我們嘗試用Python來實現Kmeans算法。
import numpy as np import pandas as pd import matplotlib.pyplot as plt from IPython.core.interactiveshell import InteractiveShell InteractiveShell.ast_node_interactivity = "all" # 解決坐標軸刻度負號亂碼 plt.rcParams['axes.unicode_minus'] = False# 解決中文亂碼問題 plt.rcParams['font.sans-serif'] = ['Simhei']2.2.1 導入數據集
此處先以經典的鳶尾花數據集為例,來幫助我們建模,數據存放在 iris.txt 中。
import numpy as np import pandas as pd import matplotlib as mpl import matplotlib.pyplot as plt %matplotlib inline #導入數據集 iris = pd.read_csv("iris.txt",header = None) iris
這里最后一類呢是標簽,不過我們不需要,后面訓練時記得不要取到最后一列。
2.2.2 編寫距離計算函數
我們需要定義一個兩個長度相等的數組之間歐式距離計算函數,在不直接應用計算距離計算結果,只比較距離遠近的情況下,我們可以用距離平方和代替距離進行比較,化簡開平方運算,從而減少函數計算量。此外需要說明的是,涉及到距離計算的,一定要注意量綱的統一。如果量綱不統一的話,模型極易偏向量綱大的那一方。此處選用鳶尾花數據集,基本不需要考慮量綱問題。
- 函數功能:計算兩個數據集之間的歐式距離
- 輸入:兩個 array 數據集
- 返回:兩個數據集之間的歐氏距離(此處用距離平方和代替距離)
2.2.3 編寫隨機生成質心函數
在定義隨機質心生成函數時,首先需要計算每列數值的范圍,然后從該范圍中隨機生成指定個數的質心。此處我們使用 numpy.random.uniform()函數生成隨機質心。
- 函數功能:隨機生成 k 個質心
- 參數說明:
dataSet:包含標簽的數據集
k:簇的個數 - 返回:
data_cent:K 個質心
2.2.4 編寫 K-Means 聚類函數
這一部分相對來說比較麻煩一點,python基礎不是很好的朋友也不用太過在意,了解為主,而且之后也會介紹如何利用sklearn實現K-Means算法。
在執行 K-Means 的時候,需要不斷的迭代質心,因此我們需要兩個可迭代容器來完成該目標:
第一個容器用于存放和更新質心,該容器可考慮使用 list 來執行,list 不僅是可迭代對象,同時 list內不同元素索引位置也可用于標記和區分各質心,即各簇的編號;即代碼中的 centroids。
第二個容器則需要記錄、保存和更新各點到質心之間的距離,并能夠方便對其進行比較,該容器考慮使用一個三列的數組來執行,其中:
- 第一列用于存放最近一次計算完成后某點到各質心的最短距離。
- 第二列用于記錄最近一次計算完成后根據最短距離得到的代表對應質心的數值索引,即所屬簇,即質心的編號。
- 第三列用于存放上一次某點所對應質心編號(某點所屬簇),后兩列用于比較質心發生變化后某點所屬簇的情況是否發生變化。
函數功能:k-均值聚類算法
參數說明:
- dataSet:帶標簽數據集
- k:簇的個數
- distMeas:距離計算函數
- createCent:隨機質心生成函數
返回:
- centroids:質心
- result_set:所有數據劃分結果
鳶尾花數據集帶進去,查看模型運行效果:
iris_cent,iris_result = kMeans(iris, 3) iris_cent iris_result.head()
以上代碼編寫時,有以下幾點需要特別注意:
- 設置統一的操作對象 result_set
為了調用和使用的方便,此處將 clusterAssment 轉換為了 DataFrame 并與輸入 DataFrame 合并,組成的對象可作為后續調用的統一對象,該對象內即保存了原始數據,也保存了迭代運算的中間結果,包括數據所屬簇標記和數據質心距離等,該對象同時也作為最終函數的返回結果; - 判斷質心發生是否發生改變條件
注意,在 K-Means 中判斷質心是否發生改變,即判斷是否繼續進行下一步迭代的依據并不是某點距離新的質心距離變短,而是某點新的距離向量(到各質心的距離)中最短的分量位置是否發生變化,即質心變化后某點是否應歸屬另外的簇。在質心變化導致各點所屬簇發生變化的過程中,點到質心的距離不一定會變短,即判斷條件不能用下述語句表示
- 質心和類別一一對應
即在最后生成的結果中,centroids 的行標即為 result_set 中各點所屬類別。
2.2.5 算法驗證
函數編寫完成后,先以 testSet 數據集測試模型運行效果(為了可以直觀看出聚類效果,此處采用一個二維數據集進行驗證)。testSet 數據集是一個二維數據集,每個觀測值都只有兩個特征,且數據之間采用空格進行分隔,因此可采用 pd.read_table()函數進行讀取。
testSet = pd.read_csv(r"testSet.txt", sep='\t') testSet.head() testSet.shape
然后利用二維平面圖形觀察其分布情況:
可以大概看出數據大概分布在空間的四個角上,后續我們將對此進行驗證。然后利用我們剛才編寫的 K-Means 算法對其進行聚類,在執行算法之前需要添加一列虛擬標簽列(算法是從倒數第二列開始計算特征值,因此這里需要人為增加多一列到最后)
然后帶入算法進行計算,根據二維平面坐標點的分布特征,我們可考慮設置四個質心,即將其分為四個簇,并簡單查看運算結果:
將分類結果進行可視化展示,使用 scatter 函數繪制不同分類點不同顏色的散點圖,同時將質心也放入同一張圖中進行觀察:
從圖的結果來看,結果還是非常符合我們預期的。
結束語
那么到這里,關于我們無監督學習及K-Means算法的介紹先告一段落啦。在下一篇文章中,我會介紹如何利用sklearn玩轉K-Means算法,以及無監督算法模型如何評估,感興趣的朋友可以關注我下面的專欄啦。
推薦關注的專欄
👨?👩?👦?👦 機器學習:分享機器學習實戰項目和常用模型講解
👨?👩?👦?👦 數據分析:分享數據分析實戰項目和常用技能整理
機器學習系列往期回顧
💚 以??簡單易懂??的語言帶你搞懂邏輯回歸算法【附Python代碼詳解】機器學習系列之邏輯回歸篇
?? 一文帶你用Python玩轉線性回歸模型 ??加利福尼亞房價預測??回歸模型評估指標介紹
💜 如何搞懂機器學習中的線性回歸模型?機器學習系列之線性回歸基礎篇
🖤 你真的了解分類模型評估指標都有哪些嗎?【附Python代碼實現】
💙 一文帶你用Python玩轉決策樹 ??畫出決策樹&各種參數詳細說明??決策樹的優缺點又有哪些?
🧡 開始學習機器學習時你必須要了解的模型有哪些?機器學習系列之決策樹進階篇
💚 開始學習機器學習時你必須要了解的模型有哪些?機器學習系列之決策樹基礎篇
?? 以??簡單易懂??的語言帶你搞懂有監督學習算法【附Python代碼詳解】機器學習系列之KNN篇
💜 開始學習機器學習之前你必須要了解的知識有哪些?機器學習系列入門篇
往期內容回顧
🖤 我和關注我的前1000個粉絲“合影”啦!收集前1000個粉絲進行了一系列數據分析,收獲滿滿
💚 MySQL必須掌握的技能有哪些?超細長文帶你掌握MySQL【建議收藏】
💜 Hive必須了解的技能有哪些?萬字博客帶你掌握Hive??【建議收藏】
關注我,了解更多相關知識!
CSDN@報告,今天也有好好學習
總結
以上是生活随笔為你收集整理的以《简单易懂》的语言带你搞懂无监督学习算法【附Python代码详解】机器学习系列之K-Means篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 科技「垦荒」,AI护虎
- 下一篇: Linux清理入侵痕迹