svmlab 1.0.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.
@@ -0,0 +1,98 @@
1
+ require 'irb/completion'
2
+ require 'rubygems'
3
+ require 'svmlab'
4
+
5
+ #require 'wirble'
6
+ #Wirble.init
7
+ #Wirble.colorize
8
+
9
+ #IRB.conf[:PROMPT][:SVMLab] = { # name of prompt mode
10
+ # :PROMPT_I => "SVMLab:%03n:%i> ", # normal prompt
11
+ # :PROMPT_S => "SVMLab:%03n:%i%l ", # prompt for continuing strings
12
+ # :PROMPT_C => "SVMLab:%03n:%i* ", # prompt for continuing statement
13
+ # :RETURN => " ==>%s\n" # format to return value
14
+ #}
15
+ ANSI_RESET = "\033[0m"
16
+ ANSI_GREEN = "\033[2;32m"
17
+ ANSI_BLUE = "\033[2;34m"
18
+
19
+ IRB.conf[:PROMPT][:SVMLab] = { # name of prompt mode
20
+ #:PROMPT_I => "#{ANSI_BLUE}SVMLab>> #{ANSI_RESET}", # normal prompt
21
+ :PROMPT_I => "SVMLab > ", # normal prompt
22
+ :PROMPT_S => " %l ", # prompt for continuing strings
23
+ :PROMPT_C => " > ", # prompt for continuing statement
24
+ #:RETURN => "#{ANSI_GREEN} ==> %s\n#{ANSI_RESET}" # format to return value
25
+ :RETURN => " ==> %s\n" # format to return value
26
+ }
27
+
28
+ IRB.conf[:PROMPT_MODE] = :SVMLab
29
+
30
+
31
+ # Sebastian Delmont
32
+ # Pretty print methods
33
+ ANSI_BOLD = "\033[1m"
34
+ #ANSI_RESET = "\033[0m"
35
+ ANSI_LGRAY = "\033[0;37m"
36
+ ANSI_GRAY = "\033[1;30m"
37
+
38
+ def pm(obj, *options) # Print methods
39
+ methods = obj.methods
40
+ methods -= Object.methods unless options.include? :more
41
+ filter = options.select {|opt| opt.kind_of? Regexp}.first
42
+ methods = methods.select {|name| name =~ filter} if filter
43
+
44
+ data = methods.sort.collect do |name|
45
+ method = obj.method(name)
46
+ if method.arity == 0
47
+ args = "()"
48
+ elsif method.arity > 0
49
+ n = method.arity
50
+ args = "(#{(1..n).collect {|i| "arg#{i}"}.join(", ")})"
51
+ elsif method.arity < 0
52
+ n = -method.arity
53
+ args = "(#{(1..n).collect {|i| "arg#{i}"}.join(", ")}, ...)"
54
+ end
55
+ klass = $1 if method.inspect =~ /Method: (.*?)#/
56
+ [name, args, klass]
57
+ end
58
+ max_name = data.collect {|item| item[0].size}.max
59
+ max_args = data.collect {|item| item[1].size}.max
60
+ data.each do |item|
61
+ print " #{ANSI_BOLD}#{item[0].rjust(max_name)}#{ANSI_RESET}"
62
+ print "#{ANSI_GRAY}#{item[1].ljust(max_args)}#{ANSI_RESET}"
63
+ print " #{ANSI_LGRAY}#{item[2]}#{ANSI_RESET}\n"
64
+ end
65
+ data.size
66
+ end
67
+
68
+ # To enable history saving between sessions
69
+ IRB.conf[:SAVE_HISTORY] = 100
70
+
71
+ # Stian Haklev / Joel VanderWerf
72
+ # To reduce lengthy output
73
+ class IRB::Context
74
+ attr_accessor :max_output_size
75
+
76
+ alias initialize_before_max_output_size initialize
77
+ def initialize(*args)
78
+ initialize_before_max_output_size(*args)
79
+ @max_output_size = IRB.conf[:MAX_OUTPUT_SIZE] || 70
80
+ end
81
+ end
82
+
83
+ class IRB::Irb
84
+ def output_value
85
+ text =
86
+ if @context.inspect?
87
+ sprintf @context.return_format, @context.last_value.inspect
88
+ else
89
+ sprintf @context.return_format, @context.last_value
90
+ end
91
+ max = @context.max_output_size
92
+ if text.size < max
93
+ puts text
94
+ else
95
+ puts text[0..max-1] + "..." + text[-2..-1]
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,556 @@
1
+
2
+ #########################################################################################
3
+ # OPTIMIZATION METHODS
4
+ #########################################################################################
5
+
6
+
7
+ class SVMLab
8
+
9
+ private
10
+
11
+ # --- updateConfig! ---
12
+ # This is the interface between an array of variables
13
+ # to be changed and a configuration hash.
14
+ # It is to be used by the pattern search, but this
15
+ # function knows nothing about pattern search. It is
16
+ # merely an interface between the hash and the
17
+ # array describing a point in the search space.
18
+ # cfg: A hash containing what should be updated.
19
+ # update: An array of paths to what should be updated
20
+ # and the new value.
21
+ # output: The cfg hash with updated values.
22
+ #
23
+ # EXAMPLE (yaml representation):
24
+ # cfg =
25
+ # ---
26
+ # a:
27
+ # a: 0
28
+ # b: 1
29
+ # b: 2
30
+ # update =
31
+ # ---
32
+ # - "a : b : 7 : exp1"
33
+ # - "b : 8 : exp1"
34
+ def updateConfig!(cfg, steps)
35
+ # For each variable to be updated
36
+ steps.each do |upd|
37
+ # Split the path into its levels
38
+ path = upd.split(/\s\:\s/)
39
+ # Check if the current value should be an integer
40
+ path[-2] = if (p=path[-2]) =~ /^\d+$/ then p.to_i
41
+ elsif p =~ /^\d+\.\d+$/ then p.to_f
42
+ else p end
43
+ # Go through the path and update the hash's value
44
+ (0...path.size-2).inject(cfg) { |c,k|
45
+ # If this key matches an integer, assume it's an integer
46
+ if path[k] =~ /^\d+$/ then path[k] = path[k].to_i end
47
+ if k == path.size-3
48
+ c[path[k]] = path[-2]
49
+ else
50
+ c[path[k]]
51
+ end
52
+ }
53
+ end
54
+ cfg
55
+ end
56
+
57
+ def scrambleArray(arr)
58
+ b = []
59
+ a = arr.clone
60
+ while a.size > 0
61
+ b << a.delete_at(rand(a.size))
62
+ end
63
+ b
64
+ end
65
+
66
+ # --- getPSsteps ---
67
+ def getPSsteps(cfg)
68
+ array = []
69
+ #1. Walk through cfg[Feature][Features] and look for scalings
70
+ cfg['Feature']['Features'].each do |feature|
71
+ if sc = cfg['SVM']['Scale'][feature]
72
+ sc.inject(0) do |i,sci|
73
+ if sci.is_a? String
74
+ sciarr = sci.split
75
+ if sciarr.size==3 and sciarr[1] =~ /step/
76
+ array.push('SVM : Scale : '+feature+' : '+i.to_s+' : '+sciarr[0]+' : '+sciarr[2])
77
+ end
78
+ end
79
+ i+=1
80
+ end
81
+ end
82
+ end
83
+ array = scrambleArray(array)
84
+ #2. Check SVM parameters
85
+ if c = cfg['SVM']['C'] and c.is_a? String
86
+ if (carr = c.split).size ==3 and carr[1] =~ /step/
87
+ array.push('SVM : C : '+carr[0]+' : '+carr[2])
88
+ end
89
+ end
90
+ if c = cfg['SVM']['e'] and c.is_a? String
91
+ if (carr = c.split).size ==3 and carr[1] =~ /step/
92
+ array.push('SVM : e : '+carr[0]+' : '+carr[2])
93
+ end
94
+ end
95
+ if c = cfg['SVM']['g'] and c.is_a? String
96
+ if (carr = c.split).size ==3 and carr[1] =~ /step/
97
+ array.push('SVM : g : '+carr[0]+' : '+carr[2])
98
+ end
99
+ end
100
+ if array.size>0 then array else nil end
101
+ end
102
+
103
+ # --- makeUpdate ---
104
+ # Creates the update array required by 'updateConfig!'.
105
+ # steps : Array of strings.
106
+ # Each string :
107
+ # <lvl 1> : <lvl 2> : ... : <lvl n> : <val> : <X / expX>
108
+ # movearr : Array of step sizes corresponding to the steps array.
109
+ # E.g. movearr = [1, 0] means change the first element
110
+ # of the steps array as curval + 1 * stepsize and leave
111
+ # the second element unchanged.
112
+ # Returns a steps array.
113
+ def makeUpdate(steps,movearr = nil)
114
+ movearr = Array.new(step.size,0) if !movearr
115
+ steps.zip(movearr).map { |pm|
116
+ tmparr = pm[0].split(/\s\:\s/)
117
+ tmparr[0...-2].join(' : ') + ' : ' + # 1. All leading fields
118
+ if (num = if tmparr[-1] =~ /^exp\d/ # 2. The value
119
+ (tmparr[-2].to_f * 10 ** (tmparr[-1].sub(/exp/,'').to_f * pm[1])).to_s
120
+ elsif tmparr[-1] =~ /^\d$/
121
+ (tmparr[-2].to_f + tmparr[-1].to_f * pm[1]).to_s
122
+ end) =~ /\.0$/
123
+ then num.to_i.to_s
124
+ else num end + ' : ' +
125
+ tmparr.last # 3. The step size
126
+ }
127
+ end
128
+
129
+
130
+ # --- patternsearch ---
131
+ # Should possible be named 'coordinatesearch' since that is
132
+ # the algorithm that is implemented.
133
+ def patternsearch(cfg, x, verbose = nil)
134
+ if verbose
135
+ line = '#'+Array.new(60,'-').join
136
+ halfline = '#'+Array.new(43,'-').join
137
+ puts line,'#PATTERN SEARCH INITIAL POINT',{'init'=> x}.to_yaml,line
138
+ end
139
+ xn = x.size
140
+ s = Array.new(xn,0)
141
+ updateConfig!(cfg, makeUpdate(x,s))
142
+ delta = 1.0
143
+ iteration = 0
144
+ pred = SVMLab.new(cfg).crossvalidate
145
+ bestpred = pred
146
+ m = pred.rmsd
147
+ @pslog = [ {'time' => Time.now,
148
+ 'rmsd' => m,
149
+ 'cc' => bestpred.cc,
150
+ 'delta' => delta,
151
+ 'x' => x.dup,
152
+ 'cfg' => deepcopy(cfg)} ]
153
+ outputtitle =
154
+ (['Iter','Delta'] +
155
+ x.map{|xi|
156
+ arr = xi.split(' : ')
157
+ arr[arr.size>4 ? -4 : -3]} +
158
+ ['RMSD','CC']).join("\t")
159
+ outputline =
160
+ ([iteration, '-'] +
161
+ x.map{|xi| "%.2f"%(xi.split(':')[-2].to_f)} +
162
+ ["%.2f"%m, "%.2f"%bestpred.cc]).join("\t")
163
+ puts "PATTERN SEARCH"
164
+ puts outputtitle,outputline
165
+ if verbose
166
+ puts "#INITIAL VALUE : %.3f"%m + " (cc %.3f)"%pred.cc, line
167
+ puts halfline, "#\t\t\tDELTA -> " + delta.to_s, halfline
168
+ puts ( {'errors' => [m]}.to_yaml[5..-1] )
169
+ end
170
+ nhalf = 0
171
+ while nhalf <= cfg['SVM']['Optimization']['Nhalf'] do
172
+ s = Array.new(xn,0)
173
+ (0...xn).each do |i|
174
+ ei = Array.new(xn,0); ei[i] = 1
175
+ [-1,1].each do |d|
176
+ si = s.zip(ei).map { |se| se[0] + delta * d * se[1] }
177
+ updateConfig!(cfg, makeUpdate(x,si))
178
+ pred = SVMLab.new(cfg.to_yaml).crossvalidate
179
+ val = pred.rmsd
180
+ #val = 1 - pred.cc # Try CC as measure instead
181
+ if m - m*10**-5 > val
182
+ s = si.dup
183
+ m = val
184
+ bestpred = pred
185
+ puts '#' + x[i].gsub("\s",'').split(/\:/)[0...-1].join(':') +
186
+ ' -> ' + si[i].to_s +
187
+ "\tRMSD -> %.3f"%val +
188
+ "\t(cc %.3f)"%pred.cc if verbose
189
+ break
190
+ end
191
+ end
192
+ end
193
+ olddelta = delta
194
+ if s.detect{|ss| ss != 0}
195
+ updateConfig!(cfg, x = makeUpdate(x,s) )
196
+ else
197
+ delta = delta / 2
198
+ nhalf += 1
199
+ if verbose
200
+ puts "#\t\t\tDELTA -> " + delta.to_s
201
+ puts "- #{m}" if nhalf <= cfg['SVM']['Optimization']['Nhalf']
202
+ end
203
+ updateConfig!(cfg, x)
204
+ end
205
+ iteration += 1
206
+ outputline =
207
+ ([iteration, olddelta] +
208
+ x.map{|xi| "%.2f"%(xi.split(':')[-2].to_f)} +
209
+ ["%.2f"%bestpred.rmsd, "%.2f"%bestpred.cc]).join("\t")
210
+ puts outputline
211
+ puts halfline if verbose
212
+ @pslog.push( { 'time' => Time.now,
213
+ 'rmsd' => bestpred.rmsd,
214
+ 'cc' => bestpred.cc,
215
+ 'delta' => delta,
216
+ 'x' => x.dup,
217
+ 'cfg' => deepcopy(cfg) } )
218
+ end
219
+ if verbose
220
+ puts line,'#'+Time.now.to_s + ' PATTERN SEARCH FINAL ERROR ' + m.to_s
221
+ puts ( {'finalerr' => m}.to_yaml[5..-1] )
222
+ puts line,'#PATTERN SEARCH FINAL POINT',{'final'=>x}.to_yaml[5..-1],line
223
+ puts ( {'endtime' => Time.now.to_s}.to_yaml[5..-1] )
224
+ end
225
+ end
226
+
227
+
228
+ # --- quasiNewton ---
229
+ def quasiNewton(cfg, x, verbose = nil)
230
+ delta = 1.0
231
+ nhalved = 0
232
+ s = Array.new(x.size,0)
233
+ loop do
234
+ # Calculate the center value
235
+ updateConfig!(cfg, x = makeUpdate(x,s))
236
+ centerval = SVMLab.new(cfg.to_yaml).crossvalidate.rmsd
237
+ # Calculate values around the current point
238
+ puts '***',"%.3f"%centerval,'***' if verbose
239
+ val = (0...x.size).map { |i|
240
+ ei=Array.new(x.size,0); ei[i] = 1
241
+ [-1,1].map { |d|
242
+ si = ei.map { |se| delta * d * se }
243
+ updateConfig!(cfg, makeUpdate(x,si))
244
+ v = SVMLab.new(cfg.to_yaml).crossvalidate.rmsd
245
+ #puts "If #{x[i]} is #{si[i]} then rmsd = #{v}"
246
+ v
247
+ } }
248
+
249
+ s = Array.new(x.size,0)
250
+
251
+ case cfg['SVM']['Optimization']['StepMethod']
252
+
253
+ when 'Gradient'
254
+ # Calculate gradient and gradient norm
255
+ gradient = val.map{ |valx|
256
+ mini = valx[0]<valx[1] ? 0 : 1
257
+ if valx[mini] < centerval
258
+ (centerval - valx[mini]) * (mini==0 ? 1 : -1)
259
+ else 0.0 end }
260
+ gradnorm = Math.sqrt(gradient.inject(0) { |sqsum,gi| sqsum += gi**2 })
261
+ delta = delta / 2 if gradnorm < 0.01
262
+ normedgrad = gradient.map{|gi| gi / gradnorm}
263
+ s = normedgrad.map{|gi| -gi * delta} # Negative gradient direction
264
+ if verbose
265
+ puts "Grad: |#{"%.3f"%gradnorm}| : #{gradient.map{|g| "%.2f"%g}.join(' ')}"
266
+ end
267
+
268
+ when 'MaxDescentAxis'
269
+ # Calculate the axis and direction that gives max descent
270
+ daxis = (0...val.size).zip(val).sort{|a,b| a[1]<=>b[1]}.first[0]
271
+ ddir = val[daxis][0] < val[daxis][1] ? 0 : 1
272
+ if val[daxis][ddir] < centerval
273
+ s[daxis] = (ddir==0?-1:1) * delta
274
+ if verbose then puts "Changing #{daxis} to #{s[daxis]} " +
275
+ "since it gives #{"%.3f"%val[daxis][ddir]}\n #{x[daxis]}"
276
+ end
277
+ else
278
+ delta = delta / 2
279
+ nhalved += 1
280
+ puts "Halving step size to #{delta}" if verbose
281
+ end
282
+ break if nhalved > cfg['SVM']['Optimization']['Nhalf']
283
+ end
284
+ #if verbose
285
+ # puts 'S: ' + s.map{|si| si.is_a? Fixnum ? si.to_s : "%.2f"%si}.join(' ')
286
+ #end
287
+ end
288
+ updateConfig!(cfg, x)
289
+ end
290
+
291
+ def checkOptimization(cfg)
292
+ if x = getPSsteps(cfg)
293
+ #puts x
294
+ if cfg['SVM']['Optimization'] and
295
+ (method = cfg['SVM']['Optimization']['Method'])
296
+ #puts '---',method,'---'
297
+ eval("#{method}(cfg, x, nil)")
298
+ # Currently implemented methods:
299
+ # patternsearch(cfg, x)
300
+ # quasiNewton(cfg, x)
301
+ else
302
+ raise "Scale optimization requested in config but " +
303
+ "no optimization method given."
304
+ end
305
+ else
306
+ cfg
307
+ end
308
+ end
309
+
310
+ def deepcopy(obj)
311
+ Marshal::load(Marshal::dump(obj))
312
+ end
313
+
314
+ # # ----------------------Old code from here----------------------------
315
+ #
316
+ #
317
+ # def patternsearch_fredrik(steps, psreport = '/tmp/ps', errormeasure = 'RMSD')
318
+ # stephalved = 0
319
+ # bestcfg = nil
320
+ # nstep = 0
321
+ # linesep = '**************'
322
+ # open(psreport,'w') { |f| f.puts linesep,'PATTERN SEARCH',Time.now,linesep }
323
+ # while stephalved<2 do
324
+ # open(psreport,'a') { |f| f.puts linesep, "STEP #{nstep+=1}, " + Time.now.to_s, steps }
325
+ # pattern = getpattern(@cfg, steps)
326
+ # bestcfg = YAML.load(pattern[0]) if !bestcfg
327
+ # pindex = -1
328
+ # maxparallel = 7
329
+ # parallel = 0
330
+ # pattern.each do |p|
331
+ # rfile = "/tmp/patternsearch#{pindex+=1}.yml"
332
+ # open("/tmp/pattern#{pindex}.yml","w"){|f| f.puts p}
333
+ # if parallel >= maxparallel
334
+ # Process.wait
335
+ # parallel -= 1
336
+ # end
337
+ # fork do
338
+ # lab = SVMLab.new(p)
339
+ # err, predictions = lab.publish_crossvalidate(rfile)
340
+ # end
341
+ # parallel += 1
342
+ # end
343
+ # Process.waitall
344
+ # evaluation = {}
345
+ # (0...pattern.size).each do |pindex|
346
+ # rfile = File.new("/tmp/patternsearch#{pindex}.yml")
347
+ # evaluation[pindex] = YAML.load(rfile)['Evaluation'][errormeasure]
348
+ # end
349
+ # # Calculate gradient
350
+ # gradient = (1..(pattern.size-1)/2).map { |dim|
351
+ # evaluation[2*dim].to_f - evaluation[2*dim-1].to_f }
352
+ # gradnorm = Math.sqrt(gradient.inject(0) { |sqsum,dim| sqsum += dim**2 })
353
+ # open(psreport,'a') { |f| f.puts "Gradient" +
354
+ # gradient.inject(''){|str,d| str+=" %.2f"%d} + " (%.2f)"%gradnorm }
355
+ # # Find minimum error configuration
356
+ # mincfg = evaluation.sort{|alfa,beta| alfa[1]<=>beta[1]}.first
357
+ # bestcfg = YAML.load( pattern[mincfg[0]] )
358
+ # open(psreport,'a') { |f| f.puts 'Error ' + evaluation[0].to_s }
359
+ # # Update steps
360
+ # if (mincfg[1] - evaluation[0]).abs < 1e-4
361
+ # open(psreport,'a') { |f| f.puts linesep,'HALVING' }
362
+ # steps.collect! do |step|
363
+ # if step=~/exp\d+/
364
+ # prefix = if step=~/int/ then 'intexp' else 'exp' end
365
+ # (step.split(/\s\:\s/)[0...-1] + [prefix+(step.split(/exp/).last.to_f/2).to_s]).join(' : ')
366
+ # else
367
+ # (step.split(/\s\:\s/)[0...-1] + [(step.split(/\s\:\s/).last.to_f/2).to_s]).join(' : ')
368
+ # end
369
+ # end
370
+ # stephalved += 1
371
+ # else
372
+ # open(psreport,'a') { |f| f.puts linesep,'MOVING ' }
373
+ # steps.collect! do |step|
374
+ # path = step.split(/\s\:\s/)
375
+ # tmpcfg = bestcfg
376
+ # path[0...-3].each do |pathpart|
377
+ # tmpcfg = tmpcfg[pathpart]
378
+ # end
379
+ # (path[0...-2] +
380
+ # [tmpcfg[ if path[-3]=~/^\d+$/ then path[-3].to_i
381
+ # else path[-3] end ].to_s ] +
382
+ # [path.last]).join(' : ')
383
+ # end
384
+ # # Gradient descent
385
+ # #gradindex = -1
386
+ # #steps.collect! do |step|
387
+ # # path = step.split(/\s\:\s/)
388
+ # # tmpcfg = bestcfg
389
+ # # path[0...-3].each do |pathpart|
390
+ # # tmpcfg = tmpcfg[pathpart]
391
+ # # end
392
+ # # (path[0...-2] +
393
+ # # [ if path[-1] =~ /exp/
394
+ # # path[-2].to_f * 10**(-path[-1].sub(/exp/,'').to_f * gradient[gradindex+=1] / gradnorm)
395
+ # # else
396
+ # # path[-2].to_f + (tmpcfg[path[-3]].to_f - path[-2].to_f).abs * gradient[gradindex+=1] / gradnorm
397
+ # # end.to_s ] +
398
+ # # [path.last]).join(' : ')
399
+ # #end
400
+ # end
401
+ # end
402
+ # open(psreport,'a') { |f| f.puts linesep,Time.now,'FINAL STEPS',steps,linesep }
403
+ # bestcfg
404
+ # end
405
+ #
406
+ # # --- getpattern ---
407
+ # # structure : A hash consisting the configuration. The leaves in the
408
+ # # hash are ignored and only the structure is utilized.
409
+ # # steps : An array of strings in which each string describes the
410
+ # # path in the "structure" hash to the parameter:
411
+ # # <Level1> : <Level2> : ... : <Parameter> : <CurValue> : <Stepsize>
412
+ # # "CurValue" is the value from which to create the pattern
413
+ # # "Stepsize" is a string :
414
+ # # <x>, exp<x> or intexp<x> where x is a Float or Fixnum
415
+ # # returns : an array of strings in which each string is the YAML
416
+ # # representation of the configuration.
417
+ # # The current point given by "CurValue" is returned as
418
+ # # the first element in the array.
419
+ # def getpattern(structure, steps)
420
+ # pattern = []
421
+ # (['dontmove'] + steps).each do |step1|
422
+ # if step1=='dontmove' then [0] else [-1,1] end.each do |factor|
423
+ # steparr = []
424
+ # steps.each do |step2|
425
+ # s2 = step2.split(/\s\:\s/)
426
+ # if step1==step2
427
+ # # This step will be changed according to factor and stepsize
428
+ # ss = if s2[-1] =~ /exp/
429
+ # ss = s2[-2].to_f * 10**(s2[-1].split(/exp/).last.to_f * factor)
430
+ # if s2[-1] =~ /int/ then ss.round else ss end
431
+ # else
432
+ # ss = s2[-2].to_f + s2[-1].to_f * factor
433
+ # if ss.to_s =~ /\.0$/ then ss.to_i else ss end
434
+ # end
435
+ # steparr.push( s2[0...-2].join(':') + ' ' + ss.to_s )
436
+ # else
437
+ # # Put the current point in steparr
438
+ # steparr.push( s2[0...-2].join(':') + ' ' + s2[-2] )
439
+ # end
440
+ # end
441
+ # # Generate config text for each step
442
+ # cfg = deepcopy(structure) # Do not change the argument given
443
+ # steparr.each do |step|
444
+ # intcfg = cfg
445
+ # path,val = step.split
446
+ # val = if val=~ /\.0$/ then val.to_i else val.to_f end
447
+ # path.split(/\:/)[0...-1].each do |p|
448
+ # intcfg = intcfg[p]
449
+ # end
450
+ # intcfg[ if (index = path.split(/\:/).last) =~ /^\d+$/
451
+ # then index.to_i
452
+ # else index end ] = val
453
+ # end
454
+ # pattern.push( cfg.to_yaml )
455
+ # end
456
+ # end
457
+ # pattern
458
+ # end
459
+ #
460
+ #
461
+ # #########################################################################################
462
+ # # Grid search - possibly obsolete
463
+ #
464
+ # # --- loo_svmoptim_gridsearch ---
465
+ # # Performs a grid search of the SVM hyperparameter space, i.e. does
466
+ # # a cross validation using different values of C, epsilon and gamma
467
+ # # (assuming we are doing epsilon regression with an RBF kernel)
468
+ # def loo_svmoptim_gridsearch()
469
+ # err, predictions = looCrossvalidate
470
+ # print 'Default: epsilon '+@par.eps.to_s
471
+ # print "\tgamma "+@par.gamma.to_s
472
+ # print "\tC "+@par.C.to_s
473
+ # print "\tError %.3f"%err
474
+ # puts
475
+ #
476
+ # epsilon = -3..0
477
+ # gamma = -2..1
478
+ # cee = -1..2
479
+ # optimum = {}
480
+ # epsilon.each { |e|
481
+ # @par.eps = 10**e
482
+ # gamma.each { |g|
483
+ # @par.gamma = 10**g
484
+ # cee.each {|c|
485
+ # @par.C = 10**c
486
+ # err,predictions = looCrossvalidate
487
+ # print 'epsilon '+@par.eps.to_s
488
+ # print "\tgamma "+@par.gamma.to_s
489
+ # print "\tC "+@par.C.to_s
490
+ # print "\tError %.3f"%err
491
+ # if !optimum['err'] or optimum['err'] > err
492
+ # optimum['err'] = err
493
+ # optimum['epsilon'] = 10**e
494
+ # optimum['gamma'] = 10**g
495
+ # optimum['C'] = 10**c
496
+ # end
497
+ # print "\tOptimum %.3f"%optimum['err'] if optimum['err']
498
+ # puts
499
+ # }
500
+ # }
501
+ # }
502
+ # @par.eps = optimum['epsilon']
503
+ # @par.gamma = optimum['gamma']
504
+ # @par.C = optimum['C']
505
+ # optimum.each{ |key,val|
506
+ # puts key + ' = ' + val.to_s
507
+ # }
508
+ # end
509
+ #
510
+ # # --- svmoptim_gridsearch ---
511
+ # # Performs a grid search of the SVM hyperparameter space, i.e. does
512
+ # # a cross validation using different values of C, epsilon and gamma
513
+ # # (assuming we are doing epsilon regression with an RBF kernel)
514
+ # def svmoptim_gridsearch(groups)
515
+ # err, predictions = crossvalidate(groups)
516
+ # print 'Default: epsilon '+@par.eps.to_s
517
+ # print "\tgamma "+@par.gamma.to_s
518
+ # print "\tC "+@par.C.to_s
519
+ # print "\tError %.3f"%err
520
+ # puts
521
+ #
522
+ # epsilon = -3..0
523
+ # gamma = -2..1
524
+ # cee = -1..2
525
+ # optimum = {}
526
+ # epsilon.each { |e|
527
+ # @par.eps = 10**e
528
+ # gamma.each { |g|
529
+ # @par.gamma = 10**g
530
+ # cee.each {|c|
531
+ # @par.C = 10**c
532
+ # err,predictions = crossvalidate(groups)
533
+ # print 'epsilon '+@par.eps.to_s
534
+ # print "\tgamma "+@par.gamma.to_s
535
+ # print "\tC "+@par.C.to_s
536
+ # print "\tError %.3f"%err
537
+ # if !optimum['err'] or optimum['err'] > err
538
+ # optimum['err'] = err
539
+ # optimum['epsilon'] = 10**e
540
+ # optimum['gamma'] = 10**g
541
+ # optimum['C'] = 10**c
542
+ # end
543
+ # print "\tOptimum %.3f"%optimum['err'] if optimum['err']
544
+ # puts
545
+ # }
546
+ # }
547
+ # }
548
+ # @par.eps = optimum['epsilon']
549
+ # @par.gamma = optimum['gamma']
550
+ # @par.C = optimum['C']
551
+ # optimum.each{ |key,val|
552
+ # puts key + ' = ' + val.to_s
553
+ # }
554
+ # end
555
+
556
+ end