Day_56-57kMeans 聚类

news2024/11/8 9:26:18

目录

Day_56-57 k-Means 聚类

一. 基本概念介绍

二. 具体过程

三. 代码实现与解释

        1. 导入数据与数据初始化

        2. 核心代码

        3. 后续信息的补充

        4. 距离计算和随机排列

四. 后续的数据分析

五. 运行结果


Day_56-57 k-Means 聚类

一. 基本概念介绍

        同我上一篇博客的介绍,机器学习从有无标签的角度有几大分类:监督学习,无监督学习和半监督学习。这里我们介绍的k-Means 算法就是无监督学习里面最具有代表性的一种,与分类(典型knn算法)等任务不同,聚类是在事先并不知道任何样本标签的情况下,通过数据之间的内在关系把样本划分为若干类别,使得同类别样本之间的相似度高,不同类别之间的样本相似度低(即增大类内聚,减少类间距)。

        它的基本过程是随机找寻k个节点作为始节点,然后从数据里面计算每个点到始节点的距离,理哪一个始节点比较近则第一次分类将这个节点分为一类。当所有的节点计算完毕(分类完成)之后,重新计算每个类的簇中心,然后继续上述的过程,直到分类的最终结果和每一个簇中心不再发生改变或者迭代次数用尽为止,最终我们将数据分成了k类。

二. 具体过程

        KMeans的核心目标是将给定的数据集划分成K个簇(K是超参),并给出每个样本数据对应的中心点。具体步骤非常简单,可以分为4步:

        1. 数据预处理,主要是标准化

        2. 随机选取k个中心,记为u_{1}^{(0)}u_{2}^{(0)}......u_{k}^{(0)}

        3. 定义优化目标J(c,u)=min\sum_{i=1}^{n}\left \| x_{i}-u_{j}^{(0)}\right \|

        4. 令t=1,2...为迭代步数,重复如下过程直到J收敛:

                4.1 对于每一个样本x_{i},将其分配到距离最近的中心

                4.2 对于每一个中心k,重新计算该类的中心

初始图
聚类1

聚类2
聚类3

完成图

