QT+VS实现Kmeans++

1、Kmeans++的原理如下:

(1)首先选取样本中任一数据点作为第一个聚类中心;

(2)计算样本每一个数据点至现所有聚类中心的最近距离,并记录下来;

(3)逐一挑选所有数据点最近距离之中的最大值,即最远距离,最大值对应的数据点为待求聚类中心;

(4)剔除已选为聚类中心的样本点,重新计算(2)、(3)步骤,得到指定的最终的聚类中心点数。

2、实现结果如下:

 

 

注:当噪点太多时,初始K个聚类中心的计算会出现偏差,从而导致整个聚类结果出现偏差。

3、原始数据读入格式如下:

点号-X坐标-Y坐标(非此格式的数据无法正常读入,程序会报错)

4、根据Kmeans++选择k个初始聚类中心的Kmeans聚类算法整体代码如下:

//Kmeans.cpp文件
#include "Kmeans.h"

Kmeans::Kmeans(QWidget *parent)
    : QWidget(parent)
{
    start = false;
    //dd = blank;
    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();
    //}

    CalK();

    CalDis();//S
    Calcentroid();//用到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();
    //drawK();
    QMessageBox box;
    box.setText("计算完成");
    box.exec();
    qDebug() << "k" << k.size();
    //for (int i = 0; i < S.size(); i++)
    //{
    //    qDebug() << "S:" <<S.at(i).no<< S.at(i).noK;
    //}
    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;
        double x1 = p.at(i).x;
        double y1 = p.at(i).y;
        //double x = k.at(0).x;
        //double y = k.at(0).y;
        //s0 = sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y));
        for (int j = 0; j < k.size(); j++)
        {
            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);
}

void Kmeans::CalK()
{
    k.push_back(p.at(0));
    CalDistance();

    while (k.size() != K)
    {
        qDebug() << k.size() << k.at(k.size() - 1).no;
        S.clear();
        CalDistance();

        for (auto& val : k)
        {
            qDebug() << "CalK.k1" << val.no << val.x << val.y;
        }
        std::vector<Pointp> vk; int t3 = k.size();
        while (vk.size() != t3)
        {
            Pointp p9 = k.at(0); int t2 = 0;
            for (int i = 1; i < k.size(); i++)
            {
                Pointp p2 = k.at(i);
                if (p9.no.toInt() < k.at(i).no.toInt())
                {
                    p9 = k.at(i);
                    t2 = i;
                }
            }
            k.erase(k.begin() + t2);//删除下标为t2的元素;
            vk.push_back(p9);
        }

        for (int i = vk.size() - 1; i >= 0; i--)
        {
            k.push_back(vk.at(i));
        }

        for (auto& val : k)
        {
            qDebug() <<"CalK.k" << val.no << val.x << val.y;
        }


        int cv = 1;
        for (auto& val : k)
        {
            S.erase(S.begin() + (val.no.toInt() - cv));//删除下标为val.number的元素;
            cv++;
        }

        double s0 = 0;
        Pointp kk;
        kk = { 0,0,0 };
        for (auto& valS : S)
        {
            if (s0 <= valS.s)
            {
                s0 = valS.s;
                kk.no = valS.no;
                kk.x = valS.x;
                kk.y = valS.y;
            }
        }
        k.push_back(kk);
    }

    int count = 1;
    for (auto& val : k)
    {
        val.no = count;
        count++;
        //qDebug() << val.no << val.x << val.y;
    }
}

void Kmeans::drawK()
{
    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);

    QColor color = QColor(123,223,46);

    for (int i = 0; i < k.size(); i++)
    {
        pen.setColor(color);
        pen.setWidth(3);
        painterP.setPen(pen);
        int radius = 10;
        double x = k.at(i).x;
        double y = k.at(i).y;
        x = (x - xmin) * a;
        y = (y - ymin) * b1;
        painterP.drawEllipse(x - radius, y - radius, radius * 2, radius * 2);
    }

    ui.label_2->setPicture(pp);
}

