聚类-kmeans

2023-09-13 17:03:17

聚类算法是无监督学习算法,指定将数据分成k个簇。然后通过每个点到各个簇的中心的欧氏距离来分类。d(x,y)=\sqrt{(x_{1}-y_{1}^{2})+(x_{2}-y_{2})^{2}+...+(x_{n}-y_{n})^{2}}

kmeans本身会陷入局部最小值的状况,二分kmeans可以解决这一点。

二分kmeans是遍历所有的簇,将其分成2个,比较哪一个分裂结果更好,用距离和来代表误差

例如现在只有一个簇A,第一轮分裂成A,A1,下一次比较A,A1两个分裂的结果哪个更换,比如A1更好,所以分裂结果为A,A1,A11。

from __future__ import print_function
from numpy import *


# 从文本中构建矩阵,加载文本文件,然后处理
def loadDataSet(fileName):  # 通用函数,用来解析以 tab 键分隔的 floats(浮点数)
    dataSet = []
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        fltLine = map(float, curLine)  # 映射所有的元素为 float(浮点数)类型
        dataSet.append(fltLine)
    return dataSet

# 计算两个向量的欧式距离(可根据场景选择)
def distEclud(vecA,vecB):
    return sqrt(sum(power(vecA-vecB,2))) # la.norm(vecA-vecB)

# 为给定数据集构建一个包含 k 个随机质心的集合。随机质心必须要在整个数据集的边界之内,这可以通过找到数据集每一维的最小和最大值来完成。然后生成 0~1.0 之间的随机数并通过取值范围和最小值,以便确保随机点在数据的边界之内。
def randCent(dataMat,k):
    n=shape(dataMat)[1] # 列的数量
    centroids=mat(zeros((k,n))) # 创建k个质心矩阵
    for j in range(n): # 创建随机簇质心,并且在每一维的边界内
        minJ=min(dataMat[:,j]) # 最小值
        rangeJ=float(max(dataMat[:,j])-minJ) # 范围=最大值-最小值
        centroids[:,j]=mat(minJ+rangeJ*random.rand(k,1)) # 随机生成
    return centroids

# k-means 聚类算法
# 该算法会创建k个质心,然后将每个点分配到最近的质心,再重新计算质心。
# 这个过程重复数次,知道数据点的簇分配结果不再改变位置。
# 运行结果(多次运行结果可能会不一样,可以试试,原因为随机质心的影响,但总的结果是对的, 因为数据足够相似,也可能会陷入局部最小值)
def KMeans(dataMat,k,distMeas=distEclud,createCent=randCent):
    m=shape(dataMat)[0] # 行数
    clusterAssment=mat(zeros((m,2))) # 创建一个与dataMat 行数一样,但是有两列的矩阵,用来保存簇分配结果
    centroids=createCent(dataMat,k) # 创建质心,随机k个质心
    clusterChanged=True
    while clusterChanged:
        clusterChanged=False
        for i in range(m): # 循环每一个数据点并分配到最近的质心中去
            minDist=inf
            minIndex=-1
            for j in range(k):
                distJI=distMeas(centroids[j,:],dataMat[i,:]) # 计算数据点到质心的距离
                if distJI<minDist: # 如果距离比 minDist(最小距离)还小,更新 minDist(最小距离)和最小质心的 index(索引)
                    minDist=distJI
                    minIndex=j
            if clusterAssment[i,0]!=minIndex: # 簇分配结果改变
                clusterChanged=True #簇改变
                clusterAssment[i,:]=minIndex,minDist**2 #更新簇分配结果为最小质心的index(索引),minDist(最小距离)的平方
        print(centroids)
        for cent in range(k): #更新质心
            ptsInClust=dataMat[nonzero(clusterAssment[:,0].A==cent)[0]] #获取该簇中所有点
            centroids[cent,:]=mean(ptsInClust,axis=0) # 将质心修改为簇中所有点的平均值,mean就是求平均值的
    return centroids,clusterAssment