三. 代码实现与解释

        1. 导入数据与数据初始化

        基本的变量设置MANHATTAN = 0表示曼哈顿计算距离方式,EUCLIDEAN = 1表示欧拉计算距离方式,dataset用来存储导入的数据,numClusters即k的数值(分成多少类),KMeans()函数表示导入的数据(路径为"D:/data/iris.arff"),setNumClusters(3)函数表示设置聚类的类的多少(分成多少类)

    /**
     * Manhattan distance.
     */
    public static final int MANHATTAN = 0;

    /**
     * Euclidean distance.
     */
    public static final int EUCLIDEAN = 1;

    /**
     * The distance measure.
     */
    public int distanceMeasure = EUCLIDEAN;

    /**
     * A random instance;
     */
    public static final Random random = new Random();

    /**
     * The data.
     */
    Instances dataset;

    /**
     * The number of clusters.
     */
    int numClusters = 2;

    /**
     * The clusters.
     */
    int[][] clusters;

    /**
     *******************************
     * The first constructor.
     *
     * @param paraFilename
     *            The data filename.
     *******************************
     */
    public KMeans(String paraFilename) {
        dataset = null;
        try {
            FileReader fileReader = new FileReader(paraFilename);
            dataset = new Instances(fileReader);
            fileReader.close();
        } catch (Exception ee) {
            System.out.println("Cannot read the file: " + paraFilename + "\r\n" + ee);
            System.exit(0);
        } // Of try
    }// Of the first constructor

    /**
     *******************************
     * A setter.
     *******************************
     */
    public void setNumClusters(int paraNumClusters) {

        numClusters = paraNumClusters;
    }// Of the setter

        2. 核心代码

        tempOldClusterArray用于存储每个节点被分为哪一类(1,2,3),tempClusterArray和tempOldClusterArray作用一致,但是是每一轮新的分类,tempOldClusterArray是上一轮的分类结果,tempCenters表示3个中心的位置(第一轮是随机设置中心位置,k=3,属性=4,3×4的一个矩阵),tempClusterLengths用于记录归入每个类的节点个数。

        while循环当新的分类和旧的分类一致时,结束循环。接着第二轮第三轮循环,计算一个节点i到各个中心的距离,记录最小值对应类别,保存到tempClusterArray矩阵里面。

        又有一个循环,用于累加同一个类的位置信息到tempNewCenters并且用于记录每个类的节点个数到tempClusterLengths。

        继续第三个循环,计算每个中心现在的位置到tempNewCenters,将新中心保存到tempCenters矩阵。

    public void clustering() {
        int[] tempOldClusterArray = new int[dataset.numInstances()];
        tempOldClusterArray[0] = -1;
        int[] tempClusterArray = new int[dataset.numInstances()];
        Arrays.fill(tempClusterArray, 0);
        double[][] tempCenters = new double[numClusters][dataset.numAttributes() - 1];

        // Step 1. Initialize centers.
        int[] tempRandomOrders = getRandomIndices(dataset.numInstances());
        for (int i = 0; i < numClusters; i++) {
            for (int j = 0; j < tempCenters[0].length; j++) {
                tempCenters[i][j] = dataset.instance(tempRandomOrders[i]).value(j);
            } // Of for j
        } // Of for i

        int[] tempClusterLengths = null;
        while (!Arrays.equals(tempOldClusterArray, tempClusterArray)) {
            System.out.println("New loop ...");
            tempOldClusterArray = tempClusterArray;
            tempClusterArray = new int[dataset.numInstances()];

            // Step 2.1 Minimization. Assign cluster to each instance.
            int tempNearestCenter;
            double tempNearestDistance;
            double tempDistance;

            for (int i = 0; i < dataset.numInstances(); i++) {
                tempNearestCenter = -1;
                tempNearestDistance = Double.MAX_VALUE;

                for (int j = 0; j < numClusters; j++) {
                    tempDistance = distance(i, tempCenters[j]);
                    if (tempNearestDistance > tempDistance) {
                        tempNearestDistance = tempDistance;
                        tempNearestCenter = j;
                    } // Of if
                } // Of for j
                tempClusterArray[i] = tempNearestCenter;
            } // Of for i

            // Step 2.2 Mean. Find new centers.
            tempClusterLengths = new int[numClusters];
            Arrays.fill(tempClusterLengths, 0);
            double[][] tempNewCenters = new double[numClusters][dataset.numAttributes() - 1];
            // Arrays.fill(tempNewCenters, 0);
            for (int i = 0; i < dataset.numInstances(); i++) {
                for (int j = 0; j < tempNewCenters[0].length; j++) {
                    tempNewCenters[tempClusterArray[i]][j] += dataset.instance(i).value(j);
                } // Of for j
                tempClusterLengths[tempClusterArray[i]]++;
            } // Of for i

            // Step 2.3 Now average
            for (int i = 0; i < tempNewCenters.length; i++) {
                for (int j = 0; j < tempNewCenters[0].length; j++) {
                    tempNewCenters[i][j] /= tempClusterLengths[i];
                } // Of for j
            } // Of for i

            System.out.println("Now the new centers are: " + Arrays.deepToString(tempNewCenters));
            tempCenters = tempNewCenters;
        } // Of while

        // Step 3. Form clusters.
        clusters = new int[numClusters][];
        int[] tempCounters = new int[numClusters];
        for (int i = 0; i < numClusters; i++) {
            clusters[i] = new int[tempClusterLengths[i]];
        } // Of for i

        for (int i = 0; i < tempClusterArray.length; i++) {
            clusters[tempClusterArray[i]][tempCounters[tempClusterArray[i]]] = i;
            tempCounters[tempClusterArray[i]]++;
        } // Of for i

        System.out.println("The clusters are: " + Arrays.deepToString(clusters));
    }// Of clustering

        3. 后续信息的补充

        clusters为k(聚类的种类数)行矩阵,列还没有确定。接着一个循环创建每一行的长度为一个类的样本数,后面一个循环用于分类每个是哪个类。

        // Step 3. Form clusters.
        clusters = new int[numClusters][];
        int[] tempCounters = new int[numClusters];
        for (int i = 0; i < numClusters; i++) {
            clusters[i] = new int[tempClusterLengths[i]];
        } // Of for i

        for (int i = 0; i < tempClusterArray.length; i++) {
            clusters[tempClusterArray[i]][tempCounters[tempClusterArray[i]]] = i;
            tempCounters[tempClusterArray[i]]++;
        } // Of for i

        System.out.println("The clusters are: " + Arrays.deepToString(clusters));

        4. 距离计算和随机排列

        这里不再详细说明,欢迎查看第51天博客

   /**
     *********************
     * Get a random indices for data randomization.
     *
     * @param paraLength
     *            The length of the sequence.
     * @return An array of indices, e.g., {4, 3, 1, 5, 0, 2} with length 6.
     *********************
     */
    public static int[] getRandomIndices(int paraLength) {
        int[] resultIndices = new int[paraLength];

        // Step 1. Initialize.
        for (int i = 0; i < paraLength; i++) {
            resultIndices[i] = i;
        } // Of for i

        // Step 2. Randomly swap.
        int tempFirst, tempSecond, tempValue;
        for (int i = 0; i < paraLength; i++) {
            // Generate two random indices.
            tempFirst = random.nextInt(paraLength);
            tempSecond = random.nextInt(paraLength);

            // Swap.
            tempValue = resultIndices[tempFirst];
            resultIndices[tempFirst] = resultIndices[tempSecond];
            resultIndices[tempSecond] = tempValue;
        } // Of for i

        return resultIndices;
    }// Of getRandomIndices

    /**
     *********************
     * The distance between two instances.
     *
     * @param paraI
     *            The index of the first instance.
     * @param paraArray
     *            The array representing a point in the space.
     * @return The distance.
     *********************
     */
    public double distance(int paraI, double[] paraArray) {
        int resultDistance = 0;
        double tempDifference;
        switch (distanceMeasure) {
            case MANHATTAN:
                for (int i = 0; i < dataset.numAttributes() - 1; i++) {
                    tempDifference = dataset.instance(paraI).value(i) - paraArray[i];
                    if (tempDifference < 0) {
                        resultDistance -= tempDifference;
                    } else {
                        resultDistance += tempDifference;
                    } // Of if
                } // Of for i
                break;

            case EUCLIDEAN:
                for (int i = 0; i < dataset.numAttributes() - 1; i++) {
                    tempDifference = dataset.instance(paraI).value(i) - paraArray[i];
                    resultDistance += tempDifference * tempDifference;
                } // Of for i
                break;
            default:
                System.out.println("Unsupported distance measure: " + distanceMeasure);
        }// Of switch

        return resultDistance;
    }// Of distance

