封装libsvm成可程序调用的C/C++类

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

1.封装的类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)
    {
        if (x.size() == 0)return;

        //释放先前的模型
        free_model();

        /*初始化*/
        long    len = x.size();
        long    dim = x[0].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 = 0;
        for (int l = 0; l < len; l++)
        {
            prob.x[l] = &x_space[j];
            for (int d = 0; d < dim; d++)
            {
                x_space[j].index = d+1;
                x_space[j].value = x[l][d];
                j++;
            }
            x_space[j++].index = -1;
            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()+1);
        for (unsigned int i=0; i<x.size(); i++)
        {
            x_test[i].index = i;
            x_test[i].value = x[i];
        }
        x_test[x.size()].index = -1;
        double *probs = new double[model_->nr_class];//存储了所有类别的概率
        //预测类别和概率
        int value = (int)svm_predict_probability(model_, x_test, probs);
        for (int k = 0; k < model_->nr_class;k++)
        {//查找类别相对应的概率
            if (model_->label[k] == value)
            {
                prob_est = probs[k];
                break;
            }
        }
        delete[] probs;
        return value;
    }

    //************************************
    // 描    述: 导入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 -1;
        return 0;
    }

    //************************************
    // 描    述: 保存模型
    // 方    法: 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);
        }
    }
};

2.调用封装的类CxLibSVM

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

