(二)k-means算法原理以及python实现

一、有监督学习和无监督学习

1. 有监督学习

监督学习(supervised learning):通过已有的训练样本(即已知数据以及其对应的输出)来训练,从而得到一个最优模型,再利用这个模型将所有新的数据样本映射为相应的输出结果,对输出结果进行简单的判断从而实现分类的目的,那么这个最优模型也就具有了对未知数据进行分类的能力。

监督学习中只要输入样本集,机器就可以从中推演出制定目标变量的可能结果.如协同过滤推荐算法,通过对训练集进行监督学习,并对测试集进行预测,从而达到预测的目的.

2. 无监督学习

现实生活中常常会有这样的问题:缺乏足够的先验知识,因此难以人工标注类别或进行人工类别标注的成本太高。很自然地,我们希望计算机能代我们完成这些工作,或至少提供一些帮助。根据类别未知(没有被标记)的训练样本解决模式识别中的各种问题,称之为无监督学习

聚类算法是一种典型的无监督学习算法,主要用于将相似的样本自动归到一个类别中,典型的分割聚类算法有K-means算法, K-medoids算法、CLARANS算法。聚类算法与分类算法最大的区别是:聚类算法是无监督的学习算法,而分类算法属于监督的学习算法。

在聚类算法中根据样本之间的相似性,将样本划分到不同的类别中,对于不同的相似度计算方法,会得到不同的聚类结果,常用的相似度计算方法有欧式距离法。

二、k-means介绍

基本K-Means算法的思想很简单,事先确定常数K,常数K意味着最终的聚类类别数,首先随机选定初始点为质心,并通过计算每一个样本与质心之间的相似度(这里为欧式距离),将样本点归到最相似的类中,接着,重新计算每个类的质心(即为类中心),重复这样的过程,知道质心不再改变,最终就确定了每个样本所属的类别以及每个类的质心。由于每次都要计算所有的样本与每一个质心之间的相似度,故在大规模的数据集上,K-Means算法的收敛速度比较慢。

三、K-means算法的流程

1.初始化常数K,随机选取初始点为质心
2.重复计算一下过程,直到每个样本所属的类不再改变
1)计算样本与每个质心之间的相似度,将样本归类到最相似的类中
2)重新计算质心
3.输出最终的质心以及每个类

四、python实现k-means

1. 数据介绍
如下面数据所示(仅部分数据),第1、2列分别代表数据坐标(x,y),第3列代表数据所属于的类,即label(该列并不会使用)。

注意:聚类算法不需要知道数据的标签的,而是自动划分该样本到相应的类中

-0.017612   14.053064   0
-1.395634   4.662541    1
-0.752157   6.538620    0
-1.322371   7.152853    0
0.423363    11.054677   0
0.406704    7.067335    1
0.667394    12.741452   0

2. 目标
使用python实现k-means算法,将数据划分到不同的类中,并用图形显示

3. python实现

#!/usr/bin/python
# -*- coding: UTF-8 -*-

from numpy import *
import random
import matplotlib.pyplot as plt

#计算两个样本之间的欧式距离
#参数是矩阵
def calDistance(vec1,vec2):
    vec1=array(vec1);#转为数组
    vec2 = array(vec2);
    return sqrt(sum(pow(vec1-vec2,2)));

#随机选取初始质心
def getInitCentroid(dataSet,k):
    m,n=shape(dataSet);
    centroid=zeros((k,n));#初始化k个质心
    for i in range(k):
        index=random.uniform(0,len(dataSet));
        centroid[i,:]=dataSet[int(index),:];
    return mat(centroid);

#核心算法
def kmeans(dataSet,k):
    m,n=shape(dataSet);
    clusterAssment=mat(zeros((m,1)))#初始化簇m行,1列,第一列为元素所属的簇  说明:簇也就是所属的类,类就是我们常说的标签
    centroid=getInitCentroid(dataSet,k)#获得初始质心
    isEnd=True;
    while isEnd:
        isEnd=False;
        for i in range(len(dataSet)):#对于每一个样本
            minDistance=100000;
            minindex=-1;
            for j in range(k):#寻找离质心最近的簇
                distance=calDistance(dataSet[i,:],centroid[j,:])
                if distance<minDistance:
                    minDistance=distance;
                    minindex=j#寻找到了离质心最近的簇
            if clusterAssment[i,0] != minindex:#若簇有变化,更新簇
                isEnd=True;
                clusterAssment[i,0]=minindex

        for n in range(k):#更新每个质心
            test1=clusterAssment[:, 0].A==n#获得与质心类型相同的簇
            test2=nonzero(test1);
            test3=test2[0];#获得与质心类型相同簇元素的下标
            test4=dataSet[test3]
            centroid[n,:]=mean(test4,axis=0);#相同的簇,计算平均值即为新的质心,axis=0为对列求平均值
    return centroid,clusterAssment

#加载数据
def loadData(filePath):
    dataSet=[];
    with open(filePath) as f:
        for line in f.readlines():
            lines=line.split("\t");
            dataSet.append([float(lines[0]),float(lines[1])]);
    return mat(dataSet)


#画图
def showCluster(dataSet, k, centroids, clusterAssment):
    numSamples, dim = dataSet.shape
    if dim != 2:
        print("Sorry! I can not draw because the dimension of your data is not 2!")
        return 1

    #颜色
    mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']
    if k > len(mark):
        print("Sorry! Your k is too large! please contact Zouxy")
        return 1

    #画样本
    for i in range(numSamples):
        markIndex = int(clusterAssment[i, 0])  # 每个样本所属族群
        plt.plot(dataSet[i, 0], dataSet[i, 1], mark[markIndex])
    mark = ['Dr', 'Db', 'Dg', 'Dk', '^b', '+b', 'sb', 'db', '<b', 'pb']

    #画质心
    for i in range(k):
        plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize=6)
    plt.show()

if __name__=='__main__':
    dataSet=loadData("D:\\testSet.txt");#加载数据
    centroid, clusterAssment=kmeans(dataSet,2)#knn算法,返回质心以及簇
    showCluster(dataSet,2,centroid,clusterAssment);#作图

4.实验结果

(1)质心个数为2,即划分为2类,k=2
这里写图片描述

(2)质心个数为3,即划分为3类,k=3
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值