Class: SVMPrediction

Inherits:
Hash
  • Object
show all
Defined in:
lib/svmprediction.rb

Instance Method Summary collapse

Methods inherited from Hash

#to_xy

Instance Method Details

#-(arg) ⇒ Object

— (minus) — Removes all predictions in arg that is found in self.



41
42
43
44
45
46
47
48
# File 'lib/svmprediction.rb', line 41

def -(arg)
  self.inject(SVMPrediction.new) do |subs, (k,v)|
    if !arg[k]
      subs[k] = v if !arg[k]
    end
    subs
  end
end

#[](expr) ⇒ Object

— [] — If indexing with a regular expression, a new SVMPrediction object is created containing all elements with matching keys.



27
28
29
30
31
32
33
34
35
36
37
# File 'lib/svmprediction.rb', line 27

def [](expr)
  if expr.is_a? Regexp
    subs = SVMPrediction.new
    self.find_all { |(k,v)| k =~ expr }.each do |i|
      subs[i[0]] = i[1]
    end
    subs
  else
    super(expr)
  end
end

#ccObject

— cc — Correlation coefficient



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/svmprediction.rb', line 140

def cc
  a = [] # Don't initialize in one line : x=y=[]
  b = [] # If doing that, they will both refer to the same array
  self.each { |example,val|
    a.push(val['truth'].to_f)
    b.push(val['pred'].to_f)
  }
  amean = a.inject(0) {|sum,i| sum + i} / a.size.to_f
  bmean = b.inject(0) {|sum,i| sum + i} / b.size.to_f
  ssa = a.inject(0.0) {|ss,i| ss + (i-amean)**2}
  ssb = b.inject(0) {|ss,i| ss + (i-bmean)**2}
  ssab = a.zip(b).inject(0) {|ss,(ai,bi)| ss + (ai-amean) * (bi-bmean)}
  if ssab > 0 
    Math::sqrt(ssab**2 / (ssa * ssb))
  else
    0
  end
end

#difficultFeature(features) ⇒ Object

— difficultFeature —



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/svmprediction.rb', line 6

def difficultFeature(features)
  if !features.is_a? SVMFeature
    raise "Please give a SVMFeature object as argument."
  end
  keys = self.keys
  names = (1...features.dim).map do |i|
    features.featname(i)
  end
  maxlen = names.map{|n| n.size}.max
  correlations = (1...features.dim).map do |i|
    predmiss = keys.map { |k|
      (self[k]['truth'] - self[k]['pred']).abs }
    feat = keys.map { |k| features[k][i] }
    "#{names[i-1].rjust(maxlen)}   %.2f"%correlation(predmiss, feat)
  end
  correlations.sort_by{|line| line.split.last.to_f.abs}.reverse
end

#f1(border = 0) ⇒ Object

— f1 — Precision Recall measure



161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/svmprediction.rb', line 161

def f1( border = 0)
  tp = self.select { |k,v| v['truth'] >= border and v['pred'] >= border}.size.to_f
  fp = self.select { |k,v| v['truth'] < border  and v['pred'] >= border}.size.to_f
  fn = self.select { |k,v| v['truth'] >= border  and v['pred'] < border}.size.to_f
  precision = if (denom=tp+fp) > 0 then tp / denom
              else 0 end
  recall = if (denom=tp+fn) > 0 then tp / denom
           else 0 end
  if (denom = precision + recall) > 0
    2 * precision * recall / denom
  else
    0
  end
end

#genericplot(plotdata, file, title = 'Plot', xtitle = 'X', ytitle = 'Y') ⇒ Object

Each should be an array giving more than one plot



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/svmprediction.rb', line 51

def genericplot(plotdata, file, title='Plot', xtitle='X', ytitle='Y')
  Gnuplot.open do |gp| # This could be either a file or the gnuplot process that we pipe to
    Gnuplot::Plot.new( gp ) do |plot|
      plot.title  title
      plot.xlabel xtitle
      plot.ylabel ytitle
      plot.set "grid"
      if file =~ /(png)|(ps)$/
        plot.terminal "png size 1024,800 font '/usr/share/fonts/truetype/ttf-bitstream-vera/VeraBd.ttf' 20" if file =~ /png$/
        plot.terminal "postscript eps color" if file =~ /ps$/          
        plot.output file
      end
      plot.data = plotdata
    end
  end
  nil
end

#plot(legends = [], title = 'SVM Prediction', err = nil, file = '') ⇒ Object

— plot — Plots true value on the X axis vs. predicted value on the Y axis.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/svmprediction.rb', line 71

def plot(legends = [], title = 'SVM Prediction', err = nil, file = '')
  # For historical reasons
  predarr = [ self ]
  # Set up dataarr
  dataarr = predarr.map do |predictions|
    x, y = predictions.inject([[],[]]) { |data,(example,val)|
      data[0].push(val['truth'])
      data[1].push(val['pred'])
      data }
  end
  
  from = dataarr.inject(dataarr[0][0][0]) { |m,a|
    [m, a[0].min, a[1].min].min }.floor
  to = dataarr.inject(dataarr[0][0][0]) { |m,a|
    [m, a[0].max, a[1].max].max }.ceil
  sampleindex = 0
  # Fiddling with legends
  legends = dataarr.map{|d| "Sample #{sampleindex+=1}"} if legends.size==0
  err = ['rmsd','cc'] if !err # Default behaviour
  err = [err] if err.is_a? String
  if err
    legends = legends.map { |legend|
      legend + ' (' +
      err.map { |e|
        begin
          args = if e.split(/,/).size==1 then nil
                 else '(' + (e.split(/,/)[1..-1]).join(',') + ')' end
          "#{e} = ".upcase + "%.2f"%eval("self.#{e.split(/,/).first.downcase}#{args}")
        rescue
          $!
        end
      }.join(', ') + ')'
    }
  end
  # Setting plotdata
  plotdata = [ Gnuplot::DataSet.new( [[from,to], [from,to]] ) { |ds|
                 ds.using = '1:2'
                 ds.with = "lines"
                 ds.title = "Correct diagonal"
                 ds.linewidth = 1
                 ds.matrix = nil } ] +
    dataarr.zip(legends).inject([]) { |arr,((x,y),legend)|
      arr.push(Gnuplot::DataSet.new( [x,y] ) { |ds|
                 ds.using = '1:2'
                 ds.with = "points"
                 ds.title = legend
                 ds.linewidth = 2
                 ds.matrix = nil }) }
  genericplot(plotdata, file, title, 'Experimental value', 'Predicted value')
end

#rmsdObject

— rmsd — Root mean square deviation



124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/svmprediction.rb', line 124

def rmsd
  a = [] # Don't initialize in one line : x=y=[]
  b = [] # If doing that, they will both refer to the same array
  self.each { |example,val|
    a.push(val['truth'].to_f)
    b.push(val['pred'].to_f)
  }
  if (x = a.zip(b).inject(0) {|sd, (d, q)| sd + (d - q)**2 }.to_f / a.length) > 0
    Math.sqrt(x)
  else
    0
  end
end