聚類分析(K-means 層次聚類和基於密度DBSCAN演算法三種實現方式)
阿新 • • 發佈:2018-12-30
之前也做過聚類,只不過是用經典資料集,這次是拿的實際資料跑的結果,效果還可以,記錄一下實驗過程。
首先:
確保自己資料集是否都完整,不能有空值,最好也不要出現為0的值,會影響聚類的效果。
其次:
想好要用什麼演算法去做,K-means,層次聚類還是基於密度演算法,如果對這些都不算特別深入瞭解,那就都嘗試一下吧,我就是這樣做的。
好了,簡單開始講解實驗的過程吧。
第一步
環境:
Windows10 + Anaconda3 + Pycharm
為了避免中文編碼錯誤,在python檔案上加一句中文編碼設定程式碼:
#-*- coding:utf-8 -*-
並且在Pycharm下修改編碼設定,安心。方法如下:
在Pycharm下開啟你的專案,左上角File–>Settings–>Editor–>File Encodings
點選那個+號先把你的專案新增進來,然後按照上面截圖將編碼格式改成UTF-8,點選Apply,再點OK。這樣編碼錯誤就不會出現了,如果讀入的檔案含有中文還是出現編碼錯誤,那就是你儲存的檔案編碼格式不對,去修改檔案儲存的編碼格式,自行百度。
一些庫的準備:
import pandas as pd
from sklearn.cluster import KMeans #匯入K均值聚類演算法
from sklearn.cluster import AgglomerativeClustering #層次聚類
from sklearn.cluster import DBSCAN #具有噪聲的基於密度聚類方法
import matplotlib.pyplot as plt #matplotlib畫圖
from sklearn.decomposition import PCA #主成分分析
from mpl_toolkits.mplot3d import Axes3D #畫三維圖
這些庫都有註釋,想了解詳細自己去看官方文件。
第二步
貼上了完整的程式碼,只需要改檔案路徑就可以了。
#-*- coding:utf-8 -*-
import pandas as pd
from sklearn.cluster import KMeans #匯入K均值聚類演算法
from sklearn.cluster import AgglomerativeClustering #層次聚類
from sklearn.cluster import DBSCAN #具有噪聲的基於密度聚類方法
import matplotlib.pyplot as plt #matplotlib畫圖
from sklearn.decomposition import PCA #主成分分析
from mpl_toolkits.mplot3d import Axes3D #畫三維圖
pltcolor=['b<', 'g>', 'r1', 'c2', 'm3', 'y4', 'ks', 'wp'] #顏色
inputfile = 'E:/Work/python/data.xlsx' #待聚類的資料檔案,需要進行標準化的資料檔案;
zscoredfile = 'E:/Work/python/zdata.xlsx' #標準差計算後的資料儲存路徑檔案;
data = pd.read_excel(inputfile) #讀取資料,因為我的檔案時CSV格式的,直接read_excel就可以,不是的話自己寫一個檔案讀取的方法讀進來。
iteration = 5000 # 聚類最大迴圈數
d = []
mink = 4 #聚類的類別範圍K值下界
maxk = mink + 1 #聚類的列別範圍上界
#data = (data - data.mean(axis = 0))/(data.std(axis = 0)) #簡潔的語句實現了標準化變換,類似地可以實現任何想要的變換。也可以直接在原始資料裡面就先處理好,這句話就可以不用了。
#data.columns=['Z'+i for i in data.columns] #表頭重新命名。
#data.to_excel(zscoredfile, index = False) #資料寫入,標準化之後資料重新寫入,直接覆蓋掉之前的檔案裡的內容
# svd_solver : string {'auto', 'full', 'arpack', 'randomized'} 這個引數可以在PCA演算法裡看到
pca = PCA(n_components=2, svd_solver='full') # 輸出兩維 PCA主成分分析抽象出維度
#下面註釋的幾行是其它幾種PCA主成分分析方法,可以嘗試使用。
# from sklearn.decomposition import KernelPCA
# kernel : "linear" | "poly" | "rbf" | "sigmoid" | "cosine" | "precomputed"
# pca = KernelPCA(n_components = 2, kernel = "poly")
# method : {'lars', 'cd'}
# from sklearn.decomposition import SparsePCA
# pca = SparsePCA(n_components = 2, method = 'cd')
# from sklearn.decomposition import TruncatedSVD
# algorithm : string, default = "randomized" "arpack"
# pca = TruncatedSVD(algorithm = "arpack")
newData = pca.fit_transform(data) # 載入N維
if __name__ == '__main__' :
print("Kmeans")
for k in range(mink, maxk): # k取值在mink-maxk值之間,做kmeans聚類,看不同k值對應的簇內誤差平方和
outputfile = 'E:/Work/python/fenlei%d.xlsx' % k
# 讀取資料並進行聚類分析
# 呼叫k-means演算法,進行聚類分析
kmodel = KMeans(n_clusters=k, init='k-means++', n_jobs=5, max_iter=iteration) # n_jobs是並行數,一般等於CPU數較好,max_iter是最大迭代次數,init='K-means++'引數的設定可以讓初始化均值向量的時候讓這幾個簇中心儘量分開
kmodel.fit(data) # 訓練模型
r1 = pd.Series(kmodel.labels_).value_counts() # 統計各個類別的數目
#r2 = pd.DataFrame(kmodel.cluster_centers_) # 找出聚類中心
print(r1)
kmlabels = kmodel.labels_ # 得到類別,label_ 是內部變數
#print(pd.Series(kmlabels, index=data.index)) #輸出為序號和對應的類別,以序號為拼接列,把類別加到最後面一列
r = pd.concat([data, pd.Series(kmlabels, index=data.index)], axis=1) # 詳細輸出每個樣本對應的類別,橫向連線(0是縱向),得到聚類中心對應的類別下的數目
r.columns = list(data.columns) + [u'聚類類別'] # 重命名錶頭 加一列的表頭
r.to_excel(outputfile) # 儲存分類結果
d.append(kmodel.inertia_) # inertia簇內誤差平方和
if mink >= maxk - 1:
x = []
y = []
for i in range(0, len(r1)):
x.append([])
y.append([])
for i in range(0, len(kmlabels)):
labelnum = kmlabels[i] #輸出每條資料的類別標籤
if labelnum >= 0:
x[labelnum].append(newData[i][0])
y[labelnum].append(newData[i][1])
# blue,green,red,cyan,magenta,yellow,black,white
for i in range(0, len(r1)):
plt.plot(x[i], y[i], pltcolor[i])
plt.show()
if mink < maxk - 1 :
plt.plot(range(mink, maxk), d, marker='o')
plt.xlabel('number of clusters')
plt.ylabel('distortions')
plt.show()
'''
k = 5 #需要進行的聚類類別數
outputfile = 'E:/Work/python/fenlei%d.xlsx' % k
iteration = 500 #聚類最大迴圈數
#讀取資料並進行聚類分析
data = pd.read_excel(inputfile) #讀取資料
#呼叫k-means演算法,進行聚類分析
kmodel = KMeans(n_clusters = k, n_jobs = 3, max_iter=iteration) #n_jobs是並行數,一般等於CPU數較好
kmodel.fit(data) #訓練模型
r1 = pd.Series(kmodel.labels_).value_counts() #統計各個類別的數目
r2 = pd.DataFrame(kmodel.cluster_centers_) #找出聚類中心
r = pd.concat([r2, r1], axis = 1) #橫向連線(0是縱向),得到聚類中心對應的類別下的數目
r.columns = list(data.columns) + [u'類別數目'] #重命名錶頭
print (r)
r = pd.concat([data, pd.Series(kmodel.labels_, index = data.index)], axis = 1) #詳細輸出每個樣本對應的類別
r.columns = list(data.columns) + [u'聚類類別'] #重命名錶頭
r.to_excel(outputfile) #儲存分類結果
'''
if False:
def density_plot(data): #自定義作圖函式
p = data.plot(kind='kde', linewidth = 2, subplots = True, sharex = False)
[p[i].set_ylabel('density') for i in range(k)]
plt.legend()
return plt
pic_output = 'E:/Work/python/' #概率密度圖檔名字首
for i in range(k):
print(u'%s%s.png' %(pic_output, i))
if i > 1:
density_plot(data[r[u'聚類類別']==i]).savefig(u'%s%s.png' %(pic_output, i))
if __name__ == "__main__2" :
print("AgglomerativeClustering")
for k in range(mink, maxk): # k取值1~11,做kmeans聚類,看不同k值對應的簇內誤差平方和
outputfile = 'E:/Work/python/fenlei%d.xlsx' % k
# 讀取資料並進行聚類分析
# 呼叫層次聚類演算法,進行聚類分析
linkages = ['ward', 'average', 'complete']
kmodel = AgglomerativeClustering(linkage=linkages[2],n_clusters = k, affinity='manhattan')
kmodel.fit(data) # 訓練模型
r1 = pd.Series(kmodel.labels_).value_counts() # 統計各個類別的數目
print(r1)
#r2 = pd.DataFrame(kmodel.cluster_centers_) # 找出聚類中心
kmlabels = kmodel.labels_
r = pd.concat([data, pd.Series(kmlabels, index=data.index)], axis=1) # 詳細輸出每個樣本對應的類別,橫向連線(0是縱向),得到聚類中心對應的類別下的數目
r.columns = list(data.columns) + [u'聚類類別'] # 重命名錶頭
#print(outputfile)
r.to_excel(outputfile) # 儲存分類結果
if mink >= maxk - 1:
x = []
y = []
for i in range(0, len(r1)):
x.append([])
y.append([])
for i in range(0, len(kmlabels)):
labelnum = kmlabels[i]
if labelnum >= 0:
x[labelnum].append(newData[i][0])
y[labelnum].append(newData[i][1])
# blue,green,red,cyan,magenta,yellow,black,white
for i in range(0, len(r1)):
plt.plot(x[i], y[i], pltcolor[i])
plt.show()
if __name__ == "__main__3" :
print("DBSCAN")
outputfile = 'E:/Work/python/fenlei_DBSCAN.xlsx'
# 讀取資料並進行聚類分析
# 呼叫DBSCAN演算法,進行聚類分析
linkages = ['ward', 'average', 'complete']
#From scikit-learn: ['cityblock', 'cosine', 'euclidean', 'l1', 'l2', 'manhattan']. These metrics support sparse matrix inputs.
#From scipy.spatial.distance: ['braycurtis', 'canberra', 'chebyshev', 'correlation', 'dice', 'hamming', 'jaccard', 'kulsinski', 'mahalanobis', 'matching', 'minkowski', 'rogerstanimoto', 'russellrao', 'seuclidean', 'sokalmichener', 'sokalsneath', 'sqeuclidean', 'yule']
kmodel = DBSCAN(eps= 0.768, min_samples=160, n_jobs=7, metric='euclidean')
# kmodel = DBSCAN(eps=0.64, min_samples=100, n_jobs=7, metric='canberra')
kmodel.fit(data) # 訓練模型
r1 = pd.Series(kmodel.labels_).value_counts() # 統計各個類別的數目
print(r1)
# r2 = pd.DataFrame(kmodel.cluster_centers_) # 找出聚類中心
kmlabels = kmodel.labels_
r = pd.concat([data, pd.Series(kmlabels, index=data.index)], axis=1) # 詳細輸出每個樣本對應的類別, 橫向連線(0是縱向),得到聚類中心對應的類別下的數目
r.columns = list(data.columns) + [u'聚類類別'] # 重命名錶頭
print(outputfile)
r.to_excel(outputfile) # 儲存分類結果
rlen = len(r1)
if (rlen <= 6):
x = []
y = []
for i in range(0, len(r1) + 1):
x.append([])
y.append([])
for i in range(0, len(kmlabels)):
labelnum = kmlabels[i] + 1
if labelnum >= 0:
x[labelnum].append(newData[i][0])
y[labelnum].append(newData[i][1])
# blue,green,red,cyan,magenta,yellow,black,white
for i in range(0, len(r1) + 1):
plt.plot(x[i], y[i], pltcolor[i])
plt.show()
第三步
可以執行看一下效果,下圖是使用K-means聚類出來的效果,K值設為4:
然後你可以去看輸出檔案分出的類別,可以嘗試改變K值,直接改minK和maxK 的值就可以了。