数据挖掘Java——Kmeans算法的实现

news2024/11/24 17:49:16

一、K-means算法的前置知识

k-means算法,也被称为k-平均或k-均值,是一种得到最广泛使用的聚类算法。相似度的计算根据一个簇中对象的平均值来进行。算法首先随机地选择k个对象,每个对象初始地代表了一个簇的平均值或中心。对剩余的每个对象根据其与各个簇中心的距离,将它赋给最近的簇。然后重新计算每个簇的平均值。这个过程不断重复,直到准则函数收敛。

聚类就是将数据对象分组成多个类或簇,划分的原则是在同一个簇中的对象之间具有较高的相似度,而不同簇中的对象差别较大。与分类不同的是,聚类操作中要划分的类是事先未知的,类的形式完全是数据驱动的,属于一种无指导的学习方法。

聚类分析源于许多研究领域,包括数据挖掘、统计学、机器学习、模式识别等。它是数据挖掘中的一个功能,但也能作为一个独立的工具来获得数据分布的情况,概括出每个簇的特点,或者集中注意力对特定的某些簇作进一步分析。此外,聚类分析也可以作为其他分析算法(如关联规则、分类等)的预处理步骤,这些算法在生成的簇上进行处理。

聚类:聚类是一个将数据集中在某些方面相似的数据成员进行分类组织的过程,聚类就是一种发现这种内在结构的技术,聚类技术经常被称为无监督学习。
K-means聚类:K-means聚类是最著名的划分聚类算法,由于简洁和效率使得他成为所有聚类算法中最广泛使用的。给定一个数据点集合和需要的聚类数目k,k由用户指定,k均值算法根据某个距离函数反复把数据分入k个聚类中。

二、K-means算法的基本思想

K-means聚类算法是先随机选取K个对象作为初始的聚类中心。然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。一旦全部对象都被分配了,每个聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是没有(或最小数目)对象被重新分配给不同的聚类,没有(或最小数目)聚类中心再发生变化,误差平方和局部最小。

三、K-means算法的例子

K-means算法例子
在这里插入图片描述
在这里插入图片描述

四、K-means算法的实现过程

实验内容
请对下表中的数据进行k-mean聚类,距离为欧氏距离,k=3
在这里插入图片描述
实验思路
(1)定义Point类,Point类中含横坐标x,纵坐标y等属性,包含静态方法getIsSame():判断两个Point类对象是否相同、calculateDistance()方法:计算两个Point类对象之间的距离(欧氏距离)、calculateMHDDistance()方法:计算两个Point类对象之间的距离(曼哈顿距离)。定义Cluster类,在Cluster类中包含属性核心点corePoint,簇内的所有点的集合sameList。
(2)定义初始数据集dataList,定义簇的数目k,调用initDataList()方法进行初始化数据集,调用getInitCluster()方法进行初始化簇。getInitCluster()方法主要作用是获取任意k个对象作为初始簇中心,将含有k个簇的集合返回。在getInitCluster()方法体内部,定义clusterList集合用于存放k个簇,调用getRandomArray()方法获取含有k个不重复随机数的数组randomArray,数据集中k个对象的下标存放在randomArray数组中,遍历数组randomArray,取出k个任意下标的Point类对象作为相应簇cluster的核心对象点,并将每一次循环定义和实例化后的cluster添加到clusterList中,最终将clusterList集合返回。
(3)进入while循环,遍历数据集dataList中的每一项point,调用getBelongCluster()方法获取point属于的那个簇在clusterList中的下标index,取出clusterList中指定下标index的簇,将点point加入到该簇的sameList中。然后遍历数据集结束后,调用calculateClusterCore()方法计算出新的簇中心并判断出簇集合中每个簇的点集合是否有发生变化,若未发生变化,则跳出while循环,表明K-means聚类结束,反之则进入下次while循环,在遍历数据集之前,要将clusterList集合中的每一项cluster的sameList集合清空。
(4)遍历clusetrList集合,将集合中的每一项cluster输出即可。
(5)getBelongCluster()方法主要作用是获取某个点属于哪个簇的下标。在方法体内部,定义了变量closestDistance和变量resultClusterIndex分别用于存放point距离簇中心最近的距离,以及point属于的哪个簇的下标。遍历簇集合clusterList,调用Point类内静态方法calculateDistance()计算点point距离簇cluster核心点的距离赋值给distance,将第一次遍历得到的distance值赋值给cloestDistance,后面的遍历如果distance小于closestDistance,就将distance赋值给closestDistance,同时将index赋值给resultClusterIndex,循环遍历结束,最终将resultClusterIndex返回。
(6)calculateClusterCore()方法主要作用是计算出新的簇中心并返回簇的点集合是否有变化。在方法体内部定义标志变量flag,然后遍历clusterList集合中的每一项cluster,定义变量sumX和变量sumY分别用于存放簇中点集合所有的x坐标之和,以及簇中点集合所有的y坐标之和,对sumX和sumY求均值后赋值给新的簇中心点clusterCore,调用Point类内静态方法getIsSame()判断clusterCore和原簇中心是否相同,若不相同则将flag赋值为true。当遍历簇集合循环结束后,将flag值返回。要注意的是这里形参类型是List集合,传的是List集合的地址,在方法体内对集合进行修改则会导致实参的值也发生改变。

