聚类k-means算法 python实现

一、k-means聚类算法

k-means聚类属于比较基础的聚类算法,它的算法步骤如下

算法步骤: 
(1) 首先我们选择一些类/组等数据,首先确定需要分组的数量k,并随机初始化数据中的K个中心点(中心点表示每种类别的中心,质心)。
(2) 对于数据集中的每个数据点计算这个数据点到中心点的距离,数据点距离哪个中心点最近就划分到哪一类中。 
(3)得到分好的数据后,重新 计算每一类中中心点作为新的中心点(即质心)。 计算均方差:  

         对于样本集。"k均值"(k-means)算法就是针对聚类划分最小化平方误差:

  

其中是簇Ci的均值向量。从上述公式中可以看出,该公式刻画了簇内样本围绕簇均值向量的紧密程度,E值越小簇内样本的相似度越高。

(4) 重复以上步骤,直到每一类中心在每次迭代后均方差小于一定阈值。也可以多次随机初始化中心点,然后选择运行结果最好的一个。 
下图演示了K-Means进行分类的过程:(菱形为每种类别的中心)

二、代码实现

1、不适用sklearn  实现的python代码

import re
import numpy as np
import random
import codecs
import matplotlib.pyplot as plt
#数据结构  cenList[]存放质心的列表  [ [x,y],[x,y],,,,[x,y]]
#          cenDiction 字典 存放质心和对应的数据 格式为[0:[[x,y],[x,y],,,,[x,y]],1:[[x,y],,[x,y]],,,k:[[x,y],,,[x,y]]
#          字典的Key为第几个之心的编号 
#          dataSet 为数据的坐标

def getDistance(v1,v2):
    dis = np.sqrt(np.sum(np.square(v1 - v2)))   #计算两个数据之间的欧式距离
    return dis


def loadData(File):
    dataSet = list()
    lines = codecs.open(File,'r','utf-8').readlines()  #按行读取文件 并保存到列表中
    for line in lines:
        line = line.strip()    #读取一行即一个数据点的坐标,去除前后多余空格
        line = re.split('   ',line)    # 根据空格分词 得到[‘x’,‘y’]形式
        # aline = np.array(line)
        coline = []
        for i in line:   #因从文件中读取的数据为str格式为方便后续运算转换成float的类型
            num = float(i)
            coline.append(num)   #每个数据坐标存储为[x,y]格式
        dataSet.append(coline)
    return dataSet     #dataSet为[[x1,y1],[x2,y2],,,,,[xn,yn]]格式


def innitCentroid(dataSet,k):
    return random.sample(dataSet,k)    #初始化质心


def getCentroid(cenList,cenDiction):   #计算每个类别中的质心
    newcen = list()
    for i in range(len(cenList)):
        newcen.append(np.mean(np.array(cenDiction[i]),0).tolist())  #对于每个类别 计算所有坐标的平均值
    print('新的质心',newcen)
    return newcen


def minDistance(dataSet,cenList):   #计算最小聚类,获得新的分类
    cenDiction = {}
    for item in dataSet:
        mind = float("inf")  #最大数
        flag = 0
        aitem = np.array(item)    #list类型不能对数据进行运算 所以转换为array类型
        for i in range(len(cenList)):   #对于每个之心 计算数据点到质心的距离
            acen = np.array(cenList[i])
            if getDistance(aitem,acen) < mind:
                mind = getDistance(aitem,acen)
                flag = i
        if flag not in cenDiction.keys():   #如果质心不再分类字典的keys()中 加入
            cenDiction[flag] = []
        cenDiction[flag].append(item)
    return cenDiction


def getDeviation(cenList,cenDiction):   #计算均方差
    sum = 0
    for i in range(len(cenList)):
        item = cenList[i]
        aitem = np.array(item)
        for data in cenDiction[i]:
            adata = np.array(data)
            sum = sum + getDistance(aitem,adata)
    return sum


def showplot(cenList,cenDiction):
    colormark = ['or','og','ob','ok','oy','ow']  #o表示圆  d表示菱形
    cenmark = ['dr','dg','db','dk','dy','dw']
    plt.figure('k-means聚类')
    for i in range(len(cenList)):
        plt.plot(cenList[i][0],cenList[i][1],cenmark[i])
        for item in cenDiction[i]:
            plt.plot(item[0],item[1],colormark[i])
    plt.show()


