tomz-libsvm-ruby-swig 0.2.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/lib/svm.rb ADDED
@@ -0,0 +1,337 @@
1
+ require 'svmc'
2
+ include Svmc
3
+
4
+ def _int_array(seq)
5
+ size = seq.size
6
+ array = new_int(size)
7
+ i = 0
8
+ for item in seq
9
+ int_setitem(array,i,item)
10
+ i = i + 1
11
+ end
12
+ return array
13
+ end
14
+
15
+ def _double_array(seq)
16
+ size = seq.size
17
+ array = new_double(size)
18
+ i = 0
19
+ for item in seq
20
+ double_setitem(array,i,item)
21
+ i = i + 1
22
+ end
23
+ return array
24
+ end
25
+
26
+ def _free_int_array(x)
27
+ if !x.nil? and !x.empty?
28
+ delete_int(x)
29
+ end
30
+ end
31
+
32
+ def _free_double_array(x)
33
+ if !x.nil? and !x.empty?
34
+ delete_double(x)
35
+ end
36
+ end
37
+
38
+ def _int_array_to_list(x,n)
39
+ list = []
40
+ (0..n-1).each {|i| list << int_getitem(x,i) }
41
+ return list
42
+ end
43
+
44
+ def _double_array_to_list(x,n)
45
+ list = []
46
+ (0..n-1).each {|i| list << double_getitem(x,i) }
47
+ return list
48
+ end
49
+
50
+ class Parameter
51
+ attr_accessor :param
52
+
53
+ def initialize(*args)
54
+ @param = Svm_parameter.new
55
+ @param.svm_type = C_SVC
56
+ @param.kernel_type = RBF
57
+ @param.degree = 3
58
+ @param.gamma = 0 # 1/k
59
+ @param.coef0 = 0
60
+ @param.nu = 0.5
61
+ @param.cache_size = 100
62
+ @param.C = 1
63
+ @param.eps = 1e-3
64
+ @param.p = 0.1
65
+ @param.shrinking = 1
66
+ @param.nr_weight = 0
67
+ #@param.weight_label = _int_array([])
68
+ #@param.weight = _double_array([])
69
+ @param.probability = 0
70
+
71
+ args[0].each {|k,v|
72
+ self.send("#{k}=",v)
73
+ } if !args[0].nil?
74
+ end
75
+
76
+ def method_missing(m, *args)
77
+ if m.to_s == 'weight_label='
78
+ @weight_label_len = args[0].size
79
+ pargs = _int_array(args[0])
80
+ _free_int_array(@param.weight_label)
81
+ elsif m.to_s == 'weight='
82
+ @weight_len = args[0].size
83
+ pargs = _double_array(args[0])
84
+ _free_double_array(@param.weight)
85
+ else
86
+ pargs = args[0]
87
+ end
88
+
89
+ if m.to_s.index('=')
90
+ @param.send("#{m}",pargs)
91
+ else
92
+ @param.send("#{m}")
93
+ end
94
+
95
+ end
96
+
97
+ def destroy
98
+ _free_int_array(@param.weight_label)
99
+ _free_double_array(@param.weight)
100
+ #delete_svm_parameter(@param)
101
+ @param = nil
102
+ end
103
+ end
104
+
105
+ def _convert_to_svm_node_array(x)
106
+ # convert a sequence or mapping to an svm_node array
107
+
108
+ # Find non zero elements
109
+ iter_range = []
110
+ if x.class == Hash
111
+ x.each {|k, v|
112
+ # all zeros kept due to the precomputed kernel; no good solution yet
113
+ iter_range << k # if v != 0
114
+ }
115
+ elsif x.class == Array
116
+ x.each_index {|j|
117
+ iter_range << j #if x[j] != 0
118
+ }
119
+ else
120
+ raise TypeError,"data must be a mapping or a sequence"
121
+ end
122
+
123
+ iter_range.sort
124
+ data = svm_node_array(iter_range.size+1)
125
+ svm_node_array_set(data,iter_range.size,-1,0)
126
+
127
+ j = 0
128
+ for k in iter_range
129
+ svm_node_array_set(data,j,k,x[k])
130
+ j = j + 1
131
+ end
132
+ return data
133
+ end
134
+
135
+ class Problem
136
+ attr_accessor :prob, :maxlen, :size
137
+
138
+ def initialize(y,x)
139
+ #assert y.size == x.size
140
+ @prob = prob = Svm_problem.new
141
+ @size = size = y.size
142
+
143
+ @y_array = y_array = new_double(size)
144
+ for i in (0..size-1)
145
+ double_setitem(@y_array,i,y[i])
146
+ end
147
+
148
+ @x_matrix = x_matrix = svm_node_matrix(size)
149
+ @data = []
150
+ @maxlen = 0
151
+ for i in (0..size-1)
152
+ data = _convert_to_svm_node_array(x[i])
153
+ @data << data
154
+ svm_node_matrix_set(x_matrix,i,data)
155
+ if x[i].class == Hash
156
+ if x[i].size > 0
157
+ @maxlen = [@maxlen,x[i].keys.max].max
158
+ end
159
+ else
160
+ @maxlen = [@maxlen,x[i].size].max
161
+ end
162
+ end
163
+
164
+ prob.l = size
165
+ prob.y = y_array
166
+ prob.x = x_matrix
167
+ end
168
+
169
+ def inspect
170
+ return "svm_problem: size = #{size}"
171
+ end
172
+
173
+ def destroy
174
+ delete_svm_problem(@prob)
175
+ delete_double(@y_array)
176
+ for i in (0..size-1)
177
+ svm_node_array_destroy(@data[i])
178
+ end
179
+ svm_node_matrix_destroy(@x_matrix)
180
+ end
181
+ end
182
+
183
+ class Model
184
+ attr_accessor :model,:objs
185
+
186
+ def initialize(arg1,arg2=nil)
187
+ if arg2 == nil
188
+ # create model from file
189
+ filename = arg1
190
+ @model = svm_load_model(filename)
191
+ else
192
+ # create model from problem and parameter
193
+ prob,param = arg1,arg2
194
+ @prob = prob
195
+ if param.gamma == 0
196
+ param.gamma = 1.0/prob.maxlen
197
+ end
198
+ msg = svm_check_parameter(prob.prob,param.param)
199
+ raise "ValueError", msg if msg
200
+ @model = svm_train(prob.prob,param.param)
201
+ end
202
+
203
+ #setup some classwide variables
204
+ @nr_class = svm_get_nr_class(@model)
205
+ @svm_type = svm_get_svm_type(@model)
206
+ #create labels(classes)
207
+ intarr = new_int(@nr_class)
208
+ svm_get_labels(@model,intarr)
209
+ @labels = _int_array_to_list(intarr, @nr_class)
210
+ delete_int(intarr)
211
+ #check if valid probability model
212
+ @probability = svm_check_probability_model(@model)
213
+
214
+ @objs = []
215
+ for i in (0..@labels.size-1)
216
+ @objs << svm_get_obj(@model, i)
217
+ end if arg2 != nil
218
+
219
+ end
220
+
221
+ def predict(x)
222
+ data = _convert_to_svm_node_array(x)
223
+ ret = svm_predict(@model,data)
224
+ svm_node_array_destroy(data)
225
+ return ret
226
+ end
227
+
228
+
229
+ def get_nr_class
230
+ return @nr_class
231
+ end
232
+
233
+ def get_labels
234
+ if @svm_type == NU_SVR or @svm_type == EPSILON_SVR or @svm_type == ONE_CLASS
235
+ raise TypeError, "Unable to get label from a SVR/ONE_CLASS model"
236
+ end
237
+ return @labels
238
+ end
239
+
240
+ def predict_values_raw(x)
241
+ #convert x into svm_node, allocate a double array for return
242
+ n = (@nr_class*(@nr_class-1)/2).floor
243
+ data = _convert_to_svm_node_array(x)
244
+ dblarr = new_double(n)
245
+ svm_predict_values(@model, data, dblarr)
246
+ ret = _double_array_to_list(dblarr, n)
247
+ delete_double(dblarr)
248
+ svm_node_array_destroy(data)
249
+ return ret
250
+ end
251
+
252
+ def predict_values(x)
253
+ v=predict_values_raw(x)
254
+ #puts v.inspect
255
+ if @svm_type == NU_SVR or @svm_type == EPSILON_SVR or @svm_type == ONE_CLASS
256
+ return v[0]
257
+ else #self.svm_type == C_SVC or self.svm_type == NU_SVC
258
+ count = 0
259
+
260
+ # create a width x height array
261
+ width = @labels.size
262
+ height = @labels.size
263
+ d = Array.new(width)
264
+ d.map! { Array.new(height) }
265
+
266
+ for i in (0..@labels.size-1)
267
+ for j in (i+1..@labels.size-1)
268
+ d[@labels[i]][@labels[j]] = v[count]
269
+ d[@labels[j]][@labels[i]] = -v[count]
270
+ count += 1
271
+ end
272
+ end
273
+ return d
274
+ end
275
+ end
276
+
277
+ def predict_probability(x)
278
+ #c code will do nothing on wrong type, so we have to check ourself
279
+ if @svm_type == NU_SVR or @svm_type == EPSILON_SVR
280
+ raise TypeError, "call get_svr_probability or get_svr_pdf for probability output of regression"
281
+ elsif @svm_type == ONE_CLASS
282
+ raise TypeError, "probability not supported yet for one-class problem"
283
+ end
284
+ #only C_SVC,NU_SVC goes in
285
+ if not @probability
286
+ raise TypeError, "model does not support probabiliy estimates"
287
+ end
288
+
289
+ #convert x into svm_node, alloc a double array to receive probabilities
290
+ data = _convert_to_svm_node_array(x)
291
+ dblarr = new_double(@nr_class)
292
+ pred = svm_predict_probability(@model, data, dblarr)
293
+ pv = _double_array_to_list(dblarr, @nr_class)
294
+ delete_double(dblarr)
295
+ svm_node_array_destroy(data)
296
+ p = {}
297
+ for i in (0..@labels.size-1)
298
+ p[@labels[i]] = pv[i]
299
+ end
300
+ return pred, p
301
+ end
302
+
303
+ def get_svr_probability
304
+ #leave the Error checking to svm.cpp code
305
+ ret = svm_get_svr_probability(@model)
306
+ if ret == 0
307
+ raise TypeError, "not a regression model or probability information not available"
308
+ end
309
+ return ret
310
+ end
311
+
312
+ def get_svr_pdf
313
+ #get_svr_probability will handle error checking
314
+ sigma = get_svr_probability()
315
+ return Proc.new{|z| exp(-z.abs/sigma)/(2*sigma)} # TODO: verify this works
316
+ end
317
+
318
+ def save(filename)
319
+ svm_save_model(filename,@model)
320
+ end
321
+
322
+ def destroy
323
+ svm_destroy_model(@model)
324
+ end
325
+ end
326
+
327
+
328
+ def cross_validation(prob, param, fold)
329
+ if param.gamma == 0
330
+ param.gamma = 1.0/prob.maxlen
331
+ end
332
+ dblarr = new_double(prob.size)
333
+ svm_cross_validation(prob.prob, param.param, fold, dblarr)
334
+ ret = _double_array_to_list(dblarr, prob.size)
335
+ delete_double(dblarr)
336
+ return ret
337
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tomz-libsvm-ruby-swig
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Tom Zeng
8
+ - FeedbackMine
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-03-04 00:00:00 -08:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: hoe
18
+ type: :development
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 1.8.3
25
+ version:
26
+ description: Ruby wrapper of LIBSVM using SWIG
27
+ email: tom.z.zeng@gmail.com
28
+ executables: []
29
+
30
+ extensions:
31
+ - ext/extconf.rb
32
+ extra_rdoc_files:
33
+ - History.txt
34
+ - Manifest.txt
35
+ - README.txt
36
+ files:
37
+ - History.txt
38
+ - COPYING
39
+ - AUTHORS
40
+ - Manifest.txt
41
+ - README.txt
42
+ - Rakefile
43
+ - lib/svm.rb
44
+ - ext/svmc_wrap.cxx
45
+ - ext/svm.cpp
46
+ - ext/svm.h
47
+ - ext/extconf.rb
48
+ has_rdoc: true
49
+ homepage: http://www.tomzconsulting.com
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --main
53
+ - README.txt
54
+ require_paths:
55
+ - ext
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.2.0
72
+ signing_key:
73
+ specification_version: 2
74
+ summary: Ruby wrapper of LIBSVM using SWIG
75
+ test_files: []
76
+