class Silicium::Regression::PolynomialRegressionByGradientDescent

Finds parameters as array [1..n] for polynom of n-th degree @param plot Actually hash x => y for different points of the plot @param n Degree of expected polynom @param alpha Speed of learning (should be little enough not to diverge) @param epsilon Accuracy @return Array coefficients (little index is lower degree parameter)

Public Class Methods

generate_function(given_plot, n = 5, alpha = 0.001, epsilon = 0.000001) click to toggle source
# File lib/regression.rb, line 52
def self.generate_function(given_plot, n = 5, alpha = 0.001, epsilon = 0.000001)
  scaling = n > 3
  if scaling
      plot, avg_x, div = feature_scaled_plot(given_plot, n)
  else
      (plot = given_plot)
  end
  array = Array.new(n + 1, 1)
  m = plot.length.to_f
  bias = old_bias = 0.5

  array = calculate([bias, epsilon, array, alpha, plot, old_bias, m])

  return array.map! {|x| x * div + avg_x } if scaling
  array
end

Private Class Methods

calculate(params) click to toggle source
# File lib/regression.rb, line 71
def self.calculate(params)
  while params[0].abs() > params[1]
    old_array = params[2].dup()
    i = -1
    params[2].map! { |elem|
      i += 1
      elem - params[3] / params[6] * d_dt(params[4], old_array, i)
    }
    params[0] = (params[2].zip(old_array).map {|new, old| (new - old).abs()}).max()
    raise "Divergence" if params[0] > params[5]
    params[5] = params[0]
  end
  params[2]
end
d_dt(plot, old_array, i) click to toggle source
# File lib/regression.rb, line 86
def self.d_dt(plot, old_array, i)
  sum = 0.0 
  plot.each { |x, y| sum += (func(old_array, x) - y) * (i + 1) * (x ** i) }

  sum
end
feature_scaled_plot(given_plot, n) click to toggle source
# File lib/regression.rb, line 103
def self.feature_scaled_plot(given_plot, n)
  max_x = given_plot[0][0]
  min_x = given_plot[0][0]
  sum_x = 0.0
  given_plot.each do |x, _|
    max_x = x if x > max_x
    min_x = x if x < min_x
    sum_x += x
  end
  avg_x = sum_x.to_f / given_plot.length
  range_x = max_x - min_x
  div = range_x ** n
  new_plot = given_plot.map {|x, y| [x, (y.to_f - avg_x) / div]}
  return new_plot, avg_x, div
end
func(array, x) click to toggle source
# File lib/regression.rb, line 93
def self.func(array, x)
  sum = 0.0 
  i = 0 
  array.each do |elem|
    sum += elem * (x ** i)
    i += 1
  end 
  sum
end