無監督學習--聚類模型--K 均值0.引入依賴1.數據的加載和預處理2.算法實現3.測試python
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)
# x # array([[-0.02708305, 5.0215929 ], ..., [-4.7583093 , 5.85803377]])
# x.shape # (100, 2)
# y.shape # (100,)
plt.figure(figsize=(9, 9))
plt.scatter(x[:,0], x[:,1], c=y)
plt.show()
做圖以下:算法
# 引入 scipy 庫中的距離函數,默認實現是歐式距離
from scipy.spatial.distance import cdist
class K_Means(object):
# 初始化,參數 n_clusters(K)、max_iter(迭代次數)、centroids(初始質心)
def __init__(self, n_clusters=6, 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.計算距離,獲得的是一個 100x6 的矩陣,該矩陣的每一行含義是:一個樣本點跟全部質心的距離
distances = cdist(data, self.centroids)
# 2.對距離按由近到遠排序,選取最近的質心點的類別,做爲當前點的分類
c_index = np.argmin(distances, axis=1) # 獲得 100x1 的矩陣
# 3.對每一類數據進行均值計算,更新質心點的座標
for i in range(self.n_clusters): # 遍歷每一類
# 排除掉沒有出如今 c_index 裏的類別
if i in c_index:
# 選擇全部類別是 i 的點,取 data 裏面座標的均值,更新第 i 個質心
self.centroids[i] = np.mean(data[c_index==i], axis=0) # 獲得一行數據,使用了布爾索引
# 定義預測模型方法
def predict(self, samples):
# 跟上面同樣,先計算距離,而後讀取距離最近的那個質心的類別
distances = cdist(samples, self.centroids)
c_index = np.argmin(distances, axis=1) # 獲得 100x1 的矩陣
return c_index
# 測試
distances = np.array([[121, 221, 32, 43],
[121, 332, 166, 52],
[96, 411, 56, 158],
[45, 235, 542, 156],
[140, 54, 63, 255],
], dtype=np.float)
c_index = np.argmin(distances, axis=1)
print(c_index)
x_new =x[0:5]
print(x_new)
print(c_index==2)
print(x_new[c_index==2])
np.mean(x_new[c_index==2], axis=0)
輸出結果以下:app
[2 3 2 0 1]
[[-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]]
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(6)), s=100)
plt.title(title)
kmeans = K_Means(max_iter=300, centroids=np.array([[2, 1],[2, 2],[2, 3],[2, 4],[2, 5],[2, 6]]))
plt.figure(figsize=(18, 9))
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], c='black', s=100)
輸出結果以下:dom
[[ 5.76444812 -4.67941789]
[-2.89174024 -0.22808556]
[-5.89115978 2.33887408]
[-4.53406813 6.11523454]
[-1.15698106 5.63230377]
[ 9.20551979 7.56124841]]
[1 5]
<matplotlib.collections.PathCollection at 0x1543350c518>
做圖以下:函數