C++实现KNN和K-Means

 学校机器学习课程的实验课要求实现KNN和K-Means:

 

 (平时没听课)临时去查了一下KNN和K-Means是啥,然后自己用C++写了小例子,想着写都写了那就把代码贴出来吧。

顺便再聊聊自己对于这俩算法的理解。

下面是文心一言的回答。

首先这俩都是分类算法,我们需要根据已经拥有的数据来对新数据进行分类。

KNN是把这个新数据扔到已有的数据里,然后找出K个距离这个新数据最近的以后数据,如果K个数据中大部分都是A类,那么我们就认为这个新数据是A类。

代码中我是自己定义了一个类来作为数据,一共有两个元素,可以把数据看作的二维的坐标点,然后要分类新数据的时候就对所有已有数据点来计算距离,然后挑出距离最近的K个点,按照类型的占比来对新数据的类型进行预测。

代码写得比较冗余,但是应该还算是好理解的(毕竟注释都写出来了)。

#include <iostream>
#include <vector>
#include <random>
#include<chrono>using namespace std;//自定义数据类型,共有两个参数
class mydata {
public:int val1;int val2;int type;mydata(int val1=0,int val2=0,int type=0):val1(val1),val2(val2),type(type) {//cout << "type is" << type << "\tval1 is" << val1 << "\tval2 is" << val2 << endl;}
};vector<vector<mydata>>Data_19(3,vector<mydata>(100));		//3分类,每类100个的数据集
vector<vector<mydata>>Validation_19(3, vector<mydata>(10));	//3分类,每类10个的验证集void CreateData() {default_random_engine e;									//默认的随机数引擎生成无符号整型e.seed(chrono::duration_cast<chrono::microseconds>(chrono::system_clock::now().time_since_epoch()).count());		//设置随机数种子uniform_int_distribution<unsigned int> type1_1(0,100);		//类型1的val1的随机数范围	uniform_int_distribution<unsigned int> type1_2(100,150);	//类型1的val2的随机数范围	uniform_int_distribution<unsigned int> type2_1(30,130);		//类型2的val1的随机数范围	uniform_int_distribution<unsigned int> type2_2(130,180);	//类型2的val2的随机数范围	uniform_int_distribution<unsigned int> type3_1(50,150);		//类型3的val1的随机数范围	uniform_int_distribution<unsigned int> type3_2(160,210);	//类型3的val2的随机数范围	for (int i = 0; i < 100; ++i) {//随机生成三个类型的数据Data_19[0][i] = mydata(type1_1(e),type1_2(e),1);Data_19[1][i] = mydata(type2_1(e),type2_2(e),2);Data_19[2][i] = mydata(type3_1(e),type3_2(e),3);if (i < 10) {//随机生成三个类型的验证集Validation_19[0][i] = mydata(type1_1(e), type1_2(e), 1);Validation_19[1][i] = mydata(type2_1(e), type2_2(e), 2);Validation_19[2][i] = mydata(type3_1(e), type3_2(e), 3);}}
}int myKNN(int k,int val1,int val2) {//定义大小为300,元素为pair(可以存放两个元素)的数组,每个元素存放数据集的数据的类型以及与待预测数据的欧式距离vector<pair<int, int>>distance_types(300);//初始化数组存放的类型for (int i = 0; i < 100; ++i) distance_types[i].first = 1;for (int i = 100; i < 200; ++i) distance_types[i].first = 2;for (int i = 200; i < 300; ++i) distance_types[i].first = 3;for (int i = 0; i < 3; ++i) {for (int j = 0; j < 100; ++j) {//计算欧式距离 distance_types[100 * i + j].second = sqrt(pow(Data_19[i][j].val1-val1,2)+pow(Data_19[i][j].val2-val2,2));}}//按照欧式距离排序sort(distance_types.begin(), distance_types.end(), [&](auto& a,auto& b) {return a.second < b.second;});//大小为3的数组,用来记录与待预测数据最近的K个数据是什么类型的vector<int>count(3);for (int i = 0; i < k; ++i) {count[distance_types[i].first - 1]++;}//将接近待预测数据最多的类型返回if (count[0] >= count[1] && count[0] >= count[2]) return 1;if (count[1] >= count[0] && count[1] >= count[2]) return 2;return 3;
}void check(int K) {						//KNN算法中的近邻数double right = 0, worry = 0;		//用于记录KNN预测的正确数以及错误数for (int n = 0; n < 100; ++n) {		//进行一百轮CreateData();					//调用生成数据集以及验证集的函数for (int i = 0; i < 3; ++i) {for (int j = 0; j < 10; ++j) {//如果预测成功则增加正确数,反之增加错误数if (myKNN(K, Validation_19[i][j].val1, Validation_19[i][j].val2) == Validation_19[i][j].type) ++right;else ++worry;}}}cout << "K is " << K << "\t\tright count: " << right << "\tworry count: " << worry << "\taccuracy is: " << right / (right + worry) << endl;
}int main(void) {for (int k = 3; k <= 10; ++k) {check(k);}return 0;
}

