QT+VS实现Kmeans聚类算法
1、Kmeans的定义
聚类是一个将数据集中在某些方面相似的数据成员进行分类组织的过程,聚类就是一种发现这种内在结构的技术,聚类技术经常被称为无监督学习。k均值聚类是最著名的划分聚类算法,由于简洁和效率使得他成为所有聚类算法中最广泛使用的。
无监督学习通常用于聚类,通过样本件的相似性对数据集进行聚类,使类内差距最小化,类间差距最大化。
2、原理
首先需要弄清楚两个概念:簇和质心
簇: 直观上来看,簇是一组聚在一起的数据,在一个簇中的数据就认为是同一类。
质心: 簇中所有数据的均值通常被称为这个簇的质心。
如何求取质心:
在一个二维平面中,一簇数据点的质心的横坐标就是这一簇数据点的横坐标的均值,质心的纵坐标就是这一簇数据点的纵坐标的均值。同理可推广至高维空间。
欧式距离计算公式:
二维平面上的欧式距离:
假设待求两点的二维平面坐标为a(
,
)和b
(
,
),则其距离公式为:
=
=
3、实现的流程步骤
- 首先随机选取样本中的K个点作为初始聚类中心(质心);
- 分别算出样本中其他数据点距离这K个聚类中心的距离,以最近距离的质心缩在的簇作为该数据点分类后的簇;
- 对上述分类完的样本再进行每个簇求平均值,求解出新的聚类质心;
- 与前一次计算得到的K个聚类质心比较,如果聚类质心发生变化,转过程b,否则转过程e;
- 当质心不再发生变化时,停止并输出聚类结果。
4、实现结果
5、部分代码解析
(1)首先,为了提高分类精度,K个质心初始值的选取,采用人工确定的方法。先人为的选取K个初值,并写成txt格式,如下:
格式:点号-X坐标-Y坐标
读取K值数据的函数如下:
void Kmeans::onBtReadK()
{QString fileName = QFileDialog::getOpenFileName(this, tr("打开"));QFile file(fileName);bool isOpen = 1;if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){isOpen = 0;QMessageBox::StandardButton btnValue = QMessageBox::information(this, tr("提示"), tr("打开失败!"));}QTextStream stream(&file);while (!stream.atEnd()){QString str = stream.readLine();QStringList list = str.split(",");Pointp k1;k1.no = list.at(0);k1.x = list.at(1).toDouble();k1.y = list.at(2).toDouble();k.push_back(k1);}//判断是否读取完毕if (stream.atEnd() && isOpen){QMessageBox box;box.setText("数据读取完毕");box.exec();}dd = readK;
}
(2)读取K个初始值之后,需要读取整个样本的数据(样本数据格式同K值格式一致),读取函数如下:
void Kmeans::onBtReadData()
{K = ui.lineEdit->text().toInt();p.clear();//打开文件对话框QString fileName = QFileDialog::getOpenFileName(this, tr("打开"));QFile file(fileName);bool isOpen = 1;if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){isOpen = 0;QMessageBox::StandardButton btnValue = QMessageBox::information(this, tr("提示"), tr("打开失败!"));}//逐行读取文本文件QTextStream stream(&file);while (!stream.atEnd()){Pointp pt;QString str = stream.readLine();QStringList list = str.split(",");pt.no = list.at(0);pt.x = list.at(1).toDouble();pt.y = list.at(2).toDouble();p.push_back(pt);}file.close();//判断是否读取完毕if (stream.atEnd()&&isOpen){QMessageBox box;box.setText("数据读取完毕");box.exec();}
}
(3)在对话框中输入簇个数,然后点击“开始聚类”按钮,开始进行聚类。首先是计算每个样本到K个聚类中心的距离,并找出最小值,作为该样本点的聚类结果。代码如下:
//计算每个对象至聚类中心的距离
void Kmeans::CalDis()
{for (int i = 0; i < p.size(); i++){double s0 = 0; QString no; Dis ss; int t = 0;for (int j = 0; j < K; j++){double x1 = p.at(i).x;double y1 = p.at(i).y;double x2 = k.at(j).x;double y2 = k.at(j).y;double s1 = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));t++;if (t == 1){s0 = s1;no = k.at(j).no;}if (s1 < s0){s0 = s1;no = k.at(j).no;}}ss.s = s0;ss.no = p.at(i).no;ss.x = p.at(i).x;ss.y = p.at(i).y;ss.noK = no;S.push_back(ss);}
}
(4)根据分类后的样本计算新的质心,如下:
//计算质心
void Kmeans::Calcentroid()
{centroid s;for (int i = 0; i < k.size(); i++){s.sx = 0; s.sy = 0; int iCt = 0;for (int j = 0; j < S.size(); j++){if (k.at(i).no == S.at(j).noK){s.sx = s.sx + S.at(j).x;s.sy = s.sy + S.at(j).y;iCt++;}}s.noK = k.at(i).no;s.sx = s.sx / iCt;s.sy = s.sy / iCt;dis.push_back(s);}
}
(5)然后判断新质心与旧质心之间的距离,若为0,则停止重新计算。
6、整体代码如下(输入的数据中不能包含负数,因为控件范围是从0开始的)
//Kmeans.cpp文件
#include "Kmeans.h"Kmeans::Kmeans(QWidget *parent): QWidget(parent)
{start = false;dd = to2K;ui.setupUi(this);connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(onBtReadData()));connect(ui.pushButton_2, SIGNAL(clicked()), this, SLOT(onBtCalKmeans()));connect(ui.pushButton_3, SIGNAL(clicked()), this, SLOT(onBtReadK()));
}void Kmeans::onBtReadData()
{K = ui.lineEdit->text().toInt();p.clear();//打开文件对话框QString fileName = QFileDialog::getOpenFileName(this, tr("打开"));QFile file(fileName);bool isOpen = 1;if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){isOpen = 0;QMessageBox::StandardButton btnValue = QMessageBox::information(this, tr("提示"), tr("打开失败!"));}//逐行读取文本文件QTextStream stream(&file);while (!stream.atEnd()){Pointp pt;QString str = stream.readLine();QStringList list = str.split(",");pt.no = list.at(0);pt.x = list.at(1).toDouble();pt.y = list.at(2).toDouble();p.push_back(pt);}file.close();//判断是否读取完毕if (stream.atEnd()&&isOpen){QMessageBox box;box.setText("数据读取完毕");box.exec();}
}void Kmeans::onBtReadK()
{QString fileName = QFileDialog::getOpenFileName(this, tr("打开"));QFile file(fileName);bool isOpen = 1;if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){isOpen = 0;QMessageBox::StandardButton btnValue = QMessageBox::information(this, tr("提示"), tr("打开失败!"));}QTextStream stream(&file);while (!stream.atEnd()){QString str = stream.readLine();QStringList list = str.split(",");Pointp k1;k1.no = list.at(0);k1.x = list.at(1).toDouble();k1.y = list.at(2).toDouble();k.push_back(k1);}//判断是否读取完毕if (stream.atEnd() && isOpen){QMessageBox box;box.setText("数据读取完毕");box.exec();}dd = readK;
}void Kmeans::toK()
{//随机选取k个初始聚类中心for (int i = 0; i < K; i++){Pointp k1;k1.no = i + 1;k1.x = p.at(i).x;k1.y = p.at(i).y;k.push_back(k1);}
}int Kmeans::onBtCalKmeans()
{K = ui.lineEdit->text().toInt();if (S.size()&&p.size()==S.size()){QMessageBox box;box.setText("已经计算完成");box.exec();return 0;}if (dd == to2K){toK();}CalDis();//SCalcentroid();//用到S,得dis//CKmeans();//用到dis,得new k.int iCount = 0;while (iCount < K){if (dis.size()){for (int i = 0; i < k.size(); i++){for (int j = 0; j < dis.size(); j++){if (k.at(i).no == dis.at(j).noK){//qDebug() <<"k:" <<k.at(i).no<< k.at(i).x << k.at(i).y;//qDebug() <<"dis:" <<dis.at(i).noK.toInt()<< dis.at(j).sx << dis.at(j).sy<<endl;double detaX = k.at(i).x - dis.at(j).sx;double detaY = k.at(i).y - dis.at(j).sy;double sk = sqrt(detaX * detaX + detaY * detaY);//qDebug() << sk;if (sk == 0){iCount++;}else{CKmeans();}}}}}dis.clear();S.clear();CalDis();Calcentroid();}start = true;qDebug() << "S" << S.size();drawPoint();QMessageBox box;box.setText("计算完成");box.exec();return 1;
}Kmeans::~Kmeans()
{}//计算质心
void Kmeans::Calcentroid()
{centroid s;for (int i = 0; i < k.size(); i++){s.sx = 0; s.sy = 0; int iCt = 0;for (int j = 0; j < S.size(); j++){if (k.at(i).no == S.at(j).noK){s.sx = s.sx + S.at(j).x;s.sy = s.sy + S.at(j).y;iCt++;}}s.noK = k.at(i).no;s.sx = s.sx / iCt;s.sy = s.sy / iCt;dis.push_back(s);}
}//计算每个对象至聚类中心的距离
void Kmeans::CalDis()
{for (int i = 0; i < p.size(); i++){double s0 = 0; QString no; Dis ss; int t = 0;for (int j = 0; j < K; j++){double x1 = p.at(i).x;double y1 = p.at(i).y;double x2 = k.at(j).x;double y2 = k.at(j).y;double s1 = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));t++;if (t == 1){s0 = s1;no = k.at(j).no;}if (s1 < s0){s0 = s1;no = k.at(j).no;}}ss.s = s0;ss.no = p.at(i).no;ss.x = p.at(i).x;ss.y = p.at(i).y;ss.noK = no;S.push_back(ss);}
}//将新的质心坐标赋值给k
void Kmeans::CKmeans()
{for (int i = 0; i < k.size(); i++){for (int j = 0; j < dis.size(); j++){if (k.at(i).no == dis.at(j).noK){k.at(i).x = dis.at(j).sx;k.at(i).y = dis.at(j).sy;}}}
}//绘图函数
void Kmeans::drawPoint()
{QPicture pp;pp.setBoundingRect(ui.label_2->rect());QPainter painterP(&pp);QPen pen;painterP.setRenderHint(QPainter::Antialiasing, true);Pointp p1;p1.no = p.at(0).no;p1.x = p.at(0).x;p1.y = p.at(0).y;for (int i = 1; i < p.size(); i++){if (p1.x > p.at(i).x){p1.x = p.at(i).x;}if (p1.y > p.at(i).y){p1.y = p.at(i).y;}}double xmin = p1.x;double ymin = p1.y;for (int i = 1; i < p.size(); i++){if (p1.x < p.at(i).x){p1.x = p.at(i).x;}if (p1.y < p.at(i).y){p1.y = p.at(i).y;}}double xmax = p1.x;double ymax = p1.y;int w=ui.label_2->width();int h=ui.label_2->height();double a = w/(xmax -xmin);double b1 = h/(ymax -ymin);for (int i = 0; i < k.size(); i++){int r = qrand() % 256;int g = qrand() % 256;int b = qrand() % 256;QColor color = QColor(r, g, b);for (int j = 0; j < S.size(); j++){if (k.at(i).no == S.at(j).noK){pen.setColor(color);painterP.setPen(pen);int radius = 5;double x = S.at(j).x;double y = S.at(j).y;x = (x - xmin)*a;y = (y - ymin)*b1;painterP.drawEllipse(x - radius, y - radius, radius * 2, radius * 2);}}}ui.label_2->setPicture(pp);
}
//Kmeans.h文件
#pragma once#include <QtWidgets/QWidget>
#include "ui_Kmeans.h"
#include<QFileDialog>
#include<QFile>
#include<QMessageBox>
#include<QTextStream>
#include<vector>
#pragma execution_character_set("UTF-8")
#include<qDebug>
#include<QPainter>
#include<QColor>
#include<QColorDialog>
#include<QPicture>struct Pointp
{double x;double y;QString no;
};struct Dis
{double x;double y;QString no;QString noK;double s;
};struct centroid
{QString noK;double sx;double sy;
};enum Pd
{readK,to2K,blank
};class Kmeans : public QWidget
{Q_OBJECTpublic:Kmeans(QWidget *parent = nullptr);~Kmeans();public slots:void onBtReadData();int onBtCalKmeans();void onBtReadK();void toK();public:std::vector<Pointp> p;//原始数据点std::vector<Pointp> k;//各簇质心坐标int K;std::vector<Dis> S;std::vector<centroid> dis;bool start;Pd dd;public:void Calcentroid();void CKmeans();void CalDis();void drawPoint();private:Ui::KmeansClass ui;
};
相关文章:

