前言

在上篇《 Python 機器學習實戰 —— 無監督學習(上)》介紹了資料集變換中最常見的 PCA 主成分分析、NMF 非負矩陣分解等無監督模型,舉例說明使用使用非監督模型對多維度特徵資料集進行降維的意義及實用方法。對 MDS 多維標度法、LLE 區域性線性嵌入法、Isomap 保距對映法、t-SNE 分佈鄰域嵌入演算法等 ML 流形學習模型的基礎使用方法進行講解。
本文將對聚類演算法進行講解,聚類演算法就是將資料集劃分成組的任務,這些組叫成簇,同一個簇內的資料點特徵非常相似,不同簇內的資料點特徵區別很大,這點與監督學習中的分類演算法很類似,執行完成後系統會為同一簇內的資料分配同一個數字,不同簇的數字都不一樣。常見的聚類模型有 KMeans、DBSCAN、GMM 、Agglomerative 等,下面將一一介紹。

目錄

一、PCA 主成分分析

二、NMF 非負矩陣分解

三、ML 流形學習

四、KMeans 均值聚類

五、GMM 高斯混合模型

六、Agglomerative 凝聚聚類

七、DBSCAN 密度聚類

四、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 的情況下分配出符合實際情況的簇。

對機器學習的原理及應用場景介紹到這裡結束,後面將開始講述深度學習的相關內容,敬請留意。
希望本篇文章對相關的開發人員有所幫助,由於時間倉促,錯漏之處敬請點評。

對 .Python  開發有興趣的朋友歡迎加入QQ群:790518786 共同探討 !
對 JAVA 開發有興趣的朋友歡迎加入QQ群:174850571 共同探討!
對 .NET  開發有興趣的朋友歡迎加入QQ群:162338858共同探討 !

機器學習相關文章

Python 機器學習實戰 —— 監督學習(上)

Python 機器學習實戰 —— 監督學習(下)

Python 機器學習實戰 —— 無監督學習(上)

Python 機器學習實戰 —— 無監督學習(下)

作者:風塵浪子

https://www.cnblogs.com/leslies2/p/15071665.html

原創作品,轉載時請註明作者及出處