如何使用Python實現(xiàn)數(shù)據(jù)聚類?KMeans算法

kmeans聚類的核心步驟包括數(shù)據(jù)預處理、模型訓練與結(jié)果評估。1. 數(shù)據(jù)預處理:使用standardscaler對數(shù)據(jù)進行標準化,消除不同特征量綱的影響;2. 模型訓練:通過kmeans類設置n_clusters參數(shù)指定簇數(shù),調(diào)用fit方法訓練模型;3. 獲取結(jié)果:使用labels_屬性獲取每個數(shù)據(jù)點所屬簇,cluster_centers_獲取簇中心坐標;4. 可視化:繪制散點圖展示聚類效果及簇中心;5. k值選擇:結(jié)合手肘法(inertia)和輪廓系數(shù)(silhouette score)確定最佳簇數(shù),提升聚類質(zhì)量;6. 優(yōu)化策略:加強數(shù)據(jù)預處理、增加n_init運行次數(shù)、處理異常值、結(jié)合業(yè)務背景綜合評估結(jié)果或選用其他算法彌補局限性。

如何使用Python實現(xiàn)數(shù)據(jù)聚類?KMeans算法

使用python實現(xiàn)數(shù)據(jù)聚類,KMeans是一個非常常用且直觀的算法。它通過迭代尋找數(shù)據(jù)點到聚類中心的最小距離來劃分簇,Scikit-learn庫提供了非常便捷的實現(xiàn)方式,讓這個過程變得相當高效。

如何使用Python實現(xiàn)數(shù)據(jù)聚類?KMeans算法

在我看來,要用Python實現(xiàn)KMeans聚類,核心步驟其實并不復雜,但有些細節(jié)處理得好不好,直接關系到最終聚類效果的質(zhì)量。

首先,你得準備好數(shù)據(jù)。通常,我們會用numpy或者pandas來處理數(shù)據(jù)。KMeans對數(shù)據(jù)尺度比較敏感,所以數(shù)據(jù)標準化(或者歸一化)幾乎是必不可少的一步。我個人習慣用StandardScaler,它能把數(shù)據(jù)轉(zhuǎn)換成均值為0、方差為1的分布,這樣不同特征之間的量綱差異就不會干擾到距離計算了。

立即學習Python免費學習筆記(深入)”;

如何使用Python實現(xiàn)數(shù)據(jù)聚類?KMeans算法

接著,就是調(diào)用sklearn.cluster里的KMeans。實例化這個類的時候,最關鍵的參數(shù)就是n_clusters,也就是你希望把數(shù)據(jù)分成多少個簇。說實話,這個K值的選擇,有時候真有點像門藝術,需要結(jié)合業(yè)務理解和一些經(jīng)驗方法。

然后,用fit方法把模型訓練起來,它會自動找到最佳的聚類中心。訓練完之后,你可以通過labels_屬性獲取每個數(shù)據(jù)點所屬的簇,cluster_centers_則會給出每個簇的中心點坐標。

如何使用Python實現(xiàn)數(shù)據(jù)聚類?KMeans算法

import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler from sklearn.datasets import make_blobs # 用于生成示例數(shù)據(jù)  # 1. 生成一些示例數(shù)據(jù) # 假設我們有3個自然的簇 X, y = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)  # 2. 數(shù)據(jù)預處理:標準化 # 這一步非常關鍵,特別是當你的特征有不同量綱時 scaler = StandardScaler() X_scaled = scaler.fit_transform(X)  # 3. 初始化并訓練KMeans模型 # 這里我們假設知道有4個簇,實際應用中K的確定是難點 # n_init='auto' 是Scikit-learn 1.2+ 的推薦設置,它會運行多次并選擇最佳結(jié)果 kmeans = KMeans(n_clusters=4, random_state=0, n_init='auto') kmeans.fit(X_scaled)  # 4. 獲取聚類結(jié)果 labels = kmeans.labels_ centers = kmeans.cluster_centers_  # 5. 可視化結(jié)果(可選,但強烈推薦) plt.figure(figsize=(8, 6)) # 繪制原始數(shù)據(jù)點,并根據(jù)聚類結(jié)果上色 plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=labels, s=50, cmap='viridis', alpha=0.7) # 繪制聚類中心 plt.scatter(centers[:, 0], centers[:, 1], c='red', s=200, marker='X', label='Cluster Centers') plt.title('KMeans Clustering Results (Scaled Data)') plt.xlabel('Feature 1 (Scaled)') plt.ylabel('Feature 2 (Scaled)') plt.legend() plt.grid(True) plt.show()  print("聚類標簽前5個樣本:", labels[:5]) print("聚類中心:n", scaler.inverse_transform(centers)) # 將中心點逆轉(zhuǎn)換為原始尺度以便理解

