Java聚类分析

聚类

  • 聚类
    • 1 解决什么问题
    • KMean聚类
    • Kmedoids聚类
    • 2 java实现计算二维点的聚类案例
      • KMean实现
        • 输出
      • K-medoids实现
        • 输出

聚类

1 解决什么问题

假设二维坐标轴上有一些点,现在让你把这些点分个类。于是对我们来说,这个分类似乎就是把距离相近的点画到一类中去。

KMean聚类

  1. 假设要划分N类,坐标点M
  2. M个坐标点随机选取N个点,作为每个分类的中心点,这N个点的列表记录为centerPointList
  3. 遍历M个坐标点中的每个点
    • 计算当前点和N个中心点的距离,dis1、dis2 ... disN
    • dis1、dis2 ... disN找到最小的距离的下标。下标记录为cluster,那么这个cluster就是这次遍历时候当前点归属的分类。
  4. 步骤3结束后,每个点都会归属到某个分类。计算每个分类中点集合的均值,把这个均值作为新的中心点,替换掉centerPointList
  5. 重复3、4直到重复次数大于约定次数,或者中心点变化较小。此时就可以知道每个点归属的分类。

Kmedoids聚类

  1. 假设要划分N类,坐标点M
  2. M个坐标点随机选取N个点,作为每个分类的中心点,这N个点的列表记录为centerPointList
  3. 遍历M个坐标点中的每个点
    • 计算当前点和N个中心点的距离,dis1、dis2 ... disN
    • dis1、dis2 ... disN找到最小的距离的下标。下标记录为cluster,那么这个cluster就是这次遍历时候当前点归属的分类。
  4. 步骤3结束后,每个点都会归属到某个分类。计算每个分类中每个点作为中心点时,其他点到该中心点的距离和,选择距离和最小时对应的中心点 作为当前分类的中心点,替换掉centerPointList
  5. 重复3、4直到重复次数大于约定次数,或者中心点变化较小。此时就可以知道每个点归属的分类。

2 java实现计算二维点的聚类案例

KMean实现