实现源码

Cluster类
package com.data.mining.entity;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
public class Cluster {
    private Point corePoint;
    private List<Point> sameList = new ArrayList<>();

    public Cluster(){}

    public Cluster(Point cp){
        corePoint = cp;
    }
}

Point类
package com.data.mining.entity;

import lombok.Data;

@Data
public class Point {
    private double x;
    private double y;

    public Point(){}

    public Point(double x, double y){
        this.x = x;
        this.y = y;
    }

    public static boolean getIsSame(Point p1, Point p2){
        if (p1.getX() == p2.getX() && p1.getY() == p2.getY()) return true;
        return false;
    }

    public static double calculateDistance(Point p1, Point p2){
        double xDistance = p1.getX() - p2.getX();
        double yDistance = p1.getY() - p2.getY();
        double tmp = xDistance * xDistance + yDistance * yDistance;
        return Math.sqrt(tmp);
    }

    public static double calculateMHDDistance(Point p1, Point p2){
        return Math.abs(p1.getX() - p2.getX()) + Math.abs(p1.getY() - p2.getY());
    }

}

K-means算法实现代码
package com.data.mining.main;

import com.data.mining.entity.Cluster;
import com.data.mining.entity.Point;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class Kmeans {
    //定义初始数据集
    public static List<Point> dataList = new ArrayList<>();
    //定义簇的数目
    public static Integer k = 3;

    public static void main(String[] args) {
        //初始化数据集和初始簇
        initDataList();
        List<Cluster> clusterList = getInitCluster();
        while(true){
            for (int j = 0; j < k; j++) {
                clusterList.get(j).getSameList().clear();
            }
            for (Point point : dataList) {
                int index = getBelongCluster(point, clusterList); //获取point属于的那个簇在clusterList中的下标
                clusterList.get(index).getSameList().add(point); //把point加入到clusterList的对应簇中;
            }
            if (!calculateClusterCore(clusterList)) break;
        }
        for (Cluster cluster : clusterList) {
            System.out.println(cluster);
        }
    }

    /**
     * 计算出新的簇中心并返回簇的点集合是否有变化
     * @param clusterList
     * @return
     */
    public static boolean calculateClusterCore(List<Cluster> clusterList){
        boolean flag = false;
        //遍历簇集合中的每一项,更新其簇中心
        for (Cluster cluster : clusterList) {
            List<Point> sameList = cluster.getSameList();
            double sumX = 0; //存放簇中点集合所有的X坐标之和
            double sumY = 0; //存放簇中点集合所有的Y坐标之和
            for (Point point : sameList) {
                sumX += point.getX();
                sumY += point.getY();
            }
            //更新簇的中心
            Point clusterCore = new Point(sumX * 1.0 / sameList.size(), sumY * 1.0 / sameList.size());
            if (!Point.getIsSame(clusterCore, cluster.getCorePoint())) flag = true;
            cluster.setCorePoint(clusterCore);
        }
        return flag;
    }

    /**
     * 获取某个点属于哪个簇的下标
     * @param point
     * @return
     */
    public static int getBelongCluster(Point point, List<Cluster> clusterList){
        double closestDistance = 0.0; //存放point距离簇中心最近的距离
        int resultClusterIndex = 0; //存放point属于的那个簇的下标
        int index = 0;
        //遍历簇集合,计算point到簇中心的距离,找出point属于的簇
        for (Cluster cluster : clusterList) {
            double distance = Point.calculateDistance(point, cluster.getCorePoint());
            if (index == 0) closestDistance = distance;
            if (distance < closestDistance){
                closestDistance = distance;
                resultClusterIndex = index;
            }
            index++;
        }
        return resultClusterIndex;
    }

    /**
     * 获取任意k个对象作为初始簇中心,将含有k个簇的集合返回
     * @return
     */
    public static List<Cluster> getInitCluster(){
        List<Cluster> clusterList = new ArrayList<>();
        int[] randomArray = getRandomArray();
        //任意选取k个对象作为初始簇中心,数据集中k个对象的下标存放在randomArray中
        for (int i = 0; i < randomArray.length; i++) {
            Point point = dataList.get(randomArray[i]);
            Cluster cluster = new Cluster(point);
            clusterList.add(cluster);
        }
        return clusterList;
    }

    /**
     * 获取含有k个不重复随机数的数组
     * @return
     */
    public static int[] getRandomArray(){
        Random random = new Random();
        int[] randomArray = new int[k];
        for (int i = 0; i < k; i++) {
            int randomItem = random.nextInt(12);
            //为保证randomArray中存放的随机数不重复
            while (Arrays.binarySearch(randomArray, randomItem) >= 0) randomItem = random.nextInt(12);
            randomArray[i] = randomItem;
        }
        return randomArray;
    }

    /**
     * 初始化数据集
     */
    public static void initDataList(){
        Point p1 = new Point(1, 2);
        Point p2 = new Point(2, 1);
        Point p3 = new Point(2, 4);
        Point p4 = new Point(4, 3);
        Point p5 = new Point(5, 8);
        Point p6 = new Point(6, 7);
        Point p7 = new Point(6, 9);
        Point p8 = new Point(7, 9);
        Point p9 = new Point(9, 5);
        Point p10 = new Point(1, 12);
        Point p11 = new Point(3, 12);
        Point p12 = new Point(5, 12);
        Point p13 = new Point(3, 3);

        dataList.add(p1);
        dataList.add(p2);
        dataList.add(p3);
        dataList.add(p4);
        dataList.add(p5);
        dataList.add(p6);
        dataList.add(p7);
        dataList.add(p8);
        dataList.add(p9);
        dataList.add(p10);
        dataList.add(p11);
        dataList.add(p12);
        dataList.add(p13);
    }
}


