聚类算法(2)--- ISODATA算法

news2024/11/28 10:52:21

       本篇文章是博主在人工智能等领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在AI学习笔记

      AI学习笔记(8)---聚类算法(2)--- ISODATA算法》

聚类算法(2)--- ISODATA算法

目录

一、 ISODATA算法

1.1算法原理

1.2实验应用

二、 ISODATA算法python实现

2.1 算法流程

2.2 算法python程序

2.3 算法注意事项

三、 ISODATA算法实验结果

四、小结


一、 ISODATA算法

        ISODATA算法(Iterative Self-Organizing Data Analysis Technique Algorithm)是一种经典的聚类算法,结合了K-均值和层次聚类的特点。该算法通过动态调整簇的数量和簇的中心点,能够根据数据特点自适应地调整聚类情况。

其他聚类算法见:

聚类算法(1)---最大最小距离、C-均值算法

1.1算法原理

        SODATA算法采用迭代的方式动态地更新簇的数目和簇的中心,根据设定的参数来调整簇的数量以及样本点与簇之间的距离等。算法首先初始化聚类中心并对样本进行初步的分组,然后根据一定

1.2实验应用

        ISODATA算法在实际应用中有着广泛的应用,特别是在数据挖掘、图像处理和生物信息学等领域。例如在地理信息系统(GIS)领域,ISODATA算法可以用于空间数据的聚类分析,对地理位置数据进行聚类,以实现地理空间上的模式识别和区域划分。


二、 ISODATA算法python实现

        ISODATA(Iterative Self-Organizing Data Analysis Technique)算法是一种自组织数据分析技术,主要用于聚类分析。其算法流程如下:

2.1 算法流程

(1)初始化参数:选择初始的簇中心数量K、设定其他参数(如每个簇的最小样本数、簇内样本方差阈值等),并随机选择K个点作为初始的簇中心。

(2)分配样本:对于数据集中的每个样本点,计算它与各个簇中心的距离,并将其分配到距离最近的簇中。

(3)簇合并:检查每个簇的样本方差是否大于预设的阈值,如果是,则将该簇进行分裂,生成新的簇中心。

(4)簇分裂:重复执行步骤2和步骤3,直至满足终止条件(如簇中心不再发生大的变化、达到最大迭代次数等)。

(5)更新簇中心:根据当前的簇分配情况,重新计算每个簇中所有样本点的均值,以此更新簇中心的位置。

(6)重复迭代:重复执行步骤2至步骤5,直至满足终止条件(如簇中心不再发生大的变化、达到最大迭代次数等)。

(7)输出结果:得到K个簇,每个簇包含若干个样本点,完成聚类过程。

2.2 算法python程序

导入需要的python库

import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import euclidean_distances
import copy

ISODATA聚类算法