if __name__ == '__main__':
    inFile = 'E:/pythontest/km.txt'
    dataSet = loadData(inFile)
    cenList = innitCentroid(dataSet,4)  #初始化质心
    print('第1次迭代')
    cenDiction = minDistance(dataSet,cenList)   #计算最小聚类 分类
    showplot(cenList, cenDiction)
    oldnum = 0.0001
    newnum = getDeviation(cenList,cenDiction)  #计算均方差
    k = 2
    while  abs(newnum - oldnum) > 0.0001:  #当新旧均方差相差小于等于0.001 结束
        cenList = getCentroid(cenList,cenDiction)  #计算新的质心
        cenDiction = minDistance(dataSet,cenList)   #重新分类
        oldnum = newnum
        newnum = getDeviation(cenList,cenDiction)
        print('第',k,'次迭代')
        showplot(cenList, cenDiction)
        k = k + 1
        print('均方差',oldnum,newnum)
    print('聚类完成')

2、使用python中的sklearn包实现聚类

自带函数:

sklearn.cluster.KMeans(n_clusters=8,
     init='k-means++', 
    n_init=10, 
    max_iter=300, 
    tol=0.0001, 
    precompute_distances='auto', 
    verbose=0, 
    random_state=None, 
    copy_x=True, 
    n_jobs=1, 
    algorithm='auto'
    )

参数的意义:

  • n_clusters:簇的个数,即你想聚成几类
  • init: 初始簇中心的获取方法
  • n_init: 获取初始簇中心的更迭次数,为了弥补初始质心的影响,算法默认会初始10次质心,实现算法,然后返回最好的结果。
  • max_iter: 最大迭代次数(因为kmeans算法的实现需要迭代)
  • tol: 容忍度,即kmeans运行准则收敛的条件
  • precompute_distances:是否需要提前计算距离,这个参数会在空间和时间之间做权衡,如果是True 会把整个距离矩阵都放到内存中,auto 会默认在数据样本大于featurs*samples 的数量大于12e6 的时候False,False 时核心实现的方法是利用Cpython 来实现的
  • verbose: 冗长模式
  • random_state: 随机生成簇中心的状态条件。
  • copy_x: 对是否修改数据的一个标记,如果True,即复制了就不会修改数据。bool 在scikit-learn 很多接口中都会有这个参数的,就是是否对输入数据继续copy 操作,以便不修改用户的输入数据。这个要理解Python 的内存机制才会比较清楚。
  • n_jobs: 并行设置
  • algorithm: kmeans的实现算法,有:’auto’, ‘full’, ‘elkan’, 其中 ‘full’表示用EM方式实现

代码如下:

from sklearn.cluster import KMeans
from sklearn.externals import joblib
import numpy
import time
import matplotlib.pyplot as plt

if __name__ == '__main__':
    ## step 1: 加载数据
    print("step 1: load data...")
    dataSet = []
    fileIn = open('E:/pythontest/km.txt')
    for line in fileIn.readlines():
        lineArr = line.strip().split('   ')
        dataSet.append([float(lineArr[0]), float(lineArr[1])])

    #设定不同k值以运算
    for k in range(2,10):
        clf = KMeans(n_clusters=k) #设定k  !!!!!!!!!!这里就是调用KMeans算法
        s = clf.fit(dataSet) #加载数据集合
        numSamples = len(dataSet)
        centroids = clf.predict(dataSet)
        #centroids = clf.fit_predict(dataSet)
        # centroids = clf.labels_
        print(centroids,type(centroids)) #显示中心点
        print(clf.inertia_ ) #显示聚类效果
        mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']
        #画出所有样例点 属于同一分类的绘制同样的颜色
        for i in range(numSamples):
            #markIndex = int(clusterAssment[i, 0])
            plt.plot(dataSet[i][0], dataSet[i][1], mark[clf.labels_[i]]) #mark[markIndex])
        mark = ['Dr', 'Db', 'Dg', 'Dk', '^b', '+b', 'sb', 'db', '<b', 'pb']
        # 画出质点,用特殊图型
        centroids =  clf.cluster_centers_
        for i in range(k):
            plt.plot(centroids[i][0], centroids[i][1], mark[i], markersize = 12)
            #print centroids[i, 0], centroids[i, 1]
        plt.show()

部分参考https://blog.csdn.net/sinat_26917383/article/details/70240628

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值