KNN(K 最近邻居)算法 该算法的基本思路是:在给定新文本后,考虑在训练文本集中与该新文本距离最近(最相似)的 K 篇文本,根据这 K 篇文本所属的类别判定新文本所属的类别,具体的算法步骤如下: STEP ONE:根据特征项集合重新描述训练文本向量 STEP TWO:在新文本到达后,根据特征词分词新文本,确定新文本的向量表示 STEP THREE:在训练文本集中选出与新文本最相似的 K 个文本,计算公式为: 其中,K 值的确定目前没有很好的方法,一般采用先定一个初始值,然后根据实验测试的结果调整 K 值,一般初始值定为几百到几千之间。 STEP FOUR:在新文本的 K 个邻居中,依次计算每类的权重,计算公式如下: 其中, 为新文本的特征向量, 为相似度计算公式,与上一步骤的计算公式相同,而 为类别属性函数,即,如果 属于类 ,那么函数值为 1,否则为 0。 STEP FIVE:比较类的权重,将文本分到权重最大的那个类别中。 除此以外,支持向量机和神经网络算法在文本分类系统中应用得也较为广泛,支持向量机的基本思想是使用简单的线形分类器划分样本空间。对于在当前特征空间中线形不可分的模式,则使用一个核函数把样本映射到一个高维空间中,使得样本能够线形可分。 而神经网络算法采用感知算法进行分类。在这种模型中,分类知识被隐式地存储在连接的权值上,使用迭代算法来确定权值向量。当网络输出判别正确时,权值向量保持不变,否则进行增加或降低的调整,因此也称为奖惩法。 |
转自 小橋流水
Knn.h
#pragma once
class Knn
{
private:
double** trainingDataset;
double* arithmeticMean;
double* standardDeviation;
int m, n;
void RescaleDistance(double* row);
void RescaleTrainingDataset();
void ComputeArithmeticMean();
void ComputeStandardDeviation();
double Distance(double* x, double* y);
public:
Knn(double** trainingDataset, int m, int n);
~Knn();
double Vote(double* test, int k);
};
Knn.cpp
#include "Knn.h"
#include <cmath>
#include <map>
using namespace std;
Knn::Knn(double** trainingDataset, int m, int n)
{
this->trainingDataset = trainingDataset;
this->m = m;
this->n = n;
ComputeArithmeticMean();
ComputeStandardDeviation();
RescaleTrainingDataset();
}
void Knn::ComputeArithmeticMean()
{
arithmeticMean = new double[n - 1];
double sum;
for(int i = 0; i < n - 1; i++)
{
sum = 0;
for(int j = 0; j < m; j++)
{
sum += trainingDataset[j][i];
}
arithmeticMean[i] = sum / n;
}
}
void Knn::ComputeStandardDeviation()
{
standardDeviation = new double[n - 1];
double sum, temp;
for(int i = 0; i < n - 1; i++)
{
sum = 0;
for(int j = 0; j < m; j++)
{
temp = trainingDataset[j][i] - arithmeticMean[i];
sum += temp * temp;
}
standardDeviation[i] = sqrt(sum / n);
}
}
void Knn::RescaleDistance(double* row)
{
for(int i = 0; i < n - 1; i++)
{
row[i] = (row[i] - arithmeticMean[i]) / standardDeviation[i];
}
}
void Knn::RescaleTrainingDataset()
{
for(int i = 0; i < m; i++)
{
RescaleDistance(trainingDataset[i]);
}
}
Knn::~Knn()
{
delete[] arithmeticMean;
delete[] standardDeviation;
}
double Knn::Distance(double* x, double* y)
{
double sum = 0, temp;
for(int i = 0; i < n - 1; i++)
{
temp = (x[i] - y[i]);
sum += temp * temp;
}
return sqrt(sum);
}
double Knn::Vote(double* test, int k)
{
RescaleDistance(test);
double distance;
map<int, double>::iterator max;
map<int, double> mins;
for(int i = 0; i < m; i++)
{
distance = Distance(test, trainingDataset[i]);
if(mins.size() < k)
mins.insert(map<int, double>::value_type(i, distance));
else
{
max = mins.begin();
for(map<int, double>::iterator it = mins.begin(); it != mins.end(); it++)
{
if(it->second > max->second)
max = it;
}
if(distance < max->second)
{
mins.erase(max);
mins.insert(map<int, double>::value_type(i, distance));
}
}
}
map<double, int> votes;
double temp;
for(map<int, double>::iterator it = mins.begin(); it != mins.end(); it++)
{
temp = trainingDataset[it->first][n-1];
map<double, int>::iterator voteIt = votes.find(temp);
if(voteIt != votes.end())
voteIt->second ++;
else
votes.insert(map<double, int>::value_type(temp, 1));
}
map<double, int>::iterator maxVote = votes.begin();
for(map<double, int>::iterator it = votes.begin(); it != votes.end(); it++)
{
if(it->second > maxVote->second)
maxVote = it;
}
test[n-1] = maxVote->first;
return maxVote->first;
}
main.cpp
#include <iostream>
#include "Knn.h"
using namespace std;
int main(const int& argc, const char* argv[])
{
double** train = new double* [14];
for(int i = 0; i < 14; i ++)
train[i] = new double[5];
double trainArray[14][5] =
{
{0, 0, 0, 0, 0},
{0, 0, 0, 1, 0},
{1, 0, 0, 0, 1},
{2, 1, 0, 0, 1},
{2, 2, 1, 0, 1},
{2, 2, 1, 1, 0},
{1, 2, 1, 1, 1},
{0, 1, 0, 0, 0},
{0, 2, 1, 0, 1},
{2, 1, 1, 0, 1},
{0, 1, 1, 1, 1},
{1, 1, 0, 1, 1},
{1, 0, 1, 0, 1},
{2, 1, 0, 1, 0}
};
for(int i = 0; i < 14; i ++)
for(int j = 0; j < 5; j ++)
train[i][j] = trainArray[i][j];
Knn knn(train, 14, 5);
double test[5] = {2, 2, 0, 1, 0};
cout<<knn.Vote(test, 3)<<endl;
for(int i = 0; i < 14; i ++)
delete[] train[i];
delete[] train;
return 0;
}