package com.forezp.kmean;import com.google.common.collect.Lists;
import com.google.common.collect.Maps;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;/*** @author yuegang*/
public class KMeanCluster {/*** 表示二维空间中的点*/public static class Point {Integer x = 0;Integer y = 0;public Point() {}public Point(Integer x, Integer y) {this.x = x;this.y = y;}public void incX(Integer x) {this.x += x;}public void incY(int y) {this.y += y;}public Integer getX() {return x;}public void setX(Integer x) {this.x = x;}public Integer getY() {return y;}public void setY(Integer y) {this.y = y;}@Overridepublic String toString() {return "(" + x + ", " + y + ")";}}/*** 表示二维空间中的点* 下标是点的顺序*/private final List<Point> pointIndexDataMap;private final List<List<Point>> centerPointList = Lists.newArrayList(); // 记录每一个分类的中心点private final List<Integer> pointClusterMap = Lists.newArrayList(); // 点所属的分类private int index = 0; // 计算次数private int clusterCount = 0; // 分类个数public KMeanCluster(List<Point> pointIndexDataMap, int clusterCount) {this.pointIndexDataMap = pointIndexDataMap;this.clusterCount = clusterCount;index = 0;initCenterPoint();initCluster(pointIndexDataMap);}private void initCluster(List<Point> pointIndexDataMap) {// 初始化每个点的分类,设置一个没有意义的值for (int j = 0; j < pointIndexDataMap.size(); ++j) {pointClusterMap.add(-1);}}private void initCenterPoint() {List<Point> objects = Lists.newArrayListWithExpectedSize(clusterCount);List<Integer> yList = Lists.newArrayListWithExpectedSize(clusterCount);Random random = new Random();for (int i = 0; i < clusterCount; ++i) { // 注意这个不能相同int i1 = random.nextInt(pointIndexDataMap.size());while (yList.contains(i1)) {i1 = random.nextInt(pointIndexDataMap.size());}yList.add(i1);}for (int i = 0; i < clusterCount; ++i) {objects.add(pointIndexDataMap.get(yList.get(i)));}centerPointList.add(objects);}public void calc() {List<Point> pointIndices = centerPointList.get(index);for (int i = 0; i < pointIndexDataMap.size(); ++i) {Point point = pointIndexDataMap.get(i);// 计算该点和那个簇最近,把把归属到这个簇中。int cluster = 0;double min = Double.MAX_VALUE;for (int inc = 0; inc < pointIndices.size(); ++inc) {Point point1 = pointIndices.get(inc);Integer x = point.getX();Integer y = point.getY();Integer x1 = point1.getX();Integer y1 = point1.getY();int i1 = x - x1;int i2 = y - y1;int total = i1 * i1 + i2 * i2;double sqrt = Math.sqrt(total);if (sqrt < min) {min = sqrt;cluster = inc;}}pointClusterMap.set(i, cluster);}// 计算每个族的中心点;int size = centerPointList.get(0).size();Map<Integer, Point> map = Maps.newTreeMap();Map<Integer, Integer> cluterCount = Maps.newHashMapWithExpectedSize(size);for (int i = 0; i < pointClusterMap.size(); ++i) {int cluster = pointClusterMap.get(i);Point point = map.computeIfAbsent(cluster, sss -> new Point());cluterCount.put(cluster, cluterCount.getOrDefault(cluster, 0) + 1);Point point1 = pointIndexDataMap.get(i);point.incX(point1.getX());point.incY(point1.getY());}for (Map.Entry<Integer, Point> integerPointEntry : map.entrySet()) {Integer key = integerPointEntry.getKey();Point point = integerPointEntry.getValue();Integer integer = cluterCount.get(key);point.setX(point.getX() / integer);point.setY(point.getY() / integer);}++index;Map<Integer, List<Point>> curClassfiyMap = Maps.newTreeMap();for (int i = 0; i < pointClusterMap.size(); ++i) {Point point = pointIndexDataMap.get(i);Integer classfly = pointClusterMap.get(i);List<Point> points = curClassfiyMap.computeIfAbsent(classfly, k -> Lists.newArrayList());points.add(point);}List<Point> curCenterPointList = new ArrayList<>(map.values());centerPointList.add(curCenterPointList);show(curClassfiyMap, curCenterPointList);}private void show(Map<Integer, List<Point>> curClassfiyMap, List<Point> curCenterPointList) {System.out.println("计算次数:" + index);System.out.println("当前分类:" + curClassfiyMap);System.out.println("当前中心点:" + curCenterPointList);}public static void main(String[] args) {Point point = new Point(100, 100);Point point1 = new Point(1, 1);Point point2 = new Point(110, 120);Point point3 = new Point(10, 20);Point point4 = new Point(130, 160);List<Point> pointIndexDataMap = Lists.newArrayList(point, point1, point2, point3, point4);KMeanCluster oneCalc = new KMeanCluster(pointIndexDataMap, 2);for (int i = 0; i < 2; ++i) {oneCalc.calc();}}
}
输出
计算次数:1
当前分类:{0=[(110, 120), (130, 160)], 1=[(100, 100), (1, 1), (10, 20)]}
当前中心点:[(120, 140), (37, 40)]
计算次数:2
当前分类:{0=[(100, 100), (110, 120), (130, 160)], 1=[(1, 1), (10, 20)]}
当前中心点:[(113, 126), (5, 10)]

K-medoids实现

