• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Kmeans聚类算法的男女性别划分

武飞扬头像
橘ju
帮助1

一.简单介绍

1.概述:

K-means聚类算法也称k均值聚类算法,是集简单和经典于一身的基于距离的聚类算法。它采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为类簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。

2.算法核心思想:

K-means聚类算法是一种迭代求解的聚类分析算法,其步骤是随机选取K个对象作为初始的聚类中心,然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。每分配一个样本,聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是没有(或最小数目)对象被重新分配给不同的聚类,没有(或最小数目)聚类中心再发生变化,误差平方和局部最小。

3.算法实现步骤:

i. 首先确定一个k值,即我们希望将数据集经过聚类得到k个集合。
ii. 从数据集中随机选择k个数据点作为质心。
iii. 对数据集中每一个点,计算其与每一个质心的距离(如欧式距离),离哪个质心近,就划分到那个质心所属的集合。
iv. 把所有数据归好集合后,一共有k个集合。然后重新计算每个集合的质心。
v. 如果新计算出来的质心和原来的质心之间的距离小于某一个设置的阈值(表示重新计算的质心的位置变化不大,趋于稳定,或者说收敛),我们可以认为聚类已经达到期望的结果,算法终止。
vi. 如果新质心和原质心距离变化很大,需要迭代3~5步骤。

4.算法步骤图解:

学新通
上图a表达了初始的数据集,假设k=2。在图b中,我们随机选择了两个k类所对应的类别质心,即图中的红色质心和蓝色质心,然后分别求样本中所有点到这两个质心的距离,并标记每个样本的类别为和该样本距离最小的质心的类别,如图c所示,经过计算样本和红色质心和蓝色质心的距离,我们得到了所有样本点的第一轮迭代后的类别。此时我们对我们当前标记为红色和蓝色的点分别求其新的质心,如图d所示,新的红色质心和蓝色质心的位置已经发生了变动。图e和图f重复了我们在图c和图d的过程,即将所有点的类别标记为距离最近的质心的类别并求新的质心。最终我们得到的两个类别如图f。

5.初值优化:

优化目标的值等于每一个训练集数据到该所属的聚类中心距离的平方的平均值,在我们进行之前所循环进行的聚类分簇和移动聚类中心的操作时,都是在不断的最小化J的大小,使J最小化。
在之前我们选择聚类中心是随机任意的选择,但是这里我们用的是更加好或者用的更加多的随机选择聚类中心的方法。我们在训练集中随机选择k个聚类中心。有时候我们的选择会很好,有时我们的随机选择会不太理想,即我们可能求得是一个不太理想的局部最优解,而不是最优解。
为了避免这种现象的出现,我们的做法是多次随机初始化聚类中心。例如我们运行100次k均值算法,这样我们就随机初始化了100次,我们分别计算出各自的代价函数值,然后选择最小的一种情况就是我们的最优解。当然这种做法,只是适用于k比较小的情况(2-10),当k值很大时就不太实用。

二.具体实验

1.识别的样本来源及分布:

样本来源于86名男、女生的身高和体重。
数据集见资源,免费下载联系邮箱2667648374@qq.com。
学新通

2. 程序开发:

当时写的时候内部有些冗余,后来也没有进行改进。

import numpy as np
import matplotlib.pyplot as plt

sample = np.loadtxt('data.txt',dtype=float,delimiter='	',usecols=(0,1,2))

def paint1(data,girl_cent,boy_cent):     #初始数据绘图 初始质心
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(data[:,0],data[:,1],c='g',marker='o')
    ax.scatter(girl_cent[0],girl_cent[1],c='r',marker='x')        #女生初始质心
    ax.scatter(boy_cent[0],boy_cent[1],c='b',marker='x')        #男生初始质心
    ax.set_xlabel('Height',fontproperties='STKAITI',fontsize=18)     #坐标标注
    ax.set_ylabel('Weight',fontproperties='STKAITI',fontsize=18)
    plt.title('男女同学体征初始散点图',fontproperties='STKAITI',fontsize=22)
    plt.show()

'''**************************************************************'''

def barycentre(girl_data,boy_data):    #质心计算
    new_girl_centre = np.sum(girl_data,axis=0)/girl_data.shape[0]   #按行相加
    new_boy_centre = np.sum(boy_data,axis=0)/boy_data.shape[0]
    return new_girl_centre,new_boy_centre