# 二分 KMeans 聚类算法, 基于 kMeans 基础之上的优化,以避免陷入局部最小值
def biKMeans(dataMat,k,distMeas=distEclud):
    m=shape(dataMat)[0]
    clusterAssment=mat(zeros((m,2))) # 保存每个数据点的簇分配结果和平方误差
    centroid0=mean(dataMat,axis=0).tolist()[0]   # 质心初始化为所有数据点的均值
    centList=[centroid0]    # 初始化只有 1 个质心的 list
    for j in range(m): # 计算所有数据点到初始质心的距离平方误差
        clusterAssment[j,1]=distMeas(mat(centroid0),dataMat[j,:])**2
    while(len(centList)<k): # 当质心数量小于k时
        lowestSSE=inf
        for i in range(len(centList)):  #对每一个质心
            ptsInCurrCluster=dataMat[nonzero(clusterAssment[:,0].A==i)[0],:]  # 获取当前簇i下的所有数据点
            centroidMat,splitClustAss=KMeans(ptsInCurrCluster,2,distMeas) # 将当前簇 i 进行二分 kMeans 处理
            sseSplit = sum(splitClustAss[:, 1])  # 将二分 kMeans 结果中的平方和的距离进行求和
            sseNotSplit =sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1]) # 将未参与二分 kMeans 分配结果中的平方和的距离进行求和
            print("sseSplit, and notSplit: ", sseSplit, sseNotSplit)
            if (sseSplit + sseNotSplit) < lowestSSE:
                bestCentToSplit = i
                bestNewCents = centroidMat
                bestClustAss = splitClustAss.copy()
                lowestSSE = sseSplit + sseNotSplit
        # 找出最好的簇分配结果    
        bestClustAss[nonzero(bestClustAss[:, 0].A == 1)[0], 0] = len(centList)  # 调用二分 kMeans 的结果,默认簇是 0,1. 当然也可以改成其它的数字
        bestClustAss[nonzero(bestClustAss[:, 0].A == 0)[0],0] = bestCentToSplit  # 更新为最佳质心
        print('the bestCentToSplit is: ', bestCentToSplit)
        print('the len of bestClustAss is: ', len(bestClustAss))
        # 更新质心列表
        centList[bestCentToSplit] = bestNewCents[0, :].tolist()[0]  # 更新原质心 list 中的第 i 个质心为使用二分 kMeans 后 bestNewCents 的第一个质心
        centList.append(bestNewCents[1, :].tolist()[0])  # 添加 bestNewCents 的第二个质心
        clusterAssment[nonzero(clusterAssment[:, 0].A == bestCentToSplit)[0], :] = bestClustAss  # 重新分配最好簇下的数据(质心)以及SSE
    return mat(centList), clusterAssment

def testBasicFunc():
    # 加载测试数据集
    dataMat = mat(loadDataSet('data/10.KMeans/testSet.txt'))

    # 测试 randCent() 函数是否正常运行。
    # 首先,先看一下矩阵中的最大值与最小值
    print('min(dataMat[:, 0])=', min(dataMat[:, 0]))
    print('min(dataMat[:, 1])=', min(dataMat[:, 1]))
    print('max(dataMat[:, 1])=', max(dataMat[:, 1]))
    print('max(dataMat[:, 0])=', max(dataMat[:, 0]))

    # 然后看看 randCent() 函数能否生成 min 到 max 之间的值
    print('randCent(dataMat, 2)=', randCent(dataMat, 2))

    # 最后测试一下距离计算方法
    print(' distEclud(dataMat[0], dataMat[1])=', distEclud(dataMat[0], dataMat[1]))


def testKMeans():
    # 加载测试数据集
    dataMat = mat(loadDataSet('data/10.KMeans/testSet.txt'))

    # 该算法会创建k个质心,然后将每个点分配到最近的质心,再重新计算质心。
    # 这个过程重复数次,知道数据点的簇分配结果不再改变位置。
    # 运行结果(多次运行结果可能会不一样,可以试试,原因为随机质心的影响,但总的结果是对的, 因为数据足够相似)
    myCentroids, clustAssing = KMeans(dataMat, 4)

    print('centroids=', myCentroids)


def testBiKMeans():
    # 加载测试数据集
    dataMat = mat(loadDataSet('data/10.KMeans/testSet2.txt'))

    centList, myNewAssments = biKMeans(dataMat, 3)

    print('centList=', centList)
# 测试基础的函数
testBasicFunc()

# 测试 kMeans 函数
testKMeans()

# 测试二分 biKMeans 函数
testBiKMeans()

更多推荐

xyhcms getshell

