目录

一、前言

二、代码实现

        1. 随即给定初始点并返回,其点个数就是K值

        2. 得到当前每一个样本到K个中心点的距离,得到每个样本距离最近的那个中心点并返回中心点

        3.更新中心点并返回

        4. 进行训练(迭代)返回最后一次的中心点和簇类中的样本(每个样本距离最近的中心点)

        5.完整代码

三、应用案例

        1.代码实现

        2. 结果显示

        3. K=3的聚类结果

        4. K=4的聚类结果

        5.总结


      

一、前言

        本文主要实现K-means这一算法,根据聚类算法理论篇(K-means,DBSCAN原理)可知:

        输入:数据data

                   K值

        输出:簇组

       其工作流程:

                1.根据K值,随机创建K个初始化质心点(Initialozation Randomly selecr K center points。

                2. 算出所有样本点到质心点的距离,得到样本属于那个簇。

                3. 更新,根据簇内样本重新算出簇内的质心。

                4. 重复执行2,3步,重新划分簇类,直至质心不在变化。

二、代码实现

        K-means的实现

        1. 随即给定初始点并返回,其点个数就是K值

    def centeroids_init(data,num_clusters):
        num_examples = data.shape[0]
        random_ids = np.random.permutation(num_examples) #洗牌操作
        centeroids = data[random_ids[:num_clusters],:]  #random_ids[:num_clusters]选择num_clusters个样本 [:num_clusters],:]所有特征
        return centeroids

        2. 得到当前每一个样本到K个中心点的距离,得到每个样本距离最近的那个中心点并返回中心点

    def centeroids_find_closet(data,centroids):
        num_examples = data.shape[0]
        num_centeroids = centroids.shape[0]
        #closet_centeroids_ids = np.zeros((num_examples,1))
        #c初始化
        closet_centeroid_ids = np.zeros((num_examples, 1))
        for example_index in range(num_examples):
            distance = np.zeros((num_centeroids,1)) #簇表
            for centeroid_index in range(num_centeroids):
                distance_diff = data[example_index,:] - centroids[centeroid_index,:] # 算出距离
                distance[centeroid_index] = np.sum(distance_diff**2) #将距离的平方值存入 簇表内
            closet_centeroid_ids[example_index] = np.argmin(distance)

        return closet_centeroid_ids

        3.更新中心点并返回

    def centroids_updata(data,closet_centroid_ids,num_clusters):
        num_features = data.shape[1]
        centroids = np.zeros((num_clusters,num_features)) # 有num_clusters个质心,每个质心有num_features个维度,即num_clusters*num_features矩阵
        for centroid_id in range(num_clusters):
            closet_id  = closet_centroid_ids == centroid_id  #最近的点
            centroids[centroid_id] = np.mean(data[closet_id.flatten(),:],axis=0) #各个维度的均值
        return centroids

        4. 进行训练(迭代)返回最后一次的中心点和簇类中的样本(每个样本距离最近的中心点)

    def train(self,max_iterations):
        #1.先随机选择K个中心点
        centroids = KMeans.centeroids_init(self.data,self.num_clusters)
        #
        num_examples = self.data.shape[0]
        #最近的中心点
        closet_centroid_ids = np.empty((num_examples,1))
        #2.开始训练
        for _ in range(max_iterations):
            #3.当前距离 得到当前每一个样本到K个中心点的距离,得到最近的那个
            closet_centroid_ids = KMeans.centeroids_find_closet(self.data,centroids)
            #4.进行中心点的更新
            centroids = KMeans.centroids_updata(self.data,closet_centroid_ids,self.num_clusters)

        return centroids,closet_centroid_ids

        5.完整代码

import numpy as np

class KMeans:
    def __init__(self,data,num_clusters):
        self.data = data
        self.num_clusters = num_clusters

    def train(self,max_iterations):
        #1.先随机选择K个中心点
        centroids = KMeans.centeroids_init(self.data,self.num_clusters)
        #
        num_examples = self.data.shape[0]
        #最近的中心点
        closet_centroid_ids = np.empty((num_examples,1))
        #2.开始训练
        for _ in range(max_iterations):
            #3.当前距离 得到当前每一个样本到K个中心点的距离,得到最近的那个
            closet_centroid_ids = KMeans.centeroids_find_closet(self.data,centroids)
            #4.进行中心点的更新
            centroids = KMeans.centroids_updata(self.data,closet_centroid_ids,self.num_clusters)

        return centroids,closet_centroid_ids





    @staticmethod
    def centeroids_init(data,num_clusters):
        num_examples = data.shape[0]
        random_ids = np.random.permutation(num_examples) #洗牌操作
        centeroids = data[random_ids[:num_clusters],:]  #random_ids[:num_clusters]选择num_clusters个样本 [:num_clusters],:]所有特征
        return centeroids

    @staticmethod
    def centeroids_find_closet(data,centroids):
        num_examples = data.shape[0]
        num_centeroids = centroids.shape[0]
        #closet_centeroids_ids = np.zeros((num_examples,1))
        #c初始化
        closet_centeroid_ids = np.zeros((num_examples, 1))
        for example_index in range(num_examples):
            distance = np.zeros((num_centeroids,1)) #簇表
            for centeroid_index in range(num_centeroids):
                distance_diff = data[example_index,:] - centroids[centeroid_index,:] # 算出距离
                distance[centeroid_index] = np.sum(distance_diff**2) #将距离的平方值存入 簇表内
            closet_centeroid_ids[example_index] = np.argmin(distance)

        return closet_centeroid_ids

    @staticmethod
    #更新质心点
    def centroids_updata(data,closet_centroid_ids,num_clusters):
        num_features = data.shape[1]
        centroids = np.zeros((num_clusters,num_features)) # 有num_clusters个质心,每个质心有num_features个维度,即num_clusters*num_features矩阵
        for centroid_id in range(num_clusters):
            closet_id  = closet_centroid_ids == centroid_id  #最近的点
            centroids[centroid_id] = np.mean(data[closet_id.flatten(),:],axis=0) #各个维度的均值
        return centroids

        
        
        

三、应用案例

        本例主要使用鸢尾花数据集,数据集读者可以自行下载

        1.代码实现

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from Kmeans_lab.kmeans.k_means import KMeans



data = pd.read_csv('../data/iris.csv')
iris_types = ['SETOSA','VERSICOLOR','VIRGINICA']

x_axis = 'petal_length'
y_axis = 'petal_width'

plt.figure(figsize=(12,5))
plt.subplot(1,2,1)
for iris_type in iris_types:
    plt.scatter(data[x_axis][data['class']==iris_type],data[y_axis][data['class']==iris_type],label = iris_type)
plt.title('label known')
plt.legend()

plt.subplot(1,2,2)
plt.scatter(data[x_axis][:],data[y_axis][:])
plt.title('label unknown')
plt.show()

num_examples = data.shape[0]
x_train = data[[x_axis,y_axis]].values.reshape(num_examples,2)

#指定好训练所需的参数
num_clusters = 3
max_iteritions = 50

k_means = KMeans(x_train,num_clusters)
centroids,closest_centroids_ids = k_means.train(max_iteritions)
# 对比结果
plt.figure(figsize=(12,5))
plt.subplot(1,2,1)
for iris_type in iris_types:
    plt.scatter(data[x_axis][data['class']==iris_type],data[y_axis][data['class']==iris_type],label = iris_type)
plt.title('label known')
plt.legend()

plt.subplot(1,2,2)
for centroid_id, centroid in enumerate(centroids):
    current_examples_index = (closest_centroids_ids == centroid_id).flatten()
    plt.scatter(data[x_axis][current_examples_index],data[y_axis][current_examples_index],label = centroid_id)

for centroid_id, centroid in enumerate(centroids):
    plt.scatter(centroid[0],centroid[1],c='black',marker = 'x')
plt.legend()    
plt.title('label kmeans')
plt.show()

         2. 结果显示

          3. K=3的聚类结果

            4. K=4的聚类结果

        5.总结

        从实验可以看出K-means只适合一些简单的数据集,最好是开始就成堆的数据。并且K值对结果的影响非常大。 

        多种聚类读者可以进行尝试

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