class ISODATA():
    def __init__(self, designCenterNum, Nc, LeastSampleNum, StdThred, LeastCenterDist, L, iterationNum):
        #  指定预期的聚类数、初始聚类中心个数、每类的最小样本数、标准差阈值、最小中心距离、每次可合并的最多对数、迭代次数
        self.K = designCenterNum
        self.centerNum = Nc
        self.thetaN = LeastSampleNum
        self.thetaS = StdThred
        self.thetaC = LeastCenterDist
        self.L = L
        self.iteration = iterationNum

        self.data = np.stack([[0, 0], [0, 1], [4, 4], [4, 5], [5, 4], [5, 5], [1, 0]], dtype=np.float64)
        self.label = np.stack([0, 0, 0, 0, 0, 0, 0])

        # 随机选取NC个初始聚类中心
        center_ind = np.random.choice(np.arange(len(self.data), dtype=np.int32), Nc, replace=False)
        self.center = np.stack([copy.deepcopy(self.data[center_ind[i], :]) for i in range(Nc)])
        self.centerMeanDist = 0

    # 更新
    def updateLabel(self):
        # 计算样本到中心的距离
        distance = euclidean_distances(self.data, self.center.reshape((self.centerNum, -1)))
        # 选出每个模式到各个中心的最小距离,并为样本重新分配标签
        self.label = np.argmin(distance, 1)
        for i in range(self.centerNum):
            # 找出同一类样本
            index = np.argwhere(self.label == i).squeeze()
            sameClassSample = self.data[index, :]
            # 更新中心
            if len(sameClassSample.shape) >= 2:
                  self.center[i, :] = np.mean(sameClassSample, 0)

        # 计算所有类到各自中心的平均距离之和
        for i in range(self.centerNum):
            # 找出同一类样本
            index = np.argwhere(self.label == i).squeeze()
            sameClassSample = self.data[index, :]
            if len(sameClassSample.shape) < 2:
                sameClassSample = sameClassSample.reshape((1,-1))
            # 计算样本到中心距离的平均值
            distance = np.mean(euclidean_distances(sameClassSample, self.center[i, :].reshape((1, -1))))
            # 更新中心
            self.centerMeanDist += distance
        self.centerMeanDist /= self.centerNum

    def divide(self):
        # 临时保存更新后的中心集合,否则在删除和添加的过程中顺序会乱
        newCenterSet = self.center
        # 计算每个类的样本在每个维度的标准差
        for i in range(self.centerNum):
            # 找出同一类样本
            index = np.argwhere(self.label == i).squeeze()
            sameClassSample = self.data[index, :]
            # 计算样本到中心每个维度的标准差
            stdEachDim = np.mean((sameClassSample - self.center[i, :])**2, axis=0)
            if type(stdEachDim) is not np.ndarray:
                maxStd = stdEachDim
                sameClassSample = sameClassSample.reshape(1,-1)
            # 找出其中维度的最大标准差
            else:
                maxIndex = np.argmax(stdEachDim)
                maxStd = stdEachDim[maxIndex]
            # 计算样本到本类中心的距离
            distance = np.mean(euclidean_distances(sameClassSample, self.center[i, :].reshape((1, -1))))
            # 如果最大标准差超过了阈值
            if maxStd > self.thetaS:
                # 还需要该类的样本数大于于阈值很多 且 太分散才进行分裂
                if self.centerNum <= self.K//2 or \
                        sameClassSample.shape[0] > 2 * (self.thetaN+1) and distance >= self.centerMeanDist:
                    newCenterFirst = self.center[i, :].copy()
                    newCenterSecond = self.center[i, :].copy()

                    newCenterFirst[maxIndex] += 0.5 * maxStd
                    newCenterSecond[maxIndex] -= 0.5 * maxStd

                    # 删除原始中心
                    newCenterSet = np.delete(newCenterSet, i, axis=0)
                    # 添加新中心
                    newCenterSet = np.vstack((newCenterSet, newCenterFirst))
                    newCenterSet = np.vstack((newCenterSet, newCenterSecond))

            else:
                continue
        # 更新中心集合
        self.center = newCenterSet
        self.centerNum = self.center.shape[0]

    def combine(self):
        # 临时保存更新后的中心集合,否则在删除和添加的过程中顺序会乱
        delIndexList = []

        # 计算中心之间的距离
        centerDist = euclidean_distances(self.center, self.center)
        centerDist += (np.eye(self.centerNum)) * 10**10
        # 把中心距离小于阈值的中心对找出来,每次和并数量少于L对
        for i in range(self.L):
            # 如果最小的中心距离都大于阈值的话,则不再进行合并
            minDist = np.min(centerDist)
            if minDist >= self.thetaC:
                break
            # 否则合并(两个中心距离太近合并)
            index = np.argmin(centerDist)
            row = index // self.centerNum
            col = index % self.centerNum
            # 找出合并的两个类别
            index = np.argwhere(self.label == row)
            classNumFirst = len(index)
            index = np.argwhere(self.label == col)
            classNumSecond = len(index)
            newCenter = self.center[row, :] * (classNumFirst / (classNumFirst+ classNumSecond)) + \
                        self.center[col, :] * (classNumSecond / (classNumFirst+ classNumSecond))
            # 记录被合并的中心
            delIndexList.append(row)
            delIndexList.append(col)
            # 增加合并后的中心
            self.center = np.vstack((self.center, newCenter))
            self.centerNum -= 1
            # 标记,以防下次选中
            centerDist[row, :] = float("inf")
            centerDist[col, :] = float("inf")
            centerDist[:, col] = float("inf")
            centerDist[:, row] = float("inf")

        # 更新中心
        self.center = np.delete(self.center, delIndexList, axis=0)
        self.centerNum = self.center.shape[0]

    def drawResult(self):
        color = ['r', 'b', 'g', 'c', 'm', 'y']
        ax = plt.gca()
        ax.clear()
        for i in range(self.centerNum):
               index = np.argwhere(self.label == i).squeeze()
               ax.scatter(self.data[index, 0], self.data[index, 1], c=color[i], label=f'Cluster { i}')
               ax.scatter(self.center[i,0], self.center[i,1], c=color[i], marker='x',
                    label=f'Centroid { i}')
        # ax.set_aspect(1)
        # 坐标信息
        plt.title('ISODATA Clustering')
        plt.xlabel('X')
        plt.ylabel('Y')
        plt.legend()
        plt.show()

    def start(self):
        # 初始化中心和label
        self.updateLabel()
        self.drawResult()

        # 到设定的次数自动退出
        for i in range(self.iteration):
            # 如果是偶数次迭代或者中心的数量太多,那么进行合并
            if self.centerNum < self.K //2:
                self.divide()
            # 偶数次迭代或者中心数大于预期的一半,进行合并
            elif (i > 0 and i % 2 == 0) or self.centerNum > 2 * self.K:
                self.combine()
            else:
                self.divide()
            # 更新中心
            self.updateLabel()
            print("中心数量:{}".format(self.centerNum))
            self.drawResult()

