1、聚類算法又叫做“無監督分類”,其目的是將數據划分成有意義或有用的組(或簇)。這種划分可以基於我們的業務需求或建模需求來完成,也可以單純地幫助我們探索數據的自然結構和分布。
2、KMeans算法將一組N個樣本的特征矩陣X划分為K個無交集的簇,直觀上來看是簇是一組一組聚集在一起的數據,在一個簇中的數據就認為是同一類。簇就是聚類的結果表現。簇中所有數據的均值通常被稱為這個簇的“質心”(centroids)。在一個二維平面中,一簇數據點的質心的橫坐標就是這一簇數據點的橫坐標的均值,質心的縱坐標就是這一簇數據點的縱坐標的均值。同理可推廣至高維空間。
3、KMeans追求的是‘簇內差異小,簇間差異大’。
所有簇的簇內平方和相加,就得到了整體平方和,又叫做total inertia。Total Inertia越小,代表着每個簇內樣本越相似,聚類的效果就越好。因此KMeans追求的是,求解能夠讓Inertia最小化的質心。實際上,在質心不斷變化不斷迭代的過程中,總體平方和是越來越小的。
注:損失函數本質是用來衡量模型的擬合效果的,只有有着求解參數需求的算法,才會有損失函數。Kmeans不求解什么參數,它的模型本質也沒有在擬合數據,而是在對數據進行一種探索,故Kmeans不存在損失函數,Inertia更像是Kmeans的評估指標,而不是損失函數。
除了模型本身的效果之外,我們還使用另一種角度來度量算法:算法復雜度。算法的復雜度分為時間復雜度和空間復雜度,時間復雜度是指執行算法所需要的計算工作量,常用大O符號表述;而空間復雜度是指執行這個算法所需要的內存空間。如果一個算法的效果很好,但需要的時間復雜度和空間復雜度都很大,那我們將會權衡算法的效果
和所需的計算成本。和KNN一樣,KMeans算法是一個計算成本很大的算法。
聚類模型的結果不是某種標簽輸出,並且聚類的結果是不確定的,其優劣由業務需求或者算法需求來決定,並且沒有永遠的正確答案。
用inertia作為衡量指標並不合適,一個較小的Inertia究竟有沒有達到模型的極限,能否繼續提高;Inertia的計算太容易受到特征數目的影響,數據維度很大的時候,Inertia的計算量會陷入維度詛咒之中,計算量會爆炸,不適合用來一次次評估模型;Inertia還會受到超參數K的影響,隨着K越大,Inertia注定會越來越小,但這並不代表模型的效果越來越好了;Inertia對數據的分布有假設,它假設數據滿足凸分布並且它假設數據是各向同性的,即是說數據的屬性在不同方向上代表着相同的含義,但是現實中的數據往往不是這樣,所以使用Inertia作為評估指標,會讓聚類算法在一些細長簇,環形簇,或者不規則形狀的流形時表現不佳。
4、KMeans模型評估指標,分兩種:
標簽已知時,如果擁有真實標簽,我們更傾向於使用分類算法。但不排除我們依然可能使用聚類算法的可能性。如果我們有樣本真實聚類情況的數據,我們可以對於聚類算法的結果和真實結果來衡量聚類的效果。常用的有以下三種方法:
互信息分;V-measure(基於條件上分析的一系列直觀度量);調整蘭德系數
真實標簽未知時,輪廓系數(評價簇內的稠密程度(簇內差異小)和簇間的離散程度(簇外差異大)來評估聚類的效果),卡林斯基-哈拉巴斯指數(Calinski-Harabaz Index,簡稱CHI,也被稱為方差比標准),戴維斯-布爾丁指數(Davies-Bouldin)以及權變矩陣(Contingency Matrix)
輪廓系數的范圍是(-1,1),值越接近1表示樣本與自己所在的簇中的樣本很相似,並且與其他簇中的樣本不相似;當樣本點與簇外的樣本更相似的時候,輪廓系數就為負;當輪廓系數為0時,則代表兩個簇中的樣本相似度一致,兩個簇本應該是一個簇。在sklearn中,我們使用模塊metrics中的類silhouette_score來計算輪廓系數,它返回的是一個數據集中,所有樣本的輪廓系數的均值。但我們還有同在metrics模塊中的silhouette_sample,它的參數與輪廓系數一致,但返回的是數據集中每個樣本自己的輪廓系數。
基於輪廓系數選擇最佳的n_clusters
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
#創建數據集
X,y=make_blobs(n_samples=500,n_features=2,centers=4,random_state=1)
fig,ax1=plt.subplots(1)
ax1.scatter(X[:,0],X[:,1],marker='o',s=8)
plt.show()
#添加顏色
color=['red','pink','orange','gray']
fig,ax1=plt.subplots(1)
for i in range(4):
ax1.scatter(X[y==i,0],X[y==i,1],marker='o',s=8,c=color[i])
plt.show()
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_samples,silhouette_score
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np
#基於輪廓系數來選擇最佳的n_clusters
#知道每個聚出來的類的輪廓系數是多少,還有各個類之間的輪廓系數的對比
#知道聚類完畢以后圖像的分布是什么樣的
#先設定要分成的簇數
n_clusters=4
#創建一個畫布,畫布上有一行兩列兩個圖
fig,(ax1,ax2)=plt.subplots(1,2)
#設置畫布尺寸
fig.set_size_inches(18,7)
ax1.set_xlim([-0.1,1])
ax1.set_ylim([0,X.shape[0]+(n_clusters+1)*10])
#建模,調用聚類好的標簽
clusterer=KMeans(n_clusters=n_clusters,random_state=10).fit(X)
cluster_labels=clusterer.labels_
#調用輪廓系數分數,silhouette_avg生成所有樣本點輪廓系數的均值
#需要輸入兩個參數,特征矩陣X與聚類完畢的標簽
silhouette_avg = silhouette_score(X, cluster_labels)
#打印現有簇數量下,輪廓系數是多少
print("For n_clusters =", n_clusters,
"The average silhouette_score is :", silhouette_avg)
#調用silhouette_samples,返回每個樣本點的輪廓系數,就是橫坐標
sample_silhouette_values = silhouette_samples(X, cluster_labels)
#設置Y軸的初始取值
y_lower = 10
#對每個簇進行循環
for i in range(n_clusters):
#從每個樣本的輪廓系數結果中抽取第i個簇的輪廓系數,並進行排序
ith_cluster_silhouette_values = sample_silhouette_values[cluster_labels == i]
#注意,.sort會直接改掉原數據的順序
ith_cluster_silhouette_values.sort()
#查看簇中究竟有多少個樣本
size_cluster_i = ith_cluster_silhouette_values.shape[0]
#一個簇在y州的取值是由初始值(y_lower)開始,到初始值加上這個簇中的樣本數量結束(y_upper)
y_upper = y_lower + size_cluster_i
#用i的浮點數除以n_clusters,在不同的i下生成不同的小數,以確保所有的簇都有不同的顏色
color = cm.nipy_spectral(float(i)/n_clusters)
#fill_between是讓一個范圍的柱狀圖都統一顏色的函數,
#fill_betweenx的范圍是在縱坐標上,參數輸入(縱坐標的下限,縱坐標的上限,X軸上的取值,柱狀圖的顏色)
ax1.fill_betweenx(np.arange(y_lower, y_upper)
,ith_cluster_silhouette_values
,facecolor=color
,alpha=0.7)
#為每個簇的輪廓系數寫上編號,並讓簇的編號顯示在坐標軸每個條形圖的中間位置
#text參數(要顯示編號位置的橫坐標,縱坐標,編號內容)
ax1.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
#為下一個簇計算新的y軸上的初始值,每一次迭代后y再加上10以保證不同簇的圖像之間顯示有空隙
y_lower = y_upper + 10
ax1.set_title("The silhouette plot for the various clusters.")
ax1.set_xlabel("The silhouette coefficient values")
ax1.set_ylabel("Cluster label")
# 把整個數據集上的輪廓系數的均值以虛線形式放入圖中
ax1.axvline(x=silhouette_avg, color="red", linestyle="--")
#讓y軸不顯示任何刻度
ax1.set_yticks([])
#讓X軸上的刻度顯示為規定的列表
ax1.set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1])
#開始處理第二個圖,首先獲取新的顏色,由於沒有循環需要一次性生成多個小數來獲取多個顏色
#cluster_labels.astype(float) 生成浮點數,nipy_spectral只能用浮點數,500個值只有4個顏色
colors = cm.nipy_spectral(cluster_labels.astype(float) / n_clusters)
ax2.scatter(X[:, 0], X[:, 1],marker='o',s=8,c=colors)
#把生成的質心放在圖像中
centers = clusterer.cluster_centers_
ax2.scatter(centers[:, 0], centers[:, 1], marker='x',c="red", alpha=1, s=200)
ax2.set_title("The visualization of the clustered data.")
ax2.set_xlabel("Feature space for the 1st feature")
ax2.set_ylabel("Feature space for the 2nd feature")
#為整個圖設置標題
plt.suptitle(("Silhouette analysis for KMeans clustering on sample data "
"with n_clusters = %d" % n_clusters),
fontsize=14, fontweight='bold')
plt.show()無錫婦科醫院 http://www.bhnnk120.com/
#將上述過程包裝稱循環
for n_clusters in [2,3,4,5,6,7]:
n_clusters = n_clusters
fig, (ax1, ax2) = plt.subplots(1, 2)
fig.set_size_inches(18, 7)
ax1.set_xlim([-0.1, 1])
ax1.set_ylim([0, X.shape[0] + (n_clusters + 1) * 10])
clusterer = KMeans(n_clusters=n_clusters, random_state=10).fit(X)
cluster_labels = clusterer.labels_
silhouette_avg = silhouette_score(X, cluster_labels)
print("For n_clusters =", n_clusters,"The average silhouette_score is :", silhouette_avg)
sample_silhouette_values = silhouette_samples(X, cluster_labels)
y_lower = 10
for i in range(n_clusters):
ith_cluster_silhouette_values = sample_silhouette_values[cluster_labels == i]
ith_cluster_silhouette_values.sort()
size_cluster_i = ith_cluster_silhouette_values.shape[0]
y_upper = y_lower + size_cluster_i
color = cm.nipy_spectral(float(i)/n_clusters)
ax1.fill_betweenx(np.arange(y_lower, y_upper)
,ith_cluster_silhouette_values
,facecolor=color
,alpha=0.7)
ax1.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
y_lower = y_upper + 10
ax1.set_title("The silhouette plot for the various clusters.")
ax1.set_xlabel("The silhouette coefficient values")
ax1.set_ylabel("Cluster label")
ax1.axvline(x=silhouette_avg, color="red", linestyle="--")
ax1.set_yticks([])
ax1.set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1])
colors = cm.nipy_spectral(cluster_labels.astype(float) / n_clusters)
ax2.scatter(X[:, 0], X[:, 1],marker='o',s=8,c=colors)
centers = clusterer.cluster_centers_
# Draw white circles at cluster centers
ax2.scatter(centers[:, 0], centers[:, 1], marker='x',c="red", alpha=1, s=200)
ax2.set_title("The visualization of the clustered data.")
ax2.set_xlabel("Feature space for the 1st feature")
ax2.set_ylabel("Feature space for the 2nd feature")
plt.suptitle(("Silhouette analysis for KMeans clustering"
"with n_clusters = %d" % n_clusters),fontsize=14, fontweight='bold')
plt.show()
5、初始質心(init)
init:可輸入**“k-means++”,“random"或者一個n維數組**。這是初始化質心的方法,默認"k-means++"。
輸入"kmeans++”:一種為K均值聚類選擇初始聚類中心的聰明的辦法(使得初始質心通常彼此遠離),以加速收斂。
"random"下,如果不指定隨機數種子,則sklearn中的K-means並不會只選擇一個隨機模式扔出結果,而會在每個隨機數種子下運行多次,並使用結果最好的一個隨機數種子來作為初始質心。可以使用參數n_init來選擇每個隨機數種子下運行的次數,這個參數不常用到,默認10次,如果我們希望運行的結果更加精確,那我們可以增加這個參數n_init的值來增加每個隨機數種子下運行的次數。然而這種方法依然是基於隨機性的。
如果輸入了n維數組,數組的形狀應該是(n_clusters,n_features)並給出初始質心。
6、max_iter & tol:讓迭代停下來
當質心不再移動,Kmeans算法就會停下來,但在完全收斂之前,可以使用max_iter(最大迭代次數)或者tol(兩次迭代間Inertia下降的量),這兩個參數來讓迭代提前停下來。數據量特別大時可以使用。
max_iter:整數,默認300,單次運行的k-means算法的最大迭代次數
tol:浮點數,默認1e-4,兩次迭代間Inertia下降的量,如果兩次迭代之間Inertia下降的值小於tol所設定的值,迭代就會停下