package com.forezp.kmean;/*** 表示二维空间中的点*/
public class Point {Integer x = 0;Integer y = 0;public long dis(Point p) {int i = getX() - p.getX();int i1 = getY() - p.getY();return ((long) i * i) + ((long) i1 * i1);}public Point() {}public Point(Integer x, Integer y) {this.x = x;this.y = y;}public void incX(Integer x) {this.x += x;}public void incY(int y) {this.y += y;}public Integer getX() {return x;}public void setX(Integer x) {this.x = x;}public Integer getY() {return y;}public void setY(Integer y) {this.y = y;}@Overridepublic String toString() {return "(" + x + ", " + y + ")";}
}
package com.forezp.kmean;import com.google.common.collect.Lists;
import com.google.common.collect.Maps;import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;/*** @author yuegang*/
public class KModiedCluster {/*** 表示二维空间中的点* 下标是点的顺序*/private final List<Point> pointIndexDataMap;private final List<List<Integer>> centerPointList = Lists.newArrayList(); // 记录每一个分类的中心点下标private final List<Integer> pointClusterMap = Lists.newArrayList(); // 点所属的分类private final List<List<Long>> distanceMap = Lists.newArrayList();private int index = 0; // 计算次数private int clusterCount = 0; // 分类个数public KModiedCluster(List<Point> pointIndexDataMap, int clusterCount) {this.pointIndexDataMap = pointIndexDataMap;this.clusterCount = clusterCount;index = 0;initCenterPoint();initCluster(pointIndexDataMap);initDistanceMap();System.out.println("点集合: " + pointIndexDataMap);System.out.println("初始点中心: " + centerPointList.get(index).stream().map(pointIndexDataMap::get).collect(Collectors.toList()));}private void initDistanceMap() {int size = pointIndexDataMap.size();for (int i = 0; i < size; ++i) {List<Long> collect = IntStream.range(0, size).boxed().map(e -> 0L).collect(Collectors.toList());distanceMap.add(collect);}for (int i = 0; i < size; ++i) {for (int j = i; j < size; ++j) {long dis = pointIndexDataMap.get(i).dis(pointIndexDataMap.get(j));distanceMap.get(i).set(j, dis);distanceMap.get(j).set(i, dis);}}}private void initCluster(List<Point> pointIndexDataMap) {// 初始化每个点的分类,设置一个没有意义的值for (int j = 0; j < pointIndexDataMap.size(); ++j) {pointClusterMap.add(-1);}}private void initCenterPoint() {List<Integer> yList = Lists.newArrayListWithExpectedSize(clusterCount);Random random = new Random();for (int i = 0; i < clusterCount; ++i) { // 注意这个不能相同int i1 = random.nextInt(pointIndexDataMap.size());while (yList.contains(i1)) {i1 = random.nextInt(pointIndexDataMap.size());}yList.add(i1);}centerPointList.add(yList);}public void calc() {List<Integer> pointIndices = centerPointList.get(index);for (int i = 0; i < pointIndexDataMap.size(); ++i) {// 计算该点和那个簇最近,把把归属到这个簇中。int cluster = 0;double min = Double.MAX_VALUE;for (int inc = 0; inc < pointIndices.size(); ++inc) {Long dis = distanceMap.get(i).get(inc);double sqrt = Math.sqrt(dis);if (sqrt < min) {min = sqrt;cluster = inc;}}pointClusterMap.set(i, cluster);}// 计算每个族的中心点;Map<Integer, List<Integer>> indexMap = Maps.newTreeMap(); // 每个分类中的下标集合for (int i = 0; i < pointClusterMap.size(); ++i) {Integer cluster = pointClusterMap.get(i);List<Integer> integers = indexMap.computeIfAbsent(cluster, k -> Lists.newArrayList());integers.add(i);}Map<Integer, Integer> map = Maps.newTreeMap();for (Map.Entry<Integer, List<Integer>> integerListEntry : indexMap.entrySet()) {Integer cluster = integerListEntry.getKey();List<Integer> indexList = integerListEntry.getValue();// 计算每个点是否可以作为中心点int newCluster = indexList.get(0);long sumDisHistory = Long.MAX_VALUE;for (int i = 0; i < indexList.size(); ++i) {long sumDis = 0;for (int j = 0; j < indexList.size(); ++j) {if (i == j) {continue;}sumDis += distanceMap.get(j).get(i);}if (sumDis < sumDisHistory) {newCluster = indexList.get(i);sumDisHistory = sumDis;}}map.put(cluster, newCluster); // 当前族的新的中心点}Map<Integer, List<Point>> curClassfiyMap = getIntegerListMap();List<Integer> curCenterPointList = new ArrayList<>(map.values());centerPointList.add(curCenterPointList);++index;show(curClassfiyMap, curCenterPointList);}private Map<Integer, List<Point>> getIntegerListMap() {Map<Integer, List<Point>> curClassfiyMap = Maps.newTreeMap();for (int i = 0; i < pointClusterMap.size(); ++i) {Point point = pointIndexDataMap.get(i);Integer classfly = pointClusterMap.get(i);List<Point> points = curClassfiyMap.computeIfAbsent(classfly, k -> Lists.newArrayList());points.add(point);}return curClassfiyMap;}private void show(Map<Integer, List<Point>> curClassfiyMap, List<Integer> curCenterPointList) {System.out.println("计算次数:" + index);System.out.println("当前分类:" + curClassfiyMap);System.out.println("当前中心点:" + curCenterPointList.stream().map(pointIndexDataMap::get).collect(Collectors.toList()));}public static void main(String[] args) {Point point = new Point(100, 100);Point point1 = new Point(1, 1);Point point2 = new Point(110, 120);Point point3 = new Point(10, 20);Point point4 = new Point(130, 160);List<Point> pointIndexDataMap = Lists.newArrayList(point, point1, point2, point3, point4,new Point(100, 160),new Point(9, 160),new Point(50, 20));KModiedCluster oneCalc = new KModiedCluster(pointIndexDataMap, 4);for (int i = 0; i < 2; ++i) {oneCalc.calc();}}
}
输出
点集合: [(100, 100), (1, 1), (110, 120), (10, 20), (130, 160), (100, 160), (9, 160), (50, 20)]
初始点中心: [(100, 100), (130, 160), (100, 160), (50, 20)]
计算次数:1
当前分类:{0=[(100, 100)], 1=[(1, 1)], 2=[(110, 120), (130, 160), (100, 160), (9, 160)], 3=[(10, 20), (50, 20)]}
当前中心点:[(100, 100), (1, 1), (110, 120), (10, 20)]
计算次数:2
当前分类:{0=[(100, 100)], 1=[(1, 1)], 2=[(110, 120), (130, 160), (100, 160), (9, 160)], 3=[(10, 20), (50, 20)]}
当前中心点:[(100, 100), (1, 1), (110, 120), (10, 20)]

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

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

