bio-statsample-timeseries 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.travis.yml +13 -0
- data/Gemfile +21 -0
- data/LICENSE.txt +20 -0
- data/README.md +47 -0
- data/README.rdoc +48 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/bin/bio-statsample-timeseries +74 -0
- data/features/acf.feature +31 -0
- data/features/pacf.feature +42 -0
- data/features/step_definitions/bio-statsample-timeseries_steps.rb +0 -0
- data/features/step_definitions/step_definitions.rb +37 -0
- data/features/step_definitions/step_definitions_acf.rb +8 -0
- data/features/support/env.rb +15 -0
- data/lib/bio-statsample-timeseries.rb +16 -0
- data/lib/bio-statsample-timeseries/arima.rb +124 -0
- data/lib/bio-statsample-timeseries/statsample-timeseries.rb +2 -0
- data/lib/bio-statsample-timeseries/timeseries.rb +181 -0
- data/lib/bio-statsample-timeseries/timeseries/pacf.rb +100 -0
- data/test/fixtures/stock_data.csv +500 -0
- data/test/helper.rb +81 -0
- data/test/test_arima_simulators.rb +176 -0
- data/test/test_pacf.rb +52 -0
- data/test/test_tseries.rb +103 -0
- data/test/test_wald.rb +71 -0
- metadata +256 -0
data/test/helper.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'minitest/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
require 'shoulda-context'
|
13
|
+
require 'mocha'
|
14
|
+
|
15
|
+
require 'bio-statsample-timeseries'
|
16
|
+
|
17
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
18
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
19
|
+
require 'bio-statsample-timeseries'
|
20
|
+
module MiniTest
|
21
|
+
class Unit
|
22
|
+
class TestCase
|
23
|
+
include Shoulda::Context::Assertions
|
24
|
+
include Shoulda::Context::InstanceMethods
|
25
|
+
extend Shoulda::Context::ClassMethods
|
26
|
+
def self.should_with_gsl(name,&block)
|
27
|
+
should(name) do
|
28
|
+
if Statsample.has_gsl?
|
29
|
+
instance_eval(&block)
|
30
|
+
else
|
31
|
+
skip("Requires GSL")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Assertions
|
39
|
+
def assert_similar_vector(exp, obs, delta=1e-10,msg=nil)
|
40
|
+
msg||="Different vectors #{exp} - #{obs}"
|
41
|
+
assert_equal(exp.size, obs.size)
|
42
|
+
exp.data_with_nils.each_with_index {|v,i|
|
43
|
+
assert_in_delta(v,obs[i],delta)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
def assert_equal_vector(exp,obs,delta=1e-10,msg=nil)
|
47
|
+
assert_equal(exp.size, obs.size, "Different size.#{msg}")
|
48
|
+
exp.size.times {|i|
|
49
|
+
assert_in_delta(exp[i],obs[i],delta, "Different element #{i}. \nExpected:\n#{exp}\nObserved:\n#{obs}.#{msg}")
|
50
|
+
}
|
51
|
+
end
|
52
|
+
def assert_equal_matrix(exp,obs,delta=1e-10,msg=nil)
|
53
|
+
assert_equal(exp.row_size, obs.row_size, "Different row size.#{msg}")
|
54
|
+
assert_equal(exp.column_size, obs.column_size, "Different column size.#{msg}")
|
55
|
+
exp.row_size.times {|i|
|
56
|
+
exp.column_size.times {|j|
|
57
|
+
assert_in_delta(exp[i,j],obs[i,j], delta, "Different element #{i},#{j}\nExpected:\n#{exp}\nObserved:\n#{obs}.#{msg}")
|
58
|
+
}
|
59
|
+
}
|
60
|
+
end
|
61
|
+
alias :assert_raise :assert_raises unless method_defined? :assert_raise
|
62
|
+
alias :assert_not_equal :refute_equal unless method_defined? :assert_not_equal
|
63
|
+
alias :assert_not_same :refute_same unless method_defined? :assert_not_same
|
64
|
+
unless method_defined? :assert_nothing_raised
|
65
|
+
def assert_nothing_raised(msg=nil)
|
66
|
+
msg||="Nothing should be raised, but raised %s"
|
67
|
+
begin
|
68
|
+
yield
|
69
|
+
not_raised=true
|
70
|
+
rescue Exception => e
|
71
|
+
not_raised=false
|
72
|
+
msg=sprintf(msg,e)
|
73
|
+
end
|
74
|
+
assert(not_raised,msg)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
MiniTest::Unit.autorun
|
81
|
+
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require(File.expand_path(File.dirname(__FILE__)+'/helper.rb'))
|
2
|
+
|
3
|
+
class StatsampleArimaSimulatorsTest < MiniTest::Unit::TestCase
|
4
|
+
def generate_acf(simulation)
|
5
|
+
ts = simulation.to_ts
|
6
|
+
ts.acf
|
7
|
+
end
|
8
|
+
|
9
|
+
def generate_pacf(simulation)
|
10
|
+
ts = simulation.to_ts
|
11
|
+
ts.pacf
|
12
|
+
end
|
13
|
+
context("AR(1) simulations") do
|
14
|
+
include Statsample::ARIMA
|
15
|
+
|
16
|
+
setup do
|
17
|
+
@series = ARIMA.new
|
18
|
+
@ar_1_positive = @series.ar_sim(1500, [0.9], 2)
|
19
|
+
@ar_1_negative = @series.ar_sim(1500, [-0.9], 2)
|
20
|
+
|
21
|
+
#generating acf
|
22
|
+
@positive_acf = generate_acf(@ar_1_positive)
|
23
|
+
@negative_acf = generate_acf(@ar_1_negative)
|
24
|
+
|
25
|
+
#generating pacf
|
26
|
+
@positive_pacf = generate_pacf(@ar_1_positive)
|
27
|
+
@negative_pacf = generate_pacf(@ar_1_negative)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
should "have exponential decay of acf on positive side with phi > 0" do
|
32
|
+
@acf = @positive_acf
|
33
|
+
assert_equal @acf[0], 1.0
|
34
|
+
assert_operator @acf[1], :>=, 0.7
|
35
|
+
assert_operator @acf[@acf.size - 1], :<=, 0.2
|
36
|
+
#visualization:
|
37
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_positive_phi_acf.png
|
38
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_positive_phi_acf_line.png
|
39
|
+
end
|
40
|
+
|
41
|
+
should "have series with alternating sign on acf starting on negative side with phi < 0" do
|
42
|
+
@acf = @negative_acf
|
43
|
+
assert_equal @acf[0], 1.0
|
44
|
+
#testing for alternating series
|
45
|
+
assert_operator @acf[1], :<, 0
|
46
|
+
assert_operator @acf[2], :>, 0
|
47
|
+
assert_operator @acf[3], :<, 0
|
48
|
+
assert_operator @acf[4], :>, 0
|
49
|
+
#visualization:
|
50
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_negative_phi_acf.png
|
51
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_negative_phi_acf_line.png
|
52
|
+
end
|
53
|
+
|
54
|
+
should "have positive spike on pacf at lag 1 for phi > 0" do
|
55
|
+
@pacf = @positive_pacf
|
56
|
+
assert_operator @pacf[1], :>=, 0.7
|
57
|
+
assert_operator @pacf[2], :<=, 0.2
|
58
|
+
assert_operator @pacf[3], :<=, 0.14
|
59
|
+
#visualization:
|
60
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_postive_phi_pacf.png
|
61
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_postive_phi_pacf_line.png
|
62
|
+
end
|
63
|
+
|
64
|
+
should "have negative spike on pacf at lag 1 for phi < 0" do
|
65
|
+
@pacf = @negative_pacf
|
66
|
+
assert_operator @pacf[1], :<=, 0
|
67
|
+
assert_operator @pacf[1], :<=, -0.5
|
68
|
+
assert_operator @pacf[2], :>=, -0.5
|
69
|
+
#visualizaton:
|
70
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%281%29_negative_phi_pacf.png
|
71
|
+
#[hided @pacf[0] = 1 to convey accurate picture]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context("AR(p) simulations") do
|
76
|
+
include Statsample::ARIMA
|
77
|
+
|
78
|
+
setup do
|
79
|
+
@series = ARIMA.new
|
80
|
+
@ar_p_positive = @series.ar_sim(1500, [0.3, 0.5], 2)
|
81
|
+
@ar_p_negative = @series.ar_sim(1500, [-0.3, -0.5], 2)
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
should "have damped sine wave starting on positive side on acf" do
|
86
|
+
@ar = @ar_p_positive
|
87
|
+
@acf = generate_acf(@ar)
|
88
|
+
assert_operator @acf[0], :>=, @acf[1]
|
89
|
+
assert_operator @acf[1], :>=, 0.0
|
90
|
+
#caution: sine curve can split on cartesian plane,
|
91
|
+
#visualization:
|
92
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR(p)_positive_phi_sine_wave.png
|
93
|
+
end
|
94
|
+
|
95
|
+
should "have damped sine wave starting on negative side on acf" do
|
96
|
+
@ar = @ar_p_negative
|
97
|
+
@acf = generate_acf(@ar)
|
98
|
+
assert_operator @acf[0], :>=, @acf[1]
|
99
|
+
assert_operator @acf[1], :<=, 0.0
|
100
|
+
assert_operator @acf[1], :>=, @acf[2]
|
101
|
+
#caution: sine curve can split on cartesian plane,
|
102
|
+
#visualization:
|
103
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR%28p%29_negative_phi_acf_sine_wave.png
|
104
|
+
end
|
105
|
+
|
106
|
+
should "have spikes from 1 to p for pacf" do
|
107
|
+
#here p = 2
|
108
|
+
@ar = @ar_p_positive
|
109
|
+
@pacf = generate_pacf(@ar)
|
110
|
+
assert_equal @pacf[0], 1.0
|
111
|
+
assert_operator @pacf[1], :>, @pacf[3]
|
112
|
+
assert_operator @pacf[1], :>, @pacf[4]
|
113
|
+
assert_operator @pacf[1], :>, @pacf[5]
|
114
|
+
assert_operator @pacf[2], :>, @pacf[3]
|
115
|
+
assert_operator @pacf[2], :>, @pacf[4]
|
116
|
+
#visualization:
|
117
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/AR(p)_positive_phi_pacf_spikes.png
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
context("MA(1) simulations") do
|
123
|
+
include Statsample::ARIMA
|
124
|
+
setup do
|
125
|
+
@series = ARIMA.new
|
126
|
+
@ma_positive = @series.ar_sim(1500, [0.5], 2)
|
127
|
+
@ma_negative = @series.ar_sim(1500, [-0.5], 2)
|
128
|
+
end
|
129
|
+
|
130
|
+
should "have one positive spike at lag 1 on acf at positive theta" do
|
131
|
+
@acf = generate_acf(@ma_positive)
|
132
|
+
assert_equal @acf[0], 1.0
|
133
|
+
assert_operator @acf[1], :>=, 0 #test if positive
|
134
|
+
#test if spike
|
135
|
+
assert_operator @acf[2], :>=, 0.1
|
136
|
+
assert_operator @acf[3], :<=, 0.2
|
137
|
+
assert_operator @acf[4], :<=, 0.2
|
138
|
+
#visualization:
|
139
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/MA%281%29_postive_acf.png
|
140
|
+
end
|
141
|
+
|
142
|
+
should "have one negative spike at lag 1 on acf at negative theta" do
|
143
|
+
@acf = generate_acf(@ma_negative)
|
144
|
+
assert_operator @acf[1], :<, 0
|
145
|
+
assert_operator @acf[2], :>=, @acf[1]
|
146
|
+
assert_operator @acf[3], :>=, @acf[1]
|
147
|
+
#visualization:
|
148
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/MA%281%29_negative_acf.png
|
149
|
+
#positive_vs_negative:
|
150
|
+
#https://dl.dropboxusercontent.com/u/102071534/sciruby/MA%281%29_acf_positive_vs_negative.png
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
context("MA(q) simulations") do
|
156
|
+
include Statsample::ARIMA
|
157
|
+
setup do
|
158
|
+
@series = ARIMA.new
|
159
|
+
@ma_positive = @series.ar_sim(1500, [0.5, 0.3, 0.2], 2)
|
160
|
+
@ma_negative = @series.ar_sim(1500, [-0.5], 2)
|
161
|
+
end
|
162
|
+
|
163
|
+
should "have q positive spikes at lag 1 to q on acf at positive thetas" do
|
164
|
+
@acf = generate_acf(@ma_positive)
|
165
|
+
assert_operator @acf[1], :>=, @acf[2]
|
166
|
+
assert_operator @acf[2], :>=, @acf[3]
|
167
|
+
assert_operator @acf[3], :>=, @acf[4]
|
168
|
+
#Visualization: http://jsfiddle.net/YeK2c/
|
169
|
+
end
|
170
|
+
|
171
|
+
should "have damped sine wave on pacf at positive thetas" do
|
172
|
+
#visualization: http://jsfiddle.net/7keHK/2/
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
data/test/test_pacf.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require(File.expand_path(File.dirname(__FILE__)+'/helper.rb'))
|
2
|
+
class StatsampleTimeSeriesPacfTestCase < MiniTest::Unit::TestCase
|
3
|
+
context(Statsample::TimeSeries) do
|
4
|
+
include Statsample::TimeSeries
|
5
|
+
setup do
|
6
|
+
@ts = (1..20).map { |x| x * 10 }.to_ts
|
7
|
+
#setting up a proc to get a closure for pacf calling with variable lags and methods
|
8
|
+
@pacf_proc =->(k, method) { @ts.pacf(k, method) }
|
9
|
+
end
|
10
|
+
|
11
|
+
should "return correct correct pacf size for lags = 5" do
|
12
|
+
assert_equal @pacf_proc.call(5, 'yw').size, 6
|
13
|
+
assert_equal @pacf_proc.call(5, 'mle').size, 6
|
14
|
+
#first element is 1.0
|
15
|
+
end
|
16
|
+
|
17
|
+
should "return correct correct pacf size for lags = 10" do
|
18
|
+
assert_equal @pacf_proc.call(10, 'yw').size, 11
|
19
|
+
assert_equal @pacf_proc.call(10, 'mle').size, 11
|
20
|
+
#first element is 1.0
|
21
|
+
end
|
22
|
+
|
23
|
+
should "have first element as 1.0" do
|
24
|
+
assert_equal @pacf_proc.call(10, 'yw')[0], 1.0
|
25
|
+
assert_equal @pacf_proc.call(10, 'mle')[0], 1.0
|
26
|
+
end
|
27
|
+
|
28
|
+
should "give correct pacf results for unbiased yule-walker" do
|
29
|
+
result_10 = [1.0, 0.8947368421052632, -0.10582010582010604, -0.11350188273265083, -0.12357534824820737, -0.13686534216335522, -0.15470588235294147, -0.17938011883732036, -0.2151192288178601, -0.2707082833133261, -0.3678160919540221]
|
30
|
+
result_5 = [1.0, 0.8947368421052632, -0.10582010582010604, -0.11350188273265083, -0.12357534824820737, -0.13686534216335522]
|
31
|
+
assert_equal @pacf_proc.call(10, 'yw'), result_10
|
32
|
+
assert_equal @pacf_proc.call(5, 'yw'), result_5
|
33
|
+
|
34
|
+
#Checking for lag = (1..10)
|
35
|
+
1.upto(10) do |i|
|
36
|
+
assert_equal @pacf_proc.call(i, 'yw'), result_10[0..i]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
should "give correct pacf results for mle yule-walker" do
|
41
|
+
result_10 = [1.0, 0.85, -0.07566212829370711, -0.07635069706072706, -0.07698628638512295, -0.07747034005560738, -0.0776780981161499, -0.07744984679625189, -0.0765803323191094, -0.07480650005932366, -0.07179435184923755]
|
42
|
+
result_5 = [1.0, 0.85, -0.07566212829370711, -0.07635069706072706, -0.07698628638512295, -0.07747034005560738]
|
43
|
+
assert_equal @pacf_proc.call(10, 'mle'), result_10
|
44
|
+
assert_equal @pacf_proc.call(5, 'mle'), result_5
|
45
|
+
|
46
|
+
#Checking for lag = (1..10)
|
47
|
+
1.upto(10) do |i|
|
48
|
+
assert_equal @pacf_proc.call(i, 'mle'), result_10[0..i]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require(File.expand_path(File.dirname(__FILE__)+'/helper.rb'))
|
2
|
+
|
3
|
+
class StatsampleTestTimeSeries < MiniTest::Unit::TestCase
|
4
|
+
include Statsample::Shorthand
|
5
|
+
|
6
|
+
# All calculations are compared to the output of the equivalent function in R
|
7
|
+
|
8
|
+
def setup
|
9
|
+
# daily closes of iShares XIU on the TSX
|
10
|
+
@xiu = Statsample::TimeSeries::TimeSeries.new [17.28, 17.45, 17.84, 17.74, 17.82, 17.85, 17.36, 17.3, 17.56, 17.49, 17.46, 17.4, 17.03, 17.01,
|
11
|
+
16.86, 16.86, 16.56, 16.36, 16.66, 16.77], :scale
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_acf
|
15
|
+
acf = @xiu.acf
|
16
|
+
|
17
|
+
assert_equal 14, acf.length
|
18
|
+
|
19
|
+
# test the first few autocorrelations
|
20
|
+
assert_in_delta 1.0, acf[0], 0.0001
|
21
|
+
assert_in_delta 0.852, acf[1], 0.001
|
22
|
+
assert_in_delta 0.669, acf[2], 0.001
|
23
|
+
assert_in_delta 0.486, acf[3], 0.001
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_lag
|
27
|
+
#test of default lag
|
28
|
+
lag1 = @xiu.lag
|
29
|
+
|
30
|
+
assert_in_delta 16.66, lag1[lag1.size - 1], 0.001
|
31
|
+
assert_in_delta 16.36, lag1[lag1.size - 2], 0.001
|
32
|
+
|
33
|
+
#test with different lagging unit
|
34
|
+
lag2 = @xiu.lag(2)
|
35
|
+
|
36
|
+
assert_in_delta 16.36, lag2[lag2.size - 1], 0.001
|
37
|
+
assert_in_delta 16.56, lag2[lag2.size - 2], 0.001
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_delta
|
41
|
+
diff = @xiu.diff
|
42
|
+
|
43
|
+
assert_in_delta 0.11, diff[@xiu.size - 1], 0.001
|
44
|
+
assert_in_delta 0.30, diff[@xiu.size - 2], 0.001
|
45
|
+
assert_in_delta -0.20, diff[@xiu.size - 3], 0.001
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_ma
|
49
|
+
# test default
|
50
|
+
ma10 = @xiu.ma
|
51
|
+
|
52
|
+
assert_in_delta ma10[-1], 16.897, 0.001
|
53
|
+
assert_in_delta ma10[-5], 17.233, 0.001
|
54
|
+
assert_in_delta ma10[-10], 17.587, 0.001
|
55
|
+
|
56
|
+
# test with a different lookback period
|
57
|
+
ma5 = @xiu.ma 5
|
58
|
+
|
59
|
+
assert_in_delta ma5[-1], 16.642, 0.001
|
60
|
+
assert_in_delta ma5[-10], 17.434, 0.001
|
61
|
+
assert_in_delta ma5[-15], 17.74, 0.001
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_ema
|
65
|
+
# test default
|
66
|
+
ema10 = @xiu.ema
|
67
|
+
|
68
|
+
assert_in_delta ema10[-1], 16.87187, 0.00001
|
69
|
+
assert_in_delta ema10[-5], 17.19187, 0.00001
|
70
|
+
assert_in_delta ema10[-10], 17.54918, 0.00001
|
71
|
+
|
72
|
+
# test with a different lookback period
|
73
|
+
ema5 = @xiu.ema 5
|
74
|
+
|
75
|
+
assert_in_delta ema5[-1], 16.71299, 0.0001
|
76
|
+
assert_in_delta ema5[-10], 17.49079, 0.0001
|
77
|
+
assert_in_delta ema5[-15], 17.70067, 0.0001
|
78
|
+
|
79
|
+
# test with a different smoother
|
80
|
+
ema_w = @xiu.ema 10, true
|
81
|
+
|
82
|
+
assert_in_delta ema_w[-1], 17.08044, 0.00001
|
83
|
+
assert_in_delta ema_w[-5], 17.33219, 0.00001
|
84
|
+
assert_in_delta ema_w[-10], 17.55810, 0.00001
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_macd
|
88
|
+
# MACD uses a lot more data than the other ones, so we need a bigger vector
|
89
|
+
data = File.readlines(File.dirname(__FILE__) + "/fixtures/stock_data.csv").map(&:to_f).to_time_series
|
90
|
+
|
91
|
+
macd, signal = data.macd
|
92
|
+
|
93
|
+
# check the MACD
|
94
|
+
assert_in_delta 3.12e-4, macd[-1], 1e-6
|
95
|
+
assert_in_delta -1.07e-2, macd[-10], 1e-4
|
96
|
+
assert_in_delta -5.65e-3, macd[-20], 1e-5
|
97
|
+
|
98
|
+
# check the signal
|
99
|
+
assert_in_delta -0.00628, signal[-1], 1e-5
|
100
|
+
assert_in_delta -0.00971, signal[-10], 1e-5
|
101
|
+
assert_in_delta -0.00338, signal[-20], 1e-5
|
102
|
+
end
|
103
|
+
end
|
data/test/test_wald.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require(File.expand_path(File.dirname(__FILE__)+'/helper.rb'))
|
2
|
+
|
3
|
+
class StatsampleWaldTest < MiniTest::Unit::TestCase
|
4
|
+
# Wald test is useful to test a series of n acf with Chi-square
|
5
|
+
# degree of freedom. It is extremely useful to test fit the fit of
|
6
|
+
# an ARIMA model to test the residuals.
|
7
|
+
|
8
|
+
include Statsample::TimeSeries
|
9
|
+
include Statsample::Shorthand
|
10
|
+
include Distribution
|
11
|
+
|
12
|
+
def setup
|
13
|
+
#create time series to evaluate later
|
14
|
+
@wald = 100.times.map { rand(100) }.to_ts
|
15
|
+
end
|
16
|
+
|
17
|
+
def sum_of_squares_of_acf_series(lags)
|
18
|
+
#perform sum of squares for a series of acf with specified lags
|
19
|
+
acf = @wald.acf(lags)
|
20
|
+
return acf.map { |x| x ** 2 }.inject(:+)
|
21
|
+
end
|
22
|
+
|
23
|
+
def chisquare_cdf(sum_of_squares, lags)
|
24
|
+
1 - ChiSquare.cdf(sum_of_squares, lags)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def test_wald_with_5_lags
|
29
|
+
#number of lags for acf = 5
|
30
|
+
lags = 5
|
31
|
+
sum_of_squares = sum_of_squares_of_acf_series(lags)
|
32
|
+
assert_in_delta chisquare_cdf(sum_of_squares, lags), 1, 0.05
|
33
|
+
assert_equal @wald.acf(lags).size, lags + 1
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def test_wald_with_10_lags
|
38
|
+
#number of lags for acf = 10
|
39
|
+
lags = 10
|
40
|
+
sum_of_squares = sum_of_squares_of_acf_series(lags)
|
41
|
+
assert_in_delta chisquare_cdf(sum_of_squares, lags), 1, 0.05
|
42
|
+
assert_equal @wald.acf(lags).size, lags + 1
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def test_wald_with_15_lags
|
47
|
+
#number of lags for acf = 15
|
48
|
+
lags = 15
|
49
|
+
sum_of_squares = sum_of_squares_of_acf_series(lags)
|
50
|
+
assert_in_delta chisquare_cdf(sum_of_squares, lags), 1, 0.05
|
51
|
+
assert_equal @wald.acf(lags).size, lags + 1
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def test_wald_with_20_lags
|
56
|
+
#number of lags for acf = 20
|
57
|
+
lags = 20
|
58
|
+
sum_of_squares = sum_of_squares_of_acf_series(lags)
|
59
|
+
assert_in_delta chisquare_cdf(sum_of_squares, lags), 1, 0.05
|
60
|
+
assert_equal @wald.acf(lags).size, lags + 1
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def test_wald_with_25_lags
|
65
|
+
#number of lags for acf = 25
|
66
|
+
lags = 25
|
67
|
+
sum_of_squares = sum_of_squares_of_acf_series(lags)
|
68
|
+
assert_in_delta chisquare_cdf(sum_of_squares, lags), 1, 0.05
|
69
|
+
assert_equal @wald.acf(lags).size, lags + 1
|
70
|
+
end
|
71
|
+
end
|