def paint2(girl_data,boy_data,girl_centre,boy_centre):     #迭代绘图
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(girl_data[:,0],girl_data[:,1],c='r',marker='o')
    ax.scatter(boy_data[:,0],boy_data[:,1],c='b',marker='o')
    ax.scatter(girl_centre[0],girl_centre[1],c='r',marker='x')        #女生质心
    ax.scatter(boy_centre[0],boy_centre[1],c='b',marker='x')        #男生质心
    plt.legend(['girl','boy'])
    ax.set_xlabel('Height',fontproperties='STKAITI',fontsize=18)     #坐标标注
    ax.set_ylabel('Weight',fontproperties='STKAITI',fontsize=18)
    plt.title('男女同学体征',fontproperties='STKAITI',fontsize=22)
    plt.show()

def distance(last_girl_cent,last_boy_cent):              #距离计算、重归集合
    dis_girl = np.sqrt((sample[:,0]-last_girl_cent[0])**2   (sample[:,1]-last_girl_cent[1])**2)
    dis_boy = np.sqrt((sample[:,0]-last_boy_cent[0])**2   (sample[:,1]-last_boy_cent[1])**2)
    j=k=0
    girl = np.zeros((86,2))
    boy = np.zeros((86,2))
    for i in range(sample.shape[0]):
        if dis_boy[i] >= dis_girl[i]:   #与女生质心距离小
            girl[j] = sample[i][0:2]
            j =1
        else:
            boy[k] = sample[i][0:2]
            k =1
    new_girl = girl[0:j,:]   #去除girl中多余的零矩阵项
    new_boy = boy[0:k,:]
    return new_girl,new_boy
def iteration(initial_girl_centre,initial_boy_centre):    #迭代并计算代价函数
    #迭代过程
    threshold_value = 1    #质心变化阈值
    [new_girl_assem,new_boy_assem] = distance(initial_girl_centre,initial_boy_centre)    #根据初始质心第一次重新划分集合
    [new_girl_centre,new_boy_centre] = barycentre(new_girl_assem,new_boy_assem)          #计算第一次划分集合的质心

    girl_centre_diff = np.sqrt((new_girl_centre[0] - initial_girl_centre[0])**2 (new_girl_centre[1] - initial_girl_centre[1])**2)  #计算第一次迭代质心差值
    boy_centre_diff = np.sqrt((new_boy_centre[0] - initial_boy_centre[0])**2 (new_boy_centre[1] - initial_boy_centre[1])**2)

    while girl_centre_diff > threshold_value or boy_centre_diff >threshold_value:  #前后两次质心值之差都小于阈值时,停止迭代
        last_girl_centre = new_girl_centre    #更新 last_centre
        last_boy_centre = new_boy_centre
        [new_girl_assem,new_boy_assem] = distance(last_girl_centre,last_boy_centre)     #根据上一个质心重新划分集合
        [new_girl_centre,new_boy_centre] = barycentre(new_girl_assem,new_boy_assem)     #根据新集合重新计算质心
        girl_centre_diff = np.sqrt((new_girl_centre[0] - last_girl_centre[0])**2 (new_girl_centre[1] - last_girl_centre[1])**2)#计算质心差
        boy_centre_diff = np.sqrt((new_boy_centre[0] - last_boy_centre[0])**2 (new_boy_centre[1] - last_boy_centre[1])**2)

    aver_cost_girl = np.sum(np.sqrt((new_girl_assem[:,0] - new_girl_centre[0])**2   (new_girl_assem[:,1] - new_girl_centre[1])**2),axis=0)/new_girl_assem.shape[0]     #女生到质心的平均距离
    aver_cost_boy = np.sum(np.sqrt((new_boy_assem[:,0] - new_boy_centre[0])**2   (new_boy_assem[:,1] - new_boy_centre[1])**2),axis=0)/new_boy_assem.shape[0]           #男生到质心的平均距离
    aver_cost_total = aver_cost_girl   aver_cost_boy
    return aver_cost_total