实验结果
在这里插入图片描述
输出结果无疑是3个簇,因为k的值就为3。这里笔者进行了多次测试,发现随着测试次数增多,会出现测试结果不同的情况,在搜集过资料后,笔者个人认为这种情况是正常的,原因是由于初始时是随机选取的簇中心点,可能开始选取的簇中心点位置过于紧凑或者过于疏散,都会影响到最后的输出结果,经过多次测试后,笔者发现有一组输出结果的出现频率是最高的,这组输出结果如图所示。这图片不知道为啥字这么小,反正我是看不清,所以用表格盛一下:
在这里插入图片描述

五、实验总结

本实验结果笔者并不保证一定是正确的,笔者仅仅是提供一种使用Java语言实现K-means算法的思路。因为实验并没有给答案,笔者已将书上有答案的实验数据输入程序后,程序输出的结果和答案一致,所以问题应该不大。若有写的不到位的地方,还请各位多多指点!
笔者主页还有其他数据挖掘算法的总结,欢迎各位光顾!

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

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

相关文章

给 VitePress 添加 algolia 搜索

大家好&#xff0c;我是 Chocolate。 最近在折腾 VitePress&#xff0c;搭建了一个文档项目&#xff1a;ChoDocs&#xff0c;不过文档还不支持搜索功能&#xff0c;虽然目前内容不多&#xff0c;但待我同步完之后&#xff0c;搜索就很有必要了。 之前看 VitePress 官网发现没有…

pikachu靶场暴力破解绕过token防护详解

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是pikachu靶场暴力破解绕过token防护详解。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#x…