主函数

if __name__ == "__main__":
    isoData = ISODATA(designCenterNum=2, Nc=3, LeastSampleNum=1, StdThred=0.1, LeastCenterDist=2, L=3, iterationNum=5)
    isoData.start()

2.3 算法注意事项

        ISODATA算法相比于传统的K-means算法增加了簇合并和簇分裂的步骤,这使得算法能够动态地调整簇的数量和形状,适应数据的复杂性。在实际应用中,还可以根据具体情况对参数进行调整,以获得更好的聚类效果。


三、 ISODATA算法实验结果

相关参数设置:

参数类型

数值

预期的聚类数

2

初始聚类中心个数

3

每类的最小样本数

3

标准差阈值

0.1

最小中心距离

2

每次可合并的最多对数

3

迭代次数

5

(1)数据可视化聚类单步输出结果:

第一步                                                 第二步

第三步                                                 第四步

第五步 

        由多次实验结果可知,一般运行到五步以内即可达到聚类目的,合理设置相关参数可以达到满足聚类的要求。

(1)调整预期聚类数:

预期的聚类数=3时,

第一步运行结果                                 最终运行结果

预期的聚类数=5时,

第一步运行结果                                    最终运行结果

        由此实验可知,设置预期的聚类数为3或者5,聚类的最终结果分类为2类。后续经过多次其他预期的聚类数设置,得到结果聚类分类为2类,初步推算,预期聚类数的设置不影响最终聚类的结果。若修改其他参数,也可分析相应的实验输出结果。


四、小结

        ISODATA算法是基于C-均值算法的改进,增加了簇的合并和分裂机制,使其能够动态地调整簇的数量和形状,适应数据的复杂性。这使得ISODATA算法更适用于数据集具有复杂形状、密度不均匀、簇的数量变化较大的情况。然而,对于该算法来说,需要合理设置参数,并且算法复杂度较高,需要更多的计算资源和时间。

        通过合理选择算法、优化参数和评估结果,可以实现对提供的数据成功的进行聚类。在实际应用中,通常会根据具体情况综合考虑算法的优缺点,选择合适的算法,并不断优化参数,以获得满足实际需求的聚类效果。


     文章若有不当和不正确之处,还望理解与指出。由于部分文字、图片等来源于互联网,无法核实真实出处,如涉及相关争议,请联系博主删除。如有错误、疑问和侵权,欢迎评论留言联系作者,或者私信联系作者。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1851464.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【金】02Y90-60 大数据-HivetoMysQL

