from:http://www.doczj.com/list_31/
使用libSVM求解分类问题的C++小例
1.libSVM简介
训练模型的结构体
struct svm_problem//储存参加计算的所有样本
{
int l; //记录样本总数
double *y; //指向样本类别的组数 //prob.y = new double[prob.l];
struct svm_node **x;//数据样本 //prob.x = new svm_node[prob.l][] ==>svm_node[index][value] ;
};
当样本类别事先已经被告知时,可以通过数字来给样本数据进行标识(如果是两类通常以1与-1来表示)。如果不清楚样本类别可以用样本个数编号来设置,这时候分类的准确率也就无法判定了。
数据样本是一个二维数组,其中每个单元格储存的是一个svm_node,y与样本数据的对应关系为:
数据节点的结构体
struct svm_node//储存单一向量的单个特征
{
int index; //索引
double value; //值
};
如果需要储存向量,就可以使用6个svm_node来保存,内存映像为:
SVM模型类型枚举
enum { C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR };
◆C_SVC: C表示惩罚因子,C越大表示对错误分类的惩罚越大
◆NU_SVC: 和C_SVC相同。
◆ONE_CLASS: 不需要类标号,用于支持向量的密度估计和聚类.
◆EPSILON_SVR:-不敏感损失函数,对样本点来说,存在着一个不为目标函数提供任何损失值的区域,即-带。
◆NU_SVR:由于EPSILON_SVR需要事先确定参数,然而在某些情况下选择合
适的参数却不是一件容易的事情。而NU_SVR能够自动计算参数。
注意:C_SVC与NU_SVC其实采用的模型相同,但是它们的参数C的范围不同C_SVC采用的是0到正无穷,NU_SVC是[0,1]。
核函数类型枚举
enum { LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED };
◆LINEAR:线性核函数(linear kernel)
◆POLY:多项式核函数(ploynomial kernel)
◆RBF:径向机核函数(radical basis function)
◆SIGMOID:神经元的非线性作用函数核函数(Sigmoid tanh)
◆PRECOMPUTED:用户自定义核函数
计算模型参数结构体
struct svm_parameter
{
int svm_type; //支持向量机模型类型
int kernel_type; //核函数类型
int kernel_type; //核函数类型
int degree; /* 使用于POLY模型*/
double gamma; /* for poly/rbf/sigmoid */
double coef0; /* for poly/sigmoid */
/* these are for training only */
double cache_size; /* 缓存块大小(MB) */
double eps; /* 终止条件(默认0.001) */
double C; /*惩罚因子for C_SVC, EPSILON_SVR and NU_SVR */
int nr_weight; /*权重的数目for C_SVC */
int *weight_label; /* for C_SVC */
double* weight; /* for C_SVC */
double nu; /* for NU_SVC, ONE_CLASS, and NU_SVR */
double p; /* for EPSILON_SVR */
int shrinking; /*指明训练过程是否使用压缩*/
int probability; /*指明是否要做概率估计*/
};
结构体svm_mod el
用于保存训练后的训练模型,当然原来的训练参数也必须保留。
struct svm_model
{
struct svm_parameter param; /*训练参数*/
int nr_class; /*类别数, = 2 in regression/one class svm */
int l; /*支持向量数*/
struct svm_node **SV; /*支持向量的指针*/
double **sv_coef; /*相当于判别函数中的alpha */
double *rho; /*相当于判别函数中的b */
double *probA; /* pariwise probability information */
double *probB; /* for classification only */
int *label; /* label of each class (label[k]) */
int *nSV; /* numbe
r of SVs for each class (nSV[k]) */
int *nSV; /* number of SVs for each class (nSV[k]) */
/* nSV[0] + nSV[1] + ... + nSV[k-1] = l */ int free_sv;
/* 1 if svm_model is created by svm_load_model*/
/* 0 if svm_model is created by svm_train */
};
2.程序代码实现
这里定义SVMExample类,类主要成员变量为:
struct svm_parameter param; //模型参数
struct svm_problem prob;//
struct svm_model *model; //
struct svm_node *x_space; //
构造函数
构造函数里主要进行参数的初始化,和基本函数的调用
param.svm_type = C_SVC;
param.kernel_type = LINEAR;
param.degree = 3;
param.gamma = 0; // 1/num_features
param.coef0 = 0;
param.nu = 0.5;
param.cache_size = 1;//缓存块大小
param.C = 1;
param.eps = 1e-3;
param.p = 0.1;
param.shrinking = 1;
param.probability = 0;
param.nr_weight = 0;
param.weight_label = NULL;
param.weight = NULL;
cross_validation = 0;
核函数的选取直接影响到分类的结果,如何正确选取核函数就需要使用者对数据的特性有所了解,根据实际情况,这里的核函数选用的是线性的。
实例分析
成员函数一:初始化样本数据
样本选取是学生的身
高和体重:
样本选取是学生的身高和体重:
男1:身高:190cm,体重:70kg;
男2:身高:180cm,体重:80kg;
女1:身高:161cm,体重:80kg;
女2:身高:161cm,体重:47kg;
这里由于事先已经知道样本有男女类别之分,所以设置男生标签为-1,女生标签为1,相对于程序中的y值(样本类别)。
void SVMExample::initliazeData()
{struct svm_node **_node = Malloc(struct svm_node*, 4);//分配4个空间存放4个人信息x_space = Malloc(svm_node, 3);//男1:身高:190cm,体重:70kg;x_space[0].index = 1;x_space[0].value = 190;x_space[1].index = 2;x_space[1].value = 70;x_space[2].index = -1; //x_space[2].value = NULL_node[0] = x_space;x_space = Malloc(svm_node, 3); //男2:身高:180cm,体重:80kg;x_space[0].index = 1;x_space[0].value = 180;x_space[1].index = 2;x_space[1].value = 80;x_space[2].index = -1;//x_space[2].value = NULL_node[1] = x_space;x_space = Malloc(svm_node, 3); //女1:身高:161cm,体重:80kg;x_space[0].index = 1;x_space[0].value = 161;x_space[1].index = 2;x_space[1].value = 45;x_space[2].index = -1;//x_space[2].value = NULL_node[2] = x_space;x_space = Malloc(svm_node, 3); //女2:身高:161cm,体重:47kg;x_space[0].index = 1;x_space[0].value = 163;x_space[1].index = 2;x_space[1].value = 47;x_space[2].index = -1;//x_space[2].value = NULL_node[3] = x_space;double *y1 = Malloc(double, 4); y1[0] = -1;y1[1] = -1;y1[2] = 1;y1[3] = 1;prob.l = 4;prob.x = _node;prob.y = y1;
}
成员函数二:训练样本数据,得出模型
void SVMExample::analysisData()
{const char *error_msg;error_msg = svm_check_parameter(&prob,¶m);if(error_msg){fprintf(stderr, "\nerror:%s\n", error_msg);exit(1);}//如果有必要可以进行交叉性检验/*if(cross_validation){do_cross_validation();}*/model = svm_train(&prob, ¶m);
}
成员函数三:预测数据
预测数据1:身高180cm,体重85kg;
预测数据2:身高161cm,体重50kg;
void SVMExample::displayResult()
{//进行预报struct svm_node *node1 = Malloc(svm_node, 3);node1[0].index = 1;node1[0].value = 180;node1[1].index = 2;node1[1].value = 85;node1[2].index = -1;double r1 = svm_predict(model, node1);printf("预测值r1:%f\n", r1);free(node1);struct svm_node *node2 = Malloc(svm_node, 3);node2[0].index = 1;node2[0].value = 161;node2[1].index = 2;node2[1].value = 50;node2[2].index = -1;double r2 = svm_predict(model, node2);printf("预测值r2:%f\n", r2);free(node2);
}
预测结果
得出分类结果:预测样本1的输出为-1(男),预测样本2的输出为1(女)。如果有需要的话请联系:ikuler@http://www.doczj.com/doc/517f7fa1f524ccbff121846b.html