K-近邻法(KNN)的实现

K-近邻法的实现

K-近邻法是根据距离最近的 k 个样例的类型来推测该样例的类型。
实现中中主要的环节有:
·训练样例格式和测试样例格式的定义
·样例结构体的定义
·训练样例和测试样例的读取
·样例距离的计算,欧氏距离
·距离矩阵的生成
·针对每个测试样例,得到其到每个训练样例的距离,根据距离由小到大排序,更具距离和权重成反比的关系,计算每个类型的总的权重,得到最大权重的那个类型,即是当前测试样例的类型
·k 值的选择和设定

训练样本的格式是:
每行代表一个样例,每行的第一个元素是该样例的类型,后面是该样例的特征向量
例如:

train.txt
a    1 2 3 4 5
b    5 4 3 2 1
c    3 3 3 3 3
d    -3 -3 -3 -3 -3
a    1 2 3 4 4
b    4 4 3 2 1
c    3 3 3 2 4
d    0 0 1 1 -2

 


测试样例的格式是:
每行代表一个样例,每行即是该样例的特征向量
例如:
test.txt
1 2 3 2 4
2 3 4 2 1
8 7 2 3 5
-3 -2 2 4 0
-4 -4 -4 -4 -4
1 2 3 4 4
4 4 3 2 1
3 3 3 2 4
0 0 1 1 -2

测试样例的输出结果的格式是:
格式与训练样例一样,即每行代表一个样例,每行的第一个元素是学习到的测试样例的类型,后面是该样例的特征向量
例如:
result.txt
a    1 2 3 2 4 
b    2 3 4 2 1 
b    8 7 2 3 5 
a    -3 -2 2 4 0 
d    -4 -4 -4 -4 -4 
a    1 2 3 4 4 
b    4 4 3 2 1 
c    3 3 3 2 4 
d    0 0 1 1 -2 