1、安装 Java 程序&#xff08;jdk&#xff09; 2、添加以下JAR包 3、确认配置成自己的数据库 ....

程序员为什么不能一次性写好,需要一直改Bug?

程序员在编写代码时不能一次性写好&#xff0c;而是需要不断修改Bug&#xff0c;这主要是由几个因素导致的&#xff1a; 复杂性&#xff1a;软件开发是一个高度复杂的过程&#xff0c;涉及到多个模块、功能、逻辑和数据的交互。即使是最有经验的程序员&#xff0c;也很难一次性…

[最新教程]Claude Sonnet 3.5注册方法详细步骤分享,新手小白收藏,文末免费送已注册的Claude账号

一.Claude sonnet 3.5大模型面世 6月21日&#xff0c;被称为“OpenAI 最强竞对”的大模型公司 Anthropic 发布了 Claude 3.5 系列模型中的第一个版本——Claude 3.5 Sonnet。 Anthropic 在官方博客中表示&#xff0c;Claude 3.5 Sonnet 提高了智能化的行业标准&#xff0c;在…

24年安克创新社招入职自适应能力cata测评真题分享北森测评高频题库

第一部分&#xff1a;安克创新自适应能力cata测评 感谢您关注安克创新社会招聘&#xff0c;期待与您一起弘扬中国智造之美。 为对您做出全面的评估&#xff0c;现诚邀您参加我们的在线测评。 测评名称&#xff1a;社招-安克创新自适应能力cata测评 第二部分&#xff1a;安克…

程序猿大战Python——面向对象——继承基础

定义类的几种语法 目标&#xff1a;了解定义类的标准语法。 我们知道&#xff0c;可以使用class关键字定义类。 在类的使用中&#xff0c;定义方式有三种&#xff1a; &#xff08;1&#xff09;【类名】 &#xff08;2&#xff09;【类名()】 &#xff08;3&#xff09;【…

【C++实验】多项式加减

题目&#xff1a;一元多项式运算 基本要求&#xff1a; &#xff08;1&#xff09; 输入并建立多项式; &#xff08;2&#xff09; 输出多项式; &#xff08;3&#xff09; 多项式加法 &#xff08;4&#xff09; 多项式减法。 测试数据&#xff1a; 代码展示&#xff1a; #i…

MarkDown基础

一、MarkDown标题 1.使用和-表示一级标题 2.使用#、##、###、####、######、######表示一级至六级标题 一级标题 二级标题 一级标题 二级标题 三级标题 四级标题 五级标题 六级标题 二、MarkDown标题 1.Markdown 段落没有特殊的格式&#xff0c;直接编写文字就好&#xff0c;…

全网最全!25届最近5年上海理工大学自动化考研院校分析

上海理工大学 目录 一、学校学院专业简介 二、考试科目指定教材 三、近5年考研分数情况 四、近5年招生录取情况 五、最新一年分数段图表 六、历年真题PDF 七、初试大纲复试大纲 八、学费&奖学金&就业方向 一、学校学院专业简介 二、考试科目指定教材 1、考试…

【Linux系统】多线程

本篇博客继上一篇《线程与线程控制》&#xff0c;又整理了多线程相关的线程安全问题、互斥与锁、同步与条件变量、生产消费模型、线程池等内容&#xff0c;旨在让读者更加深刻地理解线程和初步掌握多线程编程。&#xff08;欲知线程的相关概念、线程控制的相关接口等&#xff0…

Ansible 自动化运维实践

