1. 程式人生 > >聚類分析(K-means 層次聚類和基於密度DBSCAN演算法三種實現方式)

聚類分析(K-means 層次聚類和基於密度DBSCAN演算法三種實現方式)

之前也做過聚類,只不過是用經典資料集,這次是拿的實際資料跑的結果,效果還可以,記錄一下實驗過程。

首先:
確保自己資料集是否都完整,不能有空值,最好也不要出現為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 的值就可以了。