tomz-libsvm-ruby-swig 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
+