机器学习之Kmeans聚类算法

1.算法介绍

对于"监督学习"(supervised learning),其训练样本是带有标记信息的,并且监督学习的目的是:对带有标记的数据集进行模型学习,从而便于对新的样本进行分类。而在“无监督学习”(unsupervised learning)中,训练样本的标记信息是未知的,目标是通过对无标记训练样本的学习来揭示数据的内在性质及规律,为进一步的数据分析提供基础。对于无监督学习,应用最广的便是"聚类"(clustering)。聚类算法"试图将数据集中的样本划分为若干个通常是不相交的子集,每个子集称为一个“簇”(cluster),通过这样的划分,每个簇可能对应于一些潜在的概念或类别。

kmeans算法又名k均值算法,K-means算法中的k表示的是聚类为k个簇,means代表取每一个聚类中数据值的均值作为该簇的中心,或者称为质心,即用每一个的类的质心对该簇进行描述。其算法思想大致为:先从样本集中随机选取 k个样本作为簇中心,并计算所有样本与这 k个“簇中心”的距离,对于每一个样本,将其划分到与其距离最近的“簇中心”所在的簇中,对于新的簇计算各个簇的新的“簇中心”。根据以上描述,我们大致可以猜测到实现kmeans算法的主要四点:簇个数k 的选择、各个样本点到“簇中心”的距离、根据新划分的簇,更新“簇中心”、重复上述2、3过程,直至"簇中心"没有移动。

2.运行环境

Pycharm

3.运行步骤

4.运行结果

初始点 0 : [56.30228444197009, 92.03970140883656] 2

初始点 1 : [94.37542404009427, 43.714034475096156] 3

初始点 2 : [100.14581516307273, 41.18565216612042] 3

DB= 1.2699906930079754

第 0 簇,标签最多的类为 2 占比 100.0 %

第 1 簇,标签最多的类为 1 占比 97.0873786407767 %

第 2 簇,标签最多的类为 3 占比 100.0 %

5.运行代码

import math  # 数学
import random  # 随机
import numpy as np
import matplotlib.pyplot as plt


# 计算两个样本距离
def dist(xy, a, b):
    d_l = 0  # 储存当前距离值
    for i in range(len(xy) - 1):  # 对每个属性
        d_l += (xy[i][a] - xy[i][b]) ** 2  # 计算平方和
    d_l = d_l ** 0.5  # 开根号
    return d_l


# 计算avg(C)
def avg(xy, Ci):
    sum = 0
    for i in Ci:
        for j in Ci:
            sum += dist(xy, i, j)
    return sum * 2 / (len(Ci) * (len(Ci) - 1))


# 计算DB指数
def DB(xy, C, u):
    sum = 0
    for i in range(len(C)):  # 每一簇
        max_C = -float('inf')
        for j in range(len(C)):
            if i == j:
                continue
            dcen = 0
            for k in range(len(xy) - 1):  # 对每个属性
                dcen += (u[i][k] - u[j][k]) ** 2  # 计算平方和
            dcen = dcen ** 0.5  # 开根号
            max_ = (avg(xy, C[i]) + avg(xy, C[j])) / dcen
            if max_ > max_C:
                max_C = max_
        sum += max_C
    return sum / len(C)


# k均值聚类算法,分k簇。
def jvlei_k(xy, k):
    n = len(xy[0])  # 储存数据数。
    u = []  # 储存簇的均值向量
    C = []  # 储存簇划分
    # 挑选k个不重复的样本。
    i = 0
    j = 0
    u = random.sample(range(n), k)  # (如果数据随机,这一步其实可以直接选前k个)
    for i in range(k):  # 对每个初始点。
        l = u[i]  # 暂存
        u[i] = []
        print('初始点', i, end='\t: ')
        for j in range(len(xy) - 1):  # 对每个属性
            u[i].append(xy[j][l])
        print(u[i], xy[j + 1][l])
    while 1:
        C = []  # 储存簇划分
        for i in range(k):  # k 簇
            C.append([])  # 初始化C。
        for i in range(n):  # 所有的数据
            d = float('inf')  # 初始无穷大
            l = 0  # 属于哪个簇
            for j in range(k):  # 看和每个簇的距离,找最小。
                d_ = 0  # 储存当前距离值
                for ii in range(len(xy) - 1):  # 对每个属性
                    d_ += (xy[ii][i] - u[j][ii]) ** 2  # 计算平方和
                d_ = d_ ** 0.5  # 开根号
                if d_ < d:  # 距离更近
                    d = d_  # 最近值更改
                    l = j  # 属于第j簇
            C[l].append(i)  # 并入第l簇
        u_ = []  # 新的均值向量
        for i in range(k):  # 重新计算每个簇的均值
            u_.append([0] * (len(xy) - 1))
            for j in C[i]:  # 对簇中每个样本
                for ii in range(len(xy) - 1):  # 对每个属性
                    u_[i][ii] += xy[ii][j]  # 求和
            for ii in range(len(xy) - 1):  # 对每个属性
                u_[i][ii] /= len(C[i])  # 均值
        l = 0  # 标记
        for i in range(k):  # 每个均值向量
            for j in range(len(u[0])):  # 每个属性
                l += (u[i][j] - u_[i][j]) ** 2  # 求误差
        if l < 0.01:
            print('DB=', DB(xy, C, u))
            return C
        else:
            u = u_[:]