随着 IT 基础设施的复杂性不断增加&#xff0c;手动运维已无法满足现代企业对高效、可靠的 IT 运维需求。Ansible 作为一款开源的自动化运维工具&#xff0c;通过简洁易用的 YAML 语法和无代理&#xff08;agentless&#xff09;架构&#xff0c;极大简化了系统配置管理、应用部…

Depth Anything V2:抖音开源高性能任何单目图像深度估计V2版本,并开放具有精确注释和多样化场景的多功能评估基准

&#x1f4dc;文献卡 题目&#xff1a; Depth Anything V2作者: Lihe Yang; Bingyi Kang; Zilong Huang; Zhen Zhao; Xiaogang Xu; Jiashi Feng; Hengshuang ZhaoDOI: 10.48550/arXiv.2406.09414摘要: This work presents Depth Anything V2. Without pursuing fancy technique…

前端 JS 经典:通用性函数封装思路

前言&#xff1a;设计通用性函数&#xff0c;我们需要考虑两个方面&#xff0c;一个是函数传参的可能性&#xff0c;如果可能性很多&#xff0c;我们可以将处理参数的方法暴露出去&#xff0c;让使用者去设计。为了调用的方便性&#xff0c;我们还可以做参数的归一化。 举个例…

计算机组成原理笔记-第3章 系统总线

第三章 系统总线 笔记PDF版本已上传至Github个人仓库&#xff1a;CourseNotes&#xff0c;欢迎fork和star&#xff0c;拥抱开源&#xff0c;一起完善。 该笔记是最初是没打算发网上的&#xff0c;所以很多地方都为了自我阅读方便&#xff0c;我理解了的地方就少有解释&#xf…

RockChip Android12 System之MultipleUsers

一:概述 System中的MultipleUsers不同于其他Preference采用system_dashboard_fragment.xml文件进行加载,而是采用自身独立的xml文件user_settings.xml加载。 二:Multiple Users 1、Activity packages/apps/Settings/AndroidManifest.xml <activityandroid:name="S…

Android集成高德天气API 天气预报

1.新建工程项目WeatherForecast。 2.在AndroidManifest文件中添加网络访问相关权限。 <uses-permission android:name"android.permission.INTERNET"/> 3.设计页面布局activity_main.xml&#xff0c;界面效果如图所示。 4.注册高德开放平台&#xff0c;查阅…

代码签名证书有什么作用?有哪些申请步骤?

代码签名证书是一种数字证书&#xff0c;它为软件开发者提供一种验证软件代码真实性和完整性的方法。通过使用代码签名证书&#xff0c;开发者可以确保他们的软件在发布后没有被篡改&#xff0c;并且用户可以信任软件的来源。 什么是代码签名证书&#xff1f; 代码签名证书是提…

小程序 UI 设计缔造独特魅力

小程序 UI 设计缔造独特魅力

【面试干货】抽象类的意义与应用

【面试干货】抽象类的意义与应用 1、为其他子类提供一个公共的类型2、封装子类中重复定义的内容3、定义抽象方法&#xff0c;子类虽然有不同的实现&#xff0c;但是定义时一致的4、示例代码 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在…

jrebel安装使用教程(2022.4.1版本)

本方法适用于jrebel2022.4.1版本&#xff0c;之后的版本不再适用。 1.下载插件 下载地址 2.安装插件 可以通过idea内部安装 也可以将插件解压进idea的安装目录下的plugins。 3.激活 Team URL中填入 https://jrebel.qekang.com/{guid}这里提供两个guid生成地址&#xf…

【AI工作流-AI-Agent】FastGPT新建应用并用openai接口调用

FastGPT 简介 FastGPT是一个AI工作流搭建平台&#xff0c;它是一个开源框架&#xff0c;支持聊天&#xff0c;RAG&#xff08;知识库&#xff09;&#xff0c;工作流编排。 缺点是不支持AI搜索&#xff0c;模型支持需要依赖于第三方部署框架例如oneapi&#xff0c;ollama等。…