K-Means的K是指我们需要把已有的数据集划分成K类。

首先我们先初始化K个锚点,随便初始化(当然效果不会好),一个锚点算是单独一个类型,然后计算所有数据点到这K个锚点之间的距离,如果数据点到某个锚点最近,那么就把这个数据点划分为这个锚点的类型。

计算完毕之后,再把每个锚点下的所有数据点取平均值再赋给锚点,这样锚点就被更新到这个类型的数据点集的中心位置了。

接着再重复刚才的过程,直到锚点的坐标不再改变,那么我们就说K-Means收敛了。

完毕之后我们就得到了K个锚点。

来新数据的时候我们只需要计算新数据和这个K个锚点之间的距离,把新数据归类到最近的锚点下就完成了分类。

刚才的KNN是在分类新数据的时候要进行大量计算(计算新数据与所有老数据的距离),而K-Means是在一开始初始化的时候进行大量计算。

代码中没有像KNN那样新建一个类型来表示数据,但是每个数据还是有两个元素,可以看作是二维平面上的坐标点。

#include <iostream>
#include <vector>
#include <random>
#include <chrono>
#include <unordered_map>using namespace std;vector<vector<int>>Datas;
int N = 100;										//随机生成数据的数量
int K = 5;											//分成K类
unordered_map<char, vector<vector<int>>> M;			//用于划分数据的类
default_random_engine e;							//默认的随机数引擎生成无符号整型
uniform_int_distribution<int> u(0,100);				//控制随机数生成范围void CreateDatas_09() {//随机生成100个数据	for (int i = 0; i < N; ++i) {Datas.push_back({ u(e),u(e) });}
}void K_Means_09(int K) {vector<vector<int>>K_Sources(K);		//存放K个聚点vector<vector<int>>temp_K_Sources(K);	//用于比较是否和上次聚点的坐标一致vector<pair<double,char>>cache(K);		//临时存放数据与聚点的距离int epoch = 0;CreateDatas_09();						//调用函数生成数据集//随机初始生成K个聚点for (int i = 0; i < K; ++i) K_Sources[i]={ u(e),u(e) };while (1) {temp_K_Sources = K_Sources;			//保存当前聚点的数据,用于判断是否收敛M.clear();for (int i = 0; i < N; ++i) {for (int j = 0; j < K; ++j) {//计算欧式距离cache[j] = { sqrt(pow(K_Sources[j][0] - Datas[i][0],2) + pow(K_Sources[j][1] - Datas[i][1],2)) ,'A' + j };}//排序数据与每个聚点的距离sort(cache.begin(), cache.end(), [](auto& a,auto& b){return a.first < b.first;});//如果哈希表中没有此类聚点的键,那么添加if (M.find(cache[0].second) == M.end()) M[cache[0].second] = vector<vector<int>>(0);//分配数据到相应的类M[cache[0].second].push_back(Datas[i]);}cout << "epoch is:" << epoch++ << endl;for (int i = 0; i < K; ++i) {//重新计算聚点数据int x = 0, y = 0;//累加所有数据的值for (auto& a : M['A' + i]) {x += a[0];y += a[1];}//取平均值作为新聚点K_Sources[i][0] = x / M['A' + i].size();K_Sources[i][1] = y / M['A' + i].size();cout << static_cast<char>('A' + i) << "类的聚点:\t" << K_Sources[i][0] << "\t" << K_Sources[i][1] << endl;}//如果聚点与上次的结果相同,那么收敛,结束迭代if (temp_K_Sources == K_Sources) break;}
}int main(void) {//设置时间戳保证每次随机的数据都不同e.seed(chrono::duration_cast<chrono::microseconds>(chrono::system_clock::now().time_since_epoch()).count());K_Means_09(K);cout << "----------------------------------分割线------------------------------------------" << endl;//打印分类的结果for (int i = 0; i < K; ++i) {cout << static_cast<char>('A' + i) << "类包含的点:" << endl;for (auto& a : M['A' + 1]) cout << a[0] << '\t' << a[1] << endl;}return 0;
}

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

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