基于改进的多目标粒子群算法的微电网多目标调度(三个目标函数)(matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

中央重磅文件明确互联网医疗服务可用医保支付!

文章目录中央重磅文件明确互联网医疗服务可用医保支付&#xff01;中央重磅文件明确互联网医疗服务可用医保支付&#xff01; 当下&#xff0c;互联网医疗机构已加入到新冠防治的“主战场”&#xff0c;在分流线下诊疗发挥了很大作用。国家层面也在进一步鼓励互联网医疗行业发…

基于多尺度形态学梯度进行边缘检测(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

C++中的继承

把握住自己能把握住的点滴&#xff0c;把它做到极致&#xff0c;加油&#xff01; 本节目标1.继承的概念及定义1.1继承的概念1.2 继承定义1.2.1 定义格式1.2.2 继承方式和访问限定符1.2.3 继承基类成员访问方式的变化2.继承中的作用域练习3.基类和派生类对象赋值转换4.派生类的…

Java+SSM网上订餐系统点餐餐厅系统(含源码+论文+答辩PPT等)

项目功能简介: 该项目采用的技术实现如下 后台框架&#xff1a;Spring、SpringMVC、MyBatis UI界面&#xff1a;BootStrap、H-ui 、JSP 数据库&#xff1a;MySQL 系统功能 系统分为前台订餐和后台管理&#xff1a; 1.前台订餐 用户注册、用户登录、我的购物车、我的订单 商品列…

Linux 常用的命令

前言 Linux 的学习对于一个程序员的重要性是不言而喻的。前端开发相比后端开发&#xff0c;接触 Linux 机会相对较少&#xff0c;因此往往容易忽视它。但是学好它却是程序员必备修养之一。 作者使用的是阿里云服务器 ECS &#xff08;最便宜的那种&#xff09; CentOS 7.7 64…

快速了解JSON及JSON的使用

文章目录JSON简介JSON语法JSON 名称/值对JSON对象数组JSON的简单使用JSON简介 JSON&#xff08;JavaScriptObjectNotation&#xff0c;JS对象简谱&#xff09;是一种轻量级的数据交换格式 JS对象简谱&#xff0c;那么JSON如何转换为JS对象&#xff1a; JSON文本格式在语法上与…

多弹协同攻击时的无源定位

题目 采用被动接收方式的无源探测定位技术具有作用距离远、隐蔽接 收、不易被敌方发觉等优点&#xff0c;能有效提高探测系统在电子战环境下的 生存能力和作战能力。 在无源定位的研究中&#xff0c;测向定位技术&#xff08;Direction of Arrival&#xff0c;DOA&#xff09; …

SpringBoot操作Mongo

文章目录引入依赖yaml实体类集合操作创建删除相关注解文档操作添加实验 数据查询添加更新删除引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency><de…

Jmeter配置不同业务请求比例,应对综合场景压测

背景 在进行综合场景压测时&#xff0c;遇到了如何实现不同的请求所占比例不同的问题。 有人说将这些请求分别放到单独的线程组下&#xff0c;然后将线程组的线程数按照比例进行配置。 这种方法不是很好&#xff0c;因为服务器对不同的请求处理能力不同&#xff0c;有的处理快…

C规范编辑笔记(八)

往期文章&#xff1a; C规范编辑笔记(一) C规范编辑笔记(二) C规范编辑笔记(三) C规范编辑笔记(四) C规范编辑笔记(五) C规范编辑笔记(六) C规范编辑笔记(七) 正文&#xff1a; 今天来给大家分享我们的第八篇C规范编辑笔记&#xff0c;话不多说&#xff0c;我们直接来看&…

计算机毕设Python+Vue新闻类网站(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

基于微信小程序的灯具商城系统-计算机毕业设计

项目介绍 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&a…

Java中IO体系

File File类 File类 : 表示计算机中所有的文件和文件夹; [计算机硬盘上除了文件就是文件夹]如何创建File对象 :File(String pathname) : 传入文件路径[String],创建File对象并指向这个路径的文件/文件夹File(String parent, String child) :传入文件路径[String],创建File对象…

【机器学习---02】机器学习相关名词解释

文章目录1. 损失函数、期望风险、经验风险2. 经验风险最小化和结构风险最小化2.1 结构风险&#xff08;正则化&#xff09;2.2 两者的定义3. 训练误差 与 测试误差4. 过拟合 与 欠拟合4.1 过拟合及解决方法4.2 交叉验证4.3 欠拟合5. 泛化误差 与 泛化误差上界5.1 泛化误差5.2 泛…

Filter Listener Ajax学习笔记

1 Filter Filter用于请求的过滤&#xff0c;如请求时&#xff0c;做登录的全局性校验 1.1 示例 在创建Filter前&#xff0c;可以通过启动Tomcat访问index.jsp http://localhost:8080/Mvc-Demo/index.jsp添加Filter后&#xff0c;重新启动Tomcat&#xff0c;并再次访问index…

8、java常见名词总结

一、JMM 1.1、JMM简介 JMM 是Java内存模型&#xff08; Java Memory Model&#xff09;&#xff0c;简称JMM。它本身只是一个抽象的概念&#xff0c;并不真实存在&#xff0c;它描述的是一种规则或规范&#xff0c;是和多线程相关的一组规范。通过这组规范&#xff0c;定义了…

babel-plugin-transform-remove-console 项目打包去除console

安装babel-plugin-transform-remove-console 项目打包去除console npm install babel-plugin-transform-remove-console --save-dev 在vue项目中babel.config.js中&#xff1a; module.exports {plugins: ["transform-remove-console",], }; 如果只想在生产环境…