聚类cluster

一,k均值算法

(一)自己写程序

举例,在excel中有四个点的坐标如下,表示样本集 D=(x1,x2,x3,x4)D=(x_1,x_2,x_3,x_4)(分别对应下图中的最左边标签对应的数,x1=(2.2,2.3)...x_1=(2.2,2.3)...)
聚类cluster
现在将这四个点画出来

import numpy as np
import xlrd
import matplotlib.pyplot as plt

workbook = xlrd.open_workbook('C:/users/Lenovo/Desktop/test.xlsx')
sheet = workbook.sheet_by_name('Sheet1')

dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)

plt.scatter(dot_x,dot_y)
plt.show()

聚类cluster
随机选择两个样本作为初始均值向量,(机器学习西瓜书中随机选样本集中的数,而此处是随机生成范围内的数,未必是样本集中存在的x1x4x_1到x_4):
在上面得到了点的横纵坐标之后(即dot_x,dot_y),现在组合成数据集(注意dot_x,dot_y)都是行矢量,所以组成矩阵数据集后要转置

dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)
dataSet = np.mat([dot_x,dot_y]).T

聚类cluster
现在开始随机生成聚类中心

def randcenters(dataSet,k):    #输入数据集和k
    n = np.shape(dataSet)[1]   #查看k有多少列,实际上就是点的坐标的维度,比如两维x,y
    centroids = np.matrix(np.zeros((k,n)))  #zeros得到的是数组,一定要变成矩阵,否则centroids[:,0]并不表示第一列
    for J in range(n):
        rangeJ = float(max(dataSet[:,J])-min(dataSet[:,J])) #求出范围,注意 A
        centroids[:,J] = min(dataSet[:,J]) + rangeJ*np.random.rand(k,1) #生成聚类中心
    return centroids

上面中注意“A”部分:rangeJ=float…, 此处float一定不能少,因为max(dataSet[:,J])还是矩阵,是1×11\times 1矩阵。
聚类cluster
经过float之后变成浮点数。
测试一下

test = randcenters(dataSet,2)

聚类cluster
所以这里得到的两个质心就是初始均值向量,即
μ1=(5.000,4.939);μ2=(3.924,6.698)\mu _1=(5.000,4.939);\mu_2=(3.924,6.698)
现在计算上面的数据集到质心的距离(欧氏距离)

def distEclud(vecA,vecB):     #输入的是数组,不能用list形式
    return np.sqrt(sum(np.power(vecA-vecB,2)))

开始着手聚类算法:

def kMeans(dataSet,k): #不妨以k=2举例
    m = np.shape(dataSet)[0]  #显示数据集的个数,即有多少个数据需要处理
    ClustDist = np.mat(np.zeros((m,2))) #聚类最小距离的索引值和此距离。第一列放索引值,第二列放最小距离
    clustercents = randcenters(dataSet,k)  #调用生成随机聚类
    clusterChanged = True
    while clusterChanged:     #用while进行迭代
        clusterChanged = False # 设置初始为False
        # 计算每个数据与随机初始得到的质心的距离,比如假设只有两个质心,即k=2,那么找到每个数据分别到这两个
        # 点的距离,并保留距离小的那个。比如x1到质心Cent1和质心Cent2的距离分别为l1和l2,且l1<l2.那么
        # 就保留l1并记下l1的位置(索引)
        for i in range(m):
            distlist = [distEclud(clustercents[j,:],dataSet[i,:]) for j in range(k)] #计算每个数据与随机质心间的距离
            minDist = min(distlist)  #找到最小距离
            minIndex = distlist.index(minDist) #最小距离对应的索引值
            
            if ClustDist[i,0] != minIndex: #找到了一个新的聚类中心,因为是for i in...循环,只要数据集中有一个新中心就变True
                clusterChanged = True
            ClustDist[i,:] = minIndex,minDist  #放置找到的新的最小距离
            
        for cent in range(k):  #假设k=2,即两个聚类中心
            dInx = np.nonzero(ClustDist[:,0].A == cent)[0]
            ptsInClust = dataSet[dInx] #选择数据中的数
            clustercents[cent,:] = np.mean(ptsInClust,axis=0)
    return clustercents, ClustDist

完整代码如下:

def randcenters(dataSet,k):    #输入数据集和k
    n = np.shape(dataSet)[1]   #查看k有多少列,实际上就是点的坐标的维度,比如两维x,y
    centroids = np.matrix(np.zeros((k,n)))  #zeros得到的是数组,一定要变成矩阵,否则centroids[:,0]并不表示第一列
    for J in range(n):
        rangeJ = float(max(dataSet[:,J])-min(dataSet[:,J])) #求出范围,注意 A
        centroids[:,J] = min(dataSet[:,J]) + rangeJ*np.random.rand(k,1) #生成聚类中心
    return centroids

def distEclud(vecA,vecB):
    return np.sqrt(sum(np.power(vecA-vecB,2)))