void Kmeans::CalDistance()
{
    Dis ss;
    for (auto& valP : p)
    {
        double s0 = 0; int c = 1;
        double x1 = valP.x;
        double y1 = valP.y;
        for (auto& valK : k)
        {
            double x2 = valK.x;
            double y2 = valK.y;

            x2 = x2 - x1;
            y2 = y2 - y1;

            double s = sqrt(x2 * x2 + y2 * y2);

            if (c == 1)
            {
                s0 = s;
                ss.no = valP.no;
                ss.noK = valK.no;
                ss.x = valP.x;
                ss.y = valP.y;
                ss.s = s;
                c++;
            }

            if (s0 == 0)
            {
                ss.no = valP.no;
                ss.noK = valK.no;
                ss.x = valP.x;
                ss.y = valP.y;
                ss.s = s;
                break;
            }

            if (s < s0)
            {
                s0 = s;
                ss.no = valP.no;
                ss.noK = valK.no;
                ss.x = valP.x;
                ss.y = valP.y;
                ss.s = s;
            }
        }
        S.push_back(ss);
    }
}

#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>
#include <algorithm>

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_OBJECT

public:
    Kmeans(QWidget *parent = nullptr);
    ~Kmeans();

public slots:
    void onBtReadData();
    int onBtCalKmeans();
    void onBtReadK();

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();
    void CalK();
    void drawK();
    void toK();
    void CalDistance();

private:
    Ui::KmeansClass ui;
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】引用、内联函数、auto关键字等

前言&#xff1a;在前面我们讲解了C入门基础的一些学习例如命名空间、缺省参数、函数重载等。今天我们将进一步的学习&#xff0c;跟着博主的脚步再次往前迈一步吧。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:高质量&#xff23;学习…

SpringBoot 源码解析 - 持续更新

开始 spring initilizer&#xff1a;根据依赖构建工具、springboot 版本等生成 Java 工程。手把手教你手写一个最简单的 Spring Boot Starter Starter 命名规则 Spring 官方定义的 Starter 通常命名遵循的格式为 spring-boot-starter-{name}&#xff0c;例如 spring-boot-star…

目标检测数据集制作(VOC2007格式数据集制作和处理教程)

VOC2007数据集结构&#xff08;目标检测图像分割&#xff09; #VOC2007数据集结构如下&#xff1a; VOC2007|-Annotations#里面存放的是每一张图片对应的标注结果&#xff0c;为XML文件&#xff0c;#标注完成后JPEGImages每张图片在此都有一一对应的xml文件|-ImageSets#存放的是…

uniapp v3组合式语法-项目创建

打开uni编译器HbuildX,右键新建项目,出现如下界面 输入完项目名称和地址后.选择红色箭头所指处的vue版本3 然后点击确认,即可创建uniapp,v3项目 创建完项目后,可以看到如下项目结构 项目结构uniapp官网上已经写的很详细了,这里就使用uniapp官网的介绍 一个uni-app工程&…

用BufferedReader快速输入有巨坑!!大佬们都是这么输入的

刷洛谷题单第二天&#xff0c;今天第一道题还是挺简单的&#xff0c;但是又被现实给了一级大逼兜子&#xff0c;做这题关键还是想熟悉Java的快速输入。还有做这道题很容易出现RE错误&#xff0c;下面总结了常见的RE错误导致情况&#xff08;点击跳转下文&#xff09; 我的上篇…

增存量市场大爆发!国产通信中间件「反攻」

梳理2023年智能驾驶的发展脉络可见&#xff0c;消费者对智能驾驶的认可度和接受度越来越高&#xff0c;带动高速NOA迈向了规模化普及新阶段&#xff0c;城市NOA初露锋芒。 从更长远的行业变革周期来看&#xff0c;智能驾驶的技术迭代还在继续&#xff0c;叠加电子电气架构的深…

软件测试人员常用的功能测试方法分享

功能测试就是对产品的各功能进行验证&#xff0c;根据功能测试用例&#xff0c;逐项测试&#xff0c;检查产品是否达到用户要求的功能。 常用的测试方法如下&#xff1a; 1. 页面链接检查 每一个链接是否都有对应的页面&#xff0c;并且页面之间切换正确。 2. 相关性检查 删除/…

基于springboot的房屋交易系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

工业自动化步进电机用电机驱动芯片TMC5160