QT+VS实现Kmeans聚类算法
1、Kmeans的定义 聚类是一个将数据集中在某些方面相似的数据成员进行分类组织的过程,聚类就是一种发现这种内在结构的技术,聚类技术经常被称为无监督学习。k均值聚类是最著名的划分聚类算法,由于简洁和效率使得他成为所有聚类算法中最广泛使…...

openssl3.2 - 测试程序的学习 - test\acvp_test.c
文章目录 openssl3.2 - 测试程序的学习 - test\acvp_test.c概述笔记要单步学习的测试函数备注END openssl3.2 - 测试程序的学习 - test\acvp_test.c 概述 openssl3.2 - 测试程序的学习 将test*.c 收集起来后, 就不准备看makefile和make test的日志参考了. 按照收集的.c, 按照…...

Qt Quick 项目(第二集Qt Quick Application创建)
上集回顾 Qt Quick 项目(第一集Qt Quick UI 项目项目创建) 如果将程序的用户界面称为前端,将程序中的数据存储和业务逻辑称为后端,那么传统Qt应用程序的前端和后端都是使用C++来完成的。对于现代软件开发而言,这里有一个存在已久的冲突:前端的演化速度要远快于后端。当用…...

深度强化学习(王树森)笔记03
深度强化学习(DRL) 本文是学习笔记,如有侵权,请联系删除。本文在ChatGPT辅助下完成。 参考链接 Deep Reinforcement Learning官方链接:https://github.com/wangshusen/DRL 源代码链接:https://github.c…...