四. 后续的数据分析

        1. 时间复杂度分析

        首先对于n个样本,聚类为k个类,现在的时间复杂度为O(kn),再加上迭代次数t,故而最终的时间复杂度为O(knt)(k是聚为多少类,n是数据总量个数,t是迭代次数)

        2. 对于特殊数据的处理

        由于k-means算法是基于"距离"进行计算的,而“距离”却是基于向量的。对于有些数据的某一个向量,若方差较大的话将对数据的聚类结果产生决定性影响,所以对于聚类前的数据进行归一化和单位化相当有必要。此外对于极个别噪声数据应该检测出来,排除它对中心的影响。

        3. 对于k值的选择

        由于聚类的效果收到初始k值的影响,我们可以用试触法确定最佳的k值,即取k为不同的值,每次计算我们的优化目标J(c,u)=min\sum_{i=1}^{n}\left \| x_{i}-u_{j}^{(0)}\right \|的值,最后取一个最合适的值作为k值。

        4. 改进初始值的选择

        之前我们采取随机选择K个中心的做法,可能导致不同的中心点距离很近,就需要更多的迭代次数才能收敛。如果在选择初始中心点时能让不同的中心尽可能远离,效果往往更好。这类算法中,以K-Means++算法最具影响力。

五. 运行结果

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

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

相关文章

微博视频发布软件有哪些