TMC5160 数据手册 TMC5160 集成了完整的运动控制功能、高质量的电流调节功能和强大的外部 MOSFET 驱动&#xff0c;涵盖了多种从电池供电的高效系统到 20 安培电机线圈电流的嵌入式应用。TMC5160 包含驱动电机所需的全部智能。配置 TMC5160 目 标 位 置 就 可 以 驱 动 电 机 。…

C++初阶:C/C++内存管理、new与delete详解

之前结束了类与对象&#xff1a;今天进行下面部分内容的学习 文章目录 1.C/C内存分布2.C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free3.C动态内存管理方式3.1new/delete操作内置类型3.2new和delete操作自定义类型 4.operator new与operator delete函数5.new和…

题目:冒险者公会(蓝桥OJ 3611)

问题描述&#xff1a; 解题思路&#xff1a; 官方&#xff1a; 注意点&#xff1a; 在前期的排序操作&#xff0c;因为需要找到如样例所示的每轮最大&#xff0c;因此我们需要用0代替没有的委托&#xff08;即样例斜杠&#xff09;。如何用0代替&#xff1a;将村庄委托数量默认…

基于springboot校园交友网站源码和论文

随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&#xf…

ArcgisForJs快速入门

文章目录 0.引言1.前端代码编辑工具2.使用ArcgisForJs创建一个简单应用3.切片地图服务图层4.动态地图服务图层5.地图事件 0.引言 ArcGIS API for JavaScript是一款由Esri公司开发的用于创建WebGIS应用的JavaScript库。它允许开发者通过调用ArcGIS Server的REST API&#xff0c…

C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现

C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现 —— 杭州 2024-01-28 code review! 文章目录 C++笔记之RTTI、RAII、MVC、MVVM、SOLID在C++中的表现1.RTTI、RAII、MVC、MVVM、SOLID简述2.RAII (Resource Acquisition Is Initialization)3.RTTI (Run-Time Type Informat…

ABeam Insight | 大语言模型系列 (1) : 大语言模型概览

大语言模型系列 引入篇 ABeam Insight 自从图灵测试在20世纪50年代提出以来&#xff0c;人类一直不断探索机器如何掌握语言智能。语言本质上是一个由语法规则支配的错综复杂的人类表达系统。 近年来&#xff0c;具备与人对话互动、回答问题、协助创作等能力的ChatGPT等大语…

江科大stm32学习笔记6——GPIO输入准备

一、按键消抖 由于按键内部使用的是机械式弹簧片&#xff0c;所以在按下和松开时会产生5~10ms的抖动&#xff0c;需要通过代码来进行消抖。 二、滤波电容 在电路中&#xff0c;如果见到一端接在电路中&#xff0c;一端接地的电容&#xff0c;则可以考虑它的作用为滤波电容&am…

python爬虫实战——获取酷我音乐数据

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 开发环境: 版 本&#xff1a; python 3.8 编辑器&#xff1a;pycharm 2022.3.2 模块使用: requests >>> pip install requests 如何安装python第三方模块: win R 输入 cmd 点击确定, 输入安装命令 pip install…

职业身份来认同自己对吗?

人们常常以自己的职业身份来认同自己。这是一个巨大的错误。 你的职业身份只是一个外壳&#xff1b;它不能定义你是一个人。你可以期待你的职业媒介会随着时间而改变&#xff0c;但是你传达的信息会应该更加稳定。你的信息就是回答你是谁&#xff0c;你应该通过三十几年的工作…

linux中常用的命令

一&#xff1a;tree命令 &#xff08;码字不易&#xff0c;关注一下吧&#xff0c;w~~w) 以树状形式查看指定目录内容。 tree --树状显示当前目录下的文件信息。 tree 目录 --树状显示指定目录下的文件信息。 注意&#xff1a; tree只能查看目录内容&#xff0c;不能…

【Axure高保真原型】随机抽取案例

今天和大家分享随机抽取点餐案例的原型模板&#xff0c;包括2种效果&#xff0c;第一种是手动暂停效果&#xff0c;点击开始后随机抽取食物&#xff0c;手动点击暂停按钮后停止&#xff1b;第二种是自动暂停效果&#xff0c;点击开始按钮后随机抽取食物&#xff0c;并且开始倒计…