具体的程序实现如下:

  1  /*
  2      K-近邻法的实现
  3      mark
  4      goonyangxiaofang@163.com
  5      QQ 591 247 876
  6      2012.02.13
  7  */
  8 
  9 
 10  #include  < iostream >
 11  #include  < string >
 12  #include  < vector >
 13  #include  < set >
 14  #include  < map >
 15  #include  < fstream >
 16  #include  < sstream >
 17  #include  < cassert >
 18  #include  < cmath >
 19  using   namespace  std;
 20 
 21  //  样例结构体,所属类型和特征向量
 22  struct  sample
 23  {
 24       string  type;
 25      vector < double >  features;
 26  };
 27 
 28  //  类型和距离结构体,未用到
 29  struct  typeDistance
 30  {
 31       string  type;
 32       double  distance;
 33  };
 34 
 35  bool   operator   <  ( const  typeDistance &  lhs,  const  typeDistance &  rhs)
 36  {
 37       return  lhs.distance  <  rhs.distance;
 38  }
 39 
 40  //  读取训练样本
 41  //  训练样本的格式是:每行代表一个样例
 42  //  每行的第一个元素是类型名,后面的是样例的特征向量
 43  //  例如:
 44  /*
 45  a    1 2 3 4 5
 46  b    5 4 3 2 1
 47  c    3 3 3 3 3
 48  d    -3 -3 -3 -3 -3
 49  a    1 2 3 4 4
 50  b    4 4 3 2 1
 51  c    3 3 3 2 4
 52  d    0 0 1 1 -2
 53  */
 54  void  readTrain(vector < sample >&  train,  const   string &  file)
 55  {
 56      ifstream fin(file.c_str());
 57       if  ( ! fin)
 58      {
 59          cerr  <<   " File error! "   <<  endl;
 60          exit( 1 );
 61      }
 62       string  line;
 63       double  d  =   0.0 ;
 64       while  (getline(fin, line))
 65      {
 66          istringstream sin(line);
 67          sample ts;
 68          sin  >>  ts.type;
 69           while  (sin  >>  d)
 70          {
 71              ts.features.push_back(d);
 72          }
 73          train.push_back(ts);
 74      }
 75      fin.close();
 76  }
 77 
 78  //  读取测试样本
 79  //  每行代表一个样例
 80  //  每一行是一个样例的特征向量
 81  //  例如:
 82  /*
 83  1 2 3 2 4
 84  2 3 4 2 1
 85  8 7 2 3 5
 86  -3 -2 2 4 0
 87  -4 -4 -4 -4 -4
 88  1 2 3 4 4
 89  4 4 3 2 1
 90  3 3 3 2 4
 91  0 0 1 1 -2
 92  */
 93  void  readTest(vector < sample >&  test,  const   string &  file)
 94  {
 95      ifstream fin(file.c_str());
 96       if  ( ! fin)
 97      {
 98          cerr  <<   " File error! "   <<  endl;
 99          exit( 1 );
100      }
101       double  d  =   0.0 ;
102       string  line;
103       while  (getline(fin, line))
104      {
105          istringstream sin(line);
106          sample ts;
107           while  (sin  >>  d)
108          {
109              ts.features.push_back(d);
110          }
111          test.push_back(ts);
112      }
113      fin.close();
114  }
115 
116  //  计算欧氏距离
117  double  euclideanDistance( const  vector < double >&  v1,  const  vector < double >&  v2)
118  {
119      assert(v1.size()  ==  v2.size());
120       double  ret  =   0.0 ;
121       for  (vector < double > ::size_type i  =   0 ; i  !=  v1.size();  ++ i)
122      {
123          ret  +=  (v1[i]  -  v2[i])  *  (v1[i]  -  v2[i]);
124      }
125       return  sqrt(ret);
126  }
127 
128  //  初始化距离矩阵
129  //  该矩阵是根据训练样本和测试样本而得
130  //  矩阵的行数为测试样本的数目,列数为训练样本的数目
131  void  initDistanceMatrix(vector < vector < double >   >&  dm,  const  vector < sample >&  train,  const  vector < sample >&  test)
132  {
133       for  (vector < sample > ::size_type i  =   0 ; i  !=  test.size();  ++ i)
134      {
135          vector < double >  vd;
136           for  (vector < sample > ::size_type j  =   0 ; j  !=  train.size();  ++ j)
137          {
138              vd.push_back(euclideanDistance(test[i].features, train[j].features));
139          }
140          dm.push_back(vd);
141      }
142  }
143 
144  //  K-近邻法的实现
145  //  设定不同的 k 值,给每个测试样例予以一个类型
146  //  距离和权重成反比
147  void  knnProcess(vector < sample >&  test,  const  vector < sample >&  train,  const  vector < vector < double >   >&  dm, unsigned  int  k)
148  {
149       for  (vector < sample > ::size_type i  =   0 ; i  !=  test.size();  ++ i)
150      {
151          multimap < double string >  dts;
152           for  (vector < double > ::size_type j  =   0 ; j  !=  dm[i].size();  ++ j)
153          {
154               if  (dts.size()  <  k)
155              {
156                  dts.insert(make_pair(dm[i][j], train[j].type));
157              }
158               else
159              {
160                  multimap < double string > ::iterator it  =  dts.end();
161                   -- it;
162                   if  (dm[i][j]  <  it -> first)
163                  {
164                      dts.erase(it);
165                      dts.insert(make_pair(dm[i][j], train[j].type));
166                  }
167              }
168          }
169          map < string double >  tds;
170           string  type  =   "" ;
171           double  weight  =   0.0 ;
172           for  (multimap < double string > ::const_iterator cit  =  dts.begin(); cit  !=  dts.end();  ++ cit)
173          {
174               //  不考虑权重的情况,在 k 个样例中只要出现就加 1
175               //  ++tds[cit->second];
176 
177               //  这里是考虑距离与权重的关系,距离越大权重越小
178              tds[cit -> second]  +=   1.0   /  cit -> first;
179               if  (tds[cit -> second]  >  weight)
180              {
181                  weight  =  tds[cit -> second];
182                  type  =  cit -> second;
183              }
184          }
185          test[i].type  =  type;
186      }
187  }
188 
189  //  输出结果
190  //  输出的格式和训练样本的格式一样
191  //  每行表示一个样例,第一个元素是该样例的类型,后面是该样例的特征向量
192  //  例如:
193  /*
194  a    1 2 3 2 4 
195  b    2 3 4 2 1 
196  b    8 7 2 3 5 
197  a    -3 -2 2 4 0 
198  d    -4 -4 -4 -4 -4 
199  a    1 2 3 4 4 
200  b    4 4 3 2 1 
201  c    3 3 3 2 4 
202  d    0 0 1 1 -2 
203  */
204  void  writeTest( const  vector < sample >&  test,  const   string &  file)
205  {
206      ofstream fout(file.c_str());
207       if  ( ! fout)
208      {
209          cerr  <<   " File error! "   <<  endl;
210          exit( 1 );
211      }
212       for  (vector < sample > ::size_type i  =   0 ; i  !=  test.size();  ++ i)
213      {
214          fout  <<  test[i].type  <<   ' \t ' ;
215           for  (vector < double > ::size_type j  =   0 ; j  !=  test[i].features.size();  ++ j)
216          {
217              fout  <<  test[i].features[j]  <<   '   ' ;
218          }
219          fout  <<  endl;
220      }
221  }
222 
223  //  封装
224  void  knn( const   string &  file1,  const   string &  file2,  const   string &  file3,  int  k)
225  {
226      vector < sample >  train, test;
227      readTrain(train, file1.c_str());
228      readTest(test, file2.c_str());
229      vector < vector < double >   >  dm;
230      initDistanceMatrix(dm, train, test);
231      knnProcess(test, train, dm, k);
232      writeTest(test, file3.c_str());
233  }
234 
235  //  测试
236  int  main()
237  {
238      knn( " train.txt " " test.txt " " result.txt " 5 );
239       return   0 ;
240  }
241 
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值