相关文章

十年诉讼,迈瑞真的赢了吗?

迁延十年&#xff0c;迈瑞与科曼的知识产权纠纷案究竟要如何解读&#xff1f; 发端于2013年&#xff0c;两家国内医疗器械行业知名公司间的专利互诉官司&#xff0c;成为全行业最具代表性的案例。但这一案例本质并不复杂&#xff1a;不过商业利益之争。 要在烈度不断抬升的市…

项目管理PMP6.0-五大过程组、十大知识领域、四十九个过程(记忆码:7664363734)

项目管理PMP6.0-五大过程组、十大知识领域、四十九个过程&#xff08;记忆码&#xff1a;7664363734&#xff09; 项目经理的影响力范围三者关系图&#xff08;五大过程组、十大知识领域、四十九个过程&#xff09;五大过程组十大知识领域十大知识领域之间联系 四十九个过程&am…

如何通过提升客户体验带来更大的增长、更好的客户留存率?

客户期望的转变 在一个日益数字化的世界里&#xff0c;有必要采取以客户为中心的思维方式。因为客户与企业互动的方式有很多是在数字空间发生的&#xff0c;客户的需求和模式已经转变。 这种情况已经酝酿了几年&#xff0c;但在2020年才打开闸门。随着疫情的爆发&#xff0c;企…

FTX的前世今生:崛起、辉煌与崩塌

FTX&#xff0c;一度被誉为加密货币领域的明星交易所&#xff0c;其快速的崛起和令人瞩目的崩塌吸引了全球的关注。让我们回顾一下FTX的前世今生&#xff0c;了解其短暂的辉煌和骤然的崩塌。 1. 崛起&#xff1a; FTX的创始人山姆班克曼-弗里德在加密货币领域具有深厚的背景和…

Linux主机间的相互免秘钥

主机间的相互免秘钥 1.生成密钥 ssh-keygen -t rsa -P -f ~/.ssh/id_rsa运行以上命令后会在 ~/.ssh/ 目录下生成一对密钥对。 2.拷贝公钥 把自己的公钥传递给对方主机即可&#xff0c;这个公钥文件必须放在对方主机的~/.ssh/authorized_keys 文件中。 ssh-copy-id -i ~/.s…

智能座舱架构与芯片 - (2) 架构篇

一、定义 1.1 智能座舱定义 按照百度百科的定义&#xff0c;智能座舱&#xff08;intelligent cabin&#xff09;旨在集成多种IT和人工智能技术&#xff0c;打造全新的车内一体化数字平台&#xff0c;为驾驶员提供智能体验&#xff0c;促进行车安全。目前国内外已经有很多研究…

Django ORM 执行复杂查询的技术与实践

概要 Django ORM&#xff08;Object-Relational Mapping&#xff09;是 Django 框架的核心组件之一&#xff0c;提供了一种高效、直观的方式来处理数据库操作。尽管简单查询在 Django ORM 中相对容易实现&#xff0c;但在面对复杂的数据请求时&#xff0c;需要更深入的了解和技…

【文末送书】深入浅出嵌入式虚拟机原理

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

