libsvm很早之前就用了,现在封装一下方便自己使用,也方便大家更快的使用这个库,这个库一个挺有用的特性就是对测试样本的概率估计。源码在随笔的最后。liblinear的版本也是类似移植,主要是处理好数据的传入即可。

1.源码

码农最喜欢的稻草了,封装的项目源码,请看附件:CxLibSVM.zip

libsvm源码:libsvm

2.封装的类CxLibSVM

基于libsvm封装的类,如下:

#pragma once
#include <string>
#include <vector>
#include <iostream>
#include "./libsvm/svm.h"
using namespace std;
//内存分配
#define Malloc(type,n) (type *)malloc((n)*sizeof(type)) /************************************************************************/
/* 封装svm */
/************************************************************************/
class CxLibSVM
{
private: struct svm_model* model_;
struct svm_parameter param;
struct svm_problem prob;
struct svm_node * x_space;
public:
//************************************
// 描 述: 构造函数
// 方 法: CxLibSVM
// 文 件 名: CxLibSVM::CxLibSVM
// 访问权限: public
// 返 回 值:
// 限 定 符:
//************************************
CxLibSVM()
{
model_ = NULL;
} //************************************
// 描 述: 析构函数
// 方 法: ~CxLibSVM
// 文 件 名: CxLibSVM::~CxLibSVM
// 访问权限: public
// 返 回 值:
// 限 定 符:
//************************************
~CxLibSVM()
{
free_model();
} //************************************
// 描 述: 训练模型
// 方 法: train
// 文 件 名: CxLibSVM::train
// 访问权限: public
// 参 数: const vector<vector<double>> & x
// 参 数: const vector<double> & y
// 参 数: const int & alg_type
// 返 回 值: void
// 限 定 符:
//************************************
void train(const vector<vector<double>>& x, const vector<double>& y, const struct svm_parameter& param)
{
if (x.size() == )return; //释放先前的模型
free_model(); /*初始化*/
long len = x.size();
long dim = x[].size();
long elements = len*dim; //参数初始化,参数调整部分在这里修改即可
// 默认参数
//param.svm_type = C_SVC; //算法类型
//param.kernel_type = LINEAR; //核函数类型
//param.degree = 3; //多项式核函数的参数degree
//param.coef0 = 0; //多项式核函数的参数coef0
//param.gamma = 0.5; //1/num_features,rbf核函数参数
//param.nu = 0.5; //nu-svc的参数
//param.C = 10; //正则项的惩罚系数
//param.eps = 1e-3; //收敛精度
//param.cache_size = 100; //求解的内存缓冲 100MB
//param.p = 0.1;
//param.shrinking = 1;
//param.probability = 1; //1表示训练时生成概率模型,0表示训练时不生成概率模型,用于预测样本的所属类别的概率
//param.nr_weight = 0; //类别权重
//param.weight = NULL; //样本权重
//param.weight_label = NULL; //类别权重 //转换数据为libsvm格式
prob.l = len;
prob.y = Malloc(double, prob.l);
prob.x = Malloc(struct svm_node *, prob.l);
x_space = Malloc(struct svm_node, elements+len);
int j = ;
for (int l = ; l < len; l++)
{
prob.x[l] = &x_space[j];
for (int d = ; d < dim; d++)
{
x_space[j].index = d+;
x_space[j].value = x[l][d];
j++;
}
x_space[j++].index = -;
prob.y[l] = y[l];
} /*训练*/
model_ = svm_train(&prob, &param);
} //************************************
// 描 述: 预测测试样本所属类别和概率
// 方 法: predict
// 文 件 名: CxLibSVM::predict
// 访问权限: public
// 参 数: const vector<double> & x 样本
// 参 数: double & prob_est 类别估计的概率
// 返 回 值: double 预测的类别
// 限 定 符:
//************************************
int predict(const vector<double>& x,double& prob_est)
{
//数据转换
svm_node* x_test = Malloc(struct svm_node, x.size()+);
for (unsigned int i=; i<x.size(); i++)
{
x_test[i].index = i;
x_test[i].value = x[i];
}
x_test[x.size()].index = -;
double *probs = new double[model_->nr_class];//存储了所有类别的概率
//预测类别和概率
int value = (int)svm_predict_probability(model_, x_test, probs);
for (int k = ; k < model_->nr_class;k++)
{//查找类别相对应的概率
if (model_->label[k] == value)
{
prob_est = probs[k];
break;
}
}
delete[] probs;
return value;
} void do_cross_validation(const vector<vector<double>>& x, const vector<double>& y, const struct svm_parameter& param, const int & nr_fold)
{
if (x.size() == )return; /*初始化*/
long len = x.size();
long dim = x[].size();
long elements = len*dim; //转换数据为libsvm格式
prob.l = len;
prob.y = Malloc(double, prob.l);
prob.x = Malloc(struct svm_node *, prob.l);
x_space = Malloc(struct svm_node, elements + len);
int j = ;
for (int l = ; l < len; l++)
{
prob.x[l] = &x_space[j];
for (int d = ; d < dim; d++)
{
x_space[j].index = d + ;
x_space[j].value = x[l][d];
j++;
}
x_space[j++].index = -;
prob.y[l] = y[l];
} int i;
int total_correct = ;
double total_error = ;
double sumv = , sumy = , sumvv = , sumyy = , sumvy = ;
double *target = Malloc(double, prob.l); svm_cross_validation(&prob, &param, nr_fold, target);
if (param.svm_type == EPSILON_SVR ||
param.svm_type == NU_SVR)
{
for (i = ; i < prob.l; i++)
{
double y = prob.y[i];
double v = target[i];
total_error += (v - y)*(v - y);
sumv += v;
sumy += y;
sumvv += v*v;
sumyy += y*y;
sumvy += v*y;
}
printf("Cross Validation Mean squared error = %g\n", total_error / prob.l);
printf("Cross Validation Squared correlation coefficient = %g\n",
((prob.l*sumvy - sumv*sumy)*(prob.l*sumvy - sumv*sumy)) /
((prob.l*sumvv - sumv*sumv)*(prob.l*sumyy - sumy*sumy))
);
}
else
{
for (i = ; i < prob.l; i++)
if (target[i] == prob.y[i])
++total_correct;
printf("Cross Validation Accuracy = %g%%\n", 100.0*total_correct / prob.l);
}
free(target);
} //************************************
// 描 述: 导入svm模型
// 方 法: load_model
// 文 件 名: CxLibSVM::load_model
// 访问权限: public
// 参 数: string model_path 模型路径
// 返 回 值: int 0表示成功;-1表示失败
// 限 定 符:
//************************************
int load_model(string model_path)
{
//释放原来的模型
free_model();
//导入模型
model_ = svm_load_model(model_path.c_str());
if (model_ == NULL)return -;
return ;
} //************************************
// 描 述: 保存模型
// 方 法: save_model
// 文 件 名: CxLibSVM::save_model
// 访问权限: public
// 参 数: string model_path 模型路径
// 返 回 值: int 0表示成功,-1表示失败
// 限 定 符:
//************************************
int save_model(string model_path)
{
int flag = svm_save_model(model_path.c_str(), model_);
return flag;
} private: //************************************
// 描 述: 释放svm模型内存
// 方 法: free_model
// 文 件 名: CxLibSVM::free_model
// 访问权限: private
// 返 回 值: void
// 限 定 符:
//************************************
void free_model()
{
if (model_ != NULL)
{
svm_free_and_destroy_model(&model_);
svm_destroy_param(&param);
free(prob.y);
free(prob.x);
free(x_space);
}
}
};