# 簇分类和标签对比,返回【最多标签,最多标签所占比例】
def panduan(yi, Ci):
    biaoqian = {}  # 标签,出现次数
    for i in Ci:
        if yi[i] in biaoqian:  # 存在
            biaoqian[yi[i]] += 1  # 加一
        else:
            biaoqian[yi[i]] = 1  # 创建
    max_ = -1  # 标签
    max_t = -1  # 标签数
    for i in biaoqian:  # 所有标签
        if biaoqian[i] > max_t:  # 找最多的
            max_ = i
            max_t = biaoqian[i]
    return [max_, (max_t * 100 / len(Ci))]


# 生成数据集=============================================
x = []  # 数据集x属性
y = []  # 数据集y属性
x.extend(np.random.normal(loc=040.0, scale=10, size=100))  # 向x中放100个均值为40,标准差为10,正态分布的随机数
x.extend(np.random.normal(loc=060.0, scale=10, size=200))  # 向x中放200个均值为60,标准差为10,正态分布的随机数
x.extend(np.random.normal(loc=100.0, scale=10, size=300))  # 向x中放300个均值为100,标准差为10,正态分布的随机数
y.extend(np.random.normal(loc=050.0, scale=10, size=100))  # 向y中放100个均值为50,标准差为10,正态分布的随机数
y.extend(np.random.normal(loc=100.0, scale=10, size=200))  # 向y中放200个均值为100,标准差为10,正态分布的随机数
y.extend(np.random.normal(loc=040.0, scale=10, size=300))  # 向y中放300个均值为40,标准差为10,正态分布的随机数
c = [1] * 100  # c标签第一类为 1  x均值:40 y均值:50
c.extend([2] * 200)  # # c标签第二类为 2  x均值:60 y均值:100
c.extend([3] * 300)  # # c标签第三类为 3  x均值:100 y均值:40
# 生成训练集与测试集=======================================
lt = list(range(600))  # 得到一个顺序序列
random.shuffle(lt)  # 打乱序列
x1 = [[], [], []]  # 初始化x1
for i in lt:  # 做训练集
    x1[0].append(x[i])  # 加上数据集x属性
    x1[1].append(y[i])  # 加上数据集y属性
    x1[2].append(c[i])  # 加上数据集c标签
# 生成簇划分 ==========================================
k = 3  # 分成三簇
C = jvlei_k(x1, k)
# 计算正确率===========================================
for i in range(k):
    c = panduan(x1[2], C[i])
    print('第', i, '簇,标签最多的类为', c[0], '占比', c[1], '%')
# 绘图 ===============================================

plt.figure(1)  # 第一张画布
for i in range(len(x1[2])):  # 对数据集‘上色’
    if x1[2][i] == 1:
        x1[2][i] = 'r'  # 数据集  1 红色
    else:
        if x1[2][i] == 2:
            x1[2][i] = 'y'  # 数据集 2 黄色
        else:
            x1[2][i] = 'b'  # 数据集 3 蓝色
plt.scatter(x1[0], x1[1], c=x1[2], alpha=0.5)  # 绘点数据集
plt.xlabel('x')  # x轴标签
plt.ylabel('y')  # y轴标签
plt.title('Initial')  # 标题
#  簇划分:==========================================
plt.figure(2)  # 第二张画布
for i in range(k):  # 对数据集‘上色’
    for j in C[i]:
        if i == 1:
            x1[2][j] = 'r'  # 簇  1 红色
        else:
            if i == 2:
                x1[2][j] = 'y'  # 簇 2 黄色
            else:
                x1[2][j] = 'b'  # 簇 3 蓝色
plt.scatter(x1[0], x1[1], c=x1[2], alpha=0.5)  # 绘点数据集
plt.xlabel('x')  # x轴标签
plt.ylabel('y')  # y轴标签
plt.title('End')  # 标题
plt.show()  # 显示
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Joey.Chao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值