這段代碼跑下來,你就能看到數(shù)據(jù)點被分成了幾個不同的顏色區(qū)域,每個區(qū)域都有一個紅色的’X’標記著它的中心。這感覺還是挺直觀的。

如何選擇KMeans算法中的最佳聚類數(shù)量K?

說實話,KMeans最大的一個痛點,就是你得提前告訴它要分多少個簇(K值)。這不像有些算法,能自己發(fā)現(xiàn)簇的數(shù)量。所以,確定這個K值,往往是聚類任務里最讓人頭疼,也最能體現(xiàn)數(shù)據(jù)分析師功力的地方。

最常用的方法之一是手肘法(Elbow Method)。它的核心思想是,隨著K值的增加,每個數(shù)據(jù)點到其對應簇中心的距離之和(也叫作簇內(nèi)平方和,Inertia)會不斷減小。但這個減小的速度,在達到一個“最佳”K值后會顯著放緩,圖形上看起來就像一個手肘。你需要在圖上找到那個“拐點”。這個方法雖然直觀,但有時候“手肘”并不那么明顯,需要一點主觀判斷。

另一個我個人覺得更靠譜,或者說更量化的方法是輪廓系數(shù)(Silhouette Score)。輪廓系數(shù)衡量的是一個數(shù)據(jù)點與其所在簇的凝合度( cohesion)和與其他簇的分離度(separation)。它的值介于-1到1之間:

  • 接近1表示該點與自身簇內(nèi)點很近,與相鄰簇點很遠,聚類效果很好。
  • 接近0表示該點在兩個簇的邊界上。
  • 接近-1表示該點可能被分到了錯誤的簇。 我們通常會計算不同K值下的平均輪廓系數(shù),然后選擇那個平均輪廓系數(shù)最高的K值。這比手肘法看起來更“客觀”一些,但也不是萬能的。
from sklearn.metrics import silhouette_score  # 嘗試不同K值 inertias = [] silhouette_scores = [] k_range = range(2, 11) # 通常K從2開始,因為K=1沒有聚類意義  for k in k_range:     kmeans = KMeans(n_clusters=k, random_state=0, n_init='auto')     kmeans.fit(X_scaled)     inertias.append(kmeans.inertia_)      # 計算輪廓系數(shù),需要至少2個簇     if k > 1:         score = silhouette_score(X_scaled, kmeans.labels_)         silhouette_scores.append(score)     else:         silhouette_scores.append(0) # K=1時輪廓系數(shù)無意義  # 繪制手肘圖 plt.figure(figsize=(12, 5)) plt.subplot(1, 2, 1) plt.plot(k_range, inertias, marker='o') plt.title('Elbow Method (Inertia vs. K)') plt.xlabel('Number of Clusters (K)') plt.ylabel('Inertia') plt.grid(True)  # 繪制輪廓系數(shù)圖 plt.subplot(1, 2, 2) # 注意:silhouette_scores 列表長度會比 k_range 少1,因為K=1時沒有輪廓系數(shù) plt.plot(k_range, silhouette_scores, marker='o', color='red') plt.title('Silhouette Score vs. K') plt.xlabel('Number of Clusters (K)') plt.ylabel('Silhouette Score') plt.grid(True) plt.tight_layout() plt.show()  # 找到輪廓系數(shù)最高的K值 # 注意索引對應關系,因為silhouette_scores是從k=2開始的 best_k_silhouette = k_range[np.argmax(silhouette_scores)] print(f"根據(jù)輪廓系數(shù),最佳K值可能為: {best_k_silhouette}")

在我看來,這兩種方法結(jié)合起來看,會讓你對K的選擇更有信心。但最終,還是得回歸到你對數(shù)據(jù)的理解,以及聚類結(jié)果是否符合你的業(yè)務預期。

KMeans算法的局限性與常見挑戰(zhàn)有哪些?

盡管KMeans非常流行且易于實現(xiàn),但它并不是萬能的,在實際應用中會遇到一些挑戰(zhàn)和局限性。這些問題有時候讓人挺頭疼的。

最明顯的一個是對初始聚類中心的敏感性。KMeans的迭代過程是從隨機選擇的K個點作為初始中心開始的。如果初始中心選得不好,算法可能會收斂到局部最優(yōu)解,而不是全局最優(yōu)解。雖然kmeans++這種初始化策略(Scikit-learn默認使用)大大緩解了這個問題,它會選擇離已選中心較遠的點作為下一個中心,但依然不能完全保證找到全局最優(yōu)。所以,通常我們會設置n_init參數(shù)(例如n_init=10),讓KMeans運行多次,每次用不同的初始中心,然后返回最好的那個結(jié)果,這能有效提高聚類質(zhì)量。