3.调用封装的类CxLibSVM

如何调用该类请看如下代码:

#include "cxlibsvm.hpp"
#include <time.h>
#include <iostream>
using namespace std; void init_svm_param(struct svm_parameter& param)
{
//参数初始化,参数调整部分在这里修改即可
// 默认参数
param.svm_type = C_SVC; //算法类型
param.kernel_type = LINEAR; //核函数类型
param.degree = ; //多项式核函数的参数degree
param.coef0 = ; //多项式核函数的参数coef0
param.gamma = 0.5; //1/num_features,rbf核函数参数
param.nu = 0.5; //nu-svc的参数
param.C = ; //正则项的惩罚系数
param.eps = 1e-; //收敛精度
param.cache_size = ; //求解的内存缓冲 100MB
param.p = 0.1;
param.shrinking = ;
param.probability = ; //1表示训练时生成概率模型,0表示训练时不生成概率模型,用于预测样本的所属类别的概率
param.nr_weight = ; //类别权重
param.weight = NULL; //样本权重
param.weight_label = NULL; //类别权重
} void gen_train_sample(vector<vector<double>>& x, vector<double>& y, long sample_num = , long dim = , double scale = )
{
//long sample_num = 200; //样本数
//long dim = 10; //样本特征维度
//double scale = 1; //数据缩放尺度 srand((unsigned)time(NULL));//随机数
//生成随机的正类样本
for (int i = ; i < sample_num; i++)
{
vector<double> rx;
for (int j = ; j < dim; j++)
{
rx.push_back(scale*(rand() % ));
}
x.push_back(rx);
y.push_back();
} //生成随机的负类样本
for (int i = ; i < sample_num; i++)
{
vector<double> rx;
for (int j = ; j < dim; j++)
{
rx.push_back(-scale*(rand() % ));
}
x.push_back(rx);
y.push_back();
}
} void gen_test_sample(vector<double>& x, long sample_num = , long dim = , double scale = )
{
//long sample_num = 200; //样本数
//long dim = 10; //样本特征维度
//double scale = 1; //数据缩放尺度 srand((unsigned)time(NULL));//随机数
//生成随机的正类样本
for (int j = ; j < dim; j++)
{
x.push_back(-scale*(rand() % ));
}
} void main()
{
//初始化libsvm
CxLibSVM svm; //初始化参数
struct svm_parameter param;
init_svm_param(param); /*1、准备训练数据*/
vector<vector<double>> x; //样本集
vector<double> y; //样本类别集
gen_train_sample(x, y, , , ); /*1、交叉验证*/
int fold = ;
param.C = ;
param.svm_type = LINEAR;
svm.do_cross_validation(x, y, param, fold); /*2、训练*/
svm.train(x, y, param); /*3、保存模型*/
string model_path = ".\\svm_model.txt";
svm.save_model(model_path); /*4、导入模型*/
string model_path_p = ".\\svm_model.txt";
svm.load_model(model_path_p); /*5、预测*/
//生成随机测试数据
vector<double> x_test;
gen_test_sample(x_test, , , );
double prob_est;
//预测
double value = svm.predict(x_test, prob_est); //打印预测类别和概率
printf("label:%f,prob:%f", value, prob_est);
}

