1. 程式人生 > >python_sklearn機器學習算法系列之K-Means(硬聚類演算法)

python_sklearn機器學習算法系列之K-Means(硬聚類演算法)

          本文主要目的是通過一段及其簡單的小程式來快速學習python 中sklearn的K-Means這一函式的基本操作和使用,注意不是用python純粹從頭到尾自己構建K-Means,既然sklearn提供了現成的我們直接拿來用就可以了,當然K-Means原理還是十分重要,這裡簡單說一下實現這一演算法的過程:

1)從N個文件隨機選取K個文件作為質心

2)對剩餘的每個文件測量其到每個質心的距離,並把它歸到最近的質心的類

3)重新計算已經得到的各個類的質心

4)迭代2~3步直至新的質心與原質心相等或小於指定閾值,演算法結束

詳細可以參考https://baike.so.com/doc/6953641-7176056.html

在介紹程式碼之前先來看兩個概念:平均畸變程度和輪廓係數

通過平均畸變程度可以確定一個範圍內(人為給定)的最佳類簇的數量即K值,通過輪廓係數(Silhouette Coefficient)評價聚類演算法的效能

每個類的畸變程度簡單來說其實等於該類重心與其內部成員位置距離的平方和,顯而易見該值越小說明該類中的樣本越緊湊的聚集在一起,

平均畸變程度越小說明整體來說分類的效果越好了對吧,所以這個概念還是比較好理解的,也可以從下面的程式碼中清楚的看到這一概念的具體含義。

關於輪廓係數有點複雜,它由兩個因數通過決定:簇內不相似度和簇間不相似度

簇內不相似度定義為樣本n到同簇其他樣本的平均距離,記為dist1_n

樣本n到其他某簇C(i) 的所有樣本的平均距離dis_n-C(i)則簇間不相似度定義為dist2_n

=min{dis_n-C(1), dis_n-C(2), ...,dis_n-C(k)}

輪廓係數s為(圖片旋轉一下看):


s接近1,則說明樣本n聚類合理;

s接近-1,則說明樣本n更應該分類到另外的簇;

若s 近似為0,則說明樣本n在兩個簇的邊界上。

本程式源資料用的是一部分城市的經緯度即city.txt

上海上海,121.48,31.22  
上海嘉定,121.24,31.4  
上海寶山,121.48,31.41  
上海川沙,121.7,31.19  
上海南匯,121.76,31.05  
上海奉賢,121.46,30.92  
上海松江,121.24,31  
雲南昆明,102.73,25.04  
雲南富民,102.48,25.21  
雲南晉寧,102.58,24.68  
雲南呈貢,102.79,24.9  
雲南安寧,102.44,24.95  
雲南昭通,103.7,29.32  
雲南永善,103.63,28.22  
雲南大姚,101.34,25.73  
雲南永仁,101.7,26.07  
雲南祿勸,102.45,25.58  
雲南牟定,101.58,25.32  
雲南雙柏,101.67,24.68  
雲南姚安,101.24,25.4  
雲南下關,100.24,25.45  
雲南劍川,99.88,26.53  
雲南洱源,99.94,26.1  
雲南賓川,100.55,25.82  
雲南彌渡,100.52,25.34  
雲南永平,99.52,25.45  
雲南鶴慶,100.18,26.55  
雲南大理,100.19,25.69  
雲南漾濞,99.98,25.68  
北京北京,116.46,39.92  
北京平谷,117.1,40.13  
北京密雲,116.85,40.37  
北京順義,116.65,40.13  
北京通縣,116.67,39.92  
北京懷柔,116.62,40.32  
北京大興,116.33,39.73  
北京房山,115.98,39.72    
吉林長春,125.35,43.88  
吉林吉林,126.57,43.87  
吉林農安,125.15,44.45  
吉林德惠,125.68,44.52  
吉林榆樹,126.55,44.83  
吉林九臺,126.83,44.15  
吉林雙陽,125.68,43.53  
吉林永吉,126.57,43.87  
吉林舒蘭,126.97,44.4  
吉林蛟河,127.33,43.75  
吉林樺甸,126.72,42.97  
吉林磐石,126.03,42.93  
吉林延吉,129.52,42.93  
吉林汪清,129.75,43.32  
吉林琿春,130.35,42.85  
吉林大安,124.18,45.5  
吉林扶余,124.82,45.2  
吉林乾安,124.02,45  
吉林長嶺,123.97,44.3  
吉林通榆,123.13,44.82  
吉林洮安,122.75,45.35   
四川成都,104.06,30.67  
四川金堂,104.32,30.88  
四川雙流,104.94,30.57  
四川蒲江,103.29,30.2  
四川郫縣,103.86,30.8  
四川新都,104.13,30.82  
四川來易,102.15,26.9  
四川鹽邊,101.56,26.9  
天津天津,117.2,39.13  
天津寧河,117.83,39.33  
天津靜海,116.92,38.93  
天津薊縣,117.4,40.05  
天津寶坻,117.3,39.75  
天津武清,117.05,39.4  
寧夏回族自治區銀川,106.27,38.47  
寧夏回族自治區永寧,106.24,38.28  
寧夏回族自治區賀蘭,106.35,38.55  
寧夏回族自治區石嘴山,106.39,39.04  
寧夏回族自治區平羅,106.54,38.91  
寧夏回族自治區陶樂,106.69,38.82  
寧夏回族自治區吳忠,106.21,37.99  
寧夏回族自治區同心,105.94,36.97  
寧夏回族自治區靈武,106.34,38.1
安徽郎溪,119.17,31.14  
安徽廣德,119.41,30.89  
安徽涇縣,118.41,30.68  
安徽南陵,118.32,30.91  
安徽繁昌,118.21,31.07  
安徽寧國,118.95,30.62  
安徽青陽,117.84,30.64  
安徽屯溪,118.31,29.72  
安徽休寧,118.19,29.81  
安徽旌得,118.53,30.28  
安徽績溪,118.57,30.07  
安徽歙縣,118.44,29.88  