相关文章

DDT数据驱动测试

简单介绍 ​ DDT&#xff08;Date Driver Test&#xff09;&#xff0c;所谓数据驱动测试&#xff0c; 简单来说就是由数据的改变从而驱动自动化测试的执行&#xff0c;最终引起测试结果的改变。通过使用数据驱动测试的方法&#xff0c;可以在需要验证多组数据测试场景中&…

【LeetCode-452】用最少数量的箭引爆气球(贪心)

LeetCode452.用最少数量的箭引爆气球 题目描述 原题链接 在二维空间中有许多球形的气球。对于每个气球&#xff0c;提供的输入是水平方向上&#xff0c;气球直径的开始和结束坐标。由于它是水平的&#xff0c;所以纵坐标并不重要&#xff0c;因此只要知道开始和结束的横坐标…

详细分析Java的树形工具类(含注释)

目录 前言1. 基本框架2. 实战应用 前言 对应的每个子孙属于该父亲&#xff0c;这其实是数据结构的基础知识&#xff0c;那怎么划分怎么归属呢 对应的基本知识推荐如下&#xff1a; 【数据结构】树和二叉树详细分析&#xff08;全&#xff09;【数据结构】B树和B树的笔记详细…

面试 HTML 框架八股文十问十答第一期

面试 HTML 框架八股文十问十答第一期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01;关注专栏后就能收到持续更新&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;src和href的区别 src和…

数据结构与算法教程,数据结构C语言版教程!(第六部分、数据结构树,树存储结构详解)二

第六部分、数据结构树&#xff0c;树存储结构详解 数据结构的树存储结构&#xff0c;常用于存储逻辑关系为 "一对多" 的数据。 树存储结构中&#xff0c;最常用的还是二叉树&#xff0c;本章就二叉树的存储结构、二叉树的前序、中序、后序以及层次遍历、线索二叉树、…

300. 最长递增子序列(动态规划)

动态规划&#xff1a; 状态定义&#xff1a;dp[i]表示以索引为第i个字符结尾的最长递增子序列的长度&#xff0c;d[n-1]表示以第n-1个字符作为结尾的最长递增子序列的长度&#xff0c;但是这并不是答案&#xff0c;因为整个序列中的最长递增子序列不一定以n-1结尾&#xff0c;…

Docker部署思维导图工具SimpleMindMap并实现公网远程访问

文章目录 1. Docker一键部署思维导图2. 本地访问测试3. Linux安装Cpolar4. 配置公网地址5. 远程访问思维导图6. 固定Cpolar公网地址7. 固定地址访问 SimpleMindMap 是一个可私有部署的web思维导图工具。它提供了丰富的功能和特性&#xff0c;包含插件化架构、多种结构类型&…

如何重置某个css属性值(unset)

