libsvm代码阅读:关于svm_group_classes函数分析(转)

目前libsvm最新的version是3.17,主要的改变是在svm_group_classes函数中加了几行代码。官方的说明如下:

Version 3.17 released on April Fools‘ day, 2013. We slightly adjust the way class labels are handled internally. By default labels are ordered by their first occurrence in the training set. Hence for a set with -1/+1 labels, if -1 appears first, then internally -1 becomes +1. This has caused confusion. Now for data with -1/+1 labels, we specifically ensure that internally the binary SVM has positive data corresponding to the +1 instances. For developers, see changes in the subrouting svm_group_classes of svm.cpp. 

本文就对这个函数进行分析:

svm_group_classes函数的功能是:group training data of the same class

Important:如何将一堆数据归类到一起,同类的连续存储!可参考这个函数。

函数原型如下:

[cpp]   view plain copy  

<EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. void svm_group_classes(const svm_problem *prob, int *nr_class_ret, int **label_ret, int **start_ret, int **count_ret, int *perm)

主要的输入是prob这个指针,它指向svm_group_classes将要处理的样本数据集,另外几个形参是指针类型,可以相当于输出数据,其中:

  1. nr_class_ret——统计得出样本集的类别总数
  2. label_ret——指向存储类别标号的数组
  3. start_ret——指向存储每个类别的起始位置的数组
  4. count_tet——指向存储每个类别的样本个数的数组
  5. perm——指向原始数据的索引数组

下面,先看一部分代码,这部分代码中的for循环的功能:统计类别总数、将相应的相同类别y[i]赋到相应的label,并统计各个类别的样本数量count。

设一个例子:{ 有6个样本,总共4类,其中y[0]=y[1],y[2]=y[3],y[4],y[5] },则for循环的运行过程如下所示:

i=0  label[0]=y[0],           data_label[0]=0

i=1  label[0]=y[0]=y[1],   data_label[1]=0 count[0]=2

i=2  label[1]=y[2],           data_label[2]=1

i=3  label[1]=y[2]=y[3],   data_label[3]=1 count[1]=2

i=4  label[2]=y[4],           data_label[2]=2 count[2]=1

i=5  label[3]=y[5],           data_label[2]=3 count[3]=1

[cpp]   view plain copy  