Cesium材质特效
文章目录 0.引言1.视频材质2.分辨率尺度3.云4.雾5.动态水面6.雷达扫描7.流动线8.电子围栏9.粒子烟花10.粒子火焰11.粒子天气 0.引言 现有的gis开发方向较流行的是webgis开发,其中Cesium是一款开源的WebGIS库,主要用于实时地球和空间数据的可视化和分析。…...

华为产业链之车载激光雷达
一、智能汽车 NOA 加快普及,L3 上路利好智能感知硬件 1、感知层是 ADAS 最重要的一环 先进驾驶辅助系统 (ADAS, Advanced driver-assistance system)分“感知层、决策层、执行层”三个层级,其中感知层是最重要的一环…...

java的Object类的hasCode()和ToString()
(1)hasCode解释 hashCode()是Object类中定义的方法,用于返回对象的哈希码值。哈希码值是一个整数,用于在哈希表等数据结构中快速定位对象。 在Java中,哈希码值的计算是基于对象的内存地址的。默认情况下,ha…...

php数组算法(1)判断一维数组和多元数组中的元素是否相等并输出键值key
在php中,如何判断[1,0,1]和[ [0, 0, 0],//体质正常 [1, 0, 0],//气虚体质 [0, 1, 0],//血瘀体质 [0, 0, 1],//阴虚体质 [1, 1, 0],//气虚兼血瘀体质 [1, 0, 1],//气虚兼阴虚体质 [0, 1, 1],//血瘀兼阴虚体质 [1, 1, 1],//气虚兼血瘀兼阴虚体质 ];中的第n项相等&…...

已解决Error:AttributeError: module ‘numpy‘ has no attribute ‘float‘.
成功解决Error:AttributeError: module ‘numpy‘ has no attribute ‘float‘. 🌵文章目录🌵 🌳引言🌳🌳报错分析🌳🌳解决方案1:降低NumPy版本🌳ἳ…...

WordPress块编辑器(Gutenberg古腾堡)中如何添加脚注?
WordPress默认自带的块编辑器(Gutenberg古腾堡编辑器)本身就自带添加脚注功能,不过经典编辑器不行。如果想要在WordPress中添加更加专业的脚注,建议使用Modern Footnotes插件,具体介绍及使用请参考『WordPress站点如…...

burpsuite怎么进行本地抓包?ctfer测试自搭建靶场必须学会!
自己搭建靶场测试题目是ctfer不可避免的环节,怎么用burp对本地回环即localhost进行抓包?笔者在本篇分享一下自己的解决经验。 笔者用的是Chrome浏览器,如果是火狐浏览器可以参考本篇:Burp Suite抓不到本地包/localhost包问题解决…...

VSCode Python调试运行:json编写
对于需要在命令行传参运行的项目,如果想要调试运行,则需要编写对应的launch.json文件这里记录一下json文件的编写格式: {"version": "0.2.0","configurations": [{"python": "/data/xxx/minic…...

自动化Web页面性能测试介绍
随着越来越多的用户使用移动设备访问 Web 应用,使得 Web 应用需要支持一些性能并不是很好的移动设备。为了度量和测试 Web 应用是不是在高复杂度的情况下,页面性能能满足用户的需求。 同时,随着 Web 应用的空前发展,前端业务逐渐…...

可视化 | 【d3】力导向关系图优化(搜索+刷新)
文章目录 📚优化内容📚html和css优化🐇搜索框部分🐇刷新按钮部分 📚js🐇搜索框部分🐇刷新部分 前期回顾:【d3】力导图优化,本文主要是基于上篇代码,以代码段添…...

2024.1.26力扣每日一题——计算 K 置位下标对应元素的和
2024.1.26 题目来源我的题解方法一 位运算统计二进制数中1的个数方法二 官方的一种优化计算二进制中1的个数的方法 题目来源 力扣每日一题;题序:2859 我的题解 方法一 位运算统计二进制数中1的个数 对于每一个位置i都去计算i对应的二进制数中1的个数 …...

R语言【taxlist】——levels():获取或设置分类等级列表
Package taxlist version 0.2.4 Description 分类层次结构可以设置为 taxlist 对象中的级别,按从低到高的顺序排列。 在 taxlist 对象中为特定分类概念添加分类级别。此外,概念限制的变化可能涉及其分类层次结构的变化。 Usage levels(x)## S3 method…...

单元测试——题目十三
目录 题目要求: 定义类 测试类 题目要求: 根据输入的三条边值判断能组成何种三角形。三条边为变量a、b、c,范围为1≤边值≤10,不在范围内,提示“输入边值不在范围内”。不满足任意两边之和必须大于第三边,提示“输入边值不能组成三角形”。输入边值能组成三角形,只有…...

使用Linux SDK客户端向AWS Iot发送数据
参考链接: https://ap-southeast-1.console.aws.amazon.com/iot/home?regionap-southeast-1#/test 此篇文章用于测试,使用Linux SDK客户端向AWS Iot发送数据,准备环境如下: 1、客户端环境准备 1.1 客户端操作系统 虚拟机一台…...

1.27学习总结
今天做了些队列的题: 1.逛画展(单调队列) 2.打印队列 Printer Queue(优先队列) 3.[NOIP2010 提高组] 机器翻译(模拟队列) 4.求m区间内的最小值(单调队列板子题) 5.日志统计(滑动窗口,双指针) 总结一下&…...

【算法专题】二分查找(进阶)
📑前言 本文主要是二分查找(进阶)的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是青衿🥇 ☁️博客首页:CSDN主页放风讲故事 🌄每日…...

开源项目对于新用户和初学者适合哪些工作
目录 一、阅读和理解文档 二、报告问题 三、测试和验证修复 四、编写和更新文档 五、简单的代码更改和修复 六、参与社区讨论 开源项目对于新用户和初学者来说,提供了宝贵的学习和实践机会。以下是一些适合新用户和初学者参与的工作: 一、阅读和理…...

linux中配置文件目录为什么用etc来命名
在早期的 Unix 系统中,/etc 目录的名称确实来源于单词 “etcetera” 的缩写,最初意味着 “其他”,用来存放杂项或者不属于其他特定目录的文件。然而,随着时间的推移,/etc 目录的用途逐渐演变并专门化。 在现代的 Linux…...

06.领域驱动设计:使用DDD分层架构,可以有效降低层与层之间的依赖
目录 1、概述 2、什么是DDD分层架构 1.用户接口层 2.应用层 3.领域层 4.基础层 3、DDD分层架构最重要的原则是什么 4、DDD分层架构如何推动架构演进 1.微服务架构的演进 2.微服务内服务的演进 5、三层架构如何演进到DDD分层架构 我们该怎样转向DDD分层架构 6、总结…...

HCIA-Datacom实验指导手册:3.2 实验二:生成树基础实验
HCIA-Datacom实验指导手册:3.2 实验二:生成树基础实验 一、实验介绍:二、实验拓扑:三、实验目的:四、配置步骤:步骤 1 掌握启用和禁用 STP/RSTP 的方法步骤 2 掌握修改交换机 STP 模式的方法步骤 3 掌握修改桥优先级,控制根桥选举的方法步骤 4 掌握修改端口优先级,控制…...

WPF的ViewBox控件
在WPF中,ViewBox是一个用于缩放和调整其子元素大小的容器控件。它可以根据可用空间自动调整子元素的大小,以使其适应ViewBox的边界。这使得在不同尺寸的窗口或布局中保持元素的比例和缩放变得更加容易。 ViewBox具有以下重要属性: Stretch&…...

论文精读--BERT
不像视觉领域,在Bert出现之前的nlp领域还没有一个深的网络,使得能在大数据集上训练一个深的神经网络,并应用到很多nlp的任务上 Abstract We introduce a new language representation model called BERT, which stands for Bidirectional En…...

LeetCode第468题 - 验证IP地址
题目 编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。 IPv4 地址由十进制数和点来表示,每个地址包含4个十进制数,其范围为 0 - 255, 用(“.”)分割。比如,172.16.254.1; 同时,IPv4 地址内…...

淘宝API接口调用:案例分析与最佳实践
在电子商务迅猛发展的今天,淘宝作为中国最大的在线购物平台之一,为商家们提供了强大的数据分析和市场洞察工具——淘宝API。有效的API调用不仅可以提升商家的运营效率,还可以帮助商家更好地理解消费者需求、优化商品布局、提高用户满意度等。…...

中仕教育:事业单位考试考什么?
事业单位考试分为两个阶段,分别是笔试和面试,考试科目包括公共科目和专业科目两部分。 公共科目内容是公共基础知识、职业能力测试或申论。一种形式为:公共基础知识职业能力测试或职业能力测试申论。另一种形式为:公共基础申论。…...

python-自动化篇-运维-监控-简单实例-道出如何使⽤Python进⾏系统监控?
如何使⽤Python进⾏系统监控? 使⽤Python进⾏系统监控涉及以下⼀般步骤: 选择监控指标: ⾸先,确定希望监控的系统指标,这可以包括 CPU 利⽤率、内存使⽤情况、磁盘空间、⽹络流量、服务可⽤性等。选择监控⼯具&#x…...