一年前需要用聚類算法時,自己從一些sklearn文檔和博客粗略整理了一些相關的知識,記錄在電子筆記里備忘,現在發到網上,當時就整理的就很亂,以后有空慢慢把內容整理、完善,用作備忘。之前把電影標簽信息的聚類結果作為隱式反饋放進SVD++中去訓練,里面有兩個小例子
外部度量:
利用條件熵定義的同質性度量:
sklearn.metrics.homogeneity_score:每一個聚出的類僅包含一個類別的程度度量。
sklearn.metrics.completeness:每一個類別被指向相同聚出的類的程度度量。
sklearn.metrics.v_measure_score:上面兩者的一種折衷:
v = 2 * (homogeneity * completeness) / (homogeneity + completeness)
可以作為聚類結果的一種度量。
sklearn.metrics.adjusted_rand_score:調整的蘭德系數。
ARI取值范圍為[-1,1],從廣義的角度來講,ARI衡量的是兩個數據分布的吻合程度
sklearn.metrics.adjusted_mutual_info_score:調整的互信息。
利用基于互信息的方法來衡量聚類效果需要實際類別信息,MI與NMI取值范圍為[0,1],AMI取值范圍為[-1,1]。
在真實的分群label不知道的情況下(內部度量):
Calinski-Harabaz Index:
在scikit-learn中, Calinski-Harabasz Index對應的方法是metrics.calinski_harabaz_score.
CH指標通過計算類中各點與類中心的距離平方和來度量類內的緊密度,通過計算各類中心點與數據集中心點距離平方和來度量數據集的分離度,CH指標由分離度與緊密度的比值得到。從而,CH越大代表著類自身越緊密,類與類之間越分散,即更優的聚類結果。
sklearn.metrics.silhouette_score:輪廓系數
silhouette_sample
對于一個樣本點(b - a)/max(a, b)
a平均類內距離,b樣本點到與其最近的非此類的距離。
silihouette_score返回的是所有樣本的該值,取值范圍為[-1,1]。
這些度量均是越大越好
sklearn kmeans,聚類算法kmeans:
流程偽代碼:創建K個點作為起始質心(通常是隨機)
當任意一個點的簇分配結果發生改變時
對數據集中的每個數據點
對每個質心
計算質心與數據點之間的距離
將數據點分配到最近的簇
對每個簇,計算簇中所有點的均值并將均值作為質心
sklearn中的K-means
K-means算法應該算是最常見的聚類算法,該算法的目的是選擇出質心,使得各個聚類內部的inertia值最小化,計算方法如下:
inertia可以被認為是類內聚合度的一種度量方式,這種度量方式的主要缺點是:
(1)inertia假設數據內的聚類都是凸的并且各向同性( convex and isotropic),
各項同性是指在數據的屬性在不同方向上是相同的。數據并不是總能夠滿足這些前提假設的,
所以當數據事細長簇的聚類,或者不規則形狀的流形時,K-means算法的效果不理想。
(2)inertia不是一種歸一化度量方式。一般來說,inertia值越小,說明聚類效果越好。
但是在高維空間中,歐式距離的值可能會呈現迅速增長的趨勢,所以在進行K-means之前首先進行降維操作,如PCA等,可以解決高維空間中inertia快速增長的問題,也有主意提高計算速度。
K-means算法可以在足夠長的時間內收斂,但有可能收斂到一個局部最小值。
聚類的結果高度依賴質心的初始化,因此在計算過程中,采取的措施是進行不止一次的聚類,每次都初始化不同的質心。
sklearn中可以通過設置參數init='kmeans++'來采取k-means++初始化方案,
即初始化的質心相互之間距離很遠,這種方式相比于隨機初始質心,能夠取得更好的效果。
另外,sklearn中可以通過參數n_job,使得K-means采用并行計算的方式。
##sklearn 中K-means的主要參數:
1) n_clusters: 設定的k值
2)max_iter: 最大的迭代次數,一般如果是凸數據集的話可以不管這個值,如果數據集不是凸的,可能很難收斂,此時可以指定最大的迭代次數讓算法可以及時退出循環。
3)n_init:用不同的初始化質心運行算法的次數。由于K-Means是結果受初始值影響的局部最優的迭代算法,因此需要多跑幾次以選擇一個較好的聚類效果,默認是10。如果你的k值較大,則可以適當增大這個值。
4)init: 即初始值選擇的方式,可以為完全隨機選擇'random',優化過的'k-means++'或者自己指定初始化的k個質心。一般建議使用默認的'k-means++'。
5)algorithm:有“auto”, “full” or “elkan”三種選擇。"full"就是我們傳統的K-Means算法, “elkan”elkan K-Means算法。默認的"auto"則會根據數據值是否是稀疏的,來決定如何選擇"full"和“elkan”。一般來說建議直接用默認的"auto"
sklearn 中K-means的主要方法
聚類的中心
print clf.cluster_centers_
每個樣本所屬的簇
print clf.labels_
用來評估簇的個數是否合適,距離越小說明簇分的越好,選取臨界點的簇個數
print clf.inertia_
Sum of distances of samples to their closest cluster center.
兩個小例子(很久以前弄的,寫得比較簡略比較亂,有空再改,數據是movielen中的電影標簽信息):
例1:
kmeans_model = KMeans(n_clusters = 10, random_state = 1,init='k-means++')
pred = kmeans_model.fit_predict(matrix)
print pred
print kmeans_model.cluster_centers_ #聚類的中心
print kmeans_model.labels_#每個樣本所屬的簇
print kmeans_model.inertia_
例2,在區間[2,200]上遍歷k,并生成兩個聚類內部評價指標CH分、輪廓系數以及kmeans自帶inertia分和對應的k值的圖片來選擇k:
i = []
y_silhouette_score = []
inertia_score = []
calinskiharabaz_score = []
for k in range(2,201):
kmeans_model = KMeans(n_clusters = k, random_state = 1,init='k-means++')
pred = kmeans_model.fit_predict(matrix)
silhouettescore = silhouette_score(matrix, pred)
print "silhouette_score for cluster '{}'".format(k)
print silhouettescore
calinskiharabazscore = calinski_harabaz_score(matrix, pred)
print "calinski_harabaz_score '{}'".format(k)
print calinskiharabazscore
i.append( k )
y_silhouette_score.append( silhouettescore )
inertia_score.append(kmeans_model.inertia_)
calinskiharabaz_score.append( calinskiharabazscore )
print "kmeans_model.inertia_score for cluster '{}'".format(k)
print kmeans_model.inertia_
#轉成字典方便查找
#dict_silhouette = dict(zip( i,y_silhouette_score))
#dict_inertia_score = dict(zip( i,inertia_score))
#dict_calinskiharabaz_score = dict(zip( i, calinskiharabaz_score))
plt.figure()
plt.plot(i,y_silhouette_score)
plt.xlabel("kmeans-k")
plt.ylabel("silhouette_score")
plt.title("matrix")
plt.figure()
plt.plot(i,inertia_score)
plt.xlabel("kmeans-k")
plt.ylabel("inertia_score(sum of squared)")
plt.title("matrix")
plt.figure()
plt.plot(i,calinskiharabaz_score)
plt.xlabel("kmeans-k")
plt.ylabel("calinski_harabaz_score")
plt.title("matrix")
Affinity Propagation(AP聚類算法)
其中兩點相似度s(i, j)的度量默認采用負歐氏距離。
sklearn.cluster.AffinityPropagation
有參數preference(設定每一個點的偏好,將偏好于跟其他節點的相似性進行比較,選擇
高的作為exmplar,未設定則使用所有相似性的中位數)、damping (阻尼系數,
利用阻尼系數與1-阻尼系數對r 及 a進行有關迭代步數的凸組合,使得算法收斂
default 0.5 可以取值與[0.5, 1])
cluster_centers_indices_:中心樣本的指標。
AP算法的主要思想是通過數據點兩兩之間傳遞的信息進行聚類。
該算法的主要優點是能夠自主計算聚類的數目,而不用人為制定類的數目。
其缺點是計算復雜度較大 ,計算時間長同時空間復雜度大,
因此該算法適合對數據量不大的問題進行聚類分析。
數據點之間傳遞的信息包括兩個,吸引度(responsibility)r(i,k)和歸屬度(availability)a(i,k)。
吸引度r(i,k)度量的是質心k應當作為點i的質心的程度,
歸屬度a(i,k)度量的是點i應當選擇質心k作為其質心的程度。
其中t是迭代的次數,λ是阻尼因子,其值介于[0,1],在sklearn.cluster.AffinityPropagation中通過參數damping進行設置。
每次更新完矩陣后,就可以為每個數據點分配質心,分配方式?是針對數據點i,遍歷所有數據點k(包括其自身),
找到一個k使得r(i,k)+a(i,k)的值最大,則點k就是點i所屬的質心,迭代這個過程直至收斂。
所謂收斂就是所有點所屬的質心不再變化
Mean Shift
首先說明不引入核函數時的情況。
算法大致流程為:隨機選取一個點作為球心,以一定半徑畫一個高維球(數據可能是高維的),
在這個球范圍內的點都是這個球心的鄰居。這些鄰居相對于球心都存在一個偏移向量,
將這些向量相加求和再平均,就得到一個mean shift,起點在原球心,重點在球內的其他位置。
以mean shift的重點作為新的球心,重復上述過程直至收斂。
這個計算過程中,高維球內的點,無論其距離球心距離多遠,對于mean shift的計算權重是一樣的。
為了改善這種情況,在迭代計算mean shift的過程中引入了核函數
sklearn中相關實現是sklearn.cluster.MeanShift。
層次聚類說明
sklearn中實現的是自底向上的層次聚類,實現方法是sklearn.cluster.AgglomerativeClustering。
初始時,所有點各自單獨成為一類,然后采取某種度量方法將相近的類進行合并,并且度量方法有多種選擇。
合并的過程可以構成一個樹結構,其根節點就是所有數據的集合,葉子節點就是各條單一數據。
sklearn.cluster.AgglomerativeClustering中可以通過參數linkage選擇不同的度量方法,用來度量兩個類之間的距離,
可選參數有ward,complete,average三個。
ward:選擇這樣的兩個類進行合并,合并后的類的離差平方和最小。
complete:兩個類的聚類被定義為類內數據的最大距離,即分屬兩個類的距離最遠的兩個點的距離。
選擇兩個類進行合并時,從現有的類中找到兩個類使得這個值最小,就合并這兩個類。
average:兩個類內數據兩兩之間距離的平均值作為兩個類的距離。
同樣的,從現有的類中找到兩個類使得這個值最小,就合并這兩個類。
Agglomerative cluster有一個缺點,就是rich get richer現象,
這可能導致聚類結果得到的類的大小不均衡。
從這個角度考慮,complete策略效果最差,ward得到的類的大小最為均衡。
但是在ward策略下,affinity參數只能是“euclidean”,即歐式距離。
如果在歐氏距離不適用的環境中,average is a good alternative。
另外還應該注意參數affinity,這個參數設置的是計算兩個點之間距離時采用的策略,
注意和參數linkage區分,linkage設置的是衡量兩個類之間距離時采用的策略,
而點之間的距離衡量是類之間距離衡量的基礎。
affinity的可選數值包括 “euclidean”, “l1”, “l2”, “manhattan”, “cosine”,
‘precomputed’. If linkage is “ward”, only “euclidean” is accepted.
DBSCAN
DBSCAN算法的主要思想是,認為密度稠密的區域是一個聚類,各個聚類是被密度稀疏的區域劃分開來的。
也就是說,密度稀疏的區域構成了各個聚類之間的劃分界限。與K-means等算法相比,該算法的主要優點包括:可以自主計算聚類的數目,不需要認為指定;不要求類的形狀是凸的,可以是任意形狀的。
DBSCAN中包含的幾個關鍵概念包括core sample,non-core sample,min_sample,eps。
core samle是指,在該數據點周圍eps范圍內,至少包含min_sample個其他數據點,則該點是core sample,
這些數據點稱為core sample的鄰居。與之對應的,non-sample是該點周圍eps范圍內,所包含的數據點個數少于min_sample個。從定義可知,core sample是位于密度稠密區域的點。
一個聚類就是一個core sample的集合,這個集合的構建過程是一個遞歸的構成。
首先,找到任意個core sample,然后從它的鄰居中找到core sample,
接著遞歸的從這些鄰居中的core sample的鄰居中繼續找core sample。
要注意core sample的鄰居中不僅有其他core sample,也有一些non-core smaple,
也正是因為這個原因,聚類集合中也包含少量的non-core sample,它們是聚類中core sample的鄰居,
但自己不是core sample。這些non-core sample構成了邊界。
在確定了如何通過單一core sample找到了一個聚類后,下面描述DBSCAN算法的整個流程。
首先,掃描數據集找到任意一個core sample,以此core sample為起點,按照上一段描述的方法進行擴充,確定一個聚類。然后,再次掃描數據集,找到任意一個不屬于以確定類別的core sample,重復擴充過程,再次確定一個聚類。
迭代這個過程,直至數據集中不再包含有core sample。
這也是為什么DBSCAN不用認為指定聚類數目的原因。
DBSCAN算法包含一定的非確定性。數據中的core sample總是會被分配到相同的聚類中的,哪怕在統一數據集上多次運行DBSCAN。其不確定性主要體現在non-core sample的分配上。
一個non-core sample可能同時是兩個core sample的鄰居,而這兩個core sample隸屬于不同的聚類。
DBSCAN中,這個non-core sample會被分配給首先生成的那個聚類,而哪個聚類先生成是隨機的。
sklearn中DBSCAN的實現中,鄰居的確定使用的ball tree和kd-tree思想,這就避免了計算距離矩陣。