另一個大問題是它假設簇是球形的且大小相似。KMeans基于歐氏距離來劃分簇,自然傾向于找到圓形或橢圓形的簇。如果你的數(shù)據(jù)簇是任意形狀的(比如月牙形、環(huán)形),或者簇的密度差異很大,KMeans的表現(xiàn)就會很差,它會強行把非球形的數(shù)據(jù)點切分成球形簇。這時候,像DBSCAN(基于密度)或者Agglomerative Clustering(層次聚類)可能更合適。

對異常值(Outliers)的敏感也是一個痛點。單個或少數(shù)幾個離群點可能會顯著拉動聚類中心,導致整個簇的形狀和位置發(fā)生偏差,從而影響聚類結(jié)果的準確性。在進行KMeans之前,通常需要對數(shù)據(jù)進行離群點檢測和處理。

還有就是K值的選擇問題,前面已經(jīng)提過了。沒有一個放之四海而皆準的方法能確定最佳K值,這需要經(jīng)驗、業(yè)務知識和一些啟發(fā)式方法(如手肘法、輪廓系數(shù))的結(jié)合。

最后,KMeans無法處理非數(shù)值型數(shù)據(jù)。所有輸入特征都必須是數(shù)值型的。如果你有類別特征,需要進行獨熱編碼(One-Hot Encoding)或其他轉(zhuǎn)換。

這些局限性并不是說KMeans不好,而是提醒我們在使用它之前,要對數(shù)據(jù)有足夠的了解,并且在必要時考慮其他更適合的算法。

如何優(yōu)化KMeans聚類結(jié)果并提升模型性能?

既然KMeans有這些局限性,那我們有沒有辦法去“優(yōu)化”它,讓它的表現(xiàn)更好呢?當然有,有些小技巧或者說最佳實踐,能顯著提升聚類效果。

首先,數(shù)據(jù)預處理是重中之重。我前面提到過標準化,這絕對是KMeans的基石。如果你的特征量綱差異很大,或者數(shù)值范圍懸殊,不標準化就直接跑KMeans,結(jié)果往往會很糟糕。因為距離計算會被數(shù)值大的特征主導,小的特征幾乎沒啥發(fā)言權(quán)。除了標準化,有時候特征工程也能幫大忙。比如,如果你發(fā)現(xiàn)原始特征的組合能更好地揭示簇結(jié)構(gòu),那就大膽地去創(chuàng)造新特征。

其次,選擇合適的初始化策略。雖然Scikit-learn的KMeans默認使用了kmeans++,這已經(jīng)比純隨機初始化要好很多了,但如果你對結(jié)果還不滿意,可以嘗試多次運行KMeans并選擇最優(yōu)解(通過設置n_init參數(shù)為一個較大的值,例如10或20)。這能有效避免陷入局部最優(yōu)。

再來,處理異常值。正如前面所說,異常值對KMeans的影響很大。在聚類之前,可以考慮使用一些離群點檢測算法(比如Isolation Forest, LOF等)來識別并處理這些異常點。你可以選擇移除它們,或者將它們單獨標記出來,不參與核心聚類。

另外,評估指標的綜合使用。不要只盯著手肘法或者輪廓系數(shù)。有時候,一個K值在這些指標上表現(xiàn)一般,但在業(yè)務上卻非常有意義。所以,聚類結(jié)果出來后,一定要結(jié)合業(yè)務背景去解釋和評估。比如,看看每個簇的特征分布,是不是符合你的直覺,或者能給你帶來新的洞察。

最后,如果你發(fā)現(xiàn)KMeans確實不太適合你的數(shù)據(jù)(比如數(shù)據(jù)簇形狀不規(guī)則),那就考慮其他聚類算法。DBSCAN在處理不規(guī)則形狀簇和識別噪聲方面有優(yōu)勢,層次聚類(Agglomerative Clustering)則能生成聚類樹,幫助你理解不同粒度的簇結(jié)構(gòu)。選擇合適的工具,才是解決問題的關鍵。

在我看來,沒有一種算法是完美的。KMeans雖然簡單,但它強大的地方在于其直觀性和計算效率。通過這些優(yōu)化手段,我們可以在很大程度上彌補它的不足,讓它在更廣泛的場景中發(fā)揮作用。

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點贊13 分享