rb-libsvm 1.3.1 → 1.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +4 -4
- data/CHANGELOG.md +17 -0
- data/MIT-LICENSE +1 -1
- data/README.md +5 -3
- data/ext/libsvm/libsvm.c +5 -0
- data/ext/libsvm/svm.cpp +106 -88
- data/ext/libsvm/svm.h +2 -2
- data/lib/libsvm/node.rb +5 -3
- data/lib/libsvm/version.rb +1 -1
- data/lib/rb-libsvm.rb +1 -0
- data/rb-libsvm.gemspec +1 -0
- data/spec/core_ext_spec.rb +3 -3
- data/spec/model_spec.rb +4 -0
- data/spec/node_spec.rb +24 -17
- data/spec/parameter_spec.rb +19 -20
- data/spec/problem_spec.rb +19 -15
- data/spec/usage_spec.rb +5 -5
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2a9d797f41f999146257203fe3e0e1ef8a0e6145b432c21e00615b2c338f6a99
|
4
|
+
data.tar.gz: 9cbf823d14c85463d599f862c0ca2e11ea5cb9738db198a091d7168b7d005d53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6039ba512d500edb6bb7f5c32edeaf179cc2fe91c1cb0b8e094c1b5cd8117b493c00c5246b070f4f9581976a77e49aabb6b18c93b2f14cc0b7311022809fe11
|
7
|
+
data.tar.gz: b6801f7f1725507c10dd7773019e2da2f170a94265762d479336f10b12a2233ea2db9b802a88274130d05e115f475266b5ca89020c9aca529fdc45043d2d3fba
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,23 @@
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
4
4
|
|
5
|
+
## [1.4.3] - 2018-09-15
|
6
|
+
### Changed
|
7
|
+
- Upgrade to LIBSVM 3.23
|
8
|
+
|
9
|
+
## [1.4.2] - 2018-09-02
|
10
|
+
### Changed
|
11
|
+
- bundler requires automatically
|
12
|
+
|
13
|
+
## [1.4.1] - 2018-06-15
|
14
|
+
|
15
|
+
## [1.4.0] - 2015-09-18
|
16
|
+
### Changed
|
17
|
+
- Complete transition to `expect` specs.
|
18
|
+
- Raise exception in `Libsvm::Model.load` if model can't be loaded (fixes #21).
|
19
|
+
### Fixed
|
20
|
+
- Fix a bug in `Libsvm::Node#==` when comparing with `nil`.
|
21
|
+
|
5
22
|
## [1.3.1] - 2015-03-21
|
6
23
|
### Fixed
|
7
24
|
- Spelling and punctuation in documentation comments
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/rb-libsvm.png)](http://badge.fury.io/rb/rb-libsvm)
|
4
4
|
[![Build Status](https://secure.travis-ci.org/febeling/rb-libsvm.png)](http://travis-ci.org/febeling/rb-libsvm)
|
5
5
|
|
6
|
-
This package provides
|
6
|
+
This package provides Ruby bindings to the [LIBSVM][] library. SVM
|
7
7
|
is a machine learning and classification algorithm, and LIBSVM is a
|
8
8
|
popular free implementation of it, written by Chih-Chung Chang and
|
9
9
|
Chih-Jen Lin, of National Taiwan University, Taipei. See the book ["Programming
|
@@ -22,10 +22,10 @@ LIBSVM includes a number of command line tools for preprocessing
|
|
22
22
|
training data and finding parameters. These tools are not included in
|
23
23
|
this gem. You should install the original package if you need them.
|
24
24
|
|
25
|
-
It is helpful to consult the [README
|
25
|
+
It is helpful to consult the [README of the LIBSVM][README] package for
|
26
26
|
reference when configuring the training parameters.
|
27
27
|
|
28
|
-
Currently this package includes libsvm version 3.
|
28
|
+
Currently this package includes libsvm version 3.24.
|
29
29
|
|
30
30
|
## Dependencies
|
31
31
|
|
@@ -101,6 +101,8 @@ the license in the file LIBSVM-LICENSE.
|
|
101
101
|
|
102
102
|
### Posts about using SVMs with Ruby
|
103
103
|
|
104
|
+
https://www.practicalai.io/implementing-classification-using-a-svm-in-ruby/
|
105
|
+
|
104
106
|
http://neovintage.blogspot.com/2011/11/text-classification-using-support.html
|
105
107
|
|
106
108
|
http://www.igvita.com/2008/01/07/support-vector-machines-svm-in-ruby/
|
data/ext/libsvm/libsvm.c
CHANGED
@@ -490,6 +490,8 @@ static VALUE cModel_support_vectors_count(VALUE obj)
|
|
490
490
|
* internal file representation of the model.
|
491
491
|
*
|
492
492
|
* @param filename [String] name of the model file
|
493
|
+
* @raise [IOError] if the model can't be loaded,
|
494
|
+
* e.g. because the model path doesn't point to a model
|
493
495
|
* @return [Libsvm::Model] the model
|
494
496
|
*/
|
495
497
|
static VALUE cModel_class_load(VALUE cls, VALUE filename)
|
@@ -498,6 +500,9 @@ static VALUE cModel_class_load(VALUE cls, VALUE filename)
|
|
498
500
|
char *path;
|
499
501
|
path = StringValueCStr(filename);
|
500
502
|
model = svm_load_model(path);
|
503
|
+
if(model == NULL) {
|
504
|
+
rb_raise(rb_eIOError, "unable to load model from file: \"%s\"", path);
|
505
|
+
}
|
501
506
|
return Data_Wrap_Struct(cModel, 0, model_free, model);
|
502
507
|
}
|
503
508
|
|
data/ext/libsvm/svm.cpp
CHANGED
@@ -308,7 +308,7 @@ double Kernel::dot(const svm_node *px, const svm_node *py)
|
|
308
308
|
++py;
|
309
309
|
else
|
310
310
|
++px;
|
311
|
-
}
|
311
|
+
}
|
312
312
|
}
|
313
313
|
return sum;
|
314
314
|
}
|
@@ -337,7 +337,7 @@ double Kernel::k_function(const svm_node *x, const svm_node *y,
|
|
337
337
|
else
|
338
338
|
{
|
339
339
|
if(x->index > y->index)
|
340
|
-
{
|
340
|
+
{
|
341
341
|
sum += y->value * y->value;
|
342
342
|
++y;
|
343
343
|
}
|
@@ -360,7 +360,7 @@ double Kernel::k_function(const svm_node *x, const svm_node *y,
|
|
360
360
|
sum += y->value * y->value;
|
361
361
|
++y;
|
362
362
|
}
|
363
|
-
|
363
|
+
|
364
364
|
return exp(-param.gamma*sum);
|
365
365
|
}
|
366
366
|
case SIGMOID:
|
@@ -368,7 +368,7 @@ double Kernel::k_function(const svm_node *x, const svm_node *y,
|
|
368
368
|
case PRECOMPUTED: //x: test (validation), y: SV
|
369
369
|
return x[(int)(y->value)].value;
|
370
370
|
default:
|
371
|
-
return 0; // Unreachable
|
371
|
+
return 0; // Unreachable
|
372
372
|
}
|
373
373
|
}
|
374
374
|
|
@@ -560,7 +560,7 @@ void Solver::Solve(int l, const QMatrix& Q, const double *p_, const schar *y_,
|
|
560
560
|
int iter = 0;
|
561
561
|
int max_iter = max(10000000, l>INT_MAX/100 ? INT_MAX : 100*l);
|
562
562
|
int counter = min(l,1000)+1;
|
563
|
-
|
563
|
+
|
564
564
|
while(iter < max_iter)
|
565
565
|
{
|
566
566
|
// show progress and do shrinking
|
@@ -585,11 +585,11 @@ void Solver::Solve(int l, const QMatrix& Q, const double *p_, const schar *y_,
|
|
585
585
|
else
|
586
586
|
counter = 1; // do shrinking next iteration
|
587
587
|
}
|
588
|
-
|
588
|
+
|
589
589
|
++iter;
|
590
590
|
|
591
591
|
// update alpha[i] and alpha[j], handle bounds carefully
|
592
|
-
|
592
|
+
|
593
593
|
const Qfloat *Q_i = Q.get_Q(i,active_size);
|
594
594
|
const Qfloat *Q_j = Q.get_Q(j,active_size);
|
595
595
|
|
@@ -608,7 +608,7 @@ void Solver::Solve(int l, const QMatrix& Q, const double *p_, const schar *y_,
|
|
608
608
|
double diff = alpha[i] - alpha[j];
|
609
609
|
alpha[i] += delta;
|
610
610
|
alpha[j] += delta;
|
611
|
-
|
611
|
+
|
612
612
|
if(diff > 0)
|
613
613
|
{
|
614
614
|
if(alpha[j] < 0)
|
@@ -690,7 +690,7 @@ void Solver::Solve(int l, const QMatrix& Q, const double *p_, const schar *y_,
|
|
690
690
|
|
691
691
|
double delta_alpha_i = alpha[i] - old_alpha_i;
|
692
692
|
double delta_alpha_j = alpha[j] - old_alpha_j;
|
693
|
-
|
693
|
+
|
694
694
|
for(int k=0;k<active_size;k++)
|
695
695
|
{
|
696
696
|
G[k] += Q_i[k]*delta_alpha_i + Q_j[k]*delta_alpha_j;
|
@@ -790,7 +790,7 @@ int Solver::select_working_set(int &out_i, int &out_j)
|
|
790
790
|
// j: minimizes the decrease of obj value
|
791
791
|
// (if quadratic coefficeint <= 0, replace it with tau)
|
792
792
|
// -y_j*grad(f)_j < -y_i*grad(f)_i, j in I_low(\alpha)
|
793
|
-
|
793
|
+
|
794
794
|
double Gmax = -INF;
|
795
795
|
double Gmax2 = -INF;
|
796
796
|
int Gmax_idx = -1;
|
@@ -798,7 +798,7 @@ int Solver::select_working_set(int &out_i, int &out_j)
|
|
798
798
|
double obj_diff_min = INF;
|
799
799
|
|
800
800
|
for(int t=0;t<active_size;t++)
|
801
|
-
if(y[t]==+1)
|
801
|
+
if(y[t]==+1)
|
802
802
|
{
|
803
803
|
if(!is_upper_bound(t))
|
804
804
|
if(-G[t] >= Gmax)
|
@@ -874,7 +874,7 @@ int Solver::select_working_set(int &out_i, int &out_j)
|
|
874
874
|
}
|
875
875
|
}
|
876
876
|
|
877
|
-
if(Gmax+Gmax2 < eps)
|
877
|
+
if(Gmax+Gmax2 < eps || Gmin_idx == -1)
|
878
878
|
return 1;
|
879
879
|
|
880
880
|
out_i = Gmax_idx;
|
@@ -895,7 +895,7 @@ bool Solver::be_shrunk(int i, double Gmax1, double Gmax2)
|
|
895
895
|
{
|
896
896
|
if(y[i]==+1)
|
897
897
|
return(G[i] > Gmax2);
|
898
|
-
else
|
898
|
+
else
|
899
899
|
return(G[i] > Gmax1);
|
900
900
|
}
|
901
901
|
else
|
@@ -911,27 +911,27 @@ void Solver::do_shrinking()
|
|
911
911
|
// find maximal violating pair first
|
912
912
|
for(i=0;i<active_size;i++)
|
913
913
|
{
|
914
|
-
if(y[i]==+1)
|
914
|
+
if(y[i]==+1)
|
915
915
|
{
|
916
|
-
if(!is_upper_bound(i))
|
916
|
+
if(!is_upper_bound(i))
|
917
917
|
{
|
918
918
|
if(-G[i] >= Gmax1)
|
919
919
|
Gmax1 = -G[i];
|
920
920
|
}
|
921
|
-
if(!is_lower_bound(i))
|
921
|
+
if(!is_lower_bound(i))
|
922
922
|
{
|
923
923
|
if(G[i] >= Gmax2)
|
924
924
|
Gmax2 = G[i];
|
925
925
|
}
|
926
926
|
}
|
927
|
-
else
|
927
|
+
else
|
928
928
|
{
|
929
|
-
if(!is_upper_bound(i))
|
929
|
+
if(!is_upper_bound(i))
|
930
930
|
{
|
931
931
|
if(-G[i] >= Gmax2)
|
932
932
|
Gmax2 = -G[i];
|
933
933
|
}
|
934
|
-
if(!is_lower_bound(i))
|
934
|
+
if(!is_lower_bound(i))
|
935
935
|
{
|
936
936
|
if(G[i] >= Gmax1)
|
937
937
|
Gmax1 = G[i];
|
@@ -939,7 +939,7 @@ void Solver::do_shrinking()
|
|
939
939
|
}
|
940
940
|
}
|
941
941
|
|
942
|
-
if(unshrink == false && Gmax1 + Gmax2 <= eps*10)
|
942
|
+
if(unshrink == false && Gmax1 + Gmax2 <= eps*10)
|
943
943
|
{
|
944
944
|
unshrink = true;
|
945
945
|
reconstruct_gradient();
|
@@ -1078,7 +1078,7 @@ int Solver_NU::select_working_set(int &out_i, int &out_j)
|
|
1078
1078
|
{
|
1079
1079
|
if(y[j]==+1)
|
1080
1080
|
{
|
1081
|
-
if (!is_lower_bound(j))
|
1081
|
+
if (!is_lower_bound(j))
|
1082
1082
|
{
|
1083
1083
|
double grad_diff=Gmaxp+G[j];
|
1084
1084
|
if (G[j] >= Gmaxp2)
|
@@ -1126,7 +1126,7 @@ int Solver_NU::select_working_set(int &out_i, int &out_j)
|
|
1126
1126
|
}
|
1127
1127
|
}
|
1128
1128
|
|
1129
|
-
if(max(Gmaxp+Gmaxp2,Gmaxn+Gmaxn2) < eps)
|
1129
|
+
if(max(Gmaxp+Gmaxp2,Gmaxn+Gmaxn2) < eps || Gmin_idx == -1)
|
1130
1130
|
return 1;
|
1131
1131
|
|
1132
1132
|
if (y[Gmin_idx] == +1)
|
@@ -1144,14 +1144,14 @@ bool Solver_NU::be_shrunk(int i, double Gmax1, double Gmax2, double Gmax3, doubl
|
|
1144
1144
|
{
|
1145
1145
|
if(y[i]==+1)
|
1146
1146
|
return(-G[i] > Gmax1);
|
1147
|
-
else
|
1147
|
+
else
|
1148
1148
|
return(-G[i] > Gmax4);
|
1149
1149
|
}
|
1150
1150
|
else if(is_lower_bound(i))
|
1151
1151
|
{
|
1152
1152
|
if(y[i]==+1)
|
1153
1153
|
return(G[i] > Gmax2);
|
1154
|
-
else
|
1154
|
+
else
|
1155
1155
|
return(G[i] > Gmax3);
|
1156
1156
|
}
|
1157
1157
|
else
|
@@ -1180,14 +1180,14 @@ void Solver_NU::do_shrinking()
|
|
1180
1180
|
if(!is_lower_bound(i))
|
1181
1181
|
{
|
1182
1182
|
if(y[i]==+1)
|
1183
|
-
{
|
1183
|
+
{
|
1184
1184
|
if(G[i] > Gmax2) Gmax2 = G[i];
|
1185
1185
|
}
|
1186
1186
|
else if(G[i] > Gmax3) Gmax3 = G[i];
|
1187
1187
|
}
|
1188
1188
|
}
|
1189
1189
|
|
1190
|
-
if(unshrink == false && max(Gmax1+Gmax2,Gmax3+Gmax4) <= eps*10)
|
1190
|
+
if(unshrink == false && max(Gmax1+Gmax2,Gmax3+Gmax4) <= eps*10)
|
1191
1191
|
{
|
1192
1192
|
unshrink = true;
|
1193
1193
|
reconstruct_gradient();
|
@@ -1250,12 +1250,12 @@ double Solver_NU::calculate_rho()
|
|
1250
1250
|
r1 = sum_free1/nr_free1;
|
1251
1251
|
else
|
1252
1252
|
r1 = (ub1+lb1)/2;
|
1253
|
-
|
1253
|
+
|
1254
1254
|
if(nr_free2 > 0)
|
1255
1255
|
r2 = sum_free2/nr_free2;
|
1256
1256
|
else
|
1257
1257
|
r2 = (ub2+lb2)/2;
|
1258
|
-
|
1258
|
+
|
1259
1259
|
si->r = (r1+r2)/2;
|
1260
1260
|
return (r1-r2)/2;
|
1261
1261
|
}
|
@@ -1264,7 +1264,7 @@ double Solver_NU::calculate_rho()
|
|
1264
1264
|
// Q matrices for various formulations
|
1265
1265
|
//
|
1266
1266
|
class SVC_Q: public Kernel
|
1267
|
-
{
|
1267
|
+
{
|
1268
1268
|
public:
|
1269
1269
|
SVC_Q(const svm_problem& prob, const svm_parameter& param, const schar *y_)
|
1270
1270
|
:Kernel(prob.l, prob.x, param)
|
@@ -1275,7 +1275,7 @@ public:
|
|
1275
1275
|
for(int i=0;i<prob.l;i++)
|
1276
1276
|
QD[i] = (this->*kernel_function)(i,i);
|
1277
1277
|
}
|
1278
|
-
|
1278
|
+
|
1279
1279
|
Qfloat *get_Q(int i, int len) const
|
1280
1280
|
{
|
1281
1281
|
Qfloat *data;
|
@@ -1324,7 +1324,7 @@ public:
|
|
1324
1324
|
for(int i=0;i<prob.l;i++)
|
1325
1325
|
QD[i] = (this->*kernel_function)(i,i);
|
1326
1326
|
}
|
1327
|
-
|
1327
|
+
|
1328
1328
|
Qfloat *get_Q(int i, int len) const
|
1329
1329
|
{
|
1330
1330
|
Qfloat *data;
|
@@ -1360,7 +1360,7 @@ private:
|
|
1360
1360
|
};
|
1361
1361
|
|
1362
1362
|
class SVR_Q: public Kernel
|
1363
|
-
{
|
1363
|
+
{
|
1364
1364
|
public:
|
1365
1365
|
SVR_Q(const svm_problem& prob, const svm_parameter& param)
|
1366
1366
|
:Kernel(prob.l, prob.x, param)
|
@@ -1390,7 +1390,7 @@ public:
|
|
1390
1390
|
swap(index[i],index[j]);
|
1391
1391
|
swap(QD[i],QD[j]);
|
1392
1392
|
}
|
1393
|
-
|
1393
|
+
|
1394
1394
|
Qfloat *get_Q(int i, int len) const
|
1395
1395
|
{
|
1396
1396
|
Qfloat *data;
|
@@ -1703,7 +1703,7 @@ static decision_function svm_train_one(
|
|
1703
1703
|
|
1704
1704
|
// Platt's binary SVM Probablistic Output: an improvement from Lin et al.
|
1705
1705
|
static void sigmoid_train(
|
1706
|
-
int l, const double *dec_values, const double *labels,
|
1706
|
+
int l, const double *dec_values, const double *labels,
|
1707
1707
|
double& A, double& B)
|
1708
1708
|
{
|
1709
1709
|
double prior1=0, prior0 = 0;
|
@@ -1712,7 +1712,7 @@ static void sigmoid_train(
|
|
1712
1712
|
for (i=0;i<l;i++)
|
1713
1713
|
if (labels[i] > 0) prior1+=1;
|
1714
1714
|
else prior0+=1;
|
1715
|
-
|
1715
|
+
|
1716
1716
|
int max_iter=100; // Maximal number of iterations
|
1717
1717
|
double min_step=1e-10; // Minimal step taken in line search
|
1718
1718
|
double sigma=1e-12; // For numerically strict PD of Hessian
|
@@ -1723,7 +1723,7 @@ static void sigmoid_train(
|
|
1723
1723
|
double fApB,p,q,h11,h22,h21,g1,g2,det,dA,dB,gd,stepsize;
|
1724
1724
|
double newA,newB,newf,d1,d2;
|
1725
1725
|
int iter;
|
1726
|
-
|
1726
|
+
|
1727
1727
|
// Initial Point and Initial Fun Value
|
1728
1728
|
A=0.0; B=log((prior0+1.0)/(prior1+1.0));
|
1729
1729
|
double fval = 0.0;
|
@@ -1833,7 +1833,7 @@ static void multiclass_probability(int k, double **r, double *p)
|
|
1833
1833
|
double **Q=Malloc(double *,k);
|
1834
1834
|
double *Qp=Malloc(double,k);
|
1835
1835
|
double pQp, eps=0.005/k;
|
1836
|
-
|
1836
|
+
|
1837
1837
|
for (t=0;t<k;t++)
|
1838
1838
|
{
|
1839
1839
|
p[t]=1.0/k; // Valid if k = 1
|
@@ -1869,7 +1869,7 @@ static void multiclass_probability(int k, double **r, double *p)
|
|
1869
1869
|
max_error=error;
|
1870
1870
|
}
|
1871
1871
|
if (max_error<eps) break;
|
1872
|
-
|
1872
|
+
|
1873
1873
|
for (t=0;t<k;t++)
|
1874
1874
|
{
|
1875
1875
|
double diff=(-Qp[t]+pQp)/Q[t][t];
|
@@ -1916,7 +1916,7 @@ static void svm_binary_svc_probability(
|
|
1916
1916
|
subprob.l = prob->l-(end-begin);
|
1917
1917
|
subprob.x = Malloc(struct svm_node*,subprob.l);
|
1918
1918
|
subprob.y = Malloc(double,subprob.l);
|
1919
|
-
|
1919
|
+
|
1920
1920
|
k=0;
|
1921
1921
|
for(j=0;j<begin;j++)
|
1922
1922
|
{
|
@@ -1964,19 +1964,19 @@ static void svm_binary_svc_probability(
|
|
1964
1964
|
svm_predict_values(submodel,prob->x[perm[j]],&(dec_values[perm[j]]));
|
1965
1965
|
// ensure +1 -1 order; reason not using CV subroutine
|
1966
1966
|
dec_values[perm[j]] *= submodel->label[0];
|
1967
|
-
}
|
1967
|
+
}
|
1968
1968
|
svm_free_and_destroy_model(&submodel);
|
1969
1969
|
svm_destroy_param(&subparam);
|
1970
1970
|
}
|
1971
1971
|
free(subprob.x);
|
1972
1972
|
free(subprob.y);
|
1973
|
-
}
|
1973
|
+
}
|
1974
1974
|
sigmoid_train(prob->l,dec_values,prob->y,probA,probB);
|
1975
1975
|
free(dec_values);
|
1976
1976
|
free(perm);
|
1977
1977
|
}
|
1978
1978
|
|
1979
|
-
// Return parameter of a Laplace distribution
|
1979
|
+
// Return parameter of a Laplace distribution
|
1980
1980
|
static double svm_svr_probability(
|
1981
1981
|
const svm_problem *prob, const svm_parameter *param)
|
1982
1982
|
{
|
@@ -1992,15 +1992,15 @@ static double svm_svr_probability(
|
|
1992
1992
|
{
|
1993
1993
|
ymv[i]=prob->y[i]-ymv[i];
|
1994
1994
|
mae += fabs(ymv[i]);
|
1995
|
-
}
|
1995
|
+
}
|
1996
1996
|
mae /= prob->l;
|
1997
1997
|
double std=sqrt(2*mae*mae);
|
1998
1998
|
int count=0;
|
1999
1999
|
mae=0;
|
2000
2000
|
for(i=0;i<prob->l;i++)
|
2001
|
-
if (fabs(ymv[i]) > 5*std)
|
2001
|
+
if (fabs(ymv[i]) > 5*std)
|
2002
2002
|
count=count+1;
|
2003
|
-
else
|
2003
|
+
else
|
2004
2004
|
mae+=fabs(ymv[i]);
|
2005
2005
|
mae /= (prob->l-count);
|
2006
2006
|
info("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma= %g\n",mae);
|
@@ -2049,8 +2049,8 @@ static void svm_group_classes(const svm_problem *prob, int *nr_class_ret, int **
|
|
2049
2049
|
}
|
2050
2050
|
|
2051
2051
|
//
|
2052
|
-
// Labels are ordered by their first occurrence in the training set.
|
2053
|
-
// However, for two-class sets with -1/+1 labels and -1 appears first,
|
2052
|
+
// Labels are ordered by their first occurrence in the training set.
|
2053
|
+
// However, for two-class sets with -1/+1 labels and -1 appears first,
|
2054
2054
|
// we swap labels to ensure that internally the binary SVM has positive data corresponding to the +1 instances.
|
2055
2055
|
//
|
2056
2056
|
if (nr_class == 2 && label[0] == -1 && label[1] == 1)
|
@@ -2106,7 +2106,7 @@ svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
|
|
2106
2106
|
model->probA = NULL; model->probB = NULL;
|
2107
2107
|
model->sv_coef = Malloc(double *,1);
|
2108
2108
|
|
2109
|
-
if(param->probability &&
|
2109
|
+
if(param->probability &&
|
2110
2110
|
(param->svm_type == EPSILON_SVR ||
|
2111
2111
|
param->svm_type == NU_SVR))
|
2112
2112
|
{
|
@@ -2134,7 +2134,7 @@ svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
|
|
2134
2134
|
model->sv_coef[0][j] = f.alpha[i];
|
2135
2135
|
model->sv_indices[j] = i+1;
|
2136
2136
|
++j;
|
2137
|
-
}
|
2137
|
+
}
|
2138
2138
|
|
2139
2139
|
free(f.alpha);
|
2140
2140
|
}
|
@@ -2150,9 +2150,9 @@ svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
|
|
2150
2150
|
|
2151
2151
|
// group training data of the same class
|
2152
2152
|
svm_group_classes(prob,&nr_class,&label,&start,&count,perm);
|
2153
|
-
if(nr_class == 1)
|
2153
|
+
if(nr_class == 1)
|
2154
2154
|
info("WARNING: training data in only one class. See README for details.\n");
|
2155
|
-
|
2155
|
+
|
2156
2156
|
svm_node **x = Malloc(svm_node *,l);
|
2157
2157
|
int i;
|
2158
2158
|
for(i=0;i<l;i++)
|
@@ -2164,7 +2164,7 @@ svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
|
|
2164
2164
|
for(i=0;i<nr_class;i++)
|
2165
2165
|
weighted_C[i] = param->C;
|
2166
2166
|
for(i=0;i<param->nr_weight;i++)
|
2167
|
-
{
|
2167
|
+
{
|
2168
2168
|
int j;
|
2169
2169
|
for(j=0;j<nr_class;j++)
|
2170
2170
|
if(param->weight_label[i] == label[j])
|
@@ -2176,7 +2176,7 @@ svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
|
|
2176
2176
|
}
|
2177
2177
|
|
2178
2178
|
// train k*(k-1)/2 models
|
2179
|
-
|
2179
|
+
|
2180
2180
|
bool *nonzero = Malloc(bool,l);
|
2181
2181
|
for(i=0;i<l;i++)
|
2182
2182
|
nonzero[i] = false;
|
@@ -2229,11 +2229,11 @@ svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
|
|
2229
2229
|
// build output
|
2230
2230
|
|
2231
2231
|
model->nr_class = nr_class;
|
2232
|
-
|
2232
|
+
|
2233
2233
|
model->label = Malloc(int,nr_class);
|
2234
2234
|
for(i=0;i<nr_class;i++)
|
2235
2235
|
model->label[i] = label[i];
|
2236
|
-
|
2236
|
+
|
2237
2237
|
model->rho = Malloc(double,nr_class*(nr_class-1)/2);
|
2238
2238
|
for(i=0;i<nr_class*(nr_class-1)/2;i++)
|
2239
2239
|
model->rho[i] = f[i].rho;
|
@@ -2262,14 +2262,14 @@ svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
|
|
2262
2262
|
int nSV = 0;
|
2263
2263
|
for(int j=0;j<count[i];j++)
|
2264
2264
|
if(nonzero[start[i]+j])
|
2265
|
-
{
|
2265
|
+
{
|
2266
2266
|
++nSV;
|
2267
2267
|
++total_sv;
|
2268
2268
|
}
|
2269
2269
|
model->nSV[i] = nSV;
|
2270
2270
|
nz_count[i] = nSV;
|
2271
2271
|
}
|
2272
|
-
|
2272
|
+
|
2273
2273
|
info("Total nSV = %d\n",total_sv);
|
2274
2274
|
|
2275
2275
|
model->l = total_sv;
|
@@ -2304,7 +2304,7 @@ svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
|
|
2304
2304
|
int sj = start[j];
|
2305
2305
|
int ci = count[i];
|
2306
2306
|
int cj = count[j];
|
2307
|
-
|
2307
|
+
|
2308
2308
|
int q = nz_start[i];
|
2309
2309
|
int k;
|
2310
2310
|
for(k=0;k<ci;k++)
|
@@ -2316,7 +2316,7 @@ svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
|
|
2316
2316
|
model->sv_coef[i][q++] = f[p].alpha[ci+k];
|
2317
2317
|
++p;
|
2318
2318
|
}
|
2319
|
-
|
2319
|
+
|
2320
2320
|
free(label);
|
2321
2321
|
free(probA);
|
2322
2322
|
free(probB);
|
@@ -2365,7 +2365,7 @@ void svm_cross_validation(const svm_problem *prob, const svm_parameter *param, i
|
|
2365
2365
|
int *index = Malloc(int,l);
|
2366
2366
|
for(i=0;i<l;i++)
|
2367
2367
|
index[i]=perm[i];
|
2368
|
-
for (c=0; c<nr_class; c++)
|
2368
|
+
for (c=0; c<nr_class; c++)
|
2369
2369
|
for(i=0;i<count[c];i++)
|
2370
2370
|
{
|
2371
2371
|
int j = i+rand()%(count[c]-i);
|
@@ -2422,7 +2422,7 @@ void svm_cross_validation(const svm_problem *prob, const svm_parameter *param, i
|
|
2422
2422
|
subprob.l = l-(end-begin);
|
2423
2423
|
subprob.x = Malloc(struct svm_node*,subprob.l);
|
2424
2424
|
subprob.y = Malloc(double,subprob.l);
|
2425
|
-
|
2425
|
+
|
2426
2426
|
k=0;
|
2427
2427
|
for(j=0;j<begin;j++)
|
2428
2428
|
{
|
@@ -2437,7 +2437,7 @@ void svm_cross_validation(const svm_problem *prob, const svm_parameter *param, i
|
|
2437
2437
|
++k;
|
2438
2438
|
}
|
2439
2439
|
struct svm_model *submodel = svm_train(&subprob,param);
|
2440
|
-
if(param->probability &&
|
2440
|
+
if(param->probability &&
|
2441
2441
|
(param->svm_type == C_SVC || param->svm_type == NU_SVC))
|
2442
2442
|
{
|
2443
2443
|
double *prob_estimates=Malloc(double,svm_get_nr_class(submodel));
|
@@ -2451,7 +2451,7 @@ void svm_cross_validation(const svm_problem *prob, const svm_parameter *param, i
|
|
2451
2451
|
svm_free_and_destroy_model(&submodel);
|
2452
2452
|
free(subprob.x);
|
2453
2453
|
free(subprob.y);
|
2454
|
-
}
|
2454
|
+
}
|
2455
2455
|
free(fold_start);
|
2456
2456
|
free(perm);
|
2457
2457
|
}
|
@@ -2521,7 +2521,7 @@ double svm_predict_values(const svm_model *model, const svm_node *x, double* dec
|
|
2521
2521
|
{
|
2522
2522
|
int nr_class = model->nr_class;
|
2523
2523
|
int l = model->l;
|
2524
|
-
|
2524
|
+
|
2525
2525
|
double *kvalue = Malloc(double,l);
|
2526
2526
|
for(i=0;i<l;i++)
|
2527
2527
|
kvalue[i] = Kernel::k_function(x,model->SV[i],model->param);
|
@@ -2544,7 +2544,7 @@ double svm_predict_values(const svm_model *model, const svm_node *x, double* dec
|
|
2544
2544
|
int sj = start[j];
|
2545
2545
|
int ci = model->nSV[i];
|
2546
2546
|
int cj = model->nSV[j];
|
2547
|
-
|
2547
|
+
|
2548
2548
|
int k;
|
2549
2549
|
double *coef1 = model->sv_coef[j-1];
|
2550
2550
|
double *coef2 = model->sv_coef[i];
|
@@ -2582,7 +2582,7 @@ double svm_predict(const svm_model *model, const svm_node *x)
|
|
2582
2582
|
model->param.svm_type == EPSILON_SVR ||
|
2583
2583
|
model->param.svm_type == NU_SVR)
|
2584
2584
|
dec_values = Malloc(double, 1);
|
2585
|
-
else
|
2585
|
+
else
|
2586
2586
|
dec_values = Malloc(double, nr_class*(nr_class-1)/2);
|
2587
2587
|
double pred_result = svm_predict_values(model, x, dec_values);
|
2588
2588
|
free(dec_values);
|
@@ -2612,7 +2612,13 @@ double svm_predict_probability(
|
|
2612
2612
|
pairwise_prob[j][i]=1-pairwise_prob[i][j];
|
2613
2613
|
k++;
|
2614
2614
|
}
|
2615
|
-
|
2615
|
+
if (nr_class == 2)
|
2616
|
+
{
|
2617
|
+
prob_estimates[0] = pairwise_prob[0][1];
|
2618
|
+
prob_estimates[1] = pairwise_prob[1][0];
|
2619
|
+
}
|
2620
|
+
else
|
2621
|
+
multiclass_probability(nr_class,pairwise_prob,prob_estimates);
|
2616
2622
|
|
2617
2623
|
int prob_max_idx = 0;
|
2618
2624
|
for(i=1;i<nr_class;i++)
|
@@ -2624,7 +2630,7 @@ double svm_predict_probability(
|
|
2624
2630
|
free(pairwise_prob);
|
2625
2631
|
return model->label[prob_max_idx];
|
2626
2632
|
}
|
2627
|
-
else
|
2633
|
+
else
|
2628
2634
|
return svm_predict(model, x);
|
2629
2635
|
}
|
2630
2636
|
|
@@ -2643,7 +2649,10 @@ int svm_save_model(const char *model_file_name, const svm_model *model)
|
|
2643
2649
|
FILE *fp = fopen(model_file_name,"w");
|
2644
2650
|
if(fp==NULL) return -1;
|
2645
2651
|
|
2646
|
-
char *old_locale =
|
2652
|
+
char *old_locale = setlocale(LC_ALL, NULL);
|
2653
|
+
if (old_locale) {
|
2654
|
+
old_locale = strdup(old_locale);
|
2655
|
+
}
|
2647
2656
|
setlocale(LC_ALL, "C");
|
2648
2657
|
|
2649
2658
|
const svm_parameter& param = model->param;
|
@@ -2655,23 +2664,23 @@ int svm_save_model(const char *model_file_name, const svm_model *model)
|
|
2655
2664
|
fprintf(fp,"degree %d\n", param.degree);
|
2656
2665
|
|
2657
2666
|
if(param.kernel_type == POLY || param.kernel_type == RBF || param.kernel_type == SIGMOID)
|
2658
|
-
fprintf(fp,"gamma
|
2667
|
+
fprintf(fp,"gamma %.17g\n", param.gamma);
|
2659
2668
|
|
2660
2669
|
if(param.kernel_type == POLY || param.kernel_type == SIGMOID)
|
2661
|
-
fprintf(fp,"coef0
|
2670
|
+
fprintf(fp,"coef0 %.17g\n", param.coef0);
|
2662
2671
|
|
2663
2672
|
int nr_class = model->nr_class;
|
2664
2673
|
int l = model->l;
|
2665
2674
|
fprintf(fp, "nr_class %d\n", nr_class);
|
2666
2675
|
fprintf(fp, "total_sv %d\n",l);
|
2667
|
-
|
2676
|
+
|
2668
2677
|
{
|
2669
2678
|
fprintf(fp, "rho");
|
2670
2679
|
for(int i=0;i<nr_class*(nr_class-1)/2;i++)
|
2671
|
-
fprintf(fp,"
|
2680
|
+
fprintf(fp," %.17g",model->rho[i]);
|
2672
2681
|
fprintf(fp, "\n");
|
2673
2682
|
}
|
2674
|
-
|
2683
|
+
|
2675
2684
|
if(model->label)
|
2676
2685
|
{
|
2677
2686
|
fprintf(fp, "label");
|
@@ -2684,14 +2693,14 @@ int svm_save_model(const char *model_file_name, const svm_model *model)
|
|
2684
2693
|
{
|
2685
2694
|
fprintf(fp, "probA");
|
2686
2695
|
for(int i=0;i<nr_class*(nr_class-1)/2;i++)
|
2687
|
-
fprintf(fp,"
|
2696
|
+
fprintf(fp," %.17g",model->probA[i]);
|
2688
2697
|
fprintf(fp, "\n");
|
2689
2698
|
}
|
2690
2699
|
if(model->probB)
|
2691
2700
|
{
|
2692
2701
|
fprintf(fp, "probB");
|
2693
2702
|
for(int i=0;i<nr_class*(nr_class-1)/2;i++)
|
2694
|
-
fprintf(fp,"
|
2703
|
+
fprintf(fp," %.17g",model->probB[i]);
|
2695
2704
|
fprintf(fp, "\n");
|
2696
2705
|
}
|
2697
2706
|
|
@@ -2710,7 +2719,7 @@ int svm_save_model(const char *model_file_name, const svm_model *model)
|
|
2710
2719
|
for(int i=0;i<l;i++)
|
2711
2720
|
{
|
2712
2721
|
for(int j=0;j<nr_class-1;j++)
|
2713
|
-
fprintf(fp, "%.
|
2722
|
+
fprintf(fp, "%.17g ",sv_coef[j][i]);
|
2714
2723
|
|
2715
2724
|
const svm_node *p = SV[i];
|
2716
2725
|
|
@@ -2764,6 +2773,11 @@ static char* readline(FILE *input)
|
|
2764
2773
|
bool read_model_header(FILE *fp, svm_model* model)
|
2765
2774
|
{
|
2766
2775
|
svm_parameter& param = model->param;
|
2776
|
+
// parameters for training only won't be assigned, but arrays are assigned as NULL for safety
|
2777
|
+
param.nr_weight = 0;
|
2778
|
+
param.weight_label = NULL;
|
2779
|
+
param.weight = NULL;
|
2780
|
+
|
2767
2781
|
char cmd[81];
|
2768
2782
|
while(1)
|
2769
2783
|
{
|
@@ -2788,7 +2802,7 @@ bool read_model_header(FILE *fp, svm_model* model)
|
|
2788
2802
|
}
|
2789
2803
|
}
|
2790
2804
|
else if(strcmp(cmd,"kernel_type")==0)
|
2791
|
-
{
|
2805
|
+
{
|
2792
2806
|
FSCANF(fp,"%80s",cmd);
|
2793
2807
|
int i;
|
2794
2808
|
for(i=0;kernel_type_table[i];i++)
|
@@ -2801,7 +2815,7 @@ bool read_model_header(FILE *fp, svm_model* model)
|
|
2801
2815
|
}
|
2802
2816
|
if(kernel_type_table[i] == NULL)
|
2803
2817
|
{
|
2804
|
-
fprintf(stderr,"unknown kernel function.\n");
|
2818
|
+
fprintf(stderr,"unknown kernel function.\n");
|
2805
2819
|
return false;
|
2806
2820
|
}
|
2807
2821
|
}
|
@@ -2875,7 +2889,10 @@ svm_model *svm_load_model(const char *model_file_name)
|
|
2875
2889
|
FILE *fp = fopen(model_file_name,"rb");
|
2876
2890
|
if(fp==NULL) return NULL;
|
2877
2891
|
|
2878
|
-
char *old_locale =
|
2892
|
+
char *old_locale = setlocale(LC_ALL, NULL);
|
2893
|
+
if (old_locale) {
|
2894
|
+
old_locale = strdup(old_locale);
|
2895
|
+
}
|
2879
2896
|
setlocale(LC_ALL, "C");
|
2880
2897
|
|
2881
2898
|
// read parameters
|
@@ -2887,7 +2904,7 @@ svm_model *svm_load_model(const char *model_file_name)
|
|
2887
2904
|
model->sv_indices = NULL;
|
2888
2905
|
model->label = NULL;
|
2889
2906
|
model->nSV = NULL;
|
2890
|
-
|
2907
|
+
|
2891
2908
|
// read header
|
2892
2909
|
if (!read_model_header(fp, model))
|
2893
2910
|
{
|
@@ -2900,7 +2917,7 @@ svm_model *svm_load_model(const char *model_file_name)
|
|
2900
2917
|
free(model);
|
2901
2918
|
return NULL;
|
2902
2919
|
}
|
2903
|
-
|
2920
|
+
|
2904
2921
|
// read sv_coef and SV
|
2905
2922
|
|
2906
2923
|
int elements = 0;
|
@@ -3037,9 +3054,9 @@ const char *svm_check_parameter(const svm_problem *prob, const svm_parameter *pa
|
|
3037
3054
|
svm_type != EPSILON_SVR &&
|
3038
3055
|
svm_type != NU_SVR)
|
3039
3056
|
return "unknown svm type";
|
3040
|
-
|
3057
|
+
|
3041
3058
|
// kernel_type, degree
|
3042
|
-
|
3059
|
+
|
3043
3060
|
int kernel_type = param->kernel_type;
|
3044
3061
|
if(kernel_type != LINEAR &&
|
3045
3062
|
kernel_type != POLY &&
|
@@ -3048,10 +3065,11 @@ const char *svm_check_parameter(const svm_problem *prob, const svm_parameter *pa
|
|
3048
3065
|
kernel_type != PRECOMPUTED)
|
3049
3066
|
return "unknown kernel type";
|
3050
3067
|
|
3051
|
-
if(
|
3068
|
+
if((kernel_type == POLY || kernel_type == RBF || kernel_type == SIGMOID) &&
|
3069
|
+
param->gamma < 0)
|
3052
3070
|
return "gamma < 0";
|
3053
3071
|
|
3054
|
-
if(param->degree < 0)
|
3072
|
+
if(kernel_type == POLY && param->degree < 0)
|
3055
3073
|
return "degree of polynomial kernel < 0";
|
3056
3074
|
|
3057
3075
|
// cache_size,eps,C,nu,p,shrinking
|
@@ -3092,7 +3110,7 @@ const char *svm_check_parameter(const svm_problem *prob, const svm_parameter *pa
|
|
3092
3110
|
|
3093
3111
|
|
3094
3112
|
// check whether nu-svc is feasible
|
3095
|
-
|
3113
|
+
|
3096
3114
|
if(svm_type == NU_SVC)
|
3097
3115
|
{
|
3098
3116
|
int l = prob->l;
|
@@ -3125,7 +3143,7 @@ const char *svm_check_parameter(const svm_problem *prob, const svm_parameter *pa
|
|
3125
3143
|
++nr_class;
|
3126
3144
|
}
|
3127
3145
|
}
|
3128
|
-
|
3146
|
+
|
3129
3147
|
for(i=0;i<nr_class;i++)
|
3130
3148
|
{
|
3131
3149
|
int n1 = count[i];
|
data/ext/libsvm/svm.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#ifndef _LIBSVM_H
|
2
2
|
#define _LIBSVM_H
|
3
3
|
|
4
|
-
#define LIBSVM_VERSION
|
4
|
+
#define LIBSVM_VERSION 324
|
5
5
|
|
6
6
|
#ifdef __cplusplus
|
7
7
|
extern "C" {
|
@@ -48,7 +48,7 @@ struct svm_parameter
|
|
48
48
|
|
49
49
|
//
|
50
50
|
// svm_model
|
51
|
-
//
|
51
|
+
//
|
52
52
|
struct svm_model
|
53
53
|
{
|
54
54
|
struct svm_parameter param; /* parameter */
|
data/lib/libsvm/node.rb
CHANGED
@@ -90,13 +90,15 @@ module Libsvm
|
|
90
90
|
self.value = value
|
91
91
|
end
|
92
92
|
|
93
|
-
# Compare
|
93
|
+
# Compare feature node for equality.
|
94
94
|
#
|
95
95
|
# Nodes with equal index and value are equal.
|
96
96
|
#
|
97
97
|
# @return [Boolean]
|
98
|
-
def ==(other)
|
99
|
-
|
98
|
+
def == (other)
|
99
|
+
other.class == self.class &&
|
100
|
+
index == other.index &&
|
101
|
+
value == other.value
|
100
102
|
end
|
101
103
|
|
102
104
|
def inspect
|
data/lib/libsvm/version.rb
CHANGED
data/lib/rb-libsvm.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'libsvm'
|
data/rb-libsvm.gemspec
CHANGED
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.summary = %q{Ruby bindings for LIBSVM}
|
12
12
|
s.description = %q{Self-contained LIBSVM package for Ruby (that doesn't use SWIG). LIBSVM is a popular implementation of SVM, a machine learning classifier.}
|
13
13
|
s.required_ruby_version = '>= 1.8.7'
|
14
|
+
s.licenses = ['MIT']
|
14
15
|
|
15
16
|
s.rubyforge_project = "rb-libsvm"
|
16
17
|
|
data/spec/core_ext_spec.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Create examples" do
|
4
|
-
|
4
|
+
it "from a hash" do
|
5
5
|
example = { 11 => 0.11, 21 => 0.21, 101 => 0.99 }.to_example.sort_by(&:index)
|
6
|
-
example.
|
6
|
+
expect(example).to eq(Node.features({11 => 0.11, 21 => 0.21, 101 => 0.99 }).sort_by(&:index))
|
7
7
|
end
|
8
8
|
|
9
9
|
describe "from an array of tuples" do
|
10
10
|
it "can create example from array of pairs" do
|
11
11
|
example = [ [11, 0.11], [21, 0.21], [101, 0.99] ].to_example
|
12
|
-
example.
|
12
|
+
expect(example).to eq(Node.features({11 => 0.11, 21 => 0.21, 101 => 0.99 }).sort_by(&:index))
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
data/spec/model_spec.rb
CHANGED
@@ -70,6 +70,10 @@ describe "A saved model" do
|
|
70
70
|
expect(Model.load(@filename)).to be_an_instance_of(Model)
|
71
71
|
end
|
72
72
|
|
73
|
+
it "missing model raises exception" do
|
74
|
+
expect{Model.load("missing.model")}.to raise_error(IOError, /unable to load model from file: "missing.model"/)
|
75
|
+
end
|
76
|
+
|
73
77
|
after(:each) do
|
74
78
|
File.delete(@filename) rescue nil
|
75
79
|
end
|
data/spec/node_spec.rb
CHANGED
@@ -28,43 +28,50 @@ describe "A Node" do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it "can be created" do
|
31
|
-
@node.
|
31
|
+
expect(@node).not_to be_nil
|
32
32
|
end
|
33
33
|
|
34
|
-
it "
|
34
|
+
it "has in :index property" do
|
35
35
|
@node.index = 99
|
36
|
-
@node.index.
|
36
|
+
expect(@node.index).to eq(99)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "has a :value porperty" do
|
37
40
|
@node.value = 3.141
|
38
|
-
@node.value.
|
41
|
+
expect(@node.value).to be_within(0.00001).of(3.141)
|
39
42
|
end
|
40
43
|
|
41
44
|
it "has inited properties" do
|
42
|
-
@node.index.
|
43
|
-
@node.value.
|
45
|
+
expect(@node.index).to eq(0)
|
46
|
+
expect(@node.value).to be_within(0.00001).of(0)
|
44
47
|
end
|
45
48
|
|
46
49
|
it "class can create nodes from an array" do
|
47
50
|
ary = Node.features([0.1, 0.2, 0.3, 0.4, 0.5])
|
48
|
-
ary.
|
49
|
-
ary.map
|
50
|
-
ary.map
|
51
|
+
expect(ary).to all(be_a(Node))
|
52
|
+
expect(ary.map(&:value).sort).to eq([0.1, 0.2, 0.3, 0.4, 0.5])
|
53
|
+
expect(ary.map(&:index).sort).to eq([0, 1, 2, 3, 4])
|
51
54
|
end
|
52
55
|
|
53
56
|
it "class can create nodes from variable parameters" do
|
54
57
|
ary = Node.features(0.1, 0.2, 0.3, 0.4, 0.5)
|
55
|
-
ary.
|
56
|
-
ary.map
|
57
|
-
ary.map
|
58
|
+
expect(ary).to all(be_a(Node))
|
59
|
+
expect(ary.map(&:value).sort).to eq([0.1, 0.2, 0.3, 0.4, 0.5])
|
60
|
+
expect(ary.map(&:index).sort).to eq([0, 1, 2, 3, 4])
|
58
61
|
end
|
59
62
|
|
60
63
|
it "class can create nodes from hash" do
|
61
64
|
ary = Node.features(3=>0.3, 5=>0.5, 6=>0.6, 10=>1.0)
|
62
|
-
ary.
|
63
|
-
ary.map
|
64
|
-
ary.map
|
65
|
+
expect(ary).to all(be_a(Node))
|
66
|
+
expect(ary.map(&:value).sort).to eq([0.3, 0.5, 0.6, 1.0])
|
67
|
+
expect(ary.map(&:index).sort).to eq([3, 5, 6, 10])
|
68
|
+
end
|
69
|
+
|
70
|
+
it "compares with nil" do
|
71
|
+
expect(Node.new(1,2)).to_not eq(nil)
|
65
72
|
end
|
66
73
|
|
67
|
-
it "implements
|
68
|
-
Node[1, 0.1].
|
74
|
+
it "implements value equality" do
|
75
|
+
expect(Node[1, 0.1]).to eq(Node[1, 0.1])
|
69
76
|
end
|
70
77
|
end
|
data/spec/parameter_spec.rb
CHANGED
@@ -5,72 +5,71 @@ describe "A Parameter has accessors for" do
|
|
5
5
|
@p = Libsvm::SvmParameter.new
|
6
6
|
end
|
7
7
|
it "int svm_type" do
|
8
|
-
SvmType::C_SVC.
|
8
|
+
expect(SvmType::C_SVC).to eq(0)
|
9
9
|
@p.svm_type = SvmType::C_SVC
|
10
|
-
@p.svm_type.
|
10
|
+
expect(@p.svm_type).to eq(SvmType::C_SVC)
|
11
11
|
end
|
12
12
|
|
13
13
|
it "int kernel_type" do
|
14
|
-
KernelType::RBF.
|
14
|
+
expect(KernelType::RBF).to eq(2)
|
15
15
|
@p.kernel_type = KernelType::RBF
|
16
|
-
@p.kernel_type.
|
16
|
+
expect(@p.kernel_type).to eq(KernelType::RBF)
|
17
17
|
end
|
18
18
|
|
19
19
|
it "int degree" do
|
20
20
|
@p.degree = 99
|
21
|
-
@p.degree.
|
21
|
+
expect(@p.degree).to eq(99)
|
22
22
|
end
|
23
23
|
|
24
24
|
it "double gamma" do
|
25
25
|
@p.gamma = 0.33
|
26
|
-
@p.gamma.
|
26
|
+
expect(@p.gamma).to eq(0.33)
|
27
27
|
end
|
28
28
|
|
29
29
|
it "double coef0" do
|
30
30
|
@p.coef0 = 0.99
|
31
|
-
@p.coef0.
|
31
|
+
expect(@p.coef0).to eq(0.99)
|
32
32
|
end
|
33
33
|
|
34
34
|
it "double cache_size" do
|
35
35
|
@p.cache_size = 0.77
|
36
|
-
@p.cache_size.
|
36
|
+
expect(@p.cache_size).to eq(0.77)
|
37
37
|
end
|
38
38
|
|
39
39
|
it "double eps" do
|
40
40
|
@p.eps = 0.111
|
41
|
-
@p.eps.
|
41
|
+
expect(@p.eps).to eq(0.111)
|
42
42
|
@p.eps = 0.112
|
43
|
-
@p.eps.
|
43
|
+
expect(@p.eps).to eq(0.112)
|
44
44
|
end
|
45
45
|
|
46
46
|
it "double C" do
|
47
47
|
@p.c = 3.141
|
48
|
-
@p.c.
|
48
|
+
expect(@p.c).to eq(3.141)
|
49
49
|
end
|
50
50
|
|
51
51
|
it "can set and read weights (weight, weight_label, nr_weight members from struct)" do
|
52
|
-
@p.label_weights = {1=> 1.2, 3=>0.2, 5=>0.888}
|
53
|
-
@p.label_weights.
|
52
|
+
@p.label_weights = {1 => 1.2, 3 => 0.2, 5 => 0.888}
|
53
|
+
expect(@p.label_weights).to eq({1 => 1.2, 3 => 0.2, 5 => 0.888})
|
54
54
|
end
|
55
55
|
|
56
|
-
|
57
56
|
it "double nu" do
|
58
57
|
@p.nu = 1.1
|
59
|
-
@p.nu.
|
58
|
+
expect(@p.nu).to eq(1.1)
|
60
59
|
end
|
61
60
|
|
62
61
|
it "double p" do
|
63
62
|
@p.p = 0.123
|
64
|
-
@p.p.
|
63
|
+
expect(@p.p).to eq(0.123)
|
65
64
|
end
|
66
65
|
|
67
|
-
it "int shrinking" do
|
66
|
+
it "boolean-as-int shrinking" do
|
68
67
|
@p.shrinking = 22
|
69
|
-
@p.shrinking.
|
68
|
+
expect(@p.shrinking).to eq(22)
|
70
69
|
end
|
71
70
|
|
72
|
-
it "int probability" do
|
71
|
+
it "boolean-as-int probability" do
|
73
72
|
@p.probability = 35
|
74
|
-
@p.probability.
|
73
|
+
expect(@p.probability).to eq(35)
|
75
74
|
end
|
76
75
|
end
|
data/spec/problem_spec.rb
CHANGED
@@ -12,26 +12,30 @@ describe "A Problem" do
|
|
12
12
|
it "examples get stored and retrieved" do
|
13
13
|
@problem.set_examples([1,2,1,2], @features)
|
14
14
|
labels, examples = @problem.examples
|
15
|
-
labels.size.
|
16
|
-
examples.size.
|
17
|
-
examples.map {|x|x.size}.
|
18
|
-
examples.first.map {|node| node.index}.
|
19
|
-
examples.first.map {|node| node.value}.
|
15
|
+
expect(labels.size).to eq(4)
|
16
|
+
expect(examples.size).to eq(4)
|
17
|
+
expect(examples.map {|x|x.size}).to eq([4,4,4,4])
|
18
|
+
expect(examples.first.map {|node| node.index}).to eq([0,1,2,3])
|
19
|
+
expect(examples.first.map {|node| node.value}).to eq([0.2,0.3,0.4,0.4])
|
20
20
|
end
|
21
21
|
|
22
22
|
it "can be populated" do
|
23
|
-
examples = [Node.features(0.2,0.3,0.4,0.4),
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
examples = [ Node.features(0.2,0.3,0.4,0.4),
|
24
|
+
Node.features(0.1,0.5,0.1,0.9),
|
25
|
+
Node.features(0.2,0.2,0.6,0.5),
|
26
|
+
Node.features(0.3,0.1,0.5,0.9) ]
|
27
|
+
expect {
|
28
|
+
@problem.set_examples([1,2,1,2], examples)
|
29
|
+
}.to_not raise_error
|
28
30
|
end
|
29
31
|
|
30
|
-
it "can be set twice
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
it "can be set twice" do
|
33
|
+
expect {
|
34
|
+
features = [Node.features(0.2, 0.3, 0.4, 0.4), Node.features(0.3,0.1,0.5,0.9)]
|
35
|
+
@problem.set_examples([1,2], features)
|
36
|
+
features = [Node.features(0.2, 0.3, 0.4, 0.4), Node.features(0.3,0.1,0.5,0.9)]
|
37
|
+
@problem.set_examples([8,2], features)
|
38
|
+
}.to_not raise_error
|
35
39
|
end
|
36
40
|
|
37
41
|
end
|
data/spec/usage_spec.rb
CHANGED
@@ -15,7 +15,7 @@ describe "Basic usage" do
|
|
15
15
|
|
16
16
|
it "has a nice API" do
|
17
17
|
example = {11 => 0.11, 21 => 0.21, 101 => 0.99 }.to_example
|
18
|
-
example.
|
18
|
+
expect(example).to eq(Node.features({11 => 0.11, 21 => 0.21, 101 => 0.99 }))
|
19
19
|
end
|
20
20
|
|
21
21
|
it "is as in [PCI,217]" do
|
@@ -26,13 +26,13 @@ describe "Basic usage" do
|
|
26
26
|
model = Model.train(@problem, @parameter)
|
27
27
|
|
28
28
|
pred = model.predict(Node.features(1, 1, 1))
|
29
|
-
pred.
|
29
|
+
expect(pred).to eq(1.0)
|
30
30
|
|
31
31
|
pred = model.predict(Node.features(-1, 1, -1))
|
32
|
-
pred.
|
32
|
+
expect(pred).to eq(-1.0)
|
33
33
|
|
34
34
|
pred = model.predict(Node.features(-1, 55, -1))
|
35
|
-
pred.
|
35
|
+
expect(pred).to eq(-1.0)
|
36
36
|
end
|
37
37
|
|
38
38
|
it "kernel parameter use" do
|
@@ -42,6 +42,6 @@ describe "Basic usage" do
|
|
42
42
|
|
43
43
|
model = Model.train(@problem, @parameter)
|
44
44
|
|
45
|
-
model.predict(Node.features(1, 2, 3)).
|
45
|
+
expect(model.predict(Node.features(1, 2, 3))).to eq(2)
|
46
46
|
end
|
47
47
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rb-libsvm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- C. Florian Ebeling
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2020-08-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake-compiler
|
@@ -73,6 +73,7 @@ files:
|
|
73
73
|
- lib/libsvm/problem.rb
|
74
74
|
- lib/libsvm/svm_parameter.rb
|
75
75
|
- lib/libsvm/version.rb
|
76
|
+
- lib/rb-libsvm.rb
|
76
77
|
- rb-libsvm.gemspec
|
77
78
|
- spec/core_ext_spec.rb
|
78
79
|
- spec/model_spec.rb
|
@@ -82,7 +83,8 @@ files:
|
|
82
83
|
- spec/spec_helper.rb
|
83
84
|
- spec/usage_spec.rb
|
84
85
|
homepage: https://github.com/febeling/rb-libsvm
|
85
|
-
licenses:
|
86
|
+
licenses:
|
87
|
+
- MIT
|
86
88
|
metadata: {}
|
87
89
|
post_install_message:
|
88
90
|
rdoc_options: []
|
@@ -99,8 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
101
|
- !ruby/object:Gem::Version
|
100
102
|
version: '0'
|
101
103
|
requirements: []
|
102
|
-
|
103
|
-
rubygems_version: 2.2.2
|
104
|
+
rubygems_version: 3.1.2
|
104
105
|
signing_key:
|
105
106
|
specification_version: 4
|
106
107
|
summary: Ruby bindings for LIBSVM
|
@@ -112,4 +113,3 @@ test_files:
|
|
112
113
|
- spec/problem_spec.rb
|
113
114
|
- spec/spec_helper.rb
|
114
115
|
- spec/usage_spec.rb
|
115
|
-
has_rdoc:
|