#ifndef KNN_H_
#define KNN_H_
#include<opencv2/opencv.hpp>
#include<string>
using cv::Mat;
using std::string;
class knn
{
public:
knn(string path = " ");
int classify0(Mat inX, Mat dataSet, Mat labels, int labelNum, int k);
bool file2matrix(Mat& dataSet, Mat& label);
void autoNorm(Mat& dataSet);
~knn(){};
private:
string dataPath;
};
#endif
#include"knn.h"
#include<iostream>
#include<vector>
#include<algorithm>
#include<fstream>
#include<sstream>
#include<string>
using std::string;
using std::vector;
using std::cout;
using std::endl;
using namespace cv;
knn::knn(string path):dataPath(path){}
int knn::classify0(Mat inX, Mat dataSet, Mat labels,int labelNum, int k)
{
Mat temp(dataSet.size(), dataSet.type());
for (int i = 0; i < dataSet.rows; i++)
{
inX.row(0).copyTo(temp.row(i));
}
Mat diffMat = temp - dataSet;
Mat sqDiffMat = diffMat.mul(diffMat);
Mat sqDistances(sqDiffMat.rows, 1, CV_32F);
reduce(sqDiffMat, sqDistances, 1, CV_REDUCE_SUM);
Mat distances;
sqrt(sqDistances, distances);
Mat index;
sortIdx(distances, index, CV_SORT_EVERY_COLUMN + CV_SORT_ASCENDING);
vector<int>classCount(labelNum,0);
for (int i = 0; i < k; i++)
{
int minIndex = index.at<int>(i, 0);
int label = labels.at<float>(minIndex, 0);
classCount[label]++;
}
int maxVal = classCount[0];
int resultLabel = 0;
for (int i = 1; i < labelNum; i++)
{
if (maxVal < classCount[i])
{
maxVal = classCount[i];
resultLabel = i;
}
}
return resultLabel;
}
bool knn::file2matrix(Mat& dataSet, Mat& labels)
{
std::ifstream file;
file.open(dataPath);
if (!file.is_open())
{
cout << "read fail..." << endl;
return false;
}
string s;
vector<Mat>vecData;
vector<Mat>vecLabels;
while (std::getline(file, s))
{
std::istringstream data(s);
float s1;
Mat temp1(1, 3, CV_32F);
Mat temp2(1, 1, CV_32F);
int count = 0;
while (data >> s1)
{
if (count != 3)
temp1.at<float>(0, count) = s1;
else
temp2.at<float>(0, 0) = s1;
count++;
}
vecData.push_back(temp1);
vecLabels.push_back(temp2);
}
dataSet.create(vecData.size(), 3, CV_32F);
labels.create(vecLabels.size(), 1, CV_32F);
for (int i = 0; i < vecData.size(); i++)
{
vecData[i].copyTo(dataSet.row(i));
vecLabels[i].copyTo(labels.row(i));
}
return true;
}
void knn::autoNorm(Mat& dataSet)
{
for (int i = 0; i < dataSet.cols; i++)
{
normalize(dataSet.col(i), dataSet.col(i), 0, 1, NORM_MINMAX);
}
}
float datingClassTest(string path)
{
knn a(path);
Mat dataSet, labels;
a.file2matrix(dataSet, labels);
a.autoNorm(dataSet);
float hoRatio = 0.1;
int num = dataSet.rows * hoRatio;
int errorCount = 0;
Mat testDataSet = dataSet(Range(0, num), Range(0, 3));
Mat testLabels = labels(Range(0, num), Range(0, 1));
Mat trainDataSet = dataSet(Range(num,dataSet.rows), Range(0, 3));
Mat trainLabels = labels(Range(num, dataSet.rows), Range(0, 1));
for (int i = 0; i < num; i++)
{
float predictLabel = a.classify0(testDataSet.row(i), trainDataSet, trainLabels, 4,4);
if (predictLabel != testLabels.at<float>(i, 0))
errorCount++;
}
float error = float(errorCount) / num;
cout << "the total error is :" << error;
return error;
}
int main()
{
string path = "E:/c++工程/knn/Ch02/datingTestSet2.txt";
datingClassTest(path);
system("pause");
}