k-means算法实现,--python

k-means算法思想:

第一步,从文件中读取数据,点用元组表示,点集用列表表示。
第二步,初始化聚类中心。首先获取数据的长度,然后在range(0,length)这个区间上随机产生k个不同的值,以此为下标提取出数据点,将它们作为聚类初始中心,产生列表center。
第三步,分配数据点。将数据点分配到距离(欧式距离)最短的聚类中心中,产生列表assigment,并计算平均误差。
第四步,如果首次分配后有结果为空,则重新初始化聚类中心。
第五步,更新聚类中心,(计算每一簇中所有点的平均值),然后再次进行分配,并计算平均误差。
第六步,比较前后两次的平均误差是否相等,若不相等则进行循环,否则终止循环,进入下一步
最少进行两次聚类,对比误差,输出较小误差时的结果,避免平均误差过大。

 

流程图:

 

结论:

 

import random
from math import *
import matplotlib.pyplot as plt
 
#从文件种读取数据
def read_data():
    data_points = []
    with open('data.txt','r') as fp:
        for line in fp:
            if line =='\n':
                continue
            data_points.append(tuple(map(float,line.split(' '))))#去掉空格,并将data中数据的类型转为tuple
        fp.close()
        return data_points
 
#初始化聚类中心
def begin_cluster_center(data_points,k):
    center=[]
    length=len(data_points)#长度
    rand_data = random.sample(range(0,length), k)#生成k个不同随机数
    for i in range(k):#得出k个聚类中心(随机选出)
        center.append(data_points[rand_data[i]])
    return center
 
#计算最短距离(欧式距离)
def distance(a,b):
    length=len(a)
    sum = 0
    for i in range(length):
        sq = (a[i] - b[i]) ** 2
        sum += sq
    return sqrt(sum)
#分配样本
# 按照最短距离将所有样本分配到k个聚类中心中的某一个
def assign_points(data_points,center,k):
    assignment=[]
    for i in range(k):
        assignment.append([])
    for point in data_points:
        min = 10000000
        flag = -1
        for i in range(k):
            value=distance(point,center[i])#计算每个点到聚类中心的距离
            if value<min:
                min=value#记录距离的最小值
                flag=i   #记录此时聚类中心的下标
        assignment[flag].append(point)
    return assignment
 
#更新聚类中心,计算每一簇中所有点的平均值
def update_cluster_center(center,assignment,k):
    for i in range(k):#assignment中的每一簇
        x=0
        y=0
        length=len(assignment[i])#每一簇的长度
        if length!=0:
            for j in range(length):  # 每一簇中的每个点
                x += assignment[i][j][0]  # 横坐标之和
                y += assignment[i][j][1]  # 纵坐标之和
            center[i] = (x / length, y / length)
    return center
 
#计算平方误差
def getE(assignment,center):
    sum_E=0
    for i in range(len(assignment)):
        for j in range(len(assignment[i])):
            sum_E+=distance(assignment[i][j],center[i])
    return sum_E
 
#计算各个聚类中心的新向量,更新距离,即每一类中每一维均值向量。
# 然后再进行分配,比较前后两个聚类中心向量是否相等,若不相等则进行循环,
# 否则终止循环,进入下一步。
def k_means(data_points,k):
    # 由于初始聚类中心是随机选择的,十分影响聚类的结果,聚类可能会出现有较大误差的现象
    # 因此如果由初始聚类中心第一次分配后有结果为空,重新选择初始聚类中心,重新再聚一遍,直到符合要求
    while 1:
        # 产生初始聚类中心
        begin_center = begin_cluster_center(data_points, k)
        # 第一次分配样本
        assignment = assign_points(data_points, begin_center, k)
        for i in range(k):
            if len(assignment[i]) == 0:#第一次分配之后有结果为空,说明聚类中心没选好,重新产生初始聚类中心
                continue
        break
    #第一次的平方误差
    begin_sum_E=getE(assignment,begin_center)
    # 更新聚类中心
    end_center = update_cluster_center(begin_center, assignment, k)
    # 第二次分配样本
    assignment = assign_points(data_points, end_center, k)
    # 第二次的平方误差
    end_sum_E = getE(assignment, end_center)
    count = 2  # 计数器
    #比较前后两个聚类中心向量是否相等
    #print(compare(end_center,begin_center)==False)
    while( begin_sum_E != end_sum_E):
        begin_center=end_center
        begin_sum_E=end_sum_E
        # 再次更新聚类中心
        end_center = update_cluster_center(begin_center, assignment, k)
        # 进行分配
        assignment = assign_points(data_points, end_center, k)
        #计算误差
        end_sum_E = getE(assignment, end_center)
        count = count + 1      #计数器加1
    return assignment,end_sum_E,end_center,count
def print_result(count,end_sum_E,k,assignment):
    # 打印最终聚类结果
    print('经过', count, '次聚类,平方误差为:', end_sum_E)
    print('---------------------------------分类结果---------------------------------------')
    for i in range(k):
        print('第',i+1,'类数据:',assignment[i])
    print('--------------------------------------------------------------------------------\n')
 
def plot(k, assignment,center):
    #初始坐标列表
    x = []
    y = []
    for i in range(k):
        x.append([])
        y.append([])
    # 填充坐标 并绘制散点图
    for j in range(k):
        for i in range(len(assignment[j])):
            x[j].append(assignment[j][i][0])# 横坐标填充
        for i in range(len(assignment[j])):
            y[j].append(assignment[j][i][1])# 纵坐标填充
        plt.scatter(x[j], y[j],marker='o')
        plt.scatter(center[j][0], center[j][1],c='b',marker='*')#画聚类中心
    # 设置标题
    plt.title('K-means Scatter Diagram')
    # 设置X轴标签
    plt.xlabel('X')
    # 设置Y轴标签
    plt.ylabel('Y')
    # 显示散点图
    plt.show()
 
def main():
    # 3个聚类中心
    k = 4
    data_points =read_data()
    assignment, end_sum_E, end_center, count = k_means(data_points, k)
    min_sum_E = 1000
    #返回较小误差
    while min_sum_E>end_sum_E:
        min_sum_E=end_sum_E
        assignment, end_sum_E, end_center, count = k_means(data_points,k)
    print_result(count, min_sum_E, k, assignment)#输出结果
    plot(k, assignment,end_center)#画图
main()

数据集:

2.0 4.2
2.1 5.0
2.3 3.8
1.2 6.1
3.5 4.4
3.6 3.7
3.0 6.2
2.5 5.6
1.7 3.3
0.9 6.0
0.4 4.1
7.0 10.0
8.0 9.0
8.2 8.2
9.3 7.9
7.4 7.1
6.8 8.0
8.1 9.5
8.5 10.4
7.6 8.5
8.6 7.3
7.7 8.8
1.8 10.9
1.5 9.5
1.7 8.7
1.3 9.0
2.8 9.6
2.2 9.9
2.1 10.5
2.5 9.2
3.1 10.4
3.9 9.5
3.7 10.4
2.6 8.2
2.8 9.2
2.2 9.3
3.4 8.5
8.1 1.3
8.5 2.4
8.8 3.3
9.0 1.2
10.7 2.9
7.9 3.7
7.5 2.5
8.5 0.6
10.8 1.6
9.2 0.5
6.8 2.0
8.5 3.6
10.0 1.7

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值