ruby_linear 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +3 -0
- data/COPYING +24 -0
- data/README.markdown +109 -0
- data/Rakefile +15 -0
- data/ext/blas.h +25 -0
- data/ext/blasp.h +430 -0
- data/ext/daxpy.c +49 -0
- data/ext/ddot.c +50 -0
- data/ext/dnrm2.c +62 -0
- data/ext/dscal.c +44 -0
- data/ext/extconf.rb +4 -0
- data/ext/linear.cpp +2385 -0
- data/ext/linear.h +77 -0
- data/ext/rubylinear.cpp +639 -0
- data/ext/tron.cpp +235 -0
- data/ext/tron.h +34 -0
- data/lib/ruby_linear.rb +11 -0
- data/spec/fixtures/dna.dat +187 -0
- data/spec/fixtures/dna.out +1186 -0
- data/spec/fixtures/dna.scale.t +1186 -0
- data/spec/fixtures/dna.scale.txt +2000 -0
- data/spec/integration_spec.rb +54 -0
- data/spec/model_spec.rb +57 -0
- data/spec/problem_spec.rb +83 -0
- data/spec/spec_helper.rb +10 -0
- metadata +71 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe(RubyLinear) do
|
5
|
+
|
6
|
+
# The data files are the data set from http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass.html#dna
|
7
|
+
# The model was created with train -s 5 -e 0.01 -B 1 dna.scale.txt dna.dat
|
8
|
+
# the output was created with predict dna.scale.t dna.dat dna.out
|
9
|
+
|
10
|
+
def parse_line(l)
|
11
|
+
h = {}
|
12
|
+
l.split(' ').each do |s|
|
13
|
+
if s =~ /(\d+):(\d+)/
|
14
|
+
h[$1.to_i] = $2.to_i
|
15
|
+
end
|
16
|
+
end
|
17
|
+
h
|
18
|
+
end
|
19
|
+
|
20
|
+
before(:each) do
|
21
|
+
problem = RubyLinear::Problem.load_file("spec/fixtures/dna.scale.txt",1)
|
22
|
+
@model = RubyLinear::Model.new(problem, :solver => RubyLinear::L1R_L2LOSS_SVC)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should produce the same output as the command line tools' do
|
26
|
+
@model.should predict_values('spec/fixtures/dna.out').for_input('spec/fixtures/dna.scale.t')
|
27
|
+
end
|
28
|
+
|
29
|
+
RSpec::Matchers.define :predict_values do |output_file|
|
30
|
+
match do |model|
|
31
|
+
input_lines = File.readlines(@input)
|
32
|
+
output_lines = File.readlines(output_file)
|
33
|
+
raise "mismatched inputs" unless input_lines.length == output_lines.length
|
34
|
+
raise "input empty" if input_lines.length < 1
|
35
|
+
input_lines.each_with_index do |line, index|
|
36
|
+
sample = parse_line(line)
|
37
|
+
if (@predicted = model.predict(sample)) != (@actual = output_lines[index].to_i)
|
38
|
+
@failed_line = index + 1
|
39
|
+
break
|
40
|
+
end
|
41
|
+
end
|
42
|
+
@failed_line.nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
failure_message_for_should do |actual|
|
46
|
+
"Incorrect prediction on line #{@failed_line}, expected #{@actual} got #{@predicted}"
|
47
|
+
end
|
48
|
+
|
49
|
+
chain :for_input do |input|
|
50
|
+
@input = input
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/spec/model_spec.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe(RubyLinear::Model) do
|
5
|
+
|
6
|
+
let :test_vector do#first line from dna.scale.t
|
7
|
+
{6 => 1, 7 => 1, 11 => 1, 18 => 1, 20 => 1, 24 => 1, 27 => 1, 30 => 1, 33 => 1, 34 => 1, 38 => 1, 42 => 1, 45 => 1, 47 => 1, 53 => 1, 60 => 1, 61 => 1, 65 => 1, 69 => 1, 70 => 1, 75 => 1, 78 => 1, 79 => 1, 84 => 1, 87 => 1, 88 => 1, 92 => 1, 99 => 1, 101 => 1, 103 => 1, 108 => 1, 110 => 1, 112 => 1, 119 => 1, 123 => 1, 124 => 1, 128 => 1, 131 => 1, 134 => 1, 137 => 1, 139 => 1, 142 => 1, 147 => 1, 149 => 1, 156 => 1, 157 => 1, 161 => 1, 164 => 1, 166 => 1, 171 => 1, 173 => 1, 180 => 1}
|
8
|
+
end
|
9
|
+
|
10
|
+
describe('load_file') do
|
11
|
+
before(:each) do
|
12
|
+
@model = RubyLinear::Model.load_file(File.dirname(__FILE__) + '/fixtures/dna.dat')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should load the model from the path' do
|
16
|
+
@model.bias.should == 1
|
17
|
+
@model.class_count.should == 3
|
18
|
+
@model.feature_count.should == 180
|
19
|
+
@model.labels.should == [3,1,2]
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should be able to predict' do
|
23
|
+
@model.predict(test_vector).should == 3
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe('predict_values') do
|
28
|
+
before(:each) do
|
29
|
+
@model = RubyLinear::Model.load_file(File.dirname(__FILE__) + '/fixtures/dna.dat')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should return the class and a hash of labels to values' do
|
33
|
+
label, values = @model.predict_values(test_vector)
|
34
|
+
|
35
|
+
label.should == 3
|
36
|
+
values.keys.should =~ [1,2,3]
|
37
|
+
values[3].should be_within(0.001).of(4.178)
|
38
|
+
values[2].should be_within(0.001).of(-8.477)
|
39
|
+
values[1].should be_within(0.001).of(-3.568)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
describe('new') do
|
43
|
+
let(:problem) {RubyLinear::Problem.load_file(File.dirname(__FILE__) + '/fixtures/dna.scale.txt', 1.0)}
|
44
|
+
it 'should train the model from the parameters and the problem' do
|
45
|
+
m = RubyLinear::Model.new(problem, :solver => RubyLinear::L1R_L2LOSS_SVC)
|
46
|
+
m.predict(test_vector).should == 3
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when unknwon options are presented' do
|
50
|
+
it 'should raise argument error' do
|
51
|
+
expect { RubyLinear::Model.new(problem, :solver => RubyLinear::L1R_L2LOSS_SVC, :bogus_option => true) }.to raise_error(ArgumentError)
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe(RubyLinear::Problem) do
|
5
|
+
|
6
|
+
describe 'load_file' do
|
7
|
+
it 'should load a libsvm format file' do
|
8
|
+
problem = RubyLinear::Problem.load_file(File.dirname(__FILE__) + '/fixtures/dna.scale.txt', -1)
|
9
|
+
problem.bias.should == -1
|
10
|
+
|
11
|
+
problem.l.should == 2000
|
12
|
+
problem.n.should == 180
|
13
|
+
|
14
|
+
#line 1 from the file
|
15
|
+
problem.feature_vector(0).should == [[2,1], [7,1], [12,1], [15,1], [17,1], [23,1], [26,1], [28,1], [33,1], [34,1], [40,1], [45,1], [47,1], [50,1], [52,1], [58,1], [63,1], [64,1], [67,1], [72,1], [73,1], [76,1], [80,1], [83,1], [85,1], [88,1], [91,1], [95,1], [97,1], [101,1], [113,1], [120,1], [122,1], [126,1], [132,1], [138,1], [144,1], [145,1], [150,1], [151,1], [154,1], [160,1], [163,1], [170,1], [172,1], [177,1], [178,1]]
|
16
|
+
|
17
|
+
problem.labels.length.should == 2000
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should add 1 to the feature count if the bias is > 0' do
|
21
|
+
problem = RubyLinear::Problem.load_file(File.dirname(__FILE__) + '/fixtures/dna.scale.txt', 1)
|
22
|
+
|
23
|
+
problem.l.should == 2000
|
24
|
+
problem.n.should == 181
|
25
|
+
|
26
|
+
problem.feature_vector(0).should == [[2,1], [7,1], [12,1], [15,1], [17,1], [23,1], [26,1], [28,1], [33,1], [34,1], [40,1], [45,1], [47,1], [50,1], [52,1], [58,1], [63,1], [64,1], [67,1], [72,1], [73,1], [76,1], [80,1], [83,1], [85,1], [88,1], [91,1], [95,1], [97,1], [101,1], [113,1], [120,1], [122,1], [126,1], [132,1], [138,1], [144,1], [145,1], [150,1], [151,1], [154,1], [160,1], [163,1], [170,1], [172,1], [177,1], [178,1],[181,1]]
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'destroy' do
|
32
|
+
|
33
|
+
it 'should release associated memory' do
|
34
|
+
problem = RubyLinear::Problem.load_file(File.dirname(__FILE__) + '/fixtures/dna.scale.txt', 1)
|
35
|
+
problem.destroyed?.should be_false
|
36
|
+
problem.destroy!
|
37
|
+
problem.destroyed?.should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'new' do
|
43
|
+
before(:each) do
|
44
|
+
@samples = [ {2=>0.1,3=>0.3,4=>-1.2},{1=>0.4},{2=>0.1, 4=>1.4,5=>0.5},{1 => -0.1, 2=> -0.2, 3=>0.1,4=>1.1,5=>0.1}]
|
45
|
+
@labels = [2,1,2,3]
|
46
|
+
@max_feature = 5
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when max feature is inconsistent with the samples' do
|
50
|
+
it 'should raise argument error' do
|
51
|
+
expect {RubyLinear::Problem.new(@labels, @samples, -1, 3)}.to raise_error(ArgumentError, /inconsistent/)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when samples and labels are of different length' do
|
56
|
+
it 'should raise argument error' do
|
57
|
+
expect {RubyLinear::Problem.new([1,2,3], @samples, -1, @max_feature)}.to raise_error(ArgumentError, /different length/)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
context 'when the bias is < 0' do
|
61
|
+
it 'should create a new problem' do
|
62
|
+
problem = RubyLinear::Problem.new(@labels, @samples, -1, @max_feature)
|
63
|
+
|
64
|
+
problem.l.should == 4
|
65
|
+
problem.n.should == 5
|
66
|
+
problem.bias.should == -1
|
67
|
+
problem.labels.should == [2,1,2,3]
|
68
|
+
problem.feature_vector(0).should == [[2,0.1], [3,0.3], [4,-1.2]]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when the bias is > 0' do
|
73
|
+
it 'should add a bias term to each vextor' do
|
74
|
+
problem = RubyLinear::Problem.new(@labels, @samples, 1.0, @max_feature)
|
75
|
+
#all the feature vectors should also be padded with
|
76
|
+
problem.l.should == 4
|
77
|
+
problem.n.should == 6
|
78
|
+
problem.bias.should == 1
|
79
|
+
problem.feature_vector(0).should == [[2,0.1], [3,0.3], [4,-1.2], [6,1]]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_linear
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Frederick Cheung
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-29 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! 'Ruby wrapper for LIBLINEAR, a library for large linear classification '
|
15
|
+
email: frederick.cheung@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions:
|
18
|
+
- ext/extconf.rb
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- COPYING
|
22
|
+
- AUTHORS
|
23
|
+
- README.markdown
|
24
|
+
- Rakefile
|
25
|
+
- ext/extconf.rb
|
26
|
+
- ext/blas.h
|
27
|
+
- ext/blasp.h
|
28
|
+
- ext/linear.h
|
29
|
+
- ext/tron.h
|
30
|
+
- ext/linear.cpp
|
31
|
+
- ext/rubylinear.cpp
|
32
|
+
- ext/tron.cpp
|
33
|
+
- ext/daxpy.c
|
34
|
+
- ext/ddot.c
|
35
|
+
- ext/dnrm2.c
|
36
|
+
- ext/dscal.c
|
37
|
+
- lib/ruby_linear.rb
|
38
|
+
- spec/fixtures/dna.dat
|
39
|
+
- spec/fixtures/dna.out
|
40
|
+
- spec/fixtures/dna.scale.t
|
41
|
+
- spec/fixtures/dna.scale.txt
|
42
|
+
- spec/integration_spec.rb
|
43
|
+
- spec/model_spec.rb
|
44
|
+
- spec/problem_spec.rb
|
45
|
+
- spec/spec_helper.rb
|
46
|
+
homepage: http://github.com/fcheung/rubylinear
|
47
|
+
licenses:
|
48
|
+
- MIT
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: 1.9.2
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.8.10
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Ruby wrapper for LIBLINEAR
|
71
|
+
test_files: []
|