目录

  • KNN算法介绍
  • 欧几里得距离介绍
    • 定义
    • 公式
  • 实现思路
    • 数据集
    • 实现步骤
  • 源码(C语言)
  • 运行结果
  • 源码下载
  • 结尾
  • 参考资料

KNN算法介绍

KNN的全称是K Nearest Neighbors,意思是K个最近的邻居,从这个名字我们就能看出一些KNN算法的蛛丝马迹了。K个最近邻居,毫无疑问,K的取值肯定是至关重要的。那么最近的邻居又是怎么回事呢?其实啊,KNN的原理就是当预测一个新的值x的时候,根据它距离最近的K个点是什么类别来判断x属于哪个类别。听起来有点绕,还是看看图吧。

图中绿色的点就是我们要预测的那个点,假设K=3。那么KNN算法就会找到与它距离最近的三个点(这里用圆圈把它圈起来了),看看哪种类别多一些,比如这个例子中是蓝色三角形多一些,新来的绿色点就归类到蓝三角了。

欧几里得距离介绍

定义

欧几里得距离( Euclidean distance)也称欧式距离,它是一个通常采用的距离定义,它是在m维空间中两个点之间的真实距离。

公式

二维:d=(x2−x1)2+(y2−y1)2二维:d=\sqrt{(x_2-x_1)^2+(y_2-y_1)^2} 二维:d=(x2​−x1​)2+(y2​−y1​)2​
n维:d(x,y)=∑i=1n(xi−yi)2n维:d(x,y)=\sqrt{\sum_{i=1}^{n}(x_i-y_i)^2} n维:d(x,y)=i=1∑n​(xi​−yi​)2​
我们用到n维的

实现思路

数据集

特征值的类别数:即花萼长度、花萼宽度、花瓣长度、花瓣宽度。
三种鸢尾花:setosa、versicolor、virginica。
(部分)

实现步骤

① 读取数据,打乱数据(或者随机读取数据),并把每种花分别设置A、B、C标签。
② 分割数据(共150组,分55组为测试集,95组为训练集)。
③遍历K(1≤K≤15,K%2≠0)K(1\leq K \leq 15,K\%2\neq0)K(1≤K≤15,K%2​=0)值。
④ 计算测试集数据对所有训练数据的距离(用欧几里得距离),将计算好的距离训练集标签绑定在一块进行保存。
⑤ 对保存好的 (距离,训练集标签) 从小到大排序,取前KKK个(即距离最近的邻居数),统计其训练集标签 出现的频数。
⑥ 将频数最高的训练集标签保存到预测标签结果集中,判断预测标签原有测试集标签是否相等,相等即为预测正确,统计数量。
⑦ 计算概率(预测标签正确的总数量 / 测试集总数),打印结果。
⑧ 重复③④⑤⑥⑦,直到遍历完所有KKK值。

!!!完整的代码以及数据文件我会全部打包分享在文章结尾!!!

源码(C语言)

头文件:

/*** @file KNN.h* @author 大熊人 (daxiongren@foxmail.com)* @brief 头文件* @version 1.0* @date 2021-11-28* @copyright Copyright (c) 2021*/
#ifndef __KNN_H
#define __KNN_H
#define TOTAL 150      // 总数据的数量
#define TEST_SIZE 55   // 测试数据的数量
#define TRAIN_SIZE 95  // 训练数据的数量
#define N 4            // 特征数据的数量(维数)
#define KN 15          // K的最大取值/* 距离结构体 */
typedef struct {double value;  // 距离数据char label;    // 用于绑定训练集标签
} Distance;/* 鸢尾花结构体 */
typedef struct {double value[N];  // 每种花的4个特征数据char type[20];    // 存放花的种类char label;       // 用于设置标签 为了方便检测
} Iris;/* 函数接口声明 */
void labelABC(char *type, char *label);
void makeRand(Iris iris[], int n);
void openDataFile(char *path);
void printData();
void loadData();
double EuclideanDistance(double d1[], double d2[], int n);
char compareLabel(int a, int b, int c);
char countLabel(int *count, int k, char forecastLabel);
int cmp(const void *d1, const void *d2);
void printResult(int k, int count);#endif

======================================================================================================
源文件:

