bio-statsample-timeseries 0.1.1
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.
- 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
|