<EMBED id=ZeroClipboardMovie_2 height=18 name=ZeroClipboardMovie_2 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=2&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. // label: label name, start: begin of each class, count: #data of classes, perm: indices to the original data
  2. // perm, length l, must be allocated before calling this subroutine
  3. static void svm_group_classes(const svm_problem *prob, int *nr_class_ret, int **label_ret, int **start_ret, int **count_ret, int *perm)
  4. {
  5. int l = prob->l;//样本总数
  6. int max_nr_class = 16;//不够的话,自动增长为原来的两倍(见下文)
  7. int nr_class = 0;
  8. int *label = Malloc(int,max_nr_class);//Malloc(type,n) (type *)malloc((n)*sizeof(type))
  9. int *count = Malloc(int,max_nr_class);
  10. int *data_label = Malloc(int,l);
  11. int i;
  12. for(i=0;i<l;i++)
  13. {
  14. int this_label = (int)prob->y[i];//将类别赋给this_label
  15. int j;
  16. for(j=0;j<nr_class;j++)
  17. {
  18. if(this_label == label[j])//虽然刚开始label里面没值,但是第一步循环本内层也没有被运行
  19. {
  20. ++count[j];
  21. break;
  22. }
  23. }
  24. data_label[i] = j;
  25. if(j == nr_class)
  26. {
  27. if(nr_class == max_nr_class)
  28. {
  29. max_nr_class *= 2;//扩大最大类别数
  30. label = (int *)realloc(label,max_nr_class*sizeof(int));
  31. count = (int *)realloc(count,max_nr_class*sizeof(int));
  32. }
  33. label[nr_class] = this_label;
  34. count[nr_class] = 1;//这个是1
  35. ++nr_class;
  36. }
  37. }

本version更新部分:本部分主要是处理二类分类,当第一个出现的是-1时,负责把-1和+1的数据对调。

[cpp]   view plain copy  

<EMBED id=ZeroClipboardMovie_3 height=18 name=ZeroClipboardMovie_3 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=3&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. //
  2. // Labels are ordered by their first occurrence in the training set.
  3. // However, for two-class sets with -1/+1 labels and -1 appears first,
  4. // we swap labels to ensure that internally the binary SVM has positive data corresponding to the +1 instances.
  5. //
  6. if (nr_class == 2 && label[0] == -1 && label[1] == 1)
  7. {
  8. swap(label[0],label[1]);
  9. swap(count[0],count[1]);
  10. for(i=0;i<l;i++)
  11. {
  12. if(data_label[i] == 0)
  13. data_label[i] = 1;
  14. else
  15. data_label[i] = 0;
  16. }
  17. }

下面这一部分代码是用来计算每个类别的起始位置start、以及各个样本分类后的在原始数据中的索引位置perm数组。其中perm[i]=j: i表示当前同类样本位置,j表示原始数据位置。

Important:如何将一堆数据归类到一起,同类的连续存储!可参考这个函数。

[cpp]   view plain copy  

<EMBED id=ZeroClipboardMovie_4 height=18 name=ZeroClipboardMovie_4 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=4&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. int *start = Malloc(int,nr_class);
  2. start[0] = 0;
  3. for(i=1;i<nr_class;i++)
  4. start[i] = start[i-1]+count[i-1];
  5. for(i=0;i<l;i++)
  6. {
  7. perm[start[data_label[i]]] = i;
  8. ++start[data_label[i]];
  9. }
  10. start[0] = 0;
  11. for(i=1;i<nr_class;i++)
  12. start[i] = start[i-1]+count[i-1];
  13. *nr_class_ret = nr_class;
  14. *label_ret = label;
  15. *start_ret = start;
  16. *count_ret = count;
  17. free(data_lab
时间: 2024-10-07 20:13:31

libsvm代码阅读:关于svm_group_classes函数分析(转)的相关文章

libsvm代码阅读(1):基础准备与svm.h头文件(转)

libsvm是国立台湾大学Chih-Jen Lin开发的一个SVM的函数库,是当前应用最广泛的svm函数库,从2000年到2010年,该函数库的下载量达到250000之多.它的最新版本是version 3.17,主要是对是svm_group_classes做了修改. 主页:LIBSVM -- A Library for Support Vector Machines 下载地址:zip.file ortar.gz 我下载后的解压文件如下所示: libsvm函数包的组织结构如下: 1.主文件路径:包

libsvm代码阅读:关于svm_train函数分析(转)

在svm中,训练是一个十分重要的步骤,下面我们来看看svm的train部分. 在libsvm中的svm_train中分别有回归和分类两部分,我只对其中分类做介绍. 分类的步骤如下: 统计类别总数,同时记录类别的标号,统计每个类的样本数目 将属于相同类的样本分组,连续存放 计算权重C 训练n(n-1)/2 个模型 初始化nozero数组,便于统计SV //初始化概率数组 训练过程中,需要重建子数据集,样本的特征不变,但样本的类别要改为+1/-1 //如有必要,先调用svm_binary_svc_p

libsvm代码阅读(2):svm.cpp浅谈和函数指针(转)

svm.cpp浅谈 svm.cpp总共有3159行代码,实现了svm算法的核心功能,里面总共有Cache.Kernel.ONE_CLASS_Q.QMatrix.Solver.Solver_NU.SVC_Q.SVR_Q 8个类(如下图1所示),而它们之间的继承和组合关系如图2.图3所示.在这些类中Cache.Kernel.Solver是核心类,对整个算法起支撑作用.在以后的博文中我们将对这3个核心类做重点注解分析,另外还将对svm.cpp中的svm_train函数做一个注解分析. 图1 图2 图3

libsvm代码阅读(3):关于Cache类的分析(转)

下面来分析Cache类的源码,该类位于svm.cpp中.这个类的主要功能是:负责运算所涉及的内存管理,包括申请.释放等. 简单来说:这个Cache类,首先通过Cache构造函数申请一块空间,这块空间的大小是:L个head_t大小的空间.然后get_data函数保证结构head_t中至少有len个float的内存,并且将可以使用的内存块的指针放在data指针中:而swap_index函数则是用于交换head[i]和head[j]. Cache类的定义如下: [cpp]       view pla

libsvm代码阅读:关于Solver类分析(二)(转)

如果你看完了上篇博文的伪代码,那么我们就可以开始谈谈它的源代码了. 下面先贴出它的类定义,一些成员函数的具体实现先忽略. [cpp]   view plain copy   <EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflas

libsvm代码阅读:关于Solver类分析(一)(转)

如果你看完了上篇博文的伪代码,那么我们就可以开始谈谈它的源代码了. 下面先贴出它的类定义,一些成员函数的具体实现先忽略. [cpp]   view plain copy   <EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflas

libsvm代码阅读:关于Kernel类分析(转)

这一篇博文来分析下Kernel类,代码上很简单,一般都能看懂.Kernel类主要是为SVM的核函数服务的,里面实现了SVM常用的核函数,通过函数指针来使用这些核函数. 其中几个常用核函数如下所示:(一般情况下,使用RBF核函数能取得很好的效果) 关于基类QMatrix在Kernel中的作用并不明显,只是定义了一些纯虚函数,Kernel继承这些函数,Kernel只对swap_index进行了定义.其余的get_Q和get_QD在Kernel并没有用到. [cpp]   view plain cop

自己学驱动9——uboot代码阅读四(start_armboot函数)

前面分析过在start.S中执行完相关的一些操作之后,会跳转到C语言的部分来执行,跳转到的目标位置就是start_armboot函数,所以现在来看一下这个函数完成了一些什么工作.在这个函数的第一行定义了一个变量如下: init_fnc_t **init_fnc_ptr; 通过查找uboot源码可以得到下面的类型重定义: typedef int (init_fnc_t) (void); typedef的使用方法非常灵活,这里这种定义方式就是定义了init_fnc_t代表一个接收参数为void类型返

代码阅读分析工具Understand 2.0试用

Understand 2.0是一款源码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实能够大大提高代码阅读效率.因为Understand功能十分强大,本文不可能详尽地介绍它的全部功能,所以仅仅列举本人觉得比較重要或有特色的功能,以做抛砖引玉之举. Understand 2.0能够从http://www.scitools.com/下载到,安装后能够试用15天. 使用Understand阅读代码前,要先创建一个Project,然后把全部的源码文件增加到这个Project里.这里我创建了一