当前位置: 移动技术网 > IT编程>脚本编程>Python > numpy手写kmeans

numpy手写kmeans

2020年07月22日  | 移动技术网IT编程  | 我要评论

numpy手写kmeans,并可视化。
由于可视化限制,拿二维数据进行示范。但该代码可适用于任意维的数据,同时可根据三种的计算距离公式(欧式距离,曼哈顿距离,余弦距离),提供不同的聚类结果。

import numpy as np
import matplotlib.pyplot as plt

def distance_cal(x, y): #计算距离
    if cal_type == "eclud":
        dis = np.sqrt(np.sum(np.square(x - y))) #欧氏距离
    elif cal_type == "manhattan": 
        dis = np.sum(np.abs(x - y)) #Manhattan距离
    elif cal_type == "cosin":
        dis = np.dot(x, y) / (np.linalg.norm(x) * np.linalg.norm(y)) #余弦距离
    return dis

def rand_cent(data, k): #初始化聚类中心点
    '''
    data: 聚类的数据集
    k: 聚类的个数
    '''
    num_features = data.shape[1] #数据集的特征数,也就是列数
    init_centers = np.zeros((k, num_features)) #确定聚类中心点的形状, 其可以理解成将数据压缩成k行数据,列数保持不变
    for i in range(num_features): #遍历每列数据,来初始化聚类中心点
        min_data = min(data[:, i]) #获得当前列的最小值,为一个数值
        max_data = max(data[:, i])
        range_data = max_data - min_data #获得该列数值的变动范围
        init_centers[:, i] = min_data + range_data * np.random.rand(k) #一次性获得k个数值,作为当前列初始中心点
    return init_centers

def kmeans(data, k): #进行kmeans聚类
    num = data.shape[0] #获得数据量
    cluster_centers = rand_cent(data, k) #获取初始化的聚类中心点,也可以完全随机初始化。只是该方法将初始点定位数据内部
    cluster_assign = np.zeros((num, ))#创建数组,用于存放所属类别
    change = True
    while change:
        change = False
        for i in range(num): #遍历每行数据,来计算其与k个聚类中心点的距离,并判定其所属类别
            min_dis = np.inf #初始化一个极大值作为最小距离
            index = 0 #初始化所属类别
            for j in range(k):
                dis = distance_cal(data[i], cluster_centers[j]) #计算当前行与每个距离中心点的距离
                if dis < min_dis:
                    min_dis = dis #重新给最小距离赋值
                    index = j #确定其所属类别
            if cluster_assign[i] != index: #如果计算的类别与所属类别不符,则需重新训练,以计算距离
                change = True
            cluster_assign[i] = index
        
        for j in range(k): #更新聚类中心点
            cluster_data = data[np.nonzero(cluster_assign == j)] #提取同属一个类别的数据
            if len(cluster_data): #确保该数组的数据非空
                cluster_centers[j] = np.mean(cluster_data, axis = 0)#将该数组的均值作为聚类中心点
    return cluster_centers, cluster_assign

if  __name__ == "__main__":
    data1 = np.random.uniform(0, 3, (100, 2))
    data2 = np.random.uniform(4, 7, (100, 2))
    data3 = np.random.uniform(8, 10, (100, 2))
    data = np.r_[data1, data2, data3] #将数组进行纵向合并
    k = 3
    cal_type = "eclud" #计算距离的类别, ["eclud", "manhattan", "cosin"]
    cluster_centers, cluster_assign = kmeans(data, k) #获得聚类中心点,及每行数据的所属类别
    
    #可视化
    plt.figure()
    for j in range(k):
        x = data[np.nonzero(cluster_assign == j), 0]
        y = data[np.nonzero(cluster_assign == j), 1]
        plt.scatter(x, y, s = 10 * (j+1), label = j)
        
    plt.scatter(cluster_centers[:, 0], cluster_centers[:, 1], s = 150, marker = "x", c = 'm')
    plt.legend()
    plt.show()

本文地址:https://blog.csdn.net/lmw0320/article/details/107462413

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网