4.测试模型

模型如下:

svm_type c_svc
kernel_type linear
nr_class
total_sv
rho -0.0379061
label
probA -3.05015
probB 0.103192
nr_sv
SV
0.002455897026356498 : : : : : : : : : :
0.007680247728335155 : : : : : : : : : :
-0.000110773050020484 :- :- :- :- :- :- :- :- :- :-
-0.002310331085133643 :- :- :- :- :- :- :- :- :- :-
-0.001462570160622233 :- :- :- :- :- :- :- :- :- :-
-0.002824751492599935 :- :- :- :- :- :- :- :- :- :-
-0.003207598246179264 :- :- :- :- :- :- :- :- :- :-
-0.0002201207201360932 :- :- :- :- :- :- :- :- :- :-

测试样本的类别如下:

label:1.000000,prob:0.994105  

封装libsvm成可程序调用的C/C++类的更多相关文章

  1. 微信小程序:封装全局的promise异步调用方法

    微信小程序:封装全局的promise异步调用方法 一:封装 function POST(url, params) { let promise = new Promise(function (resol ...

  2. C调用C++(C++封装以及C对其调用)

    C调用C++(C++封装以及C对其调用) 来源 https://blog.csdn.net/wonengguwozai/article/details/89854781 相关知识提点:很经典的exte ...

  3. Python Module_subprocess_子进程(程序调用)

    目录 目录 前言 软件环境 认识subprocess Popen Constructor构造函数 Class Popen的参数 args 调用程序 调用Shell指令 stdinstdoutstder ...

  4. nodejs打包成桌面程序(exe)的进阶之路

    nodejs打包成桌面程序(exe)的进阶之路 node js bat 前端 计划任务 前言:最近的研究,请大佬们细品 第一篇 - 任务计划程序篇 说真的研究到将nodejs打包成可执行的exe文件是 ...

  5. sencha touch打包成安装程序

    为了更好地向大家演示如何打包一个sencha touch的项目,我们用sencha cmd创建一个演示项目,如果你的sencha cmd环境还没有配置,请参照 sencha touch 入门系列 (二 ...

  6. C程序调用shell脚本共有三种方法

    C程序调用shell脚本共有三种法子 :system().popen().exec系列函数call_exec1.c ,内容为:system() 不用你自己去产生进程,它已经封装了,直接加入自己的命令e ...

  7. 【ASP.NET Web API教程】3.3 通过WPF应用程序调用Web API(C#)

    原文:[ASP.NET Web API教程]3.3 通过WPF应用程序调用Web API(C#) 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的 ...

  8. Linux:使用rpcgen实现64位程序调用32位库函数

    摘要:本文介绍使用rpcgent实现64位程序调用32位库函数的方法,并给出样例代码. 我的问题 我的程序运行在64位Linux系统上,需要使用一个从外部获得的共享库中的函数,这个共享库是32位的,无 ...

  9. Java程序调用带参数的shell脚本返回值

    Java程序调用带参数的shell脚本返回值 首先来看看linux中shell变量(\(#,\)@,$0,$1,\(2)的含义解释 变量说明: -  \)$  Shell本身的PID(ProcessI ...

随机推荐

  1. shell 指令分析nginx 日志qps

    实时分析 tail -f points.api.speiyou.cn.access.log|awk 'BEGIN{key="";cnt=0}{if(key==$5){cnt++}e ...

  2. openjudge-NOI 2.5-1700 八皇后问题

    题目链接:http://noi.openjudge.cn/ch0205/1700/ 题解: 经典深搜题目…… #include<cstdio> ][]; int num; void pri ...

  3. overridePendingTransition()使用

    实现两个 Activity 切换时的动画.在Activity中使用有两个参数:进入动画和出去的动画. 注意1.必须在 StartActivity()  或 finish() 之后立即调用.2.而且在 ...

  4. vue总结 01基础特性

    最近有时间来总结一下vue的知识: 一.vue.js 被定义成一个开发web界面的前端库,是一个非常轻量的工具.vue.js本身具有响应式和组件化的特点. 我们不需要在维护视图和数据的统一上花费大量的 ...

  5. 洛谷P3119 草鉴定

    这个题调了一天.. 传送门 读完题目之后我们不难想出这个题是个tarjan缩点问题,因为尽量多的经过草场,所以一号点所在的强连通分量里左右的点都是不需要在进行走逆向边,所能到达的. 然后问题就落在怎么 ...

  6. 一个文件系统过滤驱动的demo

    因为没写过FSD过滤驱动,所以拿来练练手,没有什么技术含量.参考自Win内核安全与驱动开发. 先梳理一下大概的流程,就是怎么去绑定设备栈.怎么去过滤各种请求的. 首先肯定是要绑定设备栈的,来看下怎么绑 ...

  7. git/github 生成密钥

    当从本地提交文件到github的时候,提交不成功,报错,可能问题就是你还没有生成ssh秘钥 github要使用ssh密钥的原因: git使用https协议,每次pull, push都要输入密码,相当的 ...

  8. http://localhost/ 或 http://127.0.0.1/ 报错:HTTP 404 的解决办法

    一些初次接触使用 Eclipse 工具来开发 JAVA Web 工程的开发人员,可能会对 Eclipse 和 Tomcat 的绑定产生一个疑惑. 那就是 在修改了 Tomcat 的8080端口为80后 ...

  9. 记录移动端html界面中底部输入框触发焦点时键盘会把输入框遮挡的问题

      //浏览器当前的高度 var oHeight = $(document).height(); //监听窗口大小的时候动态改变底部输入框控制器的定位 $(window).resize(functio ...

  10. Winsock—I/O模型之选择模型(一)

    Winsock中提供了一些I/O模型帮助应用程序以异步方式在一个或多个套接字上管理I/O. 这样的I/O模型有六种:阻塞(blocking)模型,选择(select)模型,WSAAsyncSelect ...