基于KNN的手写体数字识别的C++程序实现

最近在写一个大作业,需要用c/c++实现基于KNN的一个小程序,在网上找了找发现大部分都是用python实现的,所以我就收集了一下其他大佬已经写好的素材并进行一部分的修改。基本可以实现需要的所有要求,如有不足欢迎大家提出来进行修正。
实现功能:手写体数字识别
算法:KNN
语言:C/C++
编译工具:VS2017

数据集:train-images-idx3-ubyte.gz   train-labels-idx1-ubyte.gz 
http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz(官方数据集下载地址)

话不多说:
二值化处理后的28*28图片数据集:

作为有监督学习首先定义数字结构体用于存储一个子结构和标签:
/*一个手写数字的结构体*/
typedef struct
{
 int pixel[1024];
 int label;
}Digit;

/*一个有label的距离结构体*/
typedef struct
{
 float distance;
 int label;
}Distance;

加载数据集的实现:
int loadDigit(Digit *digit, FILE *fp, int *labels)
/*读取digit*/
{
 int index = 0;
 for (index = 0; index<784; index++)
 {
  if (!fscanf(fp, "%d", &(digit->pixel[index])))
  {
   printf("FILE already read finish.\n");
   return -1;
  }
 }
 fscanf(fp, "%d", &(digit->label));
 *labels = digit->label;

 return 1;
}

计算欧氏距离代码:

float calDistance(Digit digit1, Digit digit2)

{

int i, squareSum = 0.0;

for (i = 0; i<1024; i++)

{

squareSum += pow(digit1.pixel[i] - digit2.pixel[i], 2.0);

}

return sqrtf(squareSum);

}
用选择排序排序算法对欧式距离进行排序:

void exchange(Distance *in, int index1, int index2)
/*交换字符串两项*/
{
 Distance tmp = (Distance)in[index1];
 in[index1] = in[index2];
 in[index2] = tmp;
}

void selectSort(Distance *in, int length)
/*选择排序*/
{
 int i, j, min;
 int N = length;
 for (i = 0; i<N - 1; i++)
 {
  min = i;
  for (j = i + 1; j<N; j++)
  {
   if (in[j].distance<in[min].distance) min = j;
  }
  exchange(in, i, min);
 }
}


预测结构字代码实现:

int prediction(int K, Digit in, Digit *train, int nt)/*利用训练数据预测一个数据digit*/

{

int i, it;

Distance distance[1133];

for (it = 0; it<nt; it++)

{

distance[it].distance = calDistance(in, train[it]);

distance[it].label = train[it].label;

}

int predict = 0;

int b0[10] = { 0 };

 

selectSort(distance, nt);

for (i = 0; i<K; i++)

{

switch (distance[i].label)

{

case 0:

b0[0]++;

break;

case 1:

b0[1]++;

break;

case 2:

b0[2]++;

break;

case 3:

b0[3]++;

break;

case 4:

b0[4]++;

break;

case 5:

b0[5]++;

break;

case 6:

b0[6]++;

break;

case 7:

b0[7]++;

break;

case 8:

b0[8]++;

break;

case 9:

b0[9]++;

break;

default:

break;

}

}

int max = 0;

for (int m = 0; m < 10; m++) {

if (b0[m] >= max) {

max = b0[m];

predict = m;

}

}

return predict;

}
50个预测值:

当K值取1时模型训练的准确率为:
召回率:
混淆矩阵:




源码下载地址:https://download.csdn.net/download/qq_41910473/10483097
数据集下载地址:https://download.csdn.net/download/qq_41910473/10483113
mnist数据集官方地址:http://yann.lecun.com/exdb/mnist/

对于手写数字识别,K最近邻(K-Nearest Neighbors, KNN)是一种简单而有效的算法。下面是一个用C语言实现KNN手写数字识别的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <math.h> #define K 3 // 设置K值 typedef struct { int label; double features[64]; } Sample; double euclidean_distance(double *a, double *b, int n) { double sum = 0.0; for (int i = 0; i < n; i++) { sum += pow(a[i] - b[i], 2); } return sqrt(sum); } int knn_predict(Sample *train_set, Sample test_sample, int train_size) { double distances[train_size]; int labels[K]; // 计算测试样本与所有训练样本之间的距离 for (int i = 0; i < train_size; i++) { distances[i] = euclidean_distance(train_set[i].features, test_sample.features, 64); } // 根据距离排序,获取K个最近邻样本的标签 for (int i = 0; i < K; i++) { int min_index = 0; for (int j = 1; j < train_size; j++) { if (distances[j] < distances[min_index]) { min_index = j; } } labels[i] = train_set[min_index].label; distances[min_index] = INFINITY; // 将已选择的样本距离设为无穷大,避免再次选择 } // 统计最近邻样本中出现次数最多的标签 int counts[10] = {0}; for (int i = 0; i < K; i++) { counts[labels[i]]++; } int max_count = 0; int predicted_label = 0; for (int i = 0; i < 10; i++) { if (counts[i] > max_count) { max_count = counts[i]; predicted_label = i; } } return predicted_label; } int main() { // 读取训练数据和测试数据 FILE *train_file = fopen("train.txt", "r"); if (train_file == NULL) { printf("无法打开训练文件\n"); return 1; } int train_size; fscanf(train_file, "%d", &train_size); Sample *train_set = (Sample *)malloc(train_size * sizeof(Sample)); for (int i = 0; i < train_size; i++) { fscanf(train_file, "%d", &train_set[i].label); for (int j = 0; j < 64; j++) { fscanf(train_file, "%lf", &train_set[i].features[j]); } } fclose(train_file); FILE *test_file = fopen("test.txt", "r"); if (test_file == NULL) { printf("无法打开测试文件\n"); return 1; } int test_size; fscanf(test_file, "%d", &test_size); Sample *test_set = (Sample *)malloc(test_size * sizeof(Sample)); for (int i = 0; i < test_size; i++) { fscanf(test_file, "%d", &test_set[i].label); for (int j = 0; j < 64; j++) { fscanf(test_file, "%lf", &test_set[i].features[j]); } } fclose(test_file); // 预测并计算准确率 int correct_count = 0; for (int i = 0; i < test_size; i++) { int predicted_label = knn_predict(train_set, test_set[i], train_size); if (predicted_label == test_set[i].label) { correct_count++; } } double accuracy = (double)correct_count / test_size * 100; printf("准确率:%lf%%\n", accuracy); free(train_set); free(test_set); return 0; } ``` 以上代码是一个简单的KNN手写数字识别的实现。你需要准备训练数据和测试数据,将其分别保存在"train.txt"和"test.txt"的文本文件中。训练数据和测试数据的格式如下: ``` 2000 // 样本数量 5 // 标签 0.1 0.2 ... 0.3 // 特征 ... ``` 你可以根据实际情况调整K值和特征维度等参数来提高识别精度。希望能对你有所帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值