- 首先来看一下Libsvm的模型训练部分:采用为One-against-one的策略假如有1,2,3,4个类可以(1,2)(1,3)(1,4)(2,3)(2,4)(2,4)可以得到n(n-1)/2个决策函数,当进来一个样本采用对1,2,3,4进行投票进行选择,看属于哪个类。
- /**
- * Libsvm的模型训练函数
- * @param prob 输入的问题
- * @param param 输入的参数
- * @return 训练好的模型
- */
- public static svm_model svm_train(svm_problem prob, svm_parameter param)
- {
- /**为了代码的简洁性,此处删除了部分**/
- /**
- * 此处省略了部分代码:这里的代码主要做:
- * 1、统计类别总数,同时记录类别的标号,统计每个类的样本数目
- * 2、计算权重C
- * 3、初始化nozero数组,便于统计SV
- * 4、初始化概率数组
- */
- svm_model model = new svm_model();
- // 获取先关参数比如惩罚值
- model.param = param;
- // 将属于同一个类别的数据组织起来
- svm_group_classes(prob,tmp_nr_class,tmp_label,tmp_start,tmp_count,perm);
- //采用one-against-one进行分类
- int p = 0;
- //定义决策函数数组,将每一个而分类存储起来得到决策函数
- decision_function[] f = new decision_function[nr_class*(nr_class-1)/2];
- for(i=0;i<nr_class;i++)
- for(int j=i+1;j<nr_class;j++)
- //重新定义每个决策的svm_problem,主要用于重新训练一个新的决策函数,共有类数*(类数-1)/2
- svm_problem sub_prob = new svm_problem();
- //计算第i个类与第j个类的起始位置与数目。由于每个类都是存储在一起的,所有要获取每个类的起始地址,再根据每个类有多少样本,才能从样本节点中获取值
- int si = start[i], sj = start[j];
- int ci = count[i], cj = count[j];
- sub_prob.l = ci+cj; 得到2个类的样本数
- //将第i个类的标签定义为+1,第j个类的标签定义为-1
- for(k=0;k<ci;k++)
- {
- sub_prob.x[k] = x[si+k];
- sub_prob.y[k] = +1;
- }
- for(k=0;k<cj;k++)
- {
- sub_prob.x[ci+k] = x[sj+k];
- sub_prob.y[ci+k] = -1;
- }
- //对第i个类与第j个类采用二分类策略,训练模型,根据新的sub_prob进行训练
- f[p] = svm_train_one(sub_prob,param,weighted_C[i],weighted_C[j]);
- ++p;
- }
- /**
- * 此处省略了部分代码:这里的代码主要做:
- * 1、统计一下nozero,如果nozero已经是真,就不变,如果为假,则改为真
- * 2、输出模型,主要是填充svm_model
- */
- return model;
- }
-
- 然后再来看一下其模型预测部分:
-
- /**
- * Libsvm模型预测部分,预测该样本的类标签以及属于该类的分值。
- * 这里采用的方法为投票策略
- * @param model 已训练好的Libsvm模型
- * @param x 一个待预测的样本向量
- * @param dec_values 保存预测结果的向量,其维度为k*(k-1)/2
- * @return
- */
- public static double svm_predict_values(svm_model model, svm_node[] x, double[] dec_values)
- {
- //对一些变量进行初始化
- int i;
- int nr_class = model.nr_class; //总的类数
- int l = model.l; //支持向量总个数
- double[] kvalue = new double[l]; //每个类别的支持向量存储在一起
- //根据模型中的支持向量以及内核函数计算数值
- for(i=0;i<l;i++)
- kvalue[i] = Kernel.k_function(x,model.SV[i],model.param); //进来的测试样本与每个支持向量进行内积
- int[] start = new int[nr_class];
- start[0] = 0;
- for(i=1;i<nr_class;i++)
- start[i] = start[i-1]+model.nSV[i-1]; //得到每个类别的起始地址,有利于方便获取相应类别的核函数的值
- //初始化vote向量
- int[] vote = new int[nr_class];
- for(i=0;i<nr_class;i++)
- vote[i] = 0; //每个类的投票为0
- //依次计算k*(k-1)/2个二分类模型的预测值
- int p=0;
- for(i=0;i<nr_class;i++)
- for(int j=i+1;j<nr_class;j++)
- {
- double sum = 0;
- int si = start[i];
- int sj = start[j];
- int ci = model.nSV[i]; //得到每个类的支持向量个数,方便得到每个类别的核函数的值
- int cj = model.nSV[j];
- //根据决策函数计算每一个二分类对样本预测的分值
- int k;
- double[] coef1 = model.sv_coef[j-1];
- double[] coef2 = model.sv_coef[i];
- for(k=0;k<ci;k++)
- sum += coef1[si+k] * kvalue[si+k];
- for(k=0;k<cj;k++)
- sum += coef2[sj+k] * kvalue[sj+k];
- sum -= model.rho[p];//b
- //dec_values存储的就是第p个二分类模型对样本的预测值
- dec_values[p] = sum; //最后的预测值
- //根据dec_values 值的正负决定给那个类别投票
- if(dec_values[p] > 0)
- ++vote[i];
- else
- ++vote[j];
- p++;
- }
- //遍历vote向量,找出具有最大投票数的所对应类别即为所预测的类标签。
- //而dec_values则存储了k*(k-1)/2个二分类模型的预测值
- int vote_max_idx = 0;
- for(i=1;i<nr_class;i++)
- if(vote[i] > vote[vote_max_idx])
- vote_max_idx = i;
- return model.label[vote_max_idx]; //得到投票最多的类别,就是要分到的类别。
- }
libsvm简单代码解释
最新推荐文章于 2018-04-30 20:43:17 发布