ruby_linear 0.1.0
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/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: []
|