rb-libsvm 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +28 -0
- data/MIT-LICENSE +20 -0
- data/README.textile +37 -0
- data/Rakefile +13 -0
- data/ext/rb-libsvm/extconf.rb +46 -0
- data/ext/rb-libsvm/libsvm.c +489 -0
- data/ext/rb-libsvm/ruby-ext.h +42 -0
- data/ext/rb-libsvm/svm.cpp +3072 -0
- data/ext/rb-libsvm/svm.h +101 -0
- data/ferret_valgrind.supp +478 -0
- data/lib/libsvm.rb +63 -0
- data/lib/rb-libsvm/version.rb +3 -0
- data/rb-libsvm.gemspec +27 -0
- data/spec/model_spec.rb +95 -0
- data/spec/node_spec.rb +68 -0
- data/spec/parameter_spec.rb +76 -0
- data/spec/problem_spec.rb +37 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/usage_spec.rb +37 -0
- metadata +97 -0
data/lib/libsvm.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rb-libsvm/version'
|
2
|
+
require 'rb-libsvm/libsvm'
|
3
|
+
|
4
|
+
module Libsvm
|
5
|
+
|
6
|
+
module CoreExtensions
|
7
|
+
module Collection
|
8
|
+
def to_example
|
9
|
+
Node.features(self)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Node
|
15
|
+
|
16
|
+
class << self
|
17
|
+
|
18
|
+
def features(*vargs)
|
19
|
+
array_of_nodes = []
|
20
|
+
if vargs.size == 1
|
21
|
+
if vargs.first.class == Array
|
22
|
+
vargs.first.each_with_index do |value, index|
|
23
|
+
array_of_nodes << Node.new(index.to_i, value.to_f)
|
24
|
+
end
|
25
|
+
elsif vargs.first.class == Hash
|
26
|
+
vargs.first.each do |index, value|
|
27
|
+
array_of_nodes << Node.new(index.to_i, value.to_f)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
raise(ArgumentError.new("Node features need to be a Hash, Array or Floats"))
|
31
|
+
end
|
32
|
+
else
|
33
|
+
vargs.each_with_index do |value, index|
|
34
|
+
array_of_nodes << Node.new(index.to_i, value.to_f)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
array_of_nodes
|
38
|
+
end
|
39
|
+
|
40
|
+
def [](index, value)
|
41
|
+
new(index, value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(index=0, value=0.0)
|
46
|
+
self.index = index
|
47
|
+
self.value = value
|
48
|
+
end
|
49
|
+
|
50
|
+
def ==(other)
|
51
|
+
index == other.index && value == other.value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
class Hash
|
59
|
+
include Libsvm::CoreExtensions::Collection
|
60
|
+
end
|
61
|
+
class Array
|
62
|
+
include Libsvm::CoreExtensions::Collection
|
63
|
+
end
|
data/rb-libsvm.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require 'rb-libsvm/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rb-libsvm"
|
7
|
+
s.version = Libsvm::VERSION
|
8
|
+
s.authors = ["C. Florian Ebeling", "Rimas Silkaitis"]
|
9
|
+
s.email = ["neovintage@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/febeling/rb-libsvm"
|
11
|
+
s.summary = %q{Ruby language bindings for LIBSVM}
|
12
|
+
s.description = %q{libsvm and ruby without using swig}
|
13
|
+
|
14
|
+
s.rubyforge_project = "rb-libsvm"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "rake-compiler"
|
23
|
+
s.add_development_dependency "rspec", "2.7.0"
|
24
|
+
|
25
|
+
s.extensions << 'ext/rb-libsvm/extconf.rb'
|
26
|
+
end
|
27
|
+
|
data/spec/model_spec.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module ModelSpecHelper
|
4
|
+
|
5
|
+
def create_example
|
6
|
+
Node.features(0.2, 0.3, 0.4, 0.5)
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_problem
|
10
|
+
problem = Problem.new
|
11
|
+
features = [Node.features([0.2,0.3,0.4,0.4]),
|
12
|
+
Node.features([0.1,0.5,0.1,0.9]),
|
13
|
+
Node.features([0.2,0.2,0.6,0.5]),
|
14
|
+
Node.features([0.3,0.1,0.5,0.9])]
|
15
|
+
problem.set_examples([1,2,1,2], features)
|
16
|
+
problem
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_parameter
|
20
|
+
parameter = SvmParameter.new
|
21
|
+
parameter.cache_size = 50 # mb
|
22
|
+
parameter.eps = 0.01
|
23
|
+
parameter.c = 10
|
24
|
+
parameter
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "The Libsvm::Model class interface" do
|
30
|
+
include ModelSpecHelper
|
31
|
+
|
32
|
+
before(:each) do
|
33
|
+
@problem = create_problem
|
34
|
+
@parameter = create_parameter
|
35
|
+
end
|
36
|
+
|
37
|
+
it "results from training on a problem under a certain parameter set" do
|
38
|
+
model = Model.train(@problem,@parameter)
|
39
|
+
model.should_not be_nil
|
40
|
+
end
|
41
|
+
|
42
|
+
it "can do cross-validation" do
|
43
|
+
labels = Model.cross_validation(@problem, @parameter, fold=2)
|
44
|
+
labels.should == [anything, anything, anything, anything]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "A saved model" do
|
49
|
+
include ModelSpecHelper
|
50
|
+
|
51
|
+
before(:each) do
|
52
|
+
@filename = "svm_model.model"
|
53
|
+
model = Model.train(create_problem, create_parameter)
|
54
|
+
model.save(@filename)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "can be loaded" do
|
58
|
+
model = Model.load(@filename)
|
59
|
+
model.should_not be_nil
|
60
|
+
end
|
61
|
+
|
62
|
+
after(:each) do
|
63
|
+
File.delete(@filename) rescue nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "An Libsvm model" do
|
68
|
+
include ModelSpecHelper
|
69
|
+
|
70
|
+
before(:each) do
|
71
|
+
@problem = create_problem
|
72
|
+
@parameter = create_parameter
|
73
|
+
@model = Model.train(@problem, @parameter)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "can be saved to a file" do
|
77
|
+
file_path = "svm_model.model"
|
78
|
+
@model.save(file_path)
|
79
|
+
File.exist?(file_path).should be_true
|
80
|
+
end
|
81
|
+
|
82
|
+
it "can be asked for it's svm_type" do
|
83
|
+
@model.svm_type.should == SvmType::C_SVC
|
84
|
+
end
|
85
|
+
|
86
|
+
it "can be asked for it's number of classes (aka. labels)" do
|
87
|
+
@model.classes.should == 2
|
88
|
+
end
|
89
|
+
|
90
|
+
it "can predict" do
|
91
|
+
prediction = @model.predict(create_example)
|
92
|
+
prediction.should_not be_nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
data/spec/node_spec.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "construction of a Node" do
|
4
|
+
it "using the properties" do
|
5
|
+
n = Node.new
|
6
|
+
n.index = 11
|
7
|
+
n.value = 0.11
|
8
|
+
n.index.should == 11
|
9
|
+
n.value.should be_within(0.0001).of(0.11)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "using the :[] method" do
|
13
|
+
n = Node[12, 0.12]
|
14
|
+
n.index.should == 12
|
15
|
+
n.value.should be_within(0.00001).of(0.12)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "using the constructor parameters" do
|
19
|
+
n = Node.new(14, 0.14)
|
20
|
+
n.index.should == 14
|
21
|
+
n.value.should be_within(0.0001).of(0.14)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "A Node" do
|
26
|
+
before do
|
27
|
+
@node = Node.new
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can be created" do
|
31
|
+
@node.should_not be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it "does not segfault on setting properties" do
|
35
|
+
@node.index = 99
|
36
|
+
@node.index.should == 99
|
37
|
+
@node.value = 3.141
|
38
|
+
@node.value.should be_within(0.00001).of(3.141)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "has inited properties" do
|
42
|
+
@node.index.should == 0
|
43
|
+
@node.value.should be_within(0.00001).of(0)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "class can create nodes from an array" do
|
47
|
+
ary = Node.features([0.1, 0.2, 0.3, 0.4, 0.5])
|
48
|
+
ary.map {|n| n.class.should == Node}
|
49
|
+
ary.map {|n| n.value }.should == [0.1, 0.2, 0.3, 0.4, 0.5]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "class can create nodes from variable parameters" do
|
53
|
+
ary = Node.features(0.1, 0.2, 0.3, 0.4, 0.5)
|
54
|
+
ary.map {|n| Node.should === n }
|
55
|
+
ary.map {|n| n.value }.should == [0.1, 0.2, 0.3, 0.4, 0.5]
|
56
|
+
end
|
57
|
+
|
58
|
+
it "class can create nodes from hash" do
|
59
|
+
ary = Node.features(3=>0.3, 5=>0.5, 6=>0.6, 10=>1.0)
|
60
|
+
ary.map {|n| n.class.should == Node}
|
61
|
+
ary.map {|n| n.value }.sort.should == [0.3, 0.5, 0.6, 1.0]
|
62
|
+
ary.map {|n| n.index }.sort.should == [3, 5, 6, 10]
|
63
|
+
end
|
64
|
+
|
65
|
+
it "implements a value-like equality, not identity-notion" do
|
66
|
+
Node[1, 0.1].should == Node[1, 0.1]
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "A Parameter has accessors for" do
|
4
|
+
before do
|
5
|
+
@p = Libsvm::SvmParameter.new
|
6
|
+
end
|
7
|
+
it "int svm_type" do
|
8
|
+
SvmType::C_SVC.should == 0
|
9
|
+
@p.svm_type = SvmType::C_SVC
|
10
|
+
@p.svm_type.should == SvmType::C_SVC
|
11
|
+
end
|
12
|
+
|
13
|
+
it "int kernel_type" do
|
14
|
+
KernelType::RBF.should == 2
|
15
|
+
@p.kernel_type = KernelType::RBF
|
16
|
+
@p.kernel_type.should == KernelType::RBF
|
17
|
+
end
|
18
|
+
|
19
|
+
it "int degree" do
|
20
|
+
@p.degree = 99
|
21
|
+
@p.degree.should == 99
|
22
|
+
end
|
23
|
+
|
24
|
+
it "double gamma" do
|
25
|
+
@p.gamma = 0.33
|
26
|
+
@p.gamma.should == 0.33
|
27
|
+
end
|
28
|
+
|
29
|
+
it "double coef0" do
|
30
|
+
@p.coef0 = 0.99
|
31
|
+
@p.coef0.should == 0.99
|
32
|
+
end
|
33
|
+
|
34
|
+
it "double cache_size" do
|
35
|
+
@p.cache_size = 0.77
|
36
|
+
@p.cache_size.should == 0.77
|
37
|
+
end
|
38
|
+
|
39
|
+
it "double eps" do
|
40
|
+
@p.eps = 0.111
|
41
|
+
@p.eps.should == 0.111
|
42
|
+
@p.eps = 0.112
|
43
|
+
@p.eps.should == 0.112
|
44
|
+
end
|
45
|
+
|
46
|
+
it "double C" do
|
47
|
+
@p.c = 3.141
|
48
|
+
@p.c.should == 3.141
|
49
|
+
end
|
50
|
+
|
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.should == {1=> 1.2, 3=>0.2, 5=>0.888}
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
it "double nu" do
|
58
|
+
@p.nu = 1.1
|
59
|
+
@p.nu.should == 1.1
|
60
|
+
end
|
61
|
+
|
62
|
+
it "double p" do
|
63
|
+
@p.p = 0.123
|
64
|
+
@p.p.should == 0.123
|
65
|
+
end
|
66
|
+
|
67
|
+
it "int shrinking" do
|
68
|
+
@p.shrinking = 22
|
69
|
+
@p.shrinking.should == 22
|
70
|
+
end
|
71
|
+
|
72
|
+
it "int probability" do
|
73
|
+
@p.probability = 35
|
74
|
+
@p.probability.should == 35
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "A Problem" do
|
4
|
+
before(:each) do
|
5
|
+
@problem = Problem.new
|
6
|
+
@features = [ Node.features(0.2,0.3,0.4,0.4),
|
7
|
+
Node.features(0.1,0.5,0.1,0.9),
|
8
|
+
Node.features(0.2,0.2,0.6,0.5),
|
9
|
+
Node.features(0.3,0.1,0.5,0.9) ]
|
10
|
+
end
|
11
|
+
|
12
|
+
it "examples get stored and retrieved" do
|
13
|
+
@problem.set_examples([1,2,1,2], @features)
|
14
|
+
labels, examples = @problem.examples
|
15
|
+
labels.size.should == 4
|
16
|
+
examples.size.should == 4
|
17
|
+
examples.map {|x|x.size}.should == [4,4,4,4]
|
18
|
+
examples.first.map {|node| node.index}.should == [0,1,2,3]
|
19
|
+
examples.first.map {|node| node.value}.should == [0.2,0.3,0.4,0.4]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "can be populated" do
|
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
|
+
@problem.set_examples([1,2,1,2], examples)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can be set twice over" do
|
31
|
+
features = [Node.features(0.2, 0.3, 0.4, 0.4), Node.features(0.3,0.1,0.5,0.9)]
|
32
|
+
@problem.set_examples([1,2], features)
|
33
|
+
features = [Node.features(0.2, 0.3, 0.4, 0.4), Node.features(0.3,0.1,0.5,0.9)]
|
34
|
+
@problem.set_examples([8,2], features)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/usage_spec.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Basic usage" do
|
4
|
+
before do
|
5
|
+
@problem = Problem.new
|
6
|
+
@parameter = SvmParameter.new
|
7
|
+
@parameter.cache_size = 1 # mb
|
8
|
+
|
9
|
+
# "eps is the stopping criterion (we usually use 0.00001 in nu-SVC,
|
10
|
+
# 0.001 in others)." (from README)
|
11
|
+
@parameter.eps = 0.001
|
12
|
+
|
13
|
+
@parameter.c = 10
|
14
|
+
end
|
15
|
+
|
16
|
+
it "has a nice API" do
|
17
|
+
example = {11 => 0.11, 21 => 0.21, 101 => 0.99 }.to_example
|
18
|
+
example.should == Node.features({11 => 0.11, 21 => 0.21, 101 => 0.99 })
|
19
|
+
end
|
20
|
+
|
21
|
+
it "is as in [PCI,217]" do
|
22
|
+
examples = [ [1,0,1], [-1,0,-1] ].map {|ary| Node.features(ary) }
|
23
|
+
labels = [1, -1]
|
24
|
+
@problem.set_examples(labels, examples)
|
25
|
+
|
26
|
+
model = Model.train(@problem, @parameter)
|
27
|
+
|
28
|
+
pred = model.predict(Node.features(1, 1, 1))
|
29
|
+
pred.should == 1.0
|
30
|
+
|
31
|
+
pred = model.predict(Node.features(-1, 1, -1))
|
32
|
+
pred.should == -1.0
|
33
|
+
|
34
|
+
pred = model.predict(Node.features(-1, 55, -1))
|
35
|
+
pred.should == -1.0
|
36
|
+
end
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rb-libsvm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- C. Florian Ebeling
|
9
|
+
- Rimas Silkaitis
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2011-11-07 00:00:00.000000000Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rake-compiler
|
17
|
+
requirement: &2157654260 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2157654260
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rspec
|
28
|
+
requirement: &2157653760 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - =
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.7.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *2157653760
|
37
|
+
description: libsvm and ruby without using swig
|
38
|
+
email:
|
39
|
+
- neovintage@gmail.com
|
40
|
+
executables: []
|
41
|
+
extensions:
|
42
|
+
- ext/rb-libsvm/extconf.rb
|
43
|
+
extra_rdoc_files: []
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- .rvmrc
|
47
|
+
- Gemfile
|
48
|
+
- Gemfile.lock
|
49
|
+
- MIT-LICENSE
|
50
|
+
- README.textile
|
51
|
+
- Rakefile
|
52
|
+
- ext/rb-libsvm/extconf.rb
|
53
|
+
- ext/rb-libsvm/libsvm.c
|
54
|
+
- ext/rb-libsvm/ruby-ext.h
|
55
|
+
- ext/rb-libsvm/svm.cpp
|
56
|
+
- ext/rb-libsvm/svm.h
|
57
|
+
- ferret_valgrind.supp
|
58
|
+
- lib/libsvm.rb
|
59
|
+
- lib/rb-libsvm/version.rb
|
60
|
+
- rb-libsvm.gemspec
|
61
|
+
- spec/model_spec.rb
|
62
|
+
- spec/node_spec.rb
|
63
|
+
- spec/parameter_spec.rb
|
64
|
+
- spec/problem_spec.rb
|
65
|
+
- spec/spec_helper.rb
|
66
|
+
- spec/usage_spec.rb
|
67
|
+
homepage: https://github.com/febeling/rb-libsvm
|
68
|
+
licenses: []
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project: rb-libsvm
|
87
|
+
rubygems_version: 1.8.9
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: Ruby language bindings for LIBSVM
|
91
|
+
test_files:
|
92
|
+
- spec/model_spec.rb
|
93
|
+
- spec/node_spec.rb
|
94
|
+
- spec/parameter_spec.rb
|
95
|
+
- spec/problem_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
- spec/usage_spec.rb
|