K 均值聚類
算法交替執行以下兩個步驟:
- 將每個數據點分配給最近的簇中心
- 將每個簇中心設置為所分配的所有數據點的平均值,如果簇的分配不再發生改變,那么算法結束。
優點
- K 均值不僅相對容易理解和實現,而且運行速度也相對較快。
- K 均值可以輕松擴展到大型數據集
- scikit-learn 甚至在 MiniBatchKMeans 類中包含了一種更具可擴展性的變體,可以處理非常大的數據集。
缺點
- 需要人工預先確定初始 K 值,且該值和真實的數據未必吻合。
- 分類結果嚴重依賴于分類中心的初始化。通常進行多次k-means,然后選擇最優的那次作為最終聚類結果。
- 結果不一定是全局最優的,只能保證局部最優。
- 對噪聲敏感。因為簇的中心是取平均,因此聚類簇很遠地方的噪音會導致簇的中心點偏移。
- 無法解決不規則形狀的聚類。
- 無法處理離散特征,如:國籍、性別 等。
k-means 性質:
- k-means 實際上假設數據是呈現球形分布,實際任務中很少有這種情況。與之相比,GMM 使用更加一般的數據表示,即高斯分布。
- k-means 假設各個簇的先驗概率相同,但是各個簇的數據量可能不均勻。
- k-means 使用歐式距離來衡量樣本與各個簇的相似度。這種距離實際上假設數據的各個維度對于相似度的作用是相同的。
- k-means 中,各個樣本點只屬于與其相似度最高的那個簇,這實際上是硬 分簇。
- k-means 算法的迭代過程實際上等價于EM 算法。具體參考EM 算法章節。
3、算法調優
- 數據歸一化和離群點處理
- 合理選擇 K 值
K 值選擇方法:
- 手肘法:是一個經驗方法,缺點就是不能夠自動化。
- Gap Statistic 方法:只需要找到最大的 Gap Statistic 所對應的 K 即可。Gap(K)可以視為隨機樣本的損失和實際樣本的損失之差。
- 采用核函數:通過一個非線性映射,將輸入空間中的數據點映射到高位的特征空間中,并在新的特征空間進行聚類。非線性映射增加了數據點線性可分的概率,從而在經典聚類算法失效的情況下,通過引入核函數可以達到更為準確的聚類結果。
4、算法改進
- K-means++:解決 k-means 嚴重依賴于分類中心初始化的問題
- k-modes:解決 k-means 無法處理離散特征的問題
- k-medoids:解決k-means 對噪聲敏感的問題。
- mini-batch k-means:主要用于減少 k-means 的計算時間
- ISODATA:K值不確定可以使用
- 二分均值聚類:層次聚類
K-means++
它主要解決 k-means 嚴重依賴于分類中心初始化的問題。 已經選取了 n(0<n<k) 個初始聚類中心,距離當前 n 個聚類中心越遠的點會有更高的概率被選為第 n+1 個聚類中心。在選取第一個聚類中心(n=1)時同樣通過隨機的方法。
image.png
k-modes
主要解決 k-means 無法處理離散特征的問題
image.png
k-medoids
主要解決k-means 對噪聲敏感的問題。
image.png
mini-batch k-means
主要用于減少 k-means 的計算時間。mini-batch k-means 算法每次訓練時隨機抽取小批量的數據,然后用這個小批量數據訓練。這種做法減少了 k-means 的收斂時間,其效果略差于標準算法。
image.png
二分均值聚類
- 一種用于度量聚類效果的指標是 SSE,SSE 值越小表示數據點越接近于它們的質心,聚類效果也越好。因為對誤差取了平方,因此更加重視那些遠離中心的點。
- 一種肯定可以降低 SSE值的方式是增加簇的個數,但違背了聚類的目標,聚類的目標是在保持簇數目不變的情況下提高簇的質量。
- 一種方法是將具有最大 SSE 值的簇分為兩個簇。具體實現時可以將最大簇包含的點過濾出來并在這些點上運行 K-均值算法,其中 k 設為 2.
def biKmeans(dataSet,k,distMeas=distEclud):
m=np.shape(dataSet)[0]
clusterAssment=np.mat(np.zeros((m,2)))
centroid0=np.mean(dataSet,axis=0).tolist()[0]
centList=[centroid0]
for j in range(m):
clusterAssment[j,1]=distMeas(np.mat(centroid0),dataSet[j,:])**2
while(len(centList)<k):
lowestSSE=np.inf
for i in range(len(centList)):
ptsInCurrCluster=dataSet[np.nonzero(clusterAssment[:,0].A==i)[0],:]
centroidMat,splistClusterAss=kMeans(ptsInCurrCluster,2,distMeas)
sseSplist=np.sum(splistClusterAss[:,1])
sseNotSplit=np.sum(clusterAssment[np.nonzero(clusterAssment[:,0].A!=i)[0],1])
print('sseSplit, and notSplit:',sseSplist,sseNotSplit)
if(sseSplist+sseNotSplit<lowestSSE):
bestCentToSplit=i
bestNewCents=centroidMat
bestClustAss=splistClusterAss.copy()
lowestSSE=sseSplist+sseNotSplit
bestClustAss[np.nonzero(bestClustAss[:,0].A==1)[0],0]=len(centList)
bestClustAss[np.nonzero(bestClustAss[:,0].A==0)[0],0]=bestCentToSplit
print('the bestCentToSplit is: ',bestCentToSplit)
print('the len of bestClustAss is:',len(bestClustAss))
centList[bestCentToSplit]=bestNewCents[0,:]
centList.append(bestNewCents[1,:])
clusterAssment[np.nonzero(clusterAssment[:,0].A==bestCentToSplit)[0],:]=bestClustAss
return centList , clusterAssment
通過迭代方式尋找 K 個簇的一種劃分方案,使得聚類結果對應的代價函數最小。
ISODATA
當 K 值的大小不確定時,可以使用 ISODATA 算法。
ISODATA 的全稱是迭代自組織數據分析法。當屬于某個類別的樣本數過少,把該類別去除;當屬于某個類別的樣本數過多、分散度較大時,把該類分為兩個子類別。在 K-means 基礎上增加兩個操作,一是分裂操作,對應著增加聚類中心數;二是合并操作,對應著減少聚類中心數。
超參數設定:
- 預期的聚類中心數目 K 。具體地,最終輸出的聚類中心數目常見范圍是 K 的一半或兩倍 K。
- 每個類別要求的最少樣本數目 N。如果分裂后會導致某個子類別所包含樣本數目小于該閾值,就不會對該類別進行分裂操作
- 最大方差 Sigma。用于控制某個類別中樣本的分散程度。當樣本分散程度超過這個閾值,且分裂后滿足上條規則,進行分裂操作。
- 兩個聚類中心之間所允許最小距離 D。如果兩個類靠的非常近,小于該閾值時,則對這兩個類進行合并操作。
算法實現
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
X,y=make_blobs(random_state=1)
kmeans=KMeans(n_clusters=3)
kmeans.fit(X)
print('Cluster memberships:\n{}'.format(kmeans.labels_))
# 預測
print(kmeans.predict(X))
# 質心
print(kmeans.cluster_centers_)