下载xyhcms3.6.2021版本并用phpstudy搭建functionget_cookie($name,$key=''){if(!isset($_COOKIE[$name])){returnnull;}$key=empty($key)?C('CFG_COOKIE_ENCODE'):$key;$value=$_CO

Naivcat 数据迁移工具 | 竟然那么香

近期,我们收到一位童鞋的留言(如下图),他建议我们多宣传Navicat的数据迁移工具,因为他身边许多小伙伴并非很了解这一功能。今天,我们为大家深度介绍Naivcat安全、可靠的数据迁移工具。请童鞋们准备好NavicatPremium工具,我们马上开始!数据库数据迁移是指选择、准备、提取和转换数据,并将数据从一个计算机存

孩子写作业买什么样台灯合适?适合孩子读写台灯推荐

现在孩子的普遍都存在视力问题,而导致孩子近视的原因可能跟光线太强或太弱、不用的用眼习惯、长时间的过度用眼等因素有关,根据数据表明目前中国近视患者人数达到6亿多,其中儿童青少年的视力不良率甚至高达八成,所以在孩子的学习道路上,护眼也是重中之重的事情。平时间养成良好的用眼习惯是必不可少的,不过照明光源的选择也重要,所以挑选

树莓派4b装系统到运行 Blazor Linux 本地程序全记录

在Linux下运行gui程序,咱也是第一次做,属于是瞎子过河乱摸一通,写得有什么不对和可以优化的地方,希望各位看官斧正斧正.##1.下载烧录器https://www.raspberrypi.com/software/####我选择的是Raspbian64位系统,并配置好ssh账号密码,wifi,以便启动后可以直接黑屏s

贪心算法(Greedy Algorithm)

贪心算法(GreedyAlgorithm)是一种解决优化问题的算法策略。在贪心算法中,每一步都会选择当前情况下最优的选择,而不考虑未来的后果。贪心算法的基本思想是通过局部最优选择达到全局最优。它并不保证一定能得到全局最优解,但在某些情况下可以得到近似最优解或者符合要求的解。贪心算法的适用条件是问题具有"最优子结构"和"

Web自动化测试进阶 —— Selenium模拟鼠标操作

鼠标操作事件在实际的web产品测试中,对于鼠标的操作,不单单只有click(),有时候还要用到右击、双击、拖动等操作,这些操作包含在ActionChains类中。ActionChains类中鼠标操作常用方法:首先导入ActionChains类:fromselenium.webdriver.common.action_c

2023年9月21日,历史上的今天大事件早读

​公元前19年9月21日古罗马诗人维吉尔逝世1069年9月21日宋神宗采用王安石新法,开始实行青苗法1643年9月21日皇太极逝世1898年9月21日慈禧太后发动戊戌政变1909年9月21日我国飞机设计师冯如第一次试飞成功1920年9月21日民主革命家朱执信遇难1926年9月21日荷兰物理学家昂内斯首次发现物理超导性1

分布式/微服务---第五篇

系列文章目录文章目录系列文章目录一、简述ZAB协议二、zk的数据模型和节点类型一、简述ZAB协议ZAB协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议,实现分布式数据一致性所有客户端的请求都是写入到Leader进程中,然后,由Leader同步到其他节点,称为Follower。在集群数据同

Python中的POST请求参数

一、什么是POST请求参数在HTTP协议中,GET和POST是两种常用的请求方法。GET请求通过URL参数将请求数据传递给服务器,而POST请求则通过请求体中的参数传递数据。POST请求通常用于提交表单、上传文件等操作。POST请求参数就是请求体中的参数。在Python中,我们可以使用第三方库如requests来发送P

利用fiddler正向代理前端请求到本地后端

前景:在实际开发测试环境中,(前后端均已上线到测试服务器或前端以上线而后端还在开发中)。在测试过程中(前端页面点击,功能测试)发现了bug或异常点。正常排查问题可能是先利用浏览器检查工具查看接口的返回参数是否正常,如果异常那就得用(pycharm/vscode)启动服务再通过(postman/apifox)模拟前端请求

群晖管家+内网穿透实现公网远程访问本地黑群晖

白嫖怪狂喜!黑群晖也能使用群晖管家啦!文章目录白嫖怪狂喜!黑群晖也能使用群晖管家啦!1.使用环境要求:2.下载安装群晖管家app3.随机地址登陆群晖管家app4.固定地址登陆群晖管家app自己组装nas的白嫖怪们虽然也可以通过在局域网使用黑群晖,但是群晖quickconnect需要绑定正版群晖账号,那么白嫖怪们要怎样在

热文推荐