#include "cxlibsvm.hpp"
#include <time.h>
#include <iostream>
using namespace std;
void main()
{
    //初始化libsvm
    CxLibSVM    svm;

    /*1、准备训练数据*/
    vector<vector<double>>    x;    //样本集
    vector<double>    y;            //样本类别集
    long sample_num = 200;        //样本数
    long dim = 10000;    //样本类别
    double scale = 1;    //数据缩放尺度
    srand((unsigned)time(NULL));//随机数
    //生成随机的正类样本
    for (int i = 0; i < sample_num; i++)
    {
        vector<double> rx;
        for (int j = 0; j < dim; j++)
        {
            rx.push_back(scale*(rand() % 10) );
        }
        x.push_back(rx);
        y.push_back(1);
    }

    //生成随机的负类样本
    for (int i = 0; i < sample_num; i++)
    {
        vector<double> rx;
        for (int j = 0; j < dim; j++)
        {
            rx.push_back(-scale*(rand() % 10));
        }
        x.push_back(rx);
        y.push_back(2);
    }

    /*2、训练*/
    svm.train(x, y);

    /*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;
    for (int j = 0; j < dim; j++)
    {
        x_test.push_back(scale*(rand() % 10));
    }
    double prob_est;
    //预测
    double value = svm.predict(x_test, prob_est);

    //打印预测类别和概率
    printf("label:%f,prob:%f", value, prob_est);
}

3.测试模型

模型如下:

svm_type c_svc
kernel_type linear
nr_class 2
total_sv 8
rho -0.0379061
label 1 2
probA -3.05015
probB 0.103192
nr_sv 2 6
SV
0.002455897026356498 1:5 2:0 3:0 4:2 5:4 6:0 7:1 8:4 9:5 10:3
0.007680247728335155 1:2 2:3 3:6 4:0 5:3 6:0 7:1 8:0 9:2 10:1
-0.000110773050020484 1:-1 2:-3 3:-1 4:-2 5:-5 6:-1 7:-2 8:-4 9:-0 10:-6
-0.002310331085133643 1:-1 2:-0 3:-1 4:-2 5:-3 6:-5 7:-5 8:-5 9:-0 10:-4
-0.001462570160622233 1:-5 2:-6 3:-2 4:-9 5:-0 6:-0 7:-2 8:-0 9:-1 10:-0
-0.002824751492599935 1:-0 2:-2 3:-5 4:-0 5:-0 6:-0 7:-3 8:-8 9:-1 10:-0
-0.003207598246179264 1:-2 2:-4 3:-3 4:-1 5:-1 6:-7 7:-1 8:-2 9:-1 10:-1
-0.0002201207201360932 1:-4 2:-2 3:-1 4:-7 5:-0 6:-2 7:-0 8:-4 9:-1 10:-6 

测试样本的类别如下:

label:1.000000,prob:0.994105  

4.源码

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

libsvm源码:libsvm

时间: 2024-11-06 15:08:34

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

WEB程序调用客户端程序

最近一个项目中要点击WEB页面上的链接启动自己编写的程序,而且还要接收参数,google了1.5小时,终于初步试验通过了. 尝试google了:web send message windows form, bs call cs program, custom protocol...多个关键字组合,发现这种技术叫 registered URL protocol,在这篇文章里介绍得比较详细: http://msdn.microsoft.com/en-us/library/aa767914(v=vs.

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

参考页面: http://www.yuanjiaocheng.net/ASPNET-CORE/core-static-files.html http://www.yuanjiaocheng.net/ASPNET-CORE/setup-mvc.html http://www.yuanjiaocheng.net/ASPNET-CORE/mvc-design-pattern.html http://www.yuanjiaocheng.net/ASPNET-CORE/mvc-routing.html h

C#程序调用C++写的dll传递string出现bad ptr

本来是做C/C++的,因为项目需要,所以才搞的C#,说实话,很鄙视做C#的,总结起来,扯淡的DllImport,有本事别用这破玩意,看你C#还能干啥? 参考网上的按照下面的方式来,结果在C++的dll库中打断点,第二个参数怎么都是bad ptr,郁闷至极,耗费了两天的功夫,都没有搞定,也参考了:http://blog.csdn.net/yongshengsilingsa/article/details/7917877 的文章,也无济于事.最后就索性自己再写个简单的dll和exe,只有一个接口,调

如何打出Android程序调用stack trace

找出程序的调用堆栈 trace 可以知道是谁调用了这个接口,也能快速学习程序的调用流程,非常实用.但需要注意的是,不能在正式代码中使用,只能用于调试,这个非常耗资源也会造成 log 泛滥. 下面就介绍如何在 Android Java/C++/C 程序当中打印出程序调用 trace,如果需要在其他环境中使用的话 C++/C 部分需要移植 corkscrew 库. Java 非常简单,创建一个 Throwable 对象,就可以得到当前的 stack trace.下面例子是打出调用 foobar()

C#中参数化命令及程序调用存储过程

1.using(要释放的对象 对象名=new 要释放的对象()){}2.设置参数化命令,避免sql注入 2.1 设置占位符[不要写单引号,名字尽量和字段名保持一致,like时 '%'[email protected]名字+'%'] 2.2 创建SqlParameter对象,给占位符赋值,可以创建单个对象或者数组对象 2.3 command对象的Parameters添加 Add或者AddRange3.程序调用存储过程 3.1 sql语句替换成存储过程名字 3.2 command的CommandTy

如何让本地程序调用并处理基于Django所开发网站的数据库

Django-基于Python的Web开发架构,拥有与SQL查询语句完全分离的数据库处理机制,它可以让不懂SQL语法的开发人员轻松处理数据库内容(包括insert.delete.update等等常用功能). 该文档的需求出发点为: 当有web应用的后台数据需要批量更新时,通常的解决方案是: 1. 将文件整理成数据库table完全适配的格式并使用load(mysql)或copy(postgres)导入 2. 当文件内容需要进行预处理时,这需要一个程序调用数据库接口,边处理边存入 基于解决方案2,将

【工作笔记】没有界面程序调用ActiveX控件

背景 由于chrome浏览器调用ActiveX控件有问题,所以打算使用NPAPI再封装一层,而NPAPI不支持基于MFC的DLL,所以无法用常规的方法将ActiveX控件添加到工程中去. 解决方法 在需要调用OCX的类文件前面加上 #import "C:\\Program Files (x86)\\AnySign\\AnySignReader\\xssinterface.ocx" no_namespace named_guids 编译以后会会生成xssinterface.tlh和xss

sencha touch打包成安装程序

为了更好地向大家演示如何打包一个sencha touch的项目,我们用sencha cmd创建一个演示项目,如果你的sencha cmd环境还没有配置,请参照 sencha touch 入门系列 (二)sencha touch 开发准备 进行配置. 首先在开始->运行中输入cmd,回车,打开命令行工具,cd指令进入到我们的sencha touch的sdk目录中,执行项目创建的指令: 此时在webtest路径中便创建了一个testPackage的项目,我们打开项目中创建生成的packager.js

pyinstaller 打包python文件成.exe程序

使用pycharm写好的代码,每次都要使用pycharm来执行比较麻烦,打包成.exe程序后可以直接运行,还可以发到别的电脑上执行,比较方便. 1.打开cmd命令提示符窗口,cd到pip.exe所在的目录,使用pip.exe install pyinstaller命令安装pyinstaller模块(前提是你的电脑已经安装了python),安装完成后会在目录下生成很多py文件. 2.使用命令pyinstaller -c -F weixin.py生成weixin.exe程序 执行完之后会在当前目录下