微博视频发布软件有哪些&#xff0c;新的新浪微博怎么发微博#科技#手机操作#微信 软件有月卡、季卡、半年卡、年卡 【引流脚本软件发帖顶帖有货】 服务时间&#xff1a;&#xff08;8&#xff1a;00—23&#xff1a;00&#xff09; 需要观看软件操作视频教程的可关注↑↑↑上…

大数据开发技术与实践期末复习(HITWH)

目录 分布式文件处理系统HDFS 分布式文件系统 HDFS简介 块&#xff08;block&#xff09; 主要组件的功能 **名称节点 FsImage文件 名称节点的启动 名称节点运行期间EditLog不断变大的问题 SecondaryNameNode的工作情况 数据节点 HDFS体系结构 HDFS体系结构的局限…

游戏行业黑马昆仑万维,国产AI巨头崛起

游戏行业黑马昆仑万维&#xff0c;国产AI巨头崛起&#xff0c;其大模型技术堪比ChatGPT 随着人工智能技术的快速发展&#xff0c;越来越多的公司参与大规模语言模型的开发和应用。近日&#xff0c;昆仑万维正式发布大型语言模型“天宫”&#xff0c;宣布即日起开始邀请测试&am…

操作系统——基于信号量机制的并发程序设计

一、实验题目 基于信号量机制的并发程序设计 二、实验目的 (1) 回顾操作系统进程、线程的有关概念&#xff0c;针对经典的同步、互斥、死锁与饥饿问题进行并发 程序设计。 (2) 了解互斥体对象&#xff0c;利用互斥与同步操作编写读者-写者问题的并发程序&#xff0c;加深…

测试老鸟,带你手写Python自动化测试 ddt 数据驱动框架(超细细)

前言 python做自动化测试&#xff0c;大多数都应该使用过ddt这个模块&#xff0c;它可以自动根据用例数据&#xff0c;来生成测试用例&#xff0c;能够很方便的将测试数据和测试用例执行的逻辑进行分离。接下来和大家&#xff0c;手把手撸出一个ddt。 DDT的实现原理 首先我们…

MUR80120PT-ASEMI快恢复二极管MUR80120PT

编辑-Z MUR80120PT在TO-247封装里采用的2个芯片&#xff0c;其尺寸都是140MIL&#xff0c;是一款高耐压大电流快恢复二极管。MUR80120PT的浪涌电流Ifsm为600A&#xff0c;漏电流(Ir)为10uA&#xff0c;其工作时耐温度范围为-55~150摄氏度。MUR80120PT采用抗冲击硅芯片材质&…

DJ5-4 MAC、ARP

目录 一、链路层寻址地址 1、MAC 地址分配 2、MAC 地址识别 二、ARP 地址解析协议 1、ARP 地址解析协议 2、ARP&#xff1a;两个主机位于同一个局域网 3、ARP&#xff1a;发送数据报到子网以外 4、ARP 自举 5、ARP 攻击 一、链路层寻址地址 每个节点有网络层地址和链…

模拟电路系列分享-静态工作点

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 提示&#xff1a;这里可以添加技术概要 例如&#xff1a; 本文主要介绍静态工作点及耦合 整体架构流程 提示&#xff1a;这里可以添加技术整体架构 要想让晶体管对输入电压信号进行有效的放大&#xff0c;必须解…

win10安装配置PostgreSQL

win10安装配置PostgreSQL 1 下载安装PostgreSQL ①进入官网https://www.postgresql.org/&#xff0c;点击页面中心处的download 也可以直接跳过下面的步骤(下面的步骤主要是为了帮助大家了解一般外国软件是如何从官网进入下载页面)&#xff0c;直接进入下载页面&#xff0c;链…

网络安全是个好的专业吗?高考志愿可以选择该专业吗?

首先说说关于学校和就业的问题&#xff0c;提到国内网络安全专业比较好的学校&#xff0c;“四邮四电”&#xff08;北邮、南邮、西邮、重邮、电子科大、西安电子科大、桂林电子科大、杭州电子科大&#xff09;必须拥有姓名。 而从现在的就业形势看&#xff0c;网络安全专业其…

SuperMap GIS基础产品三维GIS FAQ集锦(3)