「Verilog学习笔记」含有无关项的序列检测

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 timescale 1ns/1ns module sequence_detect(input clk,input rst_n,input a,output reg match);reg [8:0] a_tem ; always (posedge clk or negedge rst_n) begin if (~rs…

maven打包项目,然后给其他项目引用

A项目&#xff08;这个项目需要被打包&#xff0c;作为被引入的项目&#xff09;&#xff0c;不需要启动类&#xff0c;因为作为公共模块被B项目引入&#xff1a; package com.yunya.mvndependontest.rest;import org.springframework.web.bind.annotation.RequestMapping; im…

SpringDoc枚举字段处理与SpringBoot接收枚举参数处理

本期内容 添加SpringDoc配置展示枚举字段&#xff0c;在文档页面中显示枚举值和对应的描述添加SpringMVC配置使项目可以接收枚举值&#xff0c;根据枚举值找到对应的枚举 默认内容 先不做任何处理看一下直接使用枚举当做入参是什么效果。 定义一个枚举 package com.exampl…

0基础学习VR全景平台篇第122篇:VR视频剪辑和输出 - PR软件教程

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 开始之前如果没有接触过pr这款软件的话&#xff0c;建议先去看上一篇 认识视频剪辑软件Premiere 大致了解一下pr。 回到正题今天来教大家VR视频的剪辑和输出 我们先双击打开…

喜讯 | 聚铭下一代智慧安全运营中心入选2023年江苏省大数据产业发展试点示范项目

近日&#xff0c;江苏省工信厅公示2023年江苏省大数据产业发展试点示范项目名单。聚铭下一代智慧安全运营中心凭借扎实的技术实力和突出的产品优势成功入选。 为推动新兴数字产业集群建设&#xff0c;夯实大数据产业发展基础&#xff0c;提升产业供给能力和行业赋能效应&…

AD9361寄存器功能笔记之本振频率设定

LO的产生过程如图&#xff1a; 各个模块都有高灵活性。 1、参考时钟即是AD9361全局参考时钟&#xff0c;可以是外接晶振的片上DCXO&#xff0c;或是外部输入的有驱动能力的时钟信号。根据FM-COMMS5的设计&#xff0c;参考时钟可以使用时钟Buffer 40MHz晶振构成的参考频率源。 …

人工智能基础部分21-神经网络中优化器算法的详细介绍,配套详细公式

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能基础部分21-神经网络中优化器算法的详细介绍&#xff0c;配套详细公式。本文将介绍几种算法优化器&#xff0c;并展示如何使用PyTorch中的算法优化器&#xff0c;我们将使用MNIST数据集和一个简单的多层感知…

Vue 2使用element ui 表格不显示

直接修改package.json文件 把这两个依赖修改成对应的 删除node_modules 重新安装依赖 重启

VMware Workstation系列:Win11运行VMware延迟卡顿(侧通道缓解相关)

一. Win11运行VMware延迟卡顿 最近在使用VMware时&#xff0c;开机提示如下&#xff1a; 您在运行该虚拟机时启用了侧通道缓解。侧通道缓解可增强安全性&#xff0c;但也会降低性能。 要禁用缓解&#xff0c;请在虚拟机设置的“高级”面板中更改侧通道缓解设置。有关更多详细信…

电巢科技广州科技贸易职业学院高速PCB设计工程师训练营圆满结班!

为深化校企合作&#xff0c;产教融合助力新工科建设&#xff0c;提升学生工程实践能力&#xff0c;电巢工程能力实训班按照不同岗位类别&#xff0c;匹配对应的企业岗位任职能力要求对学生开展分级培养&#xff0c;以产业需求为导向&#xff0c;培养创新型、应用型人才。 11月1…

无法创建 8192 MB 的匿名分页文件: 系统资源不足,无法完成请求的服务。

好久没用VMware Workstation&#xff0c;今天突然要用&#xff0c;发现所有的虚机在启动的时候提示都提示&#xff1a; 无法创建 XXXX MB 的匿名分页文件&#xff1a;页面文件太小&#xff0c;无法完成操作。 未能分配主内存。 模块"MainMem"启动失败。 未能启动…

PDF Reader Pro 3.0.1.0(pdf阅读器)

PDF Reader Pro是一款功能强大的PDF阅读、注释、填写表单&签名、转换、OCR、合并拆分PDF页面、编辑PDF等软件。 它支持多种颜色的高亮、下划线&#xff0c;可以按需选择&#xff0c;没有空白处可以进行注释&#xff0c;这时候便签是你最佳的选择&#xff0c;不点开时自动隐…