Python 機器學習實戰 —— 無監督學習(下)
- 2021 年 8 月 10 日
- 筆記
- Agglomerative, AI人工智慧, DBSCAN, GMM, KMeans, NMF, PCA, SpectralClustering, 無監督學習, 機器學習
前言
在上篇《 Python 機器學習實戰 —— 無監督學習(上)》介紹了數據集變換中最常見的 PCA 主成分分析、NMF 非負矩陣分解等無監督模型,舉例說明使用使用非監督模型對多維度特徵數據集進行降維的意義及實用方法。對 MDS 多維標度法、LLE 局部線性嵌入法、Isomap 保距映射法、t-SNE 分布鄰域嵌入演算法等 ML 流形學習模型的基礎使用方法進行講解。
本文將對聚類演算法進行講解,聚類演算法就是將數據集劃分成組的任務,這些組叫成簇,同一個簇內的數據點特徵非常相似,不同簇內的數據點特徵區別很大,這點與監督學習中的分類演算法很類似,運行完成後系統會為同一簇內的數據分配同一個數字,不同簇的數字都不一樣。常見的聚類模型有 KMeans、DBSCAN、GMM 、Agglomerative 等,下面將一一介紹。
目錄
四、KMeans 均值聚類
4.1 KMeans 的基本原理
KMeans 均值聚類是最簡單最常用的聚類演算法之一,它會嘗試找到代表數據區域的簇中心,並保存在 cluster_centers 屬性中。再把每個數據點分配給最接近的簇中心,並把每個簇中心設置為所分配數據點的平均值。當簇中心的值根據模型運算設置不再發生變化時,演算法結束。
構造函數
1 class KMeans(TransformerMixin, ClusterMixin, BaseEstimator): 2 @_deprecate_positional_args 3 def __init__(self, n_clusters=8, *, init='k-means++', n_init=10, 4 max_iter=300, tol=1e-4, precompute_distances='deprecated', 5 verbose=0, random_state=None, copy_x=True, 6 n_jobs='deprecated', algorithm='auto'):
- n_clusters:int 類型,默認為8,代表生成簇中心數目
- init:選擇 {』k-means++』, 『random 』} 之一, 或者傳遞一個ndarray向量,代表初始化方式,默認值為 『k-means++』。『k-means++』 用一種特殊的方法選定初始聚類中發,可加速迭代過程的收斂;『random』 隨機從訓練數據中選取初始質心。如果傳遞的是一個ndarray,則應該形如 (n_clusters, n_features) 並給出初始質心。
- n_init:int 類型,默認值為10,用不同的聚類中心初始化值運行演算法的次數,最終解是在 inertia 意義下選出的最優結果。
- max_iter: int 類型,默認值為 300 ,代表模型優化的最大迭代數。
- tol:float類型,默認值為 1e-4 ,代表求解方法精度
- precompute_distances: 可選值 {『auto』,True,False }, 代表預計算距離,計算速度更快但佔用更多記憶體。『auto』:如果 樣本數乘以聚類數大於 12million 的話則不預計算距離;True:總是預先計算距離;False:永遠不預先計算距離。』 deprecated 『 舊版本使用,新版已丟棄。
- verbose: int 類型,默認為 0,詳細程度。
- random_state:默認值為None 隨機數種子,推薦設置一個任意整數,同一個隨機值,模型可以復現
- copy_x: bool 類型,默認值True。當 precomputing distances 生效時,將數據中心化會得到更準確的結果。如果把此參數值設為True,則原始數據不會被改變。如果是False,則會直接在原始數據上做修改並在函數返回值時將其還原。但是在計算過程中由於有對數據均值的加減運算,數據返回後,原始數據和計算前可能會有細小差別。
- n_jobs:int 類型,默認為 None, CPU 並行數。內部原理是同時進行n_init指定次數的計算時,若值為 -1,則用所有的CPU進行運算。若值為1,則不進行並行運算。若值小於-1,則用到的CPU數為(n_cpus + 1 + n_jobs)。因此如果 n_jobs值為-2,則用到的CPU數為總CPU數減1。』 deprecated 『 舊版本使用,新版已丟棄。
- algorithm: str 類型,{ auto,full,elkan } 三選一。full就是一般意義上的K-Means演算法; elkan是使用的elkan K-Means演算法; auto則會根據數據值是否是稀疏的(稀疏一般指是有大量缺失值),來決定如何選擇full 和 elkan。如果數據是稠密的,就選擇elkan K-means,否則就使用普通的Kmeans演算法。
常用參數
- cluster_centers_: 代表簇中心 ,訓練後簇中心都會被保存在此屬性中
- labels_:返回數據點所屬的簇標誌,與 predict 方法返回值相同
4.2 KMeans 的應用場景
下面先用簡單的 make_blobs 數據集了解 KMeans 的基礎使用方式,KMeans 模型在分別把簇中心設置為 3 和 5,觀察一下數據的變化。注意測試數據集中默認為 3 類,然而 KMeans 是無監督學習模型,不會使用數據集給出的結果進行分類,而是按照 n_clusters 的設置進行分類。這是 KMeans 模型的優點也可以說是缺點,雖然沒有受數據集類型的限制,然而在運行前必須先設置簇的數量。實事上在現實場景中,很多數據事先是無法確定簇數量的。
1 def kmean_test(n): 2 #生成數據集 3 X, y = datasets.make_blobs(n_samples=100, n_features=2, random_state=1) 4 #使用KMeans模型,3個簇中心 5 kmean=KMeans(n_clusters=n) 6 model=kmean.fit_predict(X) 7 #顯示運算結果 8 plt.scatter(X[:,0],X[:,1],s=50,c=model,marker='^') 9 plt.xlabel('feature0') 10 plt.ylabel('feature1') 11 #顯示簇中心 12 center=kmean.cluster_centers_ 13 plt.scatter(center[:,0],center[:,1],s=200,color='red',marker='.') 14 #顯示簇邊界 15 radii=[cdist(X[model==i],[center]).max() for i,center in enumerate(center)] 16 for c,r in zip(center,radii): 17 axes.add_patch(plt.Circle(c,r,alpha=0.3,zorder=1)) 18 plt.show() 19 20 if __name__=='__main__': 21 kmean_test(3) 22 kmean_test(5)
3 簇中心運行結果
5 簇中心運行結果
下面例子嘗試利用 digits 數據集,通過 KMeans 訓練,再查看一下分辨手寫數字的準確率,可見單憑 KMeans 模型已經可以分辨手寫數字的準確率到達將近80% 。
1 def kmean_test(): 2 # 輸入測試數據 3 digits=datasets.load_digits() 4 #使用KMeans模型,10個簇中心 5 kmean=KMeans(10) 6 #訓練數據 7 model=kmean.fit_predict(digits.data) 8 #計算匹配度 9 labels=np.zeros_like(model) 10 for i in range(10): 11 mask=(model==i) 12 labels[mask]=mode(digits.target[mask])[0] 13 #計算準確率 14 acc=accuracy_score(digits.target,labels) 15 print(acc)
運行結果
還記得在上一篇文章《 Python 機器學習實戰 —— 無監督學習(上)》介紹 ML 流形學習中曾經提過, t-SNE 模型是一個非線性嵌入演算法,特別擅長保留簇中的數據點。在此嘗試把 KMeans 與 t-SNE 相結合一起使用,有意想不到的效果。
運行後可以發現末經過調試的演算法,準確率已經可以達到 94% 以上。可見,只要適當地運用無監督學習,也能夠精準地實現數據的分類。
1 def kmean_test(): 2 # 輸入測試數據 3 digits=datasets.load_digits() 4 #使用t-SNE 模型進行訓練 5 tsne=TSNE() 6 model0=tsne.fit_transform(digits.data) 7 #使用KMeans模型進行訓練 8 kmean=KMeans(10) 9 model1=kmean.fit_predict(model0) 10 #計算匹配度 11 labels=np.zeros_like(model1) 12 for i in range(10): 13 mask=(model1==i) 14 labels[mask]=mode(digits.target[mask])[0] 15 #計算準確率 16 acc=accuracy_score(digits.target,labels) 17 print(acc)
運行結果
4.3 通過核轉換解決 KMeans 的非線性數據問題
雖然 KMeans 模型適用的場景很多,然而 KMeans 也有一個問題就是它只能確定線性聚類邊界,當簇中心點呈現非線性的複雜形狀時,此演算法是不起作用的。例如以 make_moons 數據集為例,把 noise 參數設置為 0.04,用 KMeans 模型進行測試。分別把 n_clusters 設置為 2 和 10,運行一下程式,可見單憑 KMeans 模型是無法分開複雜形狀的非線性數據的。
1 def kmean_test(n): 2 #生成數據集 3 X, y = datasets.make_moons(n_samples=300, noise=0.04,random_state=1) 4 #使用KMeans模型,n個簇中心 5 kmean=KMeans(n_clusters=n) 6 model=kmean.fit_predict(X) 7 #顯示運算結果 8 plt.scatter(X[:,0],X[:,1],s=50,c=model,marker='^') 9 plt.xlabel('feature0') 10 plt.ylabel('feature1') 11 #顯示簇中心 12 center=kmean.cluster_centers_ 13 plt.scatter(center[:,0],center[:,1],s=200,color='red',marker='.') 14 plt.show() 15 16 if __name__=='__main__': 17 kmean_test(2) 18 kmean_test(10)
n_clusters 為 2 時
n_clusters 為 10 時
此時,大家可能會想起在上一章《 Python 機器學習實戰 —— 監督學習(下)》中提到的核函數技巧,類似地 skLearn 也提供了 SpectralClustering 評估器來完成 KMeans 非線性邊界的問題。
構造函數
1 class SpectralClustering(ClusterMixin, BaseEstimator): 2 @_deprecate_positional_args 3 def __init__(self, n_clusters=8, *, eigen_solver=None, n_components=None, 4 random_state=None, n_init=10, gamma=1., affinity='rbf', 5 n_neighbors=10, eigen_tol=0.0, assign_labels='kmeans', 6 degree=3, coef0=1, kernel_params=None, n_jobs=None, 7 verbose=False):
- n_clusters:int 類型,默認為 8,代表生成簇中心數目
- eigen_solver: {‘arpack’, ‘lobpcg’, ‘amg’,’None’} 之一,默認為 None ,代表特徵值求解的策略 。
- n_components:int, 默認值為 None。int 時則是直接指定特徵維度數目,此時 n_components是一個大於等於 1 的整數。當使用默認值,即不輸入n_components,此時n_components=min(樣本數,特徵數)。
- random_state:int 類型,默認值為None, 隨機數種子,推薦設置一個任意整數,同一個隨機值,模型可以復現。
- n_init: int 類型,默認為值 10,當 assign_labels 為 』kmeans’ 時,指定聚類中心初始化值運行演算法的次數。
- gamma:float 類型,默認值為1.0,指高斯核函數的中心值。如果用k近鄰法,則此參數無用。
- affinity:str 類型 {』rbf’,’nearest_neighbors’,’precomputed’ , ‘precomputed_nearest_neighbors’} 之一 或 callable,默認值為 『rbf’ ,用於設定構造矩陣的方法。 『 rbf ‘ 指使用徑向基函數構造矩陣(RBF)高斯內核 ; ‘nearest_neighbors’ 指使用 k近鄰演算法來構造內核; ‘precomputed’ 是將“X“解釋為一個預先計算的親和力矩陣,較大值表示實例之間的相似性更大; ‘precomputed_nearest_neighbors’: 將“X“解釋為稀疏圖,從每個實例的“n_neighbors“的最近鄰居構造一個二進位親和矩陣。
- n_neighbors:int 類型,默認值為10。當 affinity 設定為 『nearest_neighbors』 使用 k 近鄰內核時的鄰居數量,當使用 『rbf』 高斯內核時無效。
- eigen_tol:float 類型,默認值為 0.0。 當`eigen_solver=’arpack’ 時候,設定拉普拉斯矩陣特徵分解的停止判斷依據。
- assign_labels:str 類型 {『kmeans』, 『discretize』} 之一,默認值為 『kmeans’,用於指定分配標籤的策略 。』kmeans『 是較常用的策略,初始化時靈敏性強。 『discretize』 是隨機初始化的另一種策略,靈敏性較弱。
- degree: int 類型,默認值為 3,當 eigen_solver 為 ‘arpack’ 時,設定拉普拉斯矩陣特徵分解的停止判據依據。
- coef0: float參數 默認為1.0,核函數中的獨立項,控制模型受高階多項式的影響程度, 只有對內核為 『poly』和『sigmod』 的核函數有用
- kernel_params: dict 類型 或者 str 類型,默認值為 None ,內核的參數。
- n_job:int 類型,默認值為 None 。當 affinity 為 『nearest_neighbors』 和 『precomputed_nearest_neighbors』 指定 CPU 並行數, 為 -1 指運行所有 CPU, 為 None 時只運行1個CPU。
- verbose: int 類型,默認為 0,詳細程度。
嘗試 SpectralClustering 評估器來完成非線性數據的分類問題,把 affinity 設置 ‘nearest_neighbors『 使用 k 近鄰演算法內核,assign_labels 設置為 ‘kmeans’ 策略。從運行結果可以看到,SpectralClustering 使用 k 近鄰內核完美地實現了數據邊界的分離。
1 def kmean_test(): 2 #生成數據集 3 X, y = datasets.make_moons(n_samples=300, noise=0.04,random_state=1) 4 #使用SpectralClustering評估器 5 spectral=SpectralClustering(n_clusters=2,affinity='nearest_neighbors',assign_labels='kmeans') 6 model=spectral.fit_predict(X) 7 #顯示運算結果 8 plt.scatter(X[:,0],X[:,1],s=50,c=model,marker='^') 9 plt.xlabel('feature0') 10 plt.ylabel('feature1') 11 plt.show()
運行結果
五、GMM 高斯混合模型
5.1 GMM 的基本原理
由於 KMeans 模型是圍繞著簇中心而計算的,造成當中存在短板,數據點分配是依賴簇中心到數據點的平均值的,因此簇的模型必須是圓形的(在上節的例子中可以看出)。當簇中心比較接近時,數據點分配就會發生重疊而引起混亂。
為解決 KMeans 模型的問題,GMM 高斯混合模型應運而生,它會改 KMeans 模型簇邊界的計算方式,把圓形改成橢圓形,讓數據邊界更明顯。
構造函數
1 class GaussianMixture(BaseMixture): 2 @_deprecate_positional_args 3 def __init__(self, n_components=1, *, covariance_type='full', tol=1e-3, 4 reg_covar=1e-6, max_iter=100, n_init=1, init_params='kmeans', 5 weights_init=None, means_init=None, precisions_init=None, 6 random_state=None, warm_start=False, 7 verbose=0, verbose_interval=10):
- n_components: int 類型,默認為1,設定混合高斯模型個數
- covariance_type: str 類型 {『full』,『tied』, 『diag』, 『spherical 』} 之一,選擇四種協方差類型,默認值為 『full』 完全協方差矩陣。full: 對應完全協方差矩陣(元素都不為零), 每個分量都有各自的一般協方差矩陣 ; tied: 相同的完全協方差矩陣(HMM會用到)所有的分量都共享相同的一般協方差矩陣; 』 diag’: 對角協方差矩陣(非對角為零,對角不為零)每個分量都有各自的對角協方差矩陣 ; 『spherical’: 球面協方差矩陣(非對角為零,對角完全相同,球面特性),每個組件都有它自己的單一方差。
- tol:float 類型,默認為1e-3,EM迭代停止閾值。
- reg_covar: float 類型,默認為 1e-6,協方差對角非負正則化,保證協方差矩陣均為正。
- max_iter: int 類型,默認值 100,最大迭代次數。
- n_init: int 類型,默認為1,初始化次數,指定聚類中心初始化值運行演算法的次數。
- init_params: str 類型,{『kmeans』, 『random』} 之一,默認值 kmeans ,初始化參數實現方式
- weights_init: array 類型 (n_components, ) ,默認為 None ,用戶提供的初始權重,若為空時,則使用 init _params 方法進行初始化。
- means_init: array 類型 (n_components, n_features), 默認為 None ,用戶提供的初始權重,若為空時,則使用 init _params 方法進行初始化。
- precisions_init: array 類型 ,默認為 None ,用戶提供的初始權重,若為空時,則使用 init _params 方法進行初始化。當 covariance_type 為 full 則為 (n_components, n_features, n_features) 格式; ‘diag’ 時格式為 (n_components, n_features) ; ‘tied’ 時格式為 (n_features, n_features); ‘spherical’ 時格式為 (n_components, )
- random_state :int 類型,默認值為None, 隨機數種子,推薦設置一個任意整數,同一個隨機值,模型可以復現。
- warm_start : bool 類型,默認為 False,若為True,則fit()調用會以上一次fit()的結果作為初始化參數,適合相同問題多次fit的情況,能加速收斂。
- verbose :int 類型,默認為0,使能迭代資訊顯示,可以為1或者大於1(顯示的資訊不同)
- verbose_interval :int 類型,默認10次,與 verbose 掛鉤,若使能迭代資訊顯示,設置多少次迭代後顯示資訊。
參數說明
- weights_:array, 混合條件的權重
- means_:array, 均值
- covariances_: array 協方差陣
- converged_: bool 是否收斂
方法說明
- predict_proba(X):返回 [n_samples,n_clusters],預測給定的數據點屬於某個簇的概率
- predict_proba() :預測所有數據點屬於某個簇的概率
- score_samples(X):計算某個數據點樣本的屬於某個簇的加權對數概率
繼續使用 make_blobs 數據集進行測試,適當修改數據點之間的間距,使用 GMM 模型進行計算,將為每個數據點找到對應每個簇的概率作為權重,然後更新每個簇的位置,將其標準化,最後把所有數據點的權重來確定形狀。如此一來,數據點跟預期一樣更為集中,數據邊界會根據數據點的分布形成橢圓形。
1 def draw_ellipse(position, covariance, ax=None, **kwargs): 2 # 計算圖形邊界 3 if covariance.shape == (2, 2): 4 U, s, Vt = np.linalg.svd(covariance) 5 angle = np.degrees(np.arctan2(U[1, 0], U[0, 0])) 6 width, height = 2 * np.sqrt(s) 7 else: 8 angle = 0 9 width, height = 2 * np.sqrt(covariance) 10 # 畫圖 11 for nsig in range(1, 4): 12 ax.add_patch(Ellipse(position, nsig * width, nsig * height, 13 angle, **kwargs)) 14 15 def gmm_test(): 16 #測試數據集 17 X, y = datasets.make_blobs(n_samples=100,centers=4,n_features=2,random_state=1) 18 #修改數據點間距 19 rng=np.random.RandomState(12) 20 X1=np.dot(X,rng.randn(2,2)) 21 fig,axes=plt.subplots(1,1) 22 #使用GMM模型 23 gmm=GaussianMixture(n_components=4,random_state=28) 24 model=gmm.fit_predict(X1) 25 #顯示運算結果 26 plt.scatter(X1[:,0],X1[:,1],s=50,c=model,marker='^') 27 plt.xlabel('feature0') 28 plt.ylabel('feature1') 29 #顯示簇邊界 30 n=0.2/gmm.weights_.max() 31 for mean,covar,weight in zip(gmm.means_,gmm.covariances_,gmm.weights_): 32 draw_ellipse(mean,covar,ax=axes,alpha=weight*n) 33 plt.show() 34 35 if __name__=='__main__': 36 gmm_test()
運行結果
六、Agglomerative 凝聚聚類
Agglomerative 凝聚聚類演算法首先會聲明每個點都是一個簇,然後合併兩個最相似的簇,直到滿足設定條件準則為止。這個準則可以通過 linkage 參數確定,linkage 為 { ‘ward’, ‘complete’, ‘average’, ‘single’ } 之一,下面將會詳細說明。
觀察下面系統自帶的合併過程,當運行到第4步後,兩點最相近的簇完成合併,到第5步一個兩點簇增加到三個點,當三個點的簇完成合併後,到第8步,五點的簇開始合併,如此類推,到最後完成合併任務。
構造函數
1 class AgglomerativeClustering(ClusterMixin, BaseEstimator): 2 @_deprecate_positional_args 3 def __init__(self, n_clusters=2, *, affinity="euclidean", 4 memory=None, 5 connectivity=None, compute_full_tree='auto', 6 linkage='ward', distance_threshold=None, 7 compute_distances=False):
- n_clusters:int 類型,默認值為2,指定最終分類簇的數量
- affinity:str 類型,{ 』euclidean』,』l1』,』l2』,』mantattan』,』cosine』,』precomputed』 }之一,默認值為 』euclidean』 ,作用是選擇一個計算距離的可調用對象。當 linkage=』ward』,affinity 只能為』euclidean』
- memory:str 類型,默認值為 None, 用於快取計算結果的輸出,默認不作任何快取。如果設定字元串路徑,則它會快取到對應的路徑。
- connectivity:array-like 或 callable 類型,默認為 None,用於指定連接矩陣,臨近的數據將使用相同的結構。
- compute_full_tree:bool 類型,默認值為 auto,當訓練了 n_clusters後,訓練過程就會停止,但是如果 compute_full_tree=True,則會繼續訓練從而生成一顆完整的樹。當 distance_threshold 不為 None 時,則 compute_full_tree 必須為是 True。
- linkage:str 類型, { ‘ward’, ‘complete’, ‘average’, ‘single’ } 之一,默認值為 ‘ward’ 一個字元串,用於指定鏈接演算法。『ward』:單鏈接 single-linkage,使所有簇中的方差 dmindmin 增加最小的簇合併; 『complete』:全鏈接 complete-linkage 演算法,使簇中點之間的最大距離 dmaxdmax 最小的兩個簇合併 ; ‘average』:均連接 average-linkage 演算法,使簇中所有點之間平均距離 davgdavg 最小的兩個簇合併。』single’ :新增於 0.20 版,使簇中所有點距離最小的兩個簇合併。
- distance_threshold:float 類型,默認值為 None,鏈接距離閾值超過此設置,集群將不會合併。當使用此設置時,『n_clusters』 必須是 None 和 ‘compute_full_tree’ 必須是 True 。
- compute_distances:bool 類型,默認值為 False,當不使用 distance_threshold 時,計算簇之間的距離。此功能可以用於使樹狀圖可視化,但此計算將消耗電腦的記憶體。
使用 make_blobs 數據集作測試,把 n_cluster3 設置為 3,由於 AgglomerativeClustering 沒有 predict 方法,可以直接使用 fit_predict 方法進行計算。完成計算後,可以利用 SciPy 的 dendrogram 函數繪製樹狀圖,以觀察簇的構建過程。
1 def agglomerative_test(): 2 # 測試數據集 3 X,y=make_blobs(random_state=1) 4 # 使用 AgglomerativeClustering模型 5 agglomerative=AgglomerativeClustering(n_clusters=3) 6 # 開始運算 7 model=agglomerative.fit_predict(X) 8 # 顯示簇合併結果 9 fig, axes = plt.subplots(1, 2, figsize=(10,5)) 10 ax0=axes[0] 11 ax0.scatter(X[:,0],X[:,1],s=50,c=model,marker='^') 12 # 顯示樹狀圖 13 ax1=axes[1] 14 shc.dendrogram(shc.ward(X[::5])) 15 plt.show()
運行結果
七、DBSCAN 密度聚類
DBSCAN 密度聚類是最常用的模型之一,一般用於分析形狀比較複雜的簇,還可找到不屬於任何簇的數據點。上面介紹到的 KMeans 模型、SpectralClustering 評估器、Agglomerative 模型都需要在建立模型前通過 n_clusters 參數預先設置簇的個數,然而在複雜的數據中,單憑簡單的數據分析去正確評估簇數據是很困難的。 DBSCAN 的優點在於它不需要預先設置簇的個數,而是通過特徵空間的數據點密度來區分簇。DBSCAN 最常用到的參數是 eps 和 min_samples,eps 是用於設定距離,DBSCAN 將彼此距離小於 eps 設置值的核心樣本放在同一個簇。min_samples 則用於設置同一簇內數據點的最少數量,如果數據點數量少於此設置則把這此點默認為噪點 noise,數據點數量大於等於此數值時則默認一個簇。
1 class DBSCAN(ClusterMixin, BaseEstimator): 2 @_deprecate_positional_args 3 def __init__(self, eps=0.5, *, min_samples=5, metric='euclidean', 4 metric_params=None, algorithm='auto', leaf_size=30, p=None, 5 n_jobs=None):
- esp:float 類型,默認值為 0.5,用於設定距離,DBSCAN 將彼此距離小於 eps 設置值的核心樣本放在同一個簇。
- min_samples: int 類型,默認值為5,用於設置同一簇內數據點的最少數量,如果數據點數量少於此設置則把這此點默認為噪點 noise,數據點數量大於等於此數值時則默認一個簇。
- metric:string 或 callable 類型,[‘cityblock’, ‘cosine’, ‘euclidean’, ‘l1’, ‘l2’, ‘manhattan’] 之一,默認值為 『euclidean』, 用於定義計算數據點之間的距離時使用的度量。使用歐式距離 「euclidean」; 使用曼哈頓距離 「manhattan」;
- metric_params: dict 類型,默認值為 None,根據 metric 選擇填入相關參數。
- algorithm:str 類型,{‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’} 之一,默認值為 auto,定義計算近鄰數據點的方法。 『auto』:會在上面三種演算法中做權衡,選擇一個擬合最好的最優演算法。『ball_tree』 球面樹搜索,數據點比較分散時可試用 ball_tree; kd_tree: kd樹搜索,數據點分布比較均勻時效率較高; 『brute』:暴力搜索;
- leaf_size:int 類型,默認為30,定義停止建立子樹的葉子節點數量的閾值。 最近鄰搜索演算法參數,為使用KD樹或者球樹時, 這個值越小,則生成的KD樹或者球樹就越大,層數越深,建樹時間越長,反之,則生成的KD樹或者球樹會小,層數較淺,建樹時間較短。
- p: 最近鄰距離度量參數。只用於閔可夫斯基距離和帶權重閔可夫斯基距離中p值的選擇,p=1為曼哈頓距離, p=2為歐式距離。如果使用默認的歐式距離不需要管這個參數。
- n_jobs:CPU 並行數,默認為None,代表1。若設置為 -1 的時候,則用所有 CPU 的內核運行程式。
使用 make_blobs 數據集,分別把 eps 設置為 0.5,1.0,1.5,觀察一下測試結果,紫藍色的是噪點。隨著 eps 的增大,噪點越來越少,測試結果也越來越接近真實數據。然而 eps 對結果的影響也很大,如果 eps 設置得過大,可能會導致所有數據點形成同一個簇,如果 eps 太小,可能會導致所有數據點都是噪點。
1 def dbscan_test(eps,title): 2 # 測試數據集 3 X,y=datasets.make_blobs(random_state=1) 4 # 使用DBSCAN,輸入eps參數 5 dbscan=DBSCAN(eps=eps) 6 model=dbscan.fit_predict(X) 7 # 顯示測試後結果 8 plt.scatter(X[:,0],X[:,1],c=model,s=50,marker='^') 9 plt.xlabel('feature0') 10 plt.ylabel('feature1') 11 plt.title(title) 12 plt.show() 13 14 if __name__=='__main__': 15 dbscan_test(0.5,'EPS:0.5 ') 16 dbscan_test(1,'EPS 1') 17 dbscan_test(1.5,'EPS 1.5')
運行結果
eps = 0.5
eps = 1.0
eps = 1.5
使用相同數據集,把 eps 設置為1.0,嘗試修改 min_samples 參數,看看參數對模型的影響,紫藍色為噪點。隨著 min_samples 的減少,測試結果也越來越接近真實數據。
1 def dbscan_test(min,title): 2 # 測試數據集 3 X,y=datasets.make_blobs(random_state=1) 4 # 使用DBSCAN,輸入eps,min_samples參數 5 dbscan=DBSCAN(eps=1.0,min_samples=min) 6 model=dbscan.fit_predict(X) 7 # 顯示測試後結果 8 plt.scatter(X[:,0],X[:,1],c=model,s=50,marker='^') 9 plt.xlabel('feature0') 10 plt.ylabel('feature1') 11 plt.title(title) 12 plt.show() 13 14 if __name__=='__main__': 15 dbscan_test(20,'MIN SAMPLES 20') 16 dbscan_test(10,'MIN SAMPLES 10') 17 dbscan_test(5,'MIN SAMPLES 5')
運行結果
min_samples = 20
min_samples = 10
min_samples = 5
第四節介紹 KMeans 模型時曾經介紹到 KMeans 模型是無法分開複雜形狀的非線性數據的,只能用到 SpectralClustering 評估器來解決此類問題。然而 DBSCAN 模型的密度分布演算法側可以輕鬆地解決此類問題,同樣使用 make_moons 數據集,使用 DBSCAN 模型時把 eps 設置為0.4,min_samples 設置為30。通過測試結果可以看出,只需要利用 DBSCAN 模型最常用的參數配置就可以解決複雜的非線性數據問題。
1 def dbscan_test(title): 2 # 測試數據集 3 X, y = datasets.make_moons(n_samples=300, noise=0.04,random_state=1) 4 # 使用DBSCAN,輸入eps,min_samples參數 5 dbscan=DBSCAN(eps=0.4,min_samples=30) 6 model=dbscan.fit_predict(X) 7 # 顯示測試後結果 8 plt.scatter(X[:,0],X[:,1],c=model,s=50,marker='^') 9 plt.xlabel('feature0') 10 plt.ylabel('feature1') 11 plt.title(title) 12 plt.show() 13 14 if __name__=='__main__': 15 dbscan_test('DBSCAN')
運行結果
在前一章《 Python 機器學習實戰 —— 無監督學習(上)》中介紹到的 PCA 模型, 下面這個例子就是先利用PCA模型對數據特徵進行降維處理,然後再使用 DBSCAN 找出噪點,觀察一下噪點與簇數據的區別出自哪裡。使用 fetch_lfw_person 數據集,利用 PCA 模型把主要成分保持在 95%,完成訓練後再使用 DBSCAN 模型,把 eps 設置為 23,min_samples 設置 3 ,再進行訓練。
最後把噪點通過主要成分還原數據進行顯示,從運行結果可以看到,噪點主要是因為人物有帶帽子,眯著眼睛,張開嘴巴,用手捂嘴等動作造成的。 通過噪點分析,能找出很多有趣的與別不同的特徵。
1 def dbscan_test(): 2 # 測試數據集 3 person = datasets.fetch_lfw_people() 4 # 使用PCA模型把特徵降至60 5 pca=PCA(0.95,whiten=True,random_state=1) 6 pca_model=pca.fit_transform(person.data) 7 # 使用DBSCAN,輸入eps,min_samples參數 8 dbscan=DBSCAN(eps=23,min_samples=3) 9 model=dbscan.fit_predict(pca_model) 10 # 顯示測試後結果 11 fig,axes=plt.subplots(5, 5, figsize=(25,25)) 12 # 獲取噪點的特徵成分圖 13 noise=pca_model[model==-1] 14 # 輸出噪點數量 15 print(str.format('noise len is {0}'.format(len(noise)))) 16 for componemt,ax in zip(noise,axes.ravel()): 17 # 獲取噪點提取成分後還原圖 18 image=pca.inverse_transform(componemt) 19 ax.imshow(image.reshape(62, 47), cmap = 'viridis') 20 plt.show()
運行結果
本章總結
本單主要介紹了 KMeans、GMM 、Agglomerative 、DBSCAN 等模型的使用,KMeans 是最常用最簡單的模型,它嘗試根據 n_clusters 設置找到代表數據區域的簇中心。而 GMM 可以看成是升級版的 KMeans ,它會改 KMeans 模型簇邊界的計算方式,把圓形改成橢圓形,讓數據邊界更明顯。Agglomerative 則更類似於樹模型,使用近鄰合併的模型,把相近的數據點合併為簇。DBSCAN 是更智慧化的模型,通過數據點的聚集程度判斷簇中心,在沒有設置固定 n_clusters 的情況下分配出符合實際情況的簇。
對機器學習的原理及應用場景介紹到這裡結束,後面將開始講述深度學習的相關內容,敬請留意。
希望本篇文章對相關的開發人員有所幫助,由於時間倉促,錯漏之處敬請點評。