def visual(optimal_girl_centre,optimal_boy_centre):   #最优初始质心

    paint1(sample,optimal_girl_centre,optimal_boy_centre)    #初始数据散点图
    print('current_girl_centre=',optimal_girl_centre,'\n','current_boy_centre=',optimal_boy_centre)

    #迭代过程
    threshold_value = 1    #质心变化阈值
    [new_girl_assem,new_boy_assem] = distance(optimal_girl_centre,optimal_boy_centre)    #根据初始质心第一次重新划分集合
    [new_girl_centre,new_boy_centre] = barycentre(new_girl_assem,new_boy_assem)          #计算第一次划分集合的质心
    paint2(new_girl_assem,new_boy_assem,new_girl_centre,new_boy_centre)                  #第一次迭代图
    print('current_girl_centre=',new_girl_centre,'\n','current_boy_centre=',new_boy_centre)

    girl_centre_diff = np.sqrt((new_girl_centre[0] - optimal_girl_centre[0])**2 (new_girl_centre[1] - optimal_girl_centre[1])**2)
    boy_centre_diff = np.sqrt((new_boy_centre[0] - optimal_boy_centre[0])**2 (new_boy_centre[1] - optimal_boy_centre[1])**2)

    while girl_centre_diff > threshold_value or boy_centre_diff >threshold_value:  #前后两次质心值之差都小于阈值时,停止迭代
        last_girl_centre = new_girl_centre    #更新 last_centre
        last_boy_centre = new_boy_centre
        [new_girl_assem,new_boy_assem] = distance(last_girl_centre,last_boy_centre)     #根据上一个质心重新划分集合
        [new_girl_centre,new_boy_centre] = barycentre(new_girl_assem,new_boy_assem)     #根据新集合重新计算质心
        paint2(new_girl_assem,new_boy_assem,new_girl_centre,new_boy_centre)             #迭代图
        print('current_girl_centre=',new_girl_centre,'\n','current_boy_centre=',new_boy_centre)
        #计算质心差
        girl_centre_diff = np.sqrt((new_girl_centre[0] - last_girl_centre[0])**2 (new_girl_centre[1] - last_girl_centre[1])**2)
        boy_centre_diff = np.sqrt((new_boy_centre[0] - last_boy_centre[0])**2 (new_boy_centre[1] - last_boy_centre[1])**2)
    aver_cost_girl = np.sum(np.sqrt((new_girl_assem[:,0] - new_girl_centre[0])**2   (new_girl_assem[:,1] - new_girl_centre[1])**2),axis=0)/new_girl_assem.shape[0]     #女生到质心的平均距离
    aver_cost_boy = np.sum(np.sqrt((new_boy_assem[:,0] - new_boy_centre[0])**2   (new_boy_assem[:,1] - new_boy_centre[1])**2),axis=0)/new_boy_assem.shape[0]           #男生到质心的平均距离
    aver_cost_total = aver_cost_girl   aver_cost_boy
    return aver_cost_total


def preliminary_optimization():   #初值优化
    cost = np.zeros((100,1))      #记录值初始化
    girl_centre = np.zeros((100,2))
    boy_centre = np.zeros((100,2))
    for i in range(100):           #做100kmeans算法,选择最小代价函数时的初值即最优初值
        #随机初始化质心
        initial_girl = [np.random.randint(150,175,1),np.random.randint(40,70,1)]            #女生随机身高质心:150-175 体重质心40-70
        initial_boy = [np.random.randint(165,190,1),np.random.randint(55,100,1)]           #男生随机身高质心:165-190 体重质心55-100
        girl_centre[i] = initial_girl     #记录质心
        boy_centre[i] = initial_boy
        cost[i] = iteration(initial_girl,initial_boy)              #记录每次代价
    cost_list = list(cost)
    min_index = cost_list.index(min(cost_list))              #找出最小代价的下标
    min_cost = visual(girl_centre[min_index],boy_centre[min_index])   #返回该下标的质心并将迭代过程可视化
    print('optional girl centre:',girl_centre[min_index],'\n','optional boy centre:',boy_centre[min_index],'\n','min cost value:',min_cost)
preliminary_optimization()
学新通

3.结果分析

初始数据质心:
current_girl_centre= [154. 62.]
current_boy_centre= [167. 68.]
学新通
第一次迭代及质心:
current_girl_centre= [161.29411765 50.88235294]
current_boy_centre= [175.64492754 66.96811594]

学新通
第二次迭代及质心:
current_girl_centre= [164.6 52.61]
current_boy_centre= [177.20535714 69.77678571]
学新通
第三次迭代及质心:
current_girl_centre= [166.12820513 54.13589744]
current_boy_centre= [178.35106383 71.79787234]
学新通
最后一次迭代及质心:
current_girl_centre= [166.71428571 54.53095238]
current_boy_centre= [178.625 72.625]
学新通
最优初值及最小代价值:
optional girl centre: [154. 62.]
optional boy centre: [167. 68.]
min cost value: 16.696445630581255

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhiabcbc
系列文章
更多 icon
同类精品
更多 icon
继续加载