K-均值聚类算法(Python,机器学习 ,绘图)

内容:

        1.数据集:

        (1)人工生成数据集AriGen:自己生成含有3个类别的二维数据集,且类别间线性分开,分别具有100·200与300个样本;

        (2) Iris 数据集·


        2.编写k-均值聚类算法程序,对人工生成数据集AriGen 与 Iris数据集进行聚类﹐并计算DB指数。

一、数据集(150)

具体数据如下(如果不能运行,尝试在末尾加回车)

5.1	3.5	1.4	0.2	1
4.9	3	1.4	0.2	1
4.7	3.2	1.3	0.2	1
4.6	3.1	1.5	0.2	1
5	3.6	1.4	0.2	1
5.4	3.9	1.7	0.4	1
4.6	3.4	1.4	0.3	1
5	3.4	1.5	0.2	1
4.4	2.9	1.4	0.2	1
4.9	3.1	1.5	0.1	1
5.4	3.7	1.5	0.2	1
4.8	3.4	1.6	0.2	1
4.8	3	1.4	0.1	1
4.3	3	1.1	0.1	1
5.8	4	1.2	0.2	1
5.7	4.4	1.5	0.4	1
5.4	3.9	1.3	0.4	1
5.1	3.5	1.4	0.3	1
5.7	3.8	1.7	0.3	1
5.1	3.8	1.5	0.3	1
5.4	3.4	1.7	0.2	1
5.1	3.7	1.5	0.4	1
4.6	3.6	1	0.2	1
5.1	3.3	1.7	0.5	1
4.8	3.4	1.9	0.2	1
5	3	1.6	0.2	1
5	3.4	1.6	0.4	1
5.2	3.5	1.5	0.2	1
5.2	3.4	1.4	0.2	1
4.7	3.2	1.6	0.2	1
4.8	3.1	1.6	0.2	1
5.4	3.4	1.5	0.4	1
5.2	4.1	1.5	0.1	1
5.5	4.2	1.4	0.2	1
4.9	3.1	1.5	0.1	1
5	3.2	1.2	0.2	1
5.5	3.5	1.3	0.2	1
4.9	3.1	1.5	0.1	1
4.4	3	1.3	0.2	1
5.1	3.4	1.5	0.2	1
5	3.5	1.3	0.3	1
4.5	2.3	1.3	0.3	1
4.4	3.2	1.3	0.2	1
5	3.5	1.6	0.6	1
5.1	3.8	1.9	0.4	1
4.8	3	1.4	0.3	1
5.1	3.8	1.6	0.2	1
4.6	3.2	1.4	0.2	1
5.3	3.7	1.5	0.2	1
5	3.3	1.4	0.2	1
7	3.2	4.7	1.4	2
6.4	3.2	4.5	1.5	2
6.9	3.1	4.9	1.5	2
5.5	2.3	4	1.3	2
6.5	2.8	4.6	1.5	2
5.7	2.8	4.5	1.3	2
6.3	3.3	4.7	1.6	2
4.9	2.4	3.3	1	2
6.6	2.9	4.6	1.3	2
5.2	2.7	3.9	1.4	2
5	2	3.5	1	2
5.9	3	4.2	1.5	2
6	2.2	4	1	2
6.1	2.9	4.7	1.4	2
5.6	2.9	3.6	1.3	2
6.7	3.1	4.4	1.4	2
5.6	3	4.5	1.5	2
5.8	2.7	4.1	1	2
6.2	2.2	4.5	1.5	2
5.6	2.5	3.9	1.1	2
5.9	3.2	4.8	1.8	2
6.1	2.8	4	1.3	2
6.3	2.5	4.9	1.5	2
6.1	2.8	4.7	1.2	2
6.4	2.9	4.3	1.3	2
6.6	3	4.4	1.4	2
6.8	2.8	4.8	1.4	2
6.7	3	5	1.7	2
6	2.9	4.5	1.5	2
5.7	2.6	3.5	1	2
5.5	2.4	3.8	1.1	2
5.5	2.4	3.7	1	2
5.8	2.7	3.9	1.2	2
6	2.7	5.1	1.6	2
5.4	3	4.5	1.5	2
6	3.4	4.5	1.6	2
6.7	3.1	4.7	1.5	2
6.3	2.3	4.4	1.3	2
5.6	3	4.1	1.3	2
5.5	2.5	4	1.3	2
5.5	2.6	4.4	1.2	2
6.1	3	4.6	1.4	2
5.8	2.6	4	1.2	2
5	2.3	3.3	1	2
5.6	2.7	4.2	1.3	2
5.7	3	4.2	1.2	2
5.7	2.9	4.2	1.3	2
6.2	2.9	4.3	1.3	2
5.1	2.5	3	1.1	2
5.7	2.8	4.1	1.3	2
6.3	3.3	6	2.5	3
5.8	2.7	5.1	1.9	3
7.1	3	5.9	2.1	3
6.3	2.9	5.6	1.8	3
6.5	3	5.8	2.2	3
7.6	3	6.6	2.1	3
4.9	2.5	4.5	1.7	3
7.3	2.9	6.3	1.8	3
6.7	2.5	5.8	1.8	3
7.2	3.6	6.1	2.5	3
6.5	3.2	5.1	2	3
6.4	2.7	5.3	1.9	3
6.8	3	5.5	2.1	3
5.7	2.5	5	2	3
5.8	2.8	5.1	2.4	3
6.4	3.2	5.3	2.3	3
6.5	3	5.5	1.8	3
7.7	3.8	6.7	2.2	3
7.7	2.6	6.9	2.3	3
6	2.2	5	1.5	3
6.9	3.2	5.7	2.3	3
5.6	2.8	4.9	2	3
7.7	2.8	6.7	2	3
6.3	2.7	4.9	1.8	3
6.7	3.3	5.7	2.1	3
7.2	3.2	6	1.8	3
6.2	2.8	4.8	1.8	3
6.1	3	4.9	1.8	3
6.4	2.8	5.6	2.1	3
7.2	3	5.8	1.6	3
7.4	2.8	6.1	1.9	3
7.9	3.8	6.4	2	3
6.4	2.8	5.6	2.2	3
6.3	2.8	5.1	1.5	3
6.1	2.6	5.6	1.4	3
7.7	3	6.1	2.3	3
6.3	3.4	5.6	2.4	3
6.4	3.1	5.5	1.8	3
6	3	4.8	1.8	3
6.9	3.1	5.4	2.1	3
6.7	3.1	5.6	2.4	3
6.9	3.1	5.1	2.3	3
5.8	2.7	5.1	1.9	3
6.8	3.2	5.9	2.3	3
6.7	3.3	5.7	2.5	3
6.7	3	5.2	2.3	3
6.3	2.5	5	1.9	3
6.5	3	5.2	2	3
6.2	3.4	5.4	2.3	3
5.9	3	5.1	1.8	3

