Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
4 changed files
with
115 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,17 @@ | ||
require 'tealeaves/moving_average' | ||
require 'tealeaves/seasonal_components' | ||
require 'tealeaves/forecast' | ||
require 'tealeaves/naive_forecast' | ||
require 'tealeaves/single_exponential_smoothing_forecast' | ||
require 'tealeaves/brute_force_optimization' | ||
require 'tealeaves/exponential_smoothing_forecast' | ||
|
||
module TeaLeaves | ||
def self.optimal_model(time_series, period) | ||
BruteForceOptimization.new(time_series, period).optimize | ||
end | ||
|
||
def self.forecast(time_series, period, periods_ahead=nil) | ||
optimal_model(time_series, period).predict(periods_ahead) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
module TeaLeaves | ||
class BruteForceOptimization | ||
INITIAL_PARAMETER_VALUES = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0].freeze | ||
|
||
def initialize(time_series, period, opts={}) | ||
@time_series = time_series | ||
@period = period | ||
@opts = opts | ||
end | ||
|
||
|
||
def optimize | ||
[0.1, 0.5, 0.25, 0.125, 0.0625, 0.03125, 0.015625].inject(optimum(initial_models)) do |model, change| | ||
improve_model(model, change) | ||
end | ||
end | ||
|
||
def initial_test_parameters(opts={}) | ||
parameters = [] | ||
INITIAL_PARAMETER_VALUES.each do |alpha| | ||
parameters << {:alpha => alpha, :seasonality => :none, :trend => :none} | ||
|
||
unless opts[:seasonality] == :none && opts[:trend] == :none | ||
INITIAL_PARAMETER_VALUES.each do |b| | ||
parameters << {:alpha => alpha, :beta => b, :seasonality => :none, :trend => :additive} | ||
parameters << {:alpha => alpha, :beta => b, :seasonality => :none, :trend => :multiplicative} | ||
parameters << {:alpha => alpha, :gamma => b, :trend => :none, :seasonality => :additive} | ||
parameters << {:alpha => alpha, :gamma => b, :trend => :none, :seasonality => :multiplicative} | ||
|
||
INITIAL_PARAMETER_VALUES.each do |gamma| | ||
[:additive, :multiplicative].each do |trend| | ||
[:additive, :multiplicative].each do |seasonality| | ||
parameters << { | ||
:alpha => alpha, | ||
:beta => b, | ||
:gamma => gamma, | ||
:trend => trend, | ||
:seasonality => seasonality | ||
} | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
parameters | ||
end | ||
|
||
private | ||
|
||
def improve_model(model, change) | ||
trend_operations = model.trend == :none ? [nil] : [:+, :-, nil] | ||
season_operations = model.seasonality == :none ? [nil] : [:+, :-, nil] | ||
permutations = [:+, :-, nil].product(trend_operations, season_operations) | ||
optimum(permutations.map do |(op_1,op_2,op_3)| | ||
new_opts = {} | ||
set_value(new_opts, :alpha, model, op_1, change) | ||
set_value(new_opts, :beta, model, op_2, change) | ||
set_value(new_opts, :gamma, model, op_3, change) | ||
model.improve(new_opts) | ||
end) | ||
end | ||
|
||
def set_value(hsh, key, model, op, change) | ||
unless op.nil? | ||
new_value = model.send(key).send(op, change) | ||
if new_value >= 0.0 && new_value <= 1.0 | ||
hsh[key] = new_value | ||
end | ||
end | ||
end | ||
|
||
def optimum(models) | ||
models.min_by(&:mean_squared_error) | ||
end | ||
|
||
def initial_models | ||
initial_test_parameters.map do |parameters| | ||
ExponentialSmoothingForecast.new(@time_series, @period, parameters) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
require 'spec_helper' | ||
|
||
describe TeaLeaves::BruteForceOptimization do | ||
it "should have 1014 initial test models" do | ||
described_class.new([1,2,3,4], 1).initial_test_parameters.size.should == 1014 | ||
end | ||
|
||
it "should produce an initial model" do | ||
|
||
end | ||
end |