好了前期工作介紹完畢,終於可以看程式了

其中,模組一是平均畸變程度和輪廓係數; 模組二是預測效果

我在這裡將兩模組都註釋掉了,讀者可以分別執行

程式碼:

#K-Means   
import numpy as np  
import matplotlib.pyplot as plt  
from sklearn.cluster import KMeans
from sklearn.externals import joblib     #模組二
import pandas as pd
import matplotlib as mpl
from scipy.spatial.distance import cdist #模組一
from sklearn import metrics              #模組一

#從磁碟讀取城市經緯度資料  
X = []  
f = open('city.txt')  
for v in f:
    X.append([float(v.split(',')[1]),float(v.split(',')[2])])
f.close()

#轉換成numpy array,形如:[[1.2 , 3.2],[2.3 , 6.3 ],[1.0 , 2.3]],轉化前X是一個列表
X = np.array(X)

mpl.rcParams['font.sans-serif'] = [u'SimHei']            #繪圖時用來正常顯示中文標籤    
mpl.rcParams['axes.unicode_minus'] = False               #繪圖時用來正常顯示負號


'''
#模組一:
#通過平均畸變程度來確定類簇的數量,通過輪廓係數(Silhouette Coefficient)評價聚類演算法(具體來自https://blog.csdn.net/wangxiaopeng0329/article/details/53542606)
#d=cdist(X,Y,'euclidean')#假設X有M個元素,Y有N個元素,最終會生成M行N列的array,用來計算X、Y中每個相對元素之間的尤拉距離
#numpy.min(d,axis=1) #如果d為m行n列,axis=0時會輸出每一列的最小值,axis=1會輸出每一行最小值
n_clusters = range(2,5) #假設分別在2,3,4中選取一個最合適的n_clusters
meandistortions=[]
metrics_silhouette=[]
for k in n_clusters:
    clf=KMeans(n_clusters=k)
    cls = clf.fit(X)
    meandistortions.append(sum(np.min(cdist(X,clf.cluster_centers_,'euclidean'),axis=1))/X.shape[0])#平均畸變程度值,越小越好
    metrics_silhouette.append(metrics.silhouette_score(X,clf.labels_,metric='euclidean'))           #輪廓係數,越接近1越好   
#平均畸變程度圖   
plt.subplot(121)
plt.plot(n_clusters,meandistortions,'rx-')
plt.xlabel('k')
plt.ylabel('平均畸變程度')
plt.title('K-Means平均畸變程度圖(越小越好) ')
#輪廓係數圖
plt.subplot(122)
plt.plot(n_clusters,metrics_silhouette,'bx-')
plt.ylabel('輪廓係數')
plt.xlabel('k')
plt.title('K-Means輪廓係數(越接近1越好)')
#顯示
plt.show()

'''



'''   

#模組二:
#核心程式碼:現在把資料和對應的分類放入聚類函式中進行聚類
#其中n_clusters 需要聚成幾類,init代表初始點怎麼找,max_iter代表迭代次數, n_jobs用的cpu,precompute_distances預先需不需要計算距離
n_clusters=4
clf=KMeans(n_clusters=n_clusters)
cls = clf.fit(X)

#聚類結果的顯示,其中用clf和cls均可
print(cls.labels_)                         #顯示每個樣本所屬的簇
print(clf.cluster_centers_)                #4箇中心點的座標
print(clf.inertia_)                        #用來評估簇的個數是否合適,代表所有點到各自中心的距離和,距離越小說明簇分的越好,選取臨界點的簇個數
r1 = pd.Series(cls.labels_).value_counts()
print(r1)                                  #統計每個類別下樣本個數

#用聚類的學習結果去預測
X1=[[121.35,26.41],[123.5,45.35]]
print(clf.predict(X1))

#儲存模型,載入模型(載入後是類別標籤)
joblib.dump(clf,'d:/test/km.txt')
clf = joblib.load('d:/test/km.txt')

#畫圖
markers = ['x','o','*','+']
colors=['b','r','y','g']
for i in range(n_clusters):
     members = cls.labels_ == i
     plt.scatter(X[members,0],X[members,1],s=60,marker=markers[i],c=colors[i],alpha=0.5)
plt.xlabel('經度')
plt.ylabel('緯度')
plt.title('K-Means聚合結果(n_clusters=4)')  
plt.show()

'''

模組一結果:


模組二結果:



更多演算法可以參看博主其他文章,或者github:https://github.com/Mryangkaitong/python-Machine-learning