场景 你用了别人的UI框架&#xff0c;然后你发现&#xff0c;你给css动态赋的值&#xff0c;被UI框架的优先级更高的css覆盖了。你可以写js来改变它&#xff0c;但是如果有很多层循环操作&#xff0c;你需要写一大段的js&#xff0c;此时js并不是最优的选择&#xff0c;你真正…

【Unicode】Character ‘ENQUIRY‘ (U+0005)

询问 result.append("\u0005");Unicode Character ‘ENQUIRY’ (U0005)

js中字符串string,遍历json/Object【匹配url、邮箱、电话,版本号,千位分割,判断回文】

目录 正则 合法的URL 邮箱、电话 字符串方法 千位分割&#xff1a;num.slice(render, len).match(/\d{3}/g).join(,) 版本号比较 判断回文 json/Object 遍历 自身属性 for...inhasOwnProperty(key) Object.获取数组(obj)&#xff1a;Object.keys&#xff0c;Object…

深度强化学习(王树森)笔记02

深度强化学习&#xff08;DRL&#xff09; 本文是学习笔记&#xff0c;如有侵权&#xff0c;请联系删除。本文在ChatGPT辅助下完成。 参考链接 Deep Reinforcement Learning官方链接&#xff1a;https://github.com/wangshusen/DRL 源代码链接&#xff1a;https://github.c…

taro3 + vue3 + ts 跨平台体验记录

taro3 vue3 ts 跨平台体验记录&#xff0c;根据进度不定期更新。 目标平台包含&#xff1a;H5、微信小程序、APP。开发环境&#xff1a;windows 安装cli【官方安装文档】 npm install -g tarojs/cli常用命令 // 查看taro版本 npm info tarojs/cli创建demo项目 taro init…

Python+appium自动化测试总结

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 前言 pythonappium自动化测试系列就要告一段落了&#xff0c;本…

spring-boot redis stream消息队列demo-及死信简单处理

Redis stream 是 Redis 5 引入的一种新的数据结构&#xff0c;它是一个高性能、高可靠性的消息队列&#xff0c;主要用于异步消息处理和流式数据处理。在此之前&#xff0c;想要使用 Redis 实现消息队列&#xff0c;通常可以使用例如&#xff1a;列表&#xff0c;有序集合、发布…

【C++】istream类型对象转换为逻辑条件判断值

前言 大家好吖&#xff0c;欢迎来到 YY 滴 系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Linux》专…

使用 sorted set 实现令牌桶限流

业务场景为限制消息发送&#xff0c;要求每天不超过一次&#xff0c;每七天不超过三次。 Redission 的 RRateLimiter 虽然功能完备且支持自定义限流配置&#xff0c;但是每个限流器都需要维护三个 key&#xff0c;并且 lua 脚本中的判断逻辑较为复杂。 见&#xff1a;Redisso…

LiveGBS流媒体平台GB/T28181常见问题-如何快速查看推流上来的摄像头并停止摄像头推流?

LiveGBS流媒体平台GB/T28181常见问题-如何快速查看推流上来的摄像头并停止摄像头推流&#xff1f; 1、负载信息2、负载信息说明3、会话列表查看3.1、会话列表 4、停止会话5、搭建GB28181视频直播平台 1、负载信息 实时展示直播、回放、播放、录像、H265、级联等使用数目 2、负…

Python算法题集_接雨水

本文为Python算法题集之一的代码示例 题目42&#xff1a;接雨水 说明&#xff1a;给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1]…

ElasticSearch7.7.1集群搭建

前言 Elasticsearch&#xff08;ES&#xff09;是一个基于Apache Lucene的分布式、高扩展、近实时的搜索引擎&#xff0c;主要用于海量数据快速存储、实时检索、高效分析的场景。通过简单易用的RESTful API&#xff0c;Elasticsearch隐藏了Lucene的复杂性&#xff0c;使得全文搜…

数论Leetcode204. 计数质数、Leetcode858. 镜面反射、Leetcode952. 按公因数计算最大组件大小

Leetcode204. 计数质数 题目 给定整数 n &#xff0c;返回 所有小于非负整数 n 的质数的数量 。 代码 class Solution:def countPrimes(self, n: int) -> int:if n < 2:return 0prime_arr [1 for _ in range(n)]prime_arr[0], prime_arr[1] 0, 0ls list()for i in…