/*** @file KNN.cpp* @author 大熊人 (daxiongren@foxmail.com)* @brief 用KNN算法简单实现对鸢尾花分类* @version 1.0* @date 2021-11-28* @copyright Copyright (c) 2021*/
#include "KNN.h"#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>Iris testSet[TEST_SIZE];        // 测试集结构体数组
Iris forecastSet[TEST_SIZE];    // 保存预测的标签
Iris trainSet[TRAIN_SIZE];      // 训练集结构体数组
Iris temp[TOTAL];               // 临时存放数据结构体数组
Distance distance[TRAIN_SIZE];  // 存放距离结构体数组/*** @brief 把不同种类的花分别转化成 A B C 标签* @param type[IN] 花的种类* @param label[OUT] 转化的标签*/
void labelABC(char *type, char *label) {if (strcmp(type, "\"setosa\"") == 0) *label = 'A';if (strcmp(type, "\"versicolor\"") == 0) *label = 'B';if (strcmp(type, "\"virginica\"") == 0) *label = 'C';
}/*** @brief 利用伪随机数进行数据打乱* @param iris* @param n*/
void makeRand(Iris iris[], int n) {Iris t;int i, n1, n2;srand((unsigned int)time(NULL));  //获取随机数的种子,百度查下用法for (i = 0; i < n; i++) {n1 = (rand() % n);  //产生n以内的随机数  n是数组元素个数n2 = (rand() % n);/* 若两随机数不相等 则下标为这两随机数的数组进行交换 */if (n1 != n2) {t = iris[n1];iris[n1] = iris[n2];iris[n2] = t;}}
}/*** @brief 打开数据文件* @param path 数据文件的路径*/
void openDataFile(char *path) {int i, j;// 用于先存放150个数据后再打乱FILE *fp = NULL;fp = fopen(path, "r");for (i = 0; i < TOTAL; i++) {for (j = 0; j < N; j++) {fscanf(fp, "%lf ", &temp[i].value[j]);}fscanf(fp, "%s", temp[i].type);/* 把不同种类的花分别转化成 A B C 标签 */labelABC(temp[i].type, &temp[i].label);}makeRand(temp, TOTAL);  //打乱所有数据fclose(fp);fp = NULL;
}/*** @brief 把分割后的数据都打印出来  便于观察是否已经打乱*/
void printData() {int i, j;printf("\n设置标签 -> 打乱 -> 按%d/%d分割\n", TEST_SIZE, TRAIN_SIZE);printf("数据如下:\n\n");printf("%d组测试集:\n", TEST_SIZE);for (i = 0; i < TEST_SIZE; i++) {for (j = 0; j < N; j++) {printf("%.2lf ", testSet[i].value[j]);}printf("%c\n", testSet[i].label);}printf("\n\n%d组训练集:\n", TRAIN_SIZE);for (i = 0; i < TRAIN_SIZE; i++) {for (j = 0; j < N; j++) {printf("%.2lf ", trainSet[i].value[j]);}printf("%c\n", trainSet[i].label);}
}/*** @brief 加载数据  分割:测试TEST_SIZE组   训练TRAIN_SIZE组*/
void loadData() {int i, j, n = 0, m = 0;for (i = 0; i < TOTAL; i++) {/* 先将TEST_SIZE个数据存入测试集 */if (i < TEST_SIZE) {for (j = 0; j < N; j++) {testSet[n].value[j] = temp[i].value[j];  //存入花的四个特征数据}testSet[n].label = temp[i].label;  //存入花的标签n++;} else { /* 剩下的数据存入训练集 */for (j = 0; j < N; j++) {trainSet[m].value[j] = temp[i].value[j];  //存入花的四个特征数据}trainSet[m].label = temp[i].label;  //存入花的标签m++;}}
}/*** @brief 计算欧几里得距离* @param d1* @param d2* @param n 维数* @return double*/
double EuclideanDistance(double d1[], double d2[], int n) {double result = 0.0;int i;/* 欧几里得距离 */for (i = 0; i < n; i++) {result += pow(d1[i] - d2[i], 2.0);}result = sqrt(result);return result;  //返回距离
}/*** @brief 比较三个标签出现的频数* @param a* @param b* @param c* @return char 返回出现的频数最多的标签*/
char compareLabel(int a, int b, int c) {if (a > b && a > c) {return 'A';}if (b > a && b > c) {return 'B';}if (c > a && c > b) {return 'C';}return 0;
}/*** @brief 统计与测试集距离最邻近的k个标签出现的频数* @param count[OUT] 用于统计* @param k[IN] 当前K值* @param forecastLabel[IN] 训练集的预测标签* @return 返回频数最高的标签*/
char countLabel(int *count, int k, char forecastLabel) {int i;int sumA = 0, sumB = 0, sumC = 0;  //分别统计距离最邻近的三类标签出现的频数for (i = 0; i < k; i++) {switch (distance[i].label) {case 'A':sumA++;break;case 'B':sumB++;break;case 'C':sumC++;break;}}/* 检测出现频数最高的标签与测试集的预测标签是否相等 */char maxLabel = compareLabel(sumA, sumB, sumC);if (maxLabel == forecastLabel) {(*count)++;  //统计符合的数量}return maxLabel;
}/* 快速排序qsort函数的cmp回调函数 */
int cmp(const void *d1, const void *d2) {Distance D1 = *(Distance *)d1;Distance D2 = *(Distance *)d2;return D1.value > D2.value ? 1 : -1;
}/*** @brief 打印结果* @param k K值* @param count 预测正确的总数量*/
void printResult(int k, int count) {int i;printf("对比结果:\n");/* 打印每个K值对应的概率 */printf("K = %d     P = %.2lf%%\n", k, (100.0 * count) / TEST_SIZE);printf("原有标签:");printf("[%c", testSet[0].label);for (i = 1; i < TEST_SIZE; i++) printf(",%c", testSet[i].label);printf("]\n");printf("预测标签:");printf("[%c", forecastSet[0].label);for (i = 1; i < TEST_SIZE; i++) printf(",%c", forecastSet[i].label);printf("]\n\n");
}int main() {int i, j;int k;          // k值int count = 0;  //用于统计预测正确的标签数量/* openDataFile("你的数据文件路径")* 如果放在代码文件路径下那就直接写文件名(建议写绝对路径) */openDataFile("./iris.txt");  // 打开数据文件 -> 打乱数据loadData();                  // 加载打乱后的数据并分割printData();                 // 打印数据printf("\n\n测试集:%d组  训练集:%d组\n\n", TEST_SIZE, TRAIN_SIZE);for (k = 1; k <= KN; k += 2) {  // k值:1--KN(取奇数)  KN = 15(宏定义)for (i = 0; i < TEST_SIZE; i++) {       // 遍历测试集for (j = 0; j < TRAIN_SIZE; j++) {  // 遍历训练集/* 把计算欧几里得距离依次存入distance结构体数组的value中 */distance[j].value =EuclideanDistance(testSet[i].value, trainSet[j].value, N);/* 将训练集标签与计算好的距离绑定在一块 */distance[j].label = trainSet[j].label;}/* 用qsort函数从小到大排序(距离,训练集标签) */qsort(distance, TRAIN_SIZE, sizeof(distance[0]), cmp);/* 统计与测试集标签距离最邻近的k个标签出现的频数* 并返回频数最后高标签 即预测的标签 */forecastSet[i].label = countLabel(&count, k, testSet[i].label);}/* 打印结果 */printResult(k, count);count = 0;  // 重置}getchar();return 0;
}

运行结果

(部分)

对于每一个K(1≤K≤15,K%2≠0)K(1\leq K \leq 15,K\%2\neq0)K(1≤K≤15,K%2​=0)值,预测正确的概率:

源码下载

github地址:https://github.com/daxiongren/IrisClassification-KNNAlgorithm
百度网盘:https://pan.baidu.com/s/10dU6l52M_vjNpBIbIj6Fvw
提取码: rh2d

结尾

本人能力有限,如有错误之处望大家海涵并不吝指正!

参考资料

1.深入浅出KNN算法(一) KNN算法原理
2.欧几里得度量

KNN算法实现鸢尾花数据集分类 C语言实现(附数据集)相关推荐

  1. KNN算法实现鸢尾花的分类

    题目 原生python实现knn分类算法,用鸢尾花数据集. 题目分析 KNN算法: 准备数据:来源百度下载鸢尾花数据集,共150组数据,将数据分为训练数据和测试数据,训练数据为120组,测试数据为30 ...

  2. 用python实现KNN算法对鸢尾花的分类

    一.KNN算法 邻近算法,或者说K最近邻(kNN,k-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一.所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接 ...

  3. KNN算法实现鸢尾花数据集分类

    KNN算法实现鸢尾花数据集分类 作者介绍 数据集介绍 KNN算法介绍 用KNN实现鸢尾花分类 作者介绍 乔冠华,女,西安工程大学电子信息学院,2020级硕士研究生,张宏伟人工智能课题组. 研究方向:机 ...

  4. KNN算法解决鸢尾花分类案例

    KNN算法解决鸢尾花分类案例 本文分别通过KNN底层算法实现和sklearn中的KNeighbors Classifier(K近邻分类模拟)和对3中不同的鸢尾花的分类. 一.K近邻(KNN)算法介绍 ...

  5. Knn算法实现鸢尾花分类

    文章目录 前言 引例 KNN算法实现鸢尾花分类 1获取数据 2划分数据集 3特征工程:标准化数据 4模型训练 5模型评估 总结 前言 近朱者赤近墨者黑,物以类聚人以群分.KNN算法就是计算和别人和自己 ...

  6. 使用KNN算法对鸢尾花种类预测

    使用KNN算法对鸢尾花种类预测 一. 数据集介绍 1.1 小数据集获取 load_* 1.2 大数据集获取 fetch_* 1.3 查看数据分布 seaborn画图的 二. 数据集的划分 三. 特征工 ...

  7. 机器学习:KNN算法对鸢尾花进行分类

    机器学习:KNN算法对鸢尾花进行分类 1.KNN算法的理解: 1.算法概述 KNN(K-NearestNeighbor)算法经常用来解决分类与回归问题, KNN算法的原理可以总结为"近朱者赤 ...

  8. k近邻算法_K近邻(knn)算法是如何完成分类的?

    摘要:K近邻算法是机器学习中的一个非常基础的算法.本文通过自生成数据,通过绘图的方式演示KNN算法的思路,让你不看数学公式就看了解什么是KNN算法. 关键词:KNN算法 1 生成一个二分类的数据集 本 ...

  9. 【基础机器学习算法原理与实现】使用感知器算法LDA、最小二乘法LSM、Fisher线性判别分析与KNN算法实现鸢尾花数据集的二分类问题

    本文设计并实现了PerceptronLA.PseudoIA.LeastSM.LinearDA.KNN等五个算法类,以及DataProcessor的数据处理类.对感知器算法LDA.最小二乘法LSM的伪逆 ...

  10. Python原生代码实现KNN算法(鸢尾花数据集)

    一.作业题目 Python原生代码实现KNN分类算法,使用鸢尾花数据集. KNN算法介绍: K最近邻(k-Nearest Neighbor,KNN)分类算法,是机器学习算法之一. 该方法的思路是:如果 ...

最新文章

  1. 理解和认识udev(转载)
  2. 抽象类(c++细节篇九)
  3. 垂直居中 absolute 和 flex 方法
  4. 今晚包饺子吗?会露馅的那种......
  5. mount挂载时 no such device_mount系统调用(vfs_kern_mount-gt;mount_fs-gt;fill_super)
  6. C++/C--NULL与nullptr【转载】
  7. 笨办法学 Linux 8~11
  8. centos7 python3 爬虫登陆邮箱_Centos7搭建Scrapy爬虫环境
  9. 8086的两种工作模式_在线式UPS工作模式
  10. SLAM学习笔记-------------(八)视觉里程计2
  11. 网页爬虫实例一(网页截屏)
  12. 二分排序(java)
  13. arcgis怎么压缩tif文件_PDF文件怎么压缩才能变小?这样压缩,真的很简单!
  14. Word批量替换勾选框
  15. 粒子追踪 matlab,粒子追踪软件 - 研究粒子与场的相互作用
  16. Andriod中插入百度广告的使用
  17. 【NCRE】---拼接SQL语句(Case....When语句)
  18. un1que成员介绍
  19. mysql usleep_usleep
  20. 大文件分块计算MD5值 C++实现

热门文章

  1. C语言 switch 条件语句
  2. RMF模型评分制计算方法(2021/08/04)
  3. 柴静穹顶之下 感想
  4. 【重磅首发新品】AM335x全面升级处理器——AM62x,四核Cortex-A53+M4F,主频1.4GHz
  5. 第十届蓝桥杯省赛Scratch编程真题解析
  6. linux环境下安装cwp的地震专业软件su
  7. c编程语言real,20 种最奇怪的编程语言
  8. 计算机桌面上的声音图标没了怎么办,电脑声音图标不见了怎么办超详细教程
  9. 【DDD】领域驱动设计实践 —— Application层实现
  10. 翻转单词顺序(python)