無監督學習
相對監督學習(輸入進x,有對應的y),沒有標注
聚類
- k均值
- 基於密度的聚類
- 最大期望聚類
降維
- 潛語義分析(LSA)
- 主成分分析(PCA)
- 奇異值分解(SVD)
k 均值(k-means)是聚類算法中最為簡單、高效的,屬於無監督學習算法
核心思想:由用戶指定k個初始質心(initial centroids),以作為聚類的類別(cluster),重復迭代直至算法收斂
基本算法流程:
- 選取k個初始質心(作為初始cluster);
- repeat:
對每個樣本點,計算得到距其最近的質心,將其類別標為該質心所對應的cluster; 重新計算k個cluser對應的質心; until 質心不再發生變化或迭代達到上限
kmeans代碼實現
import numpy as np import matplotlib.pyplot as plt # 從sklearn中直接生成聚類數據 from sklearn.datasets.samples_generator import make_blobs
加載數據
x, y = make_blobs( n_samples=100, centers=6, random_state=1234, cluster_std=0.6 ) #100個樣本,centers生成的樣本中心(類別)數; random_state --seed used by the random number generator; #cluster_std為每個類別設置不同的方差 #x.shape #(100, 2) plt.figure(figsize=(6,6)) plt.scatter(x[:,0], x[:,1], c=y) #c=y 6類,變得有顏色 plt.show()
算法實現
# 引入scipy中的距離函數,默認計算歐式距離 from scipy.spatial.distance import cdist class K_Means(object): # 初始化,參數 n_clusters(K)、迭代次數max_iter、初始質心 centroids def __init__(self, n_clusters=5, max_iter=300, centroids=[]): self.n_clusters = n_clusters self.max_iter = max_iter self.centroids = np.array( centroids, dtype=np.float ) # 訓練模型方法,k-means聚類過程,傳入原始數據 def fit(self, data): # 假如沒有指定初始質心,就隨機選取data中的點作為初始質心 if( self.centroids.shape == (0,) ): # 從data中隨機生成0到data行數的6個整數,作為索引值 self.centroids = data[ np.random.randint( 0, data.shape[0], self.n_clusters ) ,: ] # 開始迭代 for i in range(self.max_iter): # 1. 計算距離矩陣,得到的是一個100*6的矩陣 distances = cdist(data, self.centroids) # 2. 對距離按有近到遠排序,選取最近的質心點的類別,作為當前點的分類 c_ind = np.argmin( distances, axis=1 ) #axis=1保留最近一列 # 3. 對每一類數據進行均值計算,更新質心點坐標 for i in range(self.n_clusters ): # 排除掉沒有出現在c_ind里的類別 if i in c_ind: # 選出所有類別是i的點,取data里面坐標的均值,更新第i個質心 #data[c_ind==i]布爾索引,拿到為true的值 self.centroids[i] = np.mean( data[c_ind==i], axis=0 ) # 實現預測方法 def predict(self, samples): # 跟上面一樣,先計算距離矩陣,然后選取距離最近的那個質心的類別 distances = cdist(samples, self.centroids) c_ind = np.argmin( distances, axis=1 ) return c_ind ##測試下,二維數組5 * 4(4個質心點),行數代表有幾個點,一行數是跟每一個質心的距離 dist = np.array([[121,221,32,43], [121,1,12,23], [65,21,2,43], [1,221,32,43], [21,11,22,3],]) c_ind = np.argmin( dist, axis=1 ) print(c_ind) #每一個元素跟哪一類最近 [2 1 2 0 3] x_new=x[0:5] print(x_new)# print(c_ind==2) #[ True False True False False] print(x_new[c_ind==2]) np.mean(x_new[c_ind==2], axis=0) #每一個坐標每一列對應的平均值
----->>
[2 1 2 0 3] [[-0.02708305 5.0215929 ] [-5.49252256 6.27366991] [-5.37691608 1.51403209] [-5.37872006 2.16059225] [ 9.58333171 8.10916554]] [ True False True False False] [[-0.02708305 5.0215929 ] [-5.37691608 1.51403209]] Out[14]: array([-2.70199956, 3.26781249])
測試
# 定義一個繪制子圖函數 def plotKMeans(x, y, centroids, subplot, title): # 分配子圖,121表示1行2列的子圖中的第一個 plt.subplot(subplot) plt.scatter(x[:,0], x[:,1], c='r') # 畫出質心點 plt.scatter(centroids[:,0], centroids[:,1], c=np.array(range(5)), s=100) plt.title(title) #centroids指定初始點 kmeans = K_Means(max_iter=300, centroids=np.array([[2,1],[2,2],[2,3],[2,4],[2,5]])) plt.figure(figsize=(16, 6)) #初始狀態的圖 plotKMeans( x, y, kmeans.centroids, 121, 'Initial State' ) # 開始聚類 kmeans.fit(x) plotKMeans( x, y, kmeans.centroids, 122, 'Final State' ) # 預測新數據點的類別 x_new = np.array([[0,0],[10,7]]) y_pred = kmeans.predict(x_new) print(kmeans.centroids) print(y_pred) plt.scatter(x_new[:,0], x_new[:,1], s=100, c='black') ---->> [[ 5.76444812 -4.67941789] [-2.89174024 -0.22808556] [-5.89115978 2.33887408] [-2.8455246 5.87376915] [ 9.20551979 7.56124841]] [1 4]