def kMeans(dataSet,k): #不妨以k=2举例
    m = np.shape(dataSet)[0]  #显示数据集的个数,即有多少个数据需要处理
    ClustDist = np.mat(np.zeros((m,2))) #聚类最小距离的索引值和此距离。第一列放索引值,第二列放最小距离
    clustercents = randcenters(dataSet,k)  #调用生成随机聚类
    clusterChanged = True
    while clusterChanged:     #用while进行迭代
        clusterChanged = False # 设置初始为False
        # 计算每个数据与随机初始得到的质心的距离,比如假设只有两个质心,即k=2,那么找到每个数据分别到这两个
        # 点的距离,并保留距离小的那个。比如x1到质心Cent1和质心Cent2的距离分别为l1和l2,且l1<l2.那么
        # 就保留l1并记下l1的位置(索引)
        for i in range(m):
            distlist = [distEclud(clustercents[j,:],dataSet[i,:]) for j in range(k)] #计算每个数据与随机质心间的距离
            minDist = min(distlist)  #找到最小距离
            minIndex = distlist.index(minDist) #最小距离对应的索引值
            
            if ClustDist[i,0] != minIndex: #找到了一个新的聚类中心,因为是for i in...循环,只要数据集中有一个新中心就变True
                clusterChanged = True
            ClustDist[i,:] = minIndex,minDist  #放置找到的新的最小距离
            
        for cent in range(k):  #假设k=2,即两个聚类中心
            dInx = np.nonzero(ClustDist[:,0].A == cent)[0]
            ptsInClust = dataSet[dInx] #选择数据中的数
            clustercents[cent,:] = np.mean(ptsInClust,axis=0)
    return clustercents, ClustDist
        

workbook = xlrd.open_workbook('C:/users/Lenovo/Desktop/test.xlsx')
sheet = workbook.sheet_by_name('Sheet1')

dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)
dataSet = np.mat([dot_x,dot_y]).T

k = 2
clustercents,ClustDist = kMeans(dataSet,k)
print(clustercents)

结果是新的聚类中心,即μ1=(2.6,2.7),μ2=(8.15,7.5)\mu_1=(2.6,2.7),\mu_2=(8.15,7.5)
聚类cluster
最后输出聚类结果图片
图片分析部分不做进一步讲解,完整代码如下

#from numpy import *
import numpy as np
import xlrd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

#随机生成聚类中心
def randcenters(dataSet,k):    #输入数据集和k
    n = np.shape(dataSet)[1]   #查看k有多少列,实际上就是点的坐标的维度,比如两维x,y
    centroids = np.matrix(np.zeros((k,n)))  #zeros得到的是数组,一定要变成矩阵,否则centroids[:,0]并不表示第一列
    for J in range(n):
        rangeJ = float(max(dataSet[:,J])-min(dataSet[:,J])) #求出范围,注意 A
        centroids[:,J] = min(dataSet[:,J]) + rangeJ*np.random.rand(k,1) #生成聚类中心
    return centroids

def distEclud(vecA,vecB):
    return np.sqrt(sum(np.power(vecA-vecB,2)))

def kMeans(dataSet,k): #不妨以k=2举例
    m = np.shape(dataSet)[0]  #显示数据集的个数,即有多少个数据需要处理
    ClustDist = np.mat(np.zeros((m,2))) #聚类最小距离的索引值和此距离。第一列放索引值,第二列放最小距离
    clustercents = randcenters(dataSet,k)  #调用生成随机聚类
    clusterChanged = True
    while clusterChanged:     #用while进行迭代
        clusterChanged = False # 设置初始为False
        # 计算每个数据与随机初始得到的质心的距离,比如假设只有两个质心,即k=2,那么找到每个数据分别到这两个
        # 点的距离,并保留距离小的那个。比如x1到质心Cent1和质心Cent2的距离分别为l1和l2,且l1<l2.那么
        # 就保留l1并记下l1的位置(索引)
        for i in range(m):
            distlist = [distEclud(clustercents[j,:],dataSet[i,:]) for j in range(k)] #计算每个数据与随机质心间的距离
            minDist = min(distlist)  #找到最小距离
            minIndex = distlist.index(minDist) #最小距离对应的索引值
            
            if ClustDist[i,0] != minIndex: #找到了一个新的聚类中心,因为是for i in...循环,只要数据集中有一个新中心就变True
                clusterChanged = True
            ClustDist[i,:] = minIndex,minDist  #放置找到的新的最小距离
            
        for cent in range(k):  #假设k=2,即两个聚类中心
            dInx = np.nonzero(ClustDist[:,0].A == cent)[0]
            ptsInClust = dataSet[dInx] #选择数据中的数
            clustercents[cent,:] = np.mean(ptsInClust,axis=0)
    return clustercents, ClustDist
        
def color_cluster(dataindx, dataSet, plt):
    datalen = len(dataindx)
    for indx in range(datalen):
        if int(dataindx[indx]) == 0:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='blue', marker='o')
        elif int(dataindx[indx]) == 1:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='green', marker='o')
        elif int(dataindx[indx]) == 2:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='red', marker='o')
        elif int(dataindx[indx]) == 3:
            plt.scatter(dataSet[indx, 0], dataSet[indx, 1], c='cyan', marker='o')
            
def drawScatter(plt, mydata, size=20, color='blue', mrkr='o'):
    plt.scatter(mydata.T[0].tolist(), mydata.T[1].tolist(), s=size, c=color, marker=mrkr)
    
workbook = xlrd.open_workbook('C:/users/Lenovo/Desktop/test.xlsx')
sheet = workbook.sheet_by_name('Sheet1')

dot_x = sheet.col_values(0)
dot_y = sheet.col_values(1)
dataSet = np.mat([dot_x,dot_y]).T

k = 2
clustercents,ClustDist = kMeans(dataSet,k)
print(clustercents)
color_cluster(ClustDist[:, 0:1], dataSet, plt)
drawScatter(plt,clustercents,color='red',mrkr='D')

聚类中心
聚类cluster
聚类结果
聚类cluster

(二)调用现有库(待续…)

关于sklearn库可以参考这篇文章:https://blog.****.net/u014248127/article/details/78885180,
作者写得很详细
参考文献
1,https://www.cnblogs.com/eczhou/p/7860424.html
2,机器学习实践第十章
3,https://blog.****.net/u014248127/article/details/78885180