SuperMap GIS基础产品三维GIS FAQ集锦&#xff08;3&#xff09; 【WebGL】如何批量管理entity图标&#xff0c;同时控制多个图标的显示和隐藏&#xff1f; 【解决办法】使用实体集合CustomDataSource进行管理&#xff0c;将实体按类别分类&#xff0c;分别添加到不同的实体集…

数字 IC 设计职位经典笔/面试题(一)

共100道经典笔试、面试题目&#xff08;文末可全领&#xff09; 什么是同步逻辑和异步逻辑&#xff1f; 同步逻辑是时钟之间有固定的因果关系。异步逻辑是各时钟之间没有固定的因果关系。同步时序逻辑电路的特点&#xff1a;各触发器的时钟端全部连接在一起&#xff0c;并接在…

NAPT之NAT地址池、NAPT之easy-ip、NAT-Server

NAPT之NAT地址池 拓扑 需求 实现企业内网主机&#xff08;PC1-PC4&#xff09;访问公网网站服务器&#xff08;Server1&#xff09; 配置步骤 第一步&#xff1a;给PC1-PC4/Server1配置接口IP地址&#xff0c;掩码&#xff0c;网关 第二步&#xff1a;R1配置默认路由 -边界…

【MySql】用户管理——用户管理|权限管理

文章目录 用户管理用户信息创建用户删除用户修改用户密码 数据库的权限给用户授权回收权限 用户管理 如果我们只能使用root用户&#xff0c;这样存在安全隐患。这时&#xff0c;就需要使用MySQL的用户管理。 比如张三只能操作mytest这个数据库&#xff0c;李四只能操作msg这个…

员工身份管理(EIAM)如何帮助企业降本增效?

随着市场竞争的加剧和经济环境的变化&#xff0c;降本增效成为了现代企业的共同目标。要实现这一目标&#xff0c;企业需要彻底改变传统的生产管理方式&#xff0c;借助数字化技术来实现数据在线、人员在线和行为在线。 数据在线意味着企业的数据可以在多个平台上进行共享、协…

FreeRTOS实时操作系统(七)时间片调度及RTOS的滴答定时器

系列文章目录 FreeRTOS实时操作系统&#xff08;一&#xff09;RTOS的基本概念 FreeRTOS实时操作系统&#xff08;二&#xff09;任务创建与任务删除&#xff08;HAL库&#xff09; FreeRTOS实时操作系统&#xff08;三&#xff09;任务挂起与恢复 FreeRTOS实时操作系统&am…

【Linux】硬件性能测试工具

1、CPU 1.1 stress 1)安装 sudo apt install stress 2)用法 stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 60s3)结果 使用htop查看: 1.2 nbench 1)安装 需要源码编译,源码下载地址 官方(下载很慢):https://www.math.utah.edu/~mayer/linux/bmark.ht…

数据产品-完善DMP系统应该是什么样子的

一、价值定位 首先需要明确DMP系统的价值定位和核心功能&#xff0c;以此才能评估需要涵括哪些内容 ✧用户刻画更清晰&#xff1a;能够通过数据标签化的形式&#xff0c;全面、精准刻画用户全貌 ✧用户触达更精准&#xff1a;能够沉淀不同的策略规则&#xff0c;精准触达不同…

转行做TA(技术美术),需要掌握哪些基础知识?

TA的岗位职责 负责美术与程序之间的沟通&#xff0c;配合实现美术效果&#xff0c;提高画面整体表现力制定美术资源规范&#xff0c;提高导出资源的可用性和规范性快速跟进研发最新的游戏引擎与渲染技术&#xff1b;在性能优化的同时&#xff0c;提高游戏画面表现&#xff1b;…

2023年6月墨天轮中国图数据库排行榜:TGS 开新局,创邻和字节多点突破露锋芒

鸿鹄不坠青云志&#xff0c;鲲鹏展翅九万里。 2023年 墨天轮中国图数据库流行度排行 已经火热出炉&#xff0c;本月中国图数据库排行榜共有31个数据库参与排名&#xff0c;相比今年1月新增3个数据库。本月图数据库榜单前十变动较大&#xff1a;TuGraph 立足创新跃榜首&#xff…