当前位置:   article > 正文

C/C++ 实现K近邻分类算法_c++怎么构建一个近邻分类器或最小距离分类器,并在分类数据集中选择一个开 展实验

c++怎么构建一个近邻分类器或最小距离分类器,并在分类数据集中选择一个开 展实验

K近邻分类算法是机器学习常用的算法之一,很多机器学习库都提供了具体实现,可以直接调用相应的方法。下面用C语言实现该算法,用了一点C++的输入输出语句。

算法思想:现在要预测某个样本的分类结果,首先到预测样本附近找K个最近邻居,然后统计这些邻居的分类,出现频率最高的分类就是预测分类结果。

数据集:海伦约会数据集。每行有4个数据,前3个是样本特征(飞行公里数,玩游戏时间百分比,吃冰激凌公升数),最后1个是分类结果(很喜欢,有点喜欢,讨厌)。原始数据的分隔符是制表符\t。

 C/C++程序如下,函数形参列表有很多数组,站在C语言语法角度,[ ]里的数值都是没用的,目的只是方便知道数组里数据个数。另外,偷了个懒,没有动态申请内存,因为样本数据量不大,栈空间基本够用。

原始数据有1000个样本,选择10%的数据(前100个样本)作为测试数据。代码框架如下(省略了函数的具体实现),主要包括:读txt文件,数据归一化处理,计算测试样本预测准确率,对某个样本进行分类预测。

  1. /k近邻分类器
  2. #include <windows.h>
  3. #include <iostream>
  4. using namespace std;
  5. #define MaxDataNum 1000
  6. #define FileMaxCol 100
  7. #define FeatureNum 3
  8. #define ClassNum 3
  9. #define K 7
  10. #define TestDataRatio 0.1
  11. int FileToArray(const char fileName[], double featureData[MaxDataNum][FeatureNum], int classLabel[MaxDataNum]);
  12. void Normalization(double featureData[MaxDataNum][FeatureNum], double normFeatureData[MaxDataNum][FeatureNum], double range[FeatureNum], double minVal[FeatureNum]);
  13. int Classify(double normOnePersonData[FeatureNum], double normTrainingFeatureData[int(MaxDataNum * (1.0 - TestDataRatio))][FeatureNum], const int trainingClassLabel[int(MaxDataNum * (1.0 - TestDataRatio))]);
  14. void ClassifyTest(double normFeatureData[MaxDataNum][FeatureNum], const int classLabel[MaxDataNum]);
  15. int ClassifyOnePerson(double normOnePersonData[FeatureNum], double normFeatureData[int(MaxDataNum * (1.0 - TestDataRatio))][FeatureNum], const int trainingClassLabel[int(MaxDataNum * (1.0 - TestDataRatio))]);
  16. int main()
  17. {
  18. clock_t t1 = clock();
  19. char fileName[] = "e:\\helenData.txt";
  20. double featureData[MaxDataNum][FeatureNum];
  21. int classLabel[MaxDataNum];
  22. double normFeatureData[MaxDataNum][FeatureNum];
  23. double range[FeatureNum];
  24. double minVal[FeatureNum];
  25. double onePersonData[FeatureNum] = { 0.0 };
  26. double normOnePersonData[FeatureNum] = { 0.0 };
  27. int testDataNum = int(MaxDataNum * TestDataRatio);
  28. double normTrainingFeatureData[int(MaxDataNum * (1.0 - TestDataRatio))][FeatureNum];
  29. int trainingClassLabel[int(MaxDataNum * (1.0 - TestDataRatio))];
  30. FileToArray(fileName, featureData, classLabel);
  31. Normalization(featureData, normFeatureData, range, minVal);
  32. ClassifyTest(normFeatureData, classLabel);
  33. for (int i = testDataNum; i < MaxDataNum; i++)
  34. {
  35. for (int j = 0; j < FeatureNum; j++)
  36. {
  37. normTrainingFeatureData[i - testDataNum][j] = normFeatureData[i][j];
  38. }
  39. trainingClassLabel[i - testDataNum] = classLabel[i];
  40. }
  41. clock_t t2 = clock();
  42. cout << t2 - t1 << "毫秒" << endl;
  43. while (true)
  44. {
  45. cout << "----------------------------------------------" << endl;
  46. cout << "输入每年飞行里程数:" << endl;
  47. cin >> onePersonData[0];
  48. cout << "输入玩视频游戏所耗时间百分比:" << endl;
  49. cin >> onePersonData[1];
  50. cout << "输入每周消费冰激淋公升数:" << endl;
  51. cin >> onePersonData[2];
  52. for (int i = 0; i < FeatureNum; i++)
  53. {
  54. normOnePersonData[i] = (onePersonData[i] - minVal[i]) / range[i];
  55. }
  56. ClassifyOnePerson(normOnePersonData, normTrainingFeatureData, trainingClassLabel);
  57. }
  58. return 0;
  59. }

运行结果如下(1,2,3分别表示讨厌,有点喜欢,很喜欢),100个测试样本错了4个,算法没有问题,一般是样本有问题,比如一个男的,他的3个特征反映出这个男的很优秀,10个女的有9个女的会喜欢这个男的,偏偏有1个女的不喜欢,对于这样一个样本,程序给出的预测结果和真实结果会不一致。

下面用一个冷门的函数式编程语言实现上述算法,使用Spark分布式计算框架。该程序很容易改成鸢尾花预测和手写数字识别程序,只要修改main函数的前5行代码即可。缺点是数据量大的时候,运行速度有点慢,比C语言慢至少2个数量级。

  1. import org.apache.spark.{SparkConf, SparkContext}
  2. import org.apache.spark.rdd.RDD
  3. import scala.collection.mutable.ListBuffer
  4. import scala.io.Source
  5. import java.util.Date
  6. object SparkKNN {
  7. def main(args: Array[String]): Unit = {
  8. val trainingDataFile="E:\\helenTrainingData.txt"
  9. val testDataFile="E:\\helenTestData.txt"
  10. val featureNumber=3
  11. val splitChar="\t"
  12. val K=7
  13. val start_time=new Date().getTime
  14. println("begin")
  15. var source = Source.fromFile(trainingDataFile, "UTF-8")
  16. var lines = source.getLines().toArray
  17. source.close()
  18. val feature_list: Array[ListBuffer[Double]] = new Array[ListBuffer[Double]](featureNumber)
  19. for(i<-0 until featureNumber){
  20. feature_list(i)=new ListBuffer[Double]
  21. }
  22. for (i <- 0 until lines.length) {
  23. val featureArray = lines(i).trim.split(splitChar)
  24. for(j<-0 until featureNumber){
  25. feature_list(j).append(featureArray(j).toDouble)
  26. }
  27. }
  28. //部分代码省略
  29. println("--------------------------------")
  30. println("预测错误次数:"+errorCount)
  31. println("错误率:"+100*errorCount.toDouble/lines.length+"%")
  32. val end_time=new Date().getTime
  33. println(end_time-start_time+"毫秒")
  34. }
  35. }

运行结果和C程序对比:

如果想知道分类预测错误的原因,可以输出相关信息:k个最近邻居的距离值和分类结果,以及这些分类结果的统计情况(每个分类结果出现了几次),例如:

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号