二、代码:

(1)人工生成数据集AriGen:

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()  # 显示

      结果示例:

 

(2) Iris 数据集:

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))]


f = open('Iris.txt', 'r')  # 读文件
x = [[], [], [], [], []]  # 花朵属性,(0,1,2,3),花朵种类
x1 = [[], [], [], [], []]
x2 = [[], [], [], [], []]
y = []  # 分支节点[分支类,[分支节点1],[分支节点2]···]  递归决策树
y1 = []
while 1:
    yihang = f.readline()  # 读一行
    if len(yihang) <= 1:  # 读到末尾结束
        break
    fenkai = yihang.split('\t')  # 按\t分开
    for i in range(5):  # 分开的五个值
        x[i].append(eval(fenkai[i]))  # 化为数字加到x中
print('数据集===============================================')
print(len(x[0]))
for i in range(len(x)):
    print(x[i])
x1 = x[:]
# 生成簇划分 ==========================================
k = 3  # 分成三簇
C = jvlei_k(x1, k)
# 计算正确率===========================================
for i in range(k):
    c = panduan(x1[4], C[i])
    print('第', i, '簇,标签最多的类为', c[0], '占比', c[1], '%')
# 绘图 ===============================================
# 这里改输出那三维,(有四维,选三维)
a = 0
b = 2
c = 3
for i in range(len(x1[4])):  # 对数据集‘上色’
    if x1[4][i] == 1:
        x1[4][i] = 'r'  # 数据集  1 红色
    else:
        if x1[4][i] == 2:
            x1[4][i] = 'y'  # 数据集 2 黄色
        else:
            x1[4][i] = 'b'  # 数据集 3 蓝色
fig = plt.figure()
m = plt.axes(projection='3d')
m.scatter3D(x1[a], x1[b], x1[c], c=x1[4], alpha=0.8)  # 绘制散点图
plt.xlabel(a)  # x轴标签
plt.ylabel(b)  # y轴标签
plt.title('Initial')  # 标题
#  簇划分:==========================================
for i in range(k):  # 对数据集‘上色’
    for j in C[i]:
        if i == 1:
            x1[4][j] = 'r'  # 簇  1 红色
        else:
            if i == 2:
                x1[4][j] = 'y'  # 簇 2 黄色
            else:
                x1[4][j] = 'b'  # 簇 3 蓝色
fig = plt.figure()
m = plt.axes(projection='3d')
m.scatter3D(x1[a], x1[b], x1[c], c=x1[4], alpha=0.8)  # 绘制散点图
plt.xlabel(a)  # x轴标签
plt.ylabel(b)  # y轴标签
plt.title('End')  # 标题
plt.show()  # 显示

  结果示例:

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值