機器學習聚類算法之K-means

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)

 

聚類結果:

相關文章
相關標籤/搜索