1、概念python
K-means是一種典型的聚類算法,它是基於距離的,是一種無監督的機器學習算法。算法
K-means須要提早設置聚類數量,咱們稱之爲簇,還要爲之設置初始質心。數組
缺點:dom
一、循環計算點到質心的距離,複雜度較高。機器學習
二、對噪聲不敏感,即便是噪聲也會被聚類。函數
三、質心數量及初始位置的選定對結果有必定的影響。學習
2、計算spa
K-means須要循環的計算點到質心的距離,有三種經常使用的方法:code
一、歐式距離blog
歐式距離源自N維歐氏空間中兩點x,y間的距離公式,在二維上(x1,y1)到(x2,y2)的距離體現爲:
在三維上體現爲:
歐式距離是K-means最經常使用的計算距離的方法。
二、曼哈頓距離
在二維上(x1,y1)到(x2,y2)的距離體現爲:
三、餘弦夾角
餘弦距離不是距離,而只是類似性,其餘距離直接測量兩個高維空間上的點的距離,若是距離爲0則兩個點「相同」;
餘弦的結果爲在[-1,1]之中,若是爲 1,只能肯定二者徹底相關、徹底類似。
在二維上(x1,y1)到(x2,y2)的距離體現爲:
聚類的基本步驟:
一、設置質心個數,這表明最終聚類數;
二、根據質心個數隨機生成初始質心點;
三、計算數據與質心距離,根據距離遠近作第一次分類;
四、將聚類結果的中心點定義爲新的質心,再進行3的計算;
五、循環迭代直到質心再也不變化,此爲最終結果。
三、實現
#!/usr/bin/env python # -*- coding: utf-8 -*- import numpy as np import matplotlib.pyplot as plt def create_sample(): np.random.seed(10) # 隨機數種子,保證隨機數生成的順序同樣 n_dim = 2 num = 100 a = 3 + 5 * np.random.randn(num, n_dim) b = 18 + 4 * np.random.randn(num, n_dim) data_mat = np.concatenate((a, b)) ay = np.zeros(num) by = np.ones(num) label = np.concatenate((ay, by)) return {'data_mat': data_mat, 'label': label} # arr[i, :] #取第i行數據 # arr[i:j, :] #取第i行到第j行的數據 # in:arr[:,0] # 取第0列的數據,以行的形式返回的 # in:arr[:,:1] # 取第0列的數據,以列的形式返回的 def k_mean(data_set, k): m, n = np.shape(data_set) # 獲取維度, 行數,列數 cluster_assignment = np.mat(np.zeros((m, 2))) # 轉換爲矩陣, zeros生成指定維數的全0數組,用來記錄迭代結果 centroids = generate_centroids(k, n) cluster_changed = True while cluster_changed: cluster_changed = False for i in range(m): min_distance = np.inf # 無限大的正數 min_index = -1 vec_b = np.array(data_set)[i, :] # i行數據,數據集內的點的位置 for j in range(k): vec_a = np.array(centroids)[j, :] # j行數據, 中心點位置 distance = calculate_distance(vec_a, vec_b) if distance < min_distance: min_distance = distance min_index = j if cluster_assignment[i, 0] != min_index: cluster_changed = True cluster_assignment[i, :] = min_index, min_distance ** 2 update_centroids(data_set, cluster_assignment, centroids, k) get_result(data_set, cluster_assignment, k) def generate_centroids(centroid_num, column_num): centroids = np.mat(np.zeros((centroid_num, column_num))) # 生成中心點矩陣 for index in range(centroid_num): # 隨機生成中心點, np.random.rand(Random values in a given shape) centroids[index, :] = np.mat(np.random.rand(1, column_num)) return centroids def calculate_distance(vec_a, vec_b): distance = np.sqrt(sum(np.power(vec_a - vec_b, 2))) # power(x1, x2) 對x1中的每一個元素求x2次方。不會改變x1上午shape。 return distance def update_centroids(data_set, cluster_assignment, centroids, k): for cent in range(k): # 取出對應簇 cluster = np.array(cluster_assignment)[:, 0] == cent # np.nonzero取出矩陣中非0的元素座標 pts_in_cluster = data_set[np.nonzero(cluster)] # print(pts_in_cluster) # mean() 函數功能:求取均值 # 常常操做的參數爲axis,以m * n矩陣舉例: # axis : 不設置值, m * n 個數求均值,返回一個實數 # axis = 0:壓縮行,對各列求均值,返回1 * n矩陣 # axis = 1 :壓縮列,對各行求均值,返回m * 1矩陣 if len(pts_in_cluster) > 0: centroids[cent, :] = np.mean(pts_in_cluster, axis=0) def get_result(data_set, cluster_assignment, k): cs = ['r', 'g', 'b'] for cent in range(k): ret_id = np.nonzero(np.array(cluster_assignment)[:, 0] == cent) plot_data(data_set[ret_id], cs[cent]) plt.show() def plot_data(samples, color, plot_type='o'): plt.plot(samples[:, 0], samples[:, 1], plot_type, markerfacecolor=color, markersize=14) data = create_sample() k_mean(data['data_mat'], 2)
聚類結果: