您的位置:首页 > 其它

实验二kNN算法之1NN分类

2016-09-26 21:36 447 查看
k-NN处理分类问题,即分类:多数投票原则,先将数据集处理成OneHot矩阵,计算测试文本与每一个训练文本的距离,如果k = 1,则找到最小的距离,则测试文本的分类对应于该训练文本的分类。在用C++实现时,通过好多次的debug,并且将最后生成的OneHot矩阵的每一行都输出到文本中去查看,再在OneHot矩阵每行测试文本尾中输出得到的类比结果,距离,分类。这里使用了欧式距离。

训练文本和测试文本形如:

documentId emotion words

1 5 sad mortar assault leav at least dead

2 4 joy goal delight for sheva

3 4 joy nigeria hostag fear dead is freed

4 3 fear bomber kill shopper

5 6 surprise veget not fruit slow brain declin

6 4 joy pm havana deal a good experi

7 4 joy kate is marri doherti

8 6 surprise nasa revisit life on mar question

9 4 joy happi birthdai ipod

10 4 joy alonso would be happi to retir with three titl

11 4 joy madonna s new tot happi at home in london

12 5 sad nicol kidman ask dad to help stop husband s drink

13 4 joy unit find good connect in win

14 4 joy runwai make good without make nice

15 5 sad we were arrog and stupid over iraq sai us diplomat

16 5 sad bad reason to be good

有246个测试样本,为了方便我在我的源代码中直接使用246这个数字,不过也可以通过读取该文件数行数时得到这个结果,C++实现代码如下:

#include<iostream>
#include<fstream>
#include<map>
#include<vector>
#include<sstream>
#include<cmath>
#include<algorithm>
using namespace std;
struct Three_Var
{
int i,j;
bool operator<(Three_Var& t) {return i<t.i||(i==t.i&&j<t.j);}
bool operator>(Three_Var& t) {return i>t.i||(i==t.i&&j>t.j);}
bool operator==(Three_Var& t) {return i==t.i&&j==t.j;}
};
bool Sort( Three_Var d1,Three_Var d2)//容器的比较函数
{
return d1 < d2;//降序排列
}
vector< vector<int> > NumsPerLines;
int main()
{
int index=0;//依次出现的(去重)词汇的对应下标
int Lines=0;//出现的行数
int ThreeVarNums=0;//三元组的个数
ifstream Input;
Input.open("train.txt");//读取文件
string line;	//一个临时变量而已
map<string, int> FirstIndex;//string是对应的词汇,int是它(无视重复下)第一次出现的在该map中的下标
map<int,int> repeatTimes;
vector<int> NumsOfLines;//每行的词汇个数 (重复不算1个)
vector<Three_Var> smat;
vector<int> Emo;
bool first = true;//因为训练文本第一行没用;
while(getline(Input,line))
{
if(first) {
first = false;
continue;
}
stringstream ss;
int temp,emotion;
//几经周折注意到一个事实:用写字板或者dev_cpp打开时可以清楚地看见是一行一句话的,所以用stringstream
//整行读入的特性会方便很多
ss.clear();
ss.str(line);
ss>>temp;
ss>>emotion;
string dict;
string EMO;
ss>>EMO;
Emo.push_back(emotion); //存储好train.txt每一行的情绪啊!
map<string,int>::iterator it1;
map<int,int>::iterator it2;
repeatTimes.clear();
while(ss>>dict)  //读入每行的数据集内容的词汇
{
it1=FirstIndex.find(dict); //first元素的map查找函数
if(it1==FirstIndex.end())//迭代器到了end(),说明这个词还没出现过
{
FirstIndex.insert(pair<string,int>(dict,index));
index++;  //维护map中的下标
}
it2=repeatTimes.find(FirstIndex[dict]);//计算该词汇在数据集中重复出现的次数
if(it2==repeatTimes.end())//这个下标第一次出现的话,放进这个repaeatTimes<int,int>中
repeatTimes.insert(pair<int,int>(FirstIndex[dict],1));
//第一个整数记录它在map中的下标,第二个整数记录它重复的次数
else
it2->second++;//否则,维护好这个RepeatTimes即可。
temp++;//这行的词汇个数(重复不算1个)
}
//读取完这行词汇了
vector <int> Temp_Vec;
for(it2=repeatTimes.begin();it2!=repeatTimes.end();it2++)  //为了在vector中有序,借用这个map
{
Three_Var item{Lines,it2->first};//利用机构体记录这个单词出现的行数,下标,重复次数
smat.push_back(item);
ThreeVarNums++;//结构体vector中放入的个数
Temp_Vec.push_back(it2->first);//这个结构存储每一行拥有的字符串的下标;
}
NumsPerLines.push_back(Temp_Vec);
Lines++;  //第几行计数
NumsOfLines.push_back(temp);//记录好每行的词汇个数
if(Lines == 246){
first = true;
Input.close();
Input.open("test.txt");
}
}
cout<<Lines<<" "<<index<<endl;
cout<<"有二元组个数"<<ThreeVarNums<<endl;

Input.close();
cout<<"Input operation has done!"<<endl;
//读取完整个文档

//接下来进行处理数据
sort(smat.begin(),smat.end(),Sort);
ofstream OneHot,SMATRIX1;
OneHot.open("OneHot.txt");
SMATRIX1.open("smatrix1.txt"); //三元组矩阵
SMATRIX1<<Lines<<endl<<index<<endl<<ThreeVarNums<<endl;
int pos=0;
int RightNums = 0;
for(int i = 0;i<Lines;i++) //行数
{
/*————————每一行的处理————————*/
for(int j = 0;j < index; j++) //字符串下标
{
if(smat[pos].i==i && smat[pos].j==j)  //匹配到一个字符串出现
{
OneHot<<1<<" ";      //OneHot矩阵为1
SMATRIX1<<i<<" "<<j<<" "<<1<<endl;	//输出到三元组
pos++;//找下一个字符串了
}
else
{
OneHot<<0<<" ";       //不出现,这3个矩阵都是0,三元组则例外
}
/*----————————--处理完一行了----——---*/
}
if(i >= 246){//test.txt来分类咯;
int MinLine = 0, MinDis = 999999;
for(int r = 0; r < 246; r++){ //与训练文本的每一行求欧式距离
if(NumsPerLines[r].size() > 3)
{
int dis = 0, c = 0 , k = 0 , equals = 0;
for(; c < NumsPerLines[i].size() ; c++){ //当前行的字符串
for(; k < NumsPerLines[r].size(); k++){
if(NumsPerLines[i][c] <  NumsPerLines[r][k]){
break;
}
else if(NumsPerLines[i][c] ==  NumsPerLines[r][k]){
equals++;
}
}
}
dis = NumsPerLines[i].size() + NumsPerLines[r].size() - equals * 2;
if(dis < MinDis){
MinDis = dis;
MinLine = r;
//cout<<"smaller, dis = "<<dis<<endl;
}
}
}
OneHot<<"min line = "<<MinLine<<"; MinDis = "<<MinDis<<"; emotion = "<<Emo[MinLine]<<"; ";
if(Emo[MinLine] == Emo[i]) RightNums++;
}
OneHot<<endl;       //每一句新闻后都换行咯
}
ofstream Info;
Info.open("EveryLine.txt");
for(int i = 0 ; i < Lines; i++)
{
Info<<i<<": ";
for(int j = 0 ; j < NumsPerLines[i].size(); j++)
{
Info<<NumsPerLines[i][j]<<" ";
}
Info<<endl;
}
cout<<"File operation has done!"<<endl;
cout<<"The right rate is "<<(double)(RightNums)/1000<<endl;
/*---------------完成操作,关闭文件输出流 ---------------*/
OneHot.close();
SMATRIX1.close();
Info.close();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: