【机器学习】k-means算法原理自实现

lixiaotao 2019-12-29

import pandas as pd
import numpy as np
import matplotlib.pyplot   as plt
from sklearn.cluster import KMeans # 导入k-means


def build_data():
    """
    构建数据
    :return:data
    """
    # (1)加载数据
    data = pd.read_table("../day08/test.txt", sep="\t")
    print("data:\n", data)
    # print("data的数据类型\n", data.dtypes)
    # (2)转化为矩阵
    data = np.mat(data.values)

    # print("data:\n",data)

    return data


def center_init(data, k):
    """
    初始化聚类中心
    :param data: 数据
    :param k: 聚类的类别数量
    :return: center
    """
    # 获取数据的行数
    index_num = data.shape[0]
    print(index_num)
    # 获取数据的列数
    columns_num = data.shape[1]
    print(columns_num)
    # for i in range(k):
    #     # 随机选择一行所有的数据作为一个中心
    #     # [low,high)
    #     r = np.random.randint(low=0, high=index_num, dtype=np.int32)
    #     print("r:\n",r)
    # 先初始化一个全为0 的聚类中心
    center = np.zeros(shape=(k, columns_num))
    # 设计列表来退出循环
    r_list = []
    # 设计一个计数器来 给聚类中心赋值
    i = 0
    while True:
        #   # 随机选择一行所有的数据作为一个中心
        #   # [low,high)
        r = np.random.randint(low=0, high=index_num, dtype=np.int32)
        if r not in r_list:
            # print("初始化为聚类中心")
            # 给聚类中心进行赋值
            center[i, :] = data[r, :]
            r_list.append(r)
            i += 1
        else:
            continue
        # 如果 随机选择了4个不同的r,那就退出循环
        if len(r_list) == k:
            break

    return center


def distance(v1, v2):
    """
    计算距离
    :param v1:点1
    :param v2: 点2
    :return: 距离dist
    """
    # 法1
    # v1 是矩阵 将矩阵转化数组,再进行降为1维
    # v1 = v1.A[0]
    # print(v1)
    # sum_ = 0
    # for i in range(v1.shape[0]):
    #     sum_ += (v1[i] - v2[i]) ** 2
    # dist = np.sqrt(sum_)
    # print(dist)
    # 法2
    dist = np.sqrt(np.sum(np.power((v1 - v2), 2)))
    return dist


def k_means_owns(data, k):
    """
    自实现k-means
    :param data: 需要的聚类的样本
    :param k: 聚类的类别数目
    :return: None
    """

    # 获取数据的行数
    index_num = data.shape[0]

    # 创建一个new_data 来保存每一个样本的最短距离与属于哪一个聚类中心的簇
    new_data = np.zeros(shape=(index_num, 2))
    print("new_data: \n", new_data)

    # (1)初始化聚类中心--随机在所有样本选择4行样本作为聚类中心
    center = center_init(data, k)
    print("center:\n", center)
    flag = True
    while flag:
        flag = False
        # (2) 计算每一个样本与每一个聚类中心的距离
        for i in range(index_num):
            min_dist = 10000000000000
            min_index = -1
            for j in range(k):
                # 计算距离
                dist = distance(data[i, :], center[j, :])
                print("dist:\n", dist)
                if dist < min_dist:
                    min_dist = dist
                    min_index = j
            if new_data[i, 0] != min_index:
                flag = True
                new_data[i, :] = min_index, min_dist

        if flag:
            # 求取各个簇的中心
            for p in range(k):
                # p   --->0 1 2 3
                p_cluster = data[new_data[:, 0] == p, :]
                # print("第%d簇的样本:" % p)
                # print(p_cluster)
                # 计算新的聚类中心
                center[p, :] = p_cluster[:, 0].mean(), p_cluster[:, 1].mean()

    return new_data, center


def show_res_owns(data, new_data, center):
    """
    结果展示
    :param data: 原数据
    :param new_data: 记录属于哪一类别的数据
    :param center: 聚类中心
    :return: None
    """
    # 1、创建画布
    plt.figure()
    # 2、绘图
    color_list = ["r", "g", "pink", "y"]
    # 散点图
    for i in range(data.shape[0]):
        plt.scatter(data[i, 0], data[i, 1], c=color_list[int(new_data[i, 0])])

    # 绘制标注
    plt.plot(center[:, 0], center[:, 1], "bx", markersize=12)
    # 3、展示
    plt.show()


def show_res(data, y_predict, center):
    """
    结果展示
    :param data: 原数据
    :param y_predict: 预测类别
    :param center: 聚类中心
    :return: None
    """
    # 1、创建画布
    plt.figure()
    # 2、绘图
    color_list = ["r", "g", "pink", "y"]
    # 散点图
    for i in range(data.shape[0]):
        plt.scatter(data[i, 0], data[i, 1], c=color_list[y_predict[i]])

    # 绘制标注
    plt.plot(center[:, 0], center[:, 1], "bx", markersize=12)
    # 3、展示
    plt.show()



def main():
    """
    主函数
    :return: None
    """
    # 1、构建数据
    data = build_data()
    print("data:\n", data)

    # 2、自实现k-means
    # (1)确定聚类的类别数目
    k = 4
    new_data, center = k_means_owns(data, k)
    #
    print("new_data:\n", new_data)
    print("最终的聚类中心:\n", center)

    # 3、结果展示
    show_res_owns(data, new_data, center)


    # 使用sklearn中的kmeans来实现聚类
    # 1、创建算法实例
    # km = KMeans(n_clusters=k)
    # # 2、训练数据
    # km.fit(data)
    # # 3、进行预测
    # y_predict = km.predict(data)
    # # 获取聚类中心
    # center = km.cluster_centers_
    #
    # print("预测值:\n",y_predict)
    # print("center:\n",center)

    # 进行结果展示
    # show_res(data,y_predict,center)


if __name__ == ‘__main__‘:
    main()

相关推荐