bio-statsample-timeseries 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -18,4 +18,5 @@ group :development do
18
18
  gem "bio", ">= 1.4.2"
19
19
  gem "rdoc", "~> 3.12"
20
20
  gem 'mocha', '~> 0.14.0'
21
+ gem 'gsl'
21
22
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
@@ -11,6 +11,8 @@
11
11
  require 'statsample'
12
12
  require_relative 'bio-statsample-timeseries/timeseries.rb'
13
13
  require_relative 'bio-statsample-timeseries/arima.rb'
14
+ require_relative 'bio-statsample-timeseries/arima/kalman'
15
+ require_relative 'bio-statsample-timeseries/arima/likelihood'
14
16
  require_relative 'bio-statsample-timeseries/utility.rb'
15
17
 
16
18
 
@@ -1,4 +1,6 @@
1
1
  #require 'debugger'
2
+ require 'bio-statsample-timeseries/arima/kalman'
3
+ require 'bio-statsample-timeseries/arima/likelihood'
2
4
  module Statsample
3
5
  module TimeSeries
4
6
 
@@ -10,21 +12,31 @@ module Statsample
10
12
 
11
13
  class ARIMA < Statsample::Vector
12
14
  include Statsample::TimeSeries
13
- # SUGGESTION: We could use an API similar to R
14
- # like
15
- # ar_obj=Statsample::TimeSeries.arima(ds,p,i,q)
16
- # which calls
17
- # Statsample::TimeSeries::Arima.new(ds,p,i,q)
18
- def arima(ds, p, i, q)
15
+
16
+ #Kalman filter on ARIMA model
17
+ #*Params*:
18
+ #-_ts_::timeseries object
19
+ #-_p_::AR order
20
+ #-_i_::Integerated part
21
+ #-_q_::MA order
22
+ #
23
+ #*Usage*:
24
+ # ts = (1..100).map { rand }.to_ts
25
+ # k_obj = ARIMA.ks(ts, 2, 1, 1)
26
+ # k_obj.ar
27
+ # #=> AR's phi coefficients
28
+ # k_obj.ma
29
+ # #=> MA's theta coefficients
30
+ #
31
+ #*Returns*:
32
+ #Kalman filter object
33
+ def self.ks(ts, p, i, q)
19
34
  #prototype
20
- # ISSUE: We should differenciate now, if i>0.
21
- # The result should be send to next step
22
- if q.zero?
23
- self.ar(p)
24
- elsif p.zero?
25
- self.ma(p)
26
- # ISSUE-> ELSE -> simultaneuos estimation of MA and AR parameters
35
+ if i > 0
36
+ ts = ts.diff(i).reject { |x| x.nil? }.to_ts
27
37
  end
38
+ filter = Arima::KalmanFilter.new(ts, p, i, q)
39
+ filter
28
40
  end
29
41
 
30
42
  def ar(p)
@@ -211,67 +223,5 @@ module Statsample
211
223
  end
212
224
  end
213
225
 
214
- module Arima
215
- class KalmanFilter < Statsample::Vector
216
- include Statsample::TimeSeries
217
-
218
- #=T
219
- #The coefficient matrix for the state vector in state equation
220
- # It's dimensions is r+k x r+k
221
- #*Parameters*
222
- #-_r_::integer, r is max(p, q+1), where p and q are orders of AR and MA respectively
223
- #-_k_::integer, number of exogeneous variables in ARMA model
224
- #-_q_::integer, The AR coefficient of ARMA model
225
-
226
- #*References*: Statsmodels tsa, Durbin and Koopman Section 4.7
227
- def self.T(r, k, p)
228
- arr = Matrix.zero(r)
229
- params_padded = Statsample::Vector.new(Array.new(r, 0), :scale)
230
-
231
- params_padded[0...p] = params[k...(p+k)]
232
- intermediate_matrix = (r-1).times.map { Array.new(r, 0) }
233
- #appending an array filled with padded values in beginning
234
- intermediate_matrix[0,0] = [params_padded]
235
-
236
- #now generating column matrix for that:
237
- arr = Matrix.columns(intermediate_matrix)
238
- arr_00 = arr[0,0]
239
-
240
- #identify matrix substituition in matrix except row[0] and column[0]
241
- r.times do |i|
242
- arr[r,r] = 1
243
- end
244
- arr[0,0] = arr_00
245
- arr
246
- end
247
-
248
-
249
- #=R
250
- #The coefficient matrix for the state vector in the observation matrix.
251
- #It's dimension is r+k x 1
252
- #*Parameters*
253
- #-_r_::integer, r is max(p, q+1) where p and q are order of AR and MA respectively
254
- #-_k_::integer, number of exogeneous variables in ARMA model
255
- #-_q_::integer, The MA order in ARMA model
256
- #-_p_::integer, The AR order in ARMA model
257
- #*References*: Statsmodels tsa, Durbin and Koopman
258
- def self.R(r, k, q, p)
259
- arr = Matrix.column_vector(Array.new(r,0.0))
260
-
261
- #pending - in kind of difficult end here;
262
- end
263
-
264
- #=Z
265
- #The Z selector matrix
266
- #*Parameters*
267
- #-_r_::integer, max(p, q+1)
268
- #Returns: vector
269
- def self.Z(r)
270
- arr = Statsample::Vector.new(Array.new(r, 0.0), :scale)
271
- arr[0] = 1.0
272
- return arr
273
- end
274
- end
275
- end
276
226
  end
277
227
  end
@@ -0,0 +1,137 @@
1
+ require 'bio-statsample-timeseries/arima/likelihood'
2
+ module Statsample
3
+ module TimeSeries
4
+ module Arima
5
+
6
+ class KalmanFilter
7
+ include Statsample::TimeSeries
8
+ include GSL::MultiMin
9
+ attr_accessor :ts, :p, :i, :q
10
+ attr_reader :ar, :ma
11
+ def initialize(ts=[].to_ts, p=0, i=0, q=0)
12
+ @ts = ts
13
+ @p = p
14
+ @i = i
15
+ @q = q
16
+ ks #call the filter
17
+ end
18
+
19
+ def to_s
20
+ sprintf("ARIMA model(p = %d, i = %d, q = %d) on series(%d elements) - [%s]",
21
+ @p, @i, @q, @ts.size, @ts.to_a.join(','))
22
+ end
23
+
24
+ #=Kalman Filter
25
+ #Function which minimizes KalmanFilter.ll iteratively for initial parameters
26
+ #*Parameters*:
27
+ #-_timeseries_: timeseries object, against which the ARMA params has to be estimated
28
+ #-_p_: order of AR
29
+ #-_q_: order of MA
30
+ #*Usage*:
31
+ #- ts = (1..100).to_a.to_ts
32
+ #- KalmanFilter.ks(ts, 3, 1)
33
+ #NOTE: Suceptible to syntactical change later. Can be called directly on timeseries.
34
+ #NOTE: Return parameters
35
+ def ks
36
+ initial = Array.new((@p+@q), 0.0)
37
+
38
+ my_f = Proc.new{ |x, params|
39
+ #In rb-gsl, params remain idle, x is varied upon
40
+ #In R code, initial parameters varied in each iteration
41
+ #my_func.set_params([(1..100).to_a.to_ts, p_value, q_value])
42
+ timeseries = params[0]
43
+ p,q = params[1], params[2]
44
+ params = x
45
+ #puts x
46
+ -Arima::KF::LogLikelihood.new(x.to_a, timeseries, p, q).ll
47
+ #KalmanFilter.ll(x.to_a, timeseries, p, q)
48
+ }
49
+ np = @p + @q
50
+ my_func = Function.alloc(my_f, np)
51
+ my_func.set_params([@ts, @p, @q])
52
+ x = GSL::Vector.alloc(initial)
53
+ ss = GSL::Vector.alloc(np)
54
+ ss.set_all(0.1)
55
+
56
+ minimizer = FMinimizer.alloc("nmsimplex", np)
57
+ minimizer.set(my_func, x, ss)
58
+ status = GSL::CONTINUE
59
+ iter = 0
60
+ while status == GSL::CONTINUE && iter < 100
61
+ iter += 1
62
+ begin
63
+ status = minimizer.iterate()
64
+ status = minimizer.test_size(1e-2)
65
+ x = minimizer.x
66
+ rescue
67
+ break
68
+ end
69
+ # printf("%5d ", iter)
70
+ # for i in 0...np do
71
+ # puts "#{x[i]}.to_f"
72
+ # #printf("%10.3e ", x[i].to_f)
73
+ # end
74
+ # printf("f() = %7.3f size = %.3f\n", minimizer.fval, minimizer.size)
75
+ end
76
+ #
77
+ @ar = (p > 0) ? x.to_a[0...p] : []
78
+ @ma = (q > 0) ? x.to_a[p...(p+q)] : []
79
+ x.to_a
80
+ end
81
+
82
+
83
+ #=log_likelihood
84
+ #Computes Log likelihood on given parameters, ARMA order and timeseries
85
+ #*params*:
86
+ #-_params_::array of floats, contains phi/theta parameters
87
+ #-_timeseries_::timeseries object
88
+ #-_p_::integer, AR(p) order
89
+ #-_q_::integer, MA(q) order
90
+ #*Returns*:
91
+ #LogLikelihood object
92
+ #*Usage*:
93
+ # s = (1..100).map { rand }.to_ts
94
+ # p, q = 1, 0
95
+ # ll = KalmanFilter.log_likelihood([0.2], s, p, q)
96
+ # ll.log_likelihood
97
+ # #=> -22.66
98
+ # ll.sigma
99
+ # #=> 0.232
100
+ def self.log_likelihood(params, timeseries, p, q)
101
+ Arima::KF::LogLikelihood.new(params, timeseries, p, q)
102
+ end
103
+
104
+ #=T
105
+ #The coefficient matrix for the state vector in state equation
106
+ # It's dimensions is r+k x r+k
107
+ #*Parameters*
108
+ #-_r_::integer, r is max(p, q+1), where p and q are orders of AR and MA respectively
109
+ #-_k_::integer, number of exogeneous variables in ARMA model
110
+ #-_q_::integer, The AR coefficient of ARMA model
111
+
112
+ #*References*: Statsmodels tsa, Durbin and Koopman Section 4.7
113
+ #def self.T(r, k, p)
114
+ # arr = Matrix.zero(r)
115
+ # params_padded = Statsample::Vector.new(Array.new(r, 0), :scale)
116
+ #
117
+ # params_padded[0...p] = params[k...(p+k)]
118
+ # intermediate_matrix = (r-1).times.map { Array.new(r, 0) }
119
+ # #appending an array filled with padded values in beginning
120
+ # intermediate_matrix[0,0] = [params_padded]
121
+ #
122
+ # #now generating column matrix for that:
123
+ # arr = Matrix.columns(intermediate_matrix)
124
+ # arr_00 = arr[0,0]
125
+ #
126
+ # #identify matrix substituition in matrix except row[0] and column[0]
127
+ # r.times do |i|
128
+ # arr[r,r] = 1
129
+ # end
130
+ # arr[0,0] = arr_00
131
+ # arr
132
+ #end
133
+
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,104 @@
1
+ module Statsample
2
+ module TimeSeries
3
+ module Arima
4
+ module KF
5
+ class LogLikelihood
6
+
7
+ #log_likelihood
8
+ #Gives log likelihood value of an ARMA(p, q) process on given parameters
9
+ attr_reader :log_likelihood
10
+
11
+ #sigma
12
+ #Gives sigma value of an ARMA(p,q) process on given parameters
13
+ attr_reader :sigma
14
+
15
+ #aic
16
+ #Gives AIC(Akaike Information Criterion)
17
+ #https://www.scss.tcd.ie/Rozenn.Dahyot/ST7005/13AICBIC.pdf
18
+ attr_reader :aic
19
+
20
+ def initialize(params, timeseries, p, q)
21
+ @params = params
22
+ @timeseries = timeseries
23
+ @p = p
24
+ @q = q
25
+ ll
26
+ end
27
+
28
+ #Log likelihood function.
29
+ #iteratively minimized by simplex algorithm via KalmanFilter.ks
30
+ #Not meant to be used directly. Will make it private later.
31
+ def ll
32
+ params, timeseries = @params, @timeseries
33
+ p, q = @p, @q
34
+
35
+ phi = []
36
+ theta = []
37
+ phi = params[0...p] if p > 0
38
+ theta = params[(p)...(p + q)] if q > 0
39
+
40
+ [phi, theta].each do |v|
41
+ if v.size>0 and v.map(&:abs).inject(:+) > 1
42
+ return
43
+ end
44
+ end
45
+
46
+ m = [p, q].max
47
+ h = Matrix.column_vector(Array.new(m,0))
48
+ m.times do |i|
49
+ h[i,0] = phi[i] if i< p
50
+ h[i,0] = h[i,0] + theta[i] if i < q
51
+ end
52
+
53
+ t = Matrix.zero(m)
54
+ #set_column is available in utility.rb
55
+ t = t.set_column(0, phi)
56
+ if(m > 1)
57
+ t[0...(m-1), 1...m] = Matrix.I(m-1)
58
+ #chances of extra constant 0 values as unbalanced column, so:
59
+ t = Matrix.columns(t.column_vectors)
60
+ end
61
+
62
+ g = Matrix[[1]]
63
+ a_t = Matrix.column_vector(Array.new(m,0))
64
+ n = timeseries.size
65
+ z = Matrix.row_vector(Array.new(m,0))
66
+ z[0,0] = 1
67
+ p_t = Matrix.I(m)
68
+ v_t, f_t = Array.new(n,0), Array.new(n, 0)
69
+
70
+ n.times do |i|
71
+ v_t[i] = (z * a_t).map { |x| timeseries[i] - x }[0,0]
72
+
73
+ f_t[i] = (z * p_t * (z.transpose)).map { |x| x + 1 }[0,0]
74
+
75
+ k_t = ((t * p_t * z.transpose) + h).map { |x| x / f_t[i] }
76
+
77
+ a_t = (t * a_t) + (k_t * v_t[i])
78
+ l_t = t - k_t * z
79
+ j_t = h - k_t
80
+
81
+ p_t = (t * p_t * (l_t.transpose)) + (h * (j_t.transpose))
82
+ end
83
+
84
+ pot = v_t.map(&:square).zip(f_t).map { |x,y| x / y}.inject(:+)
85
+ sigma_2 = pot.to_f / n.to_f
86
+
87
+ f_t_log_sum = f_t.map { |x| Math.log(x) }.inject(:+)
88
+ @log_likelihood = -0.5 * (n*Math.log(2*Math::PI) + n*Math.log(sigma_2) + f_t_log_sum + n)
89
+
90
+ @sigma = sigma_2
91
+ @aic = -(2 * @log_likelihood - 2*(p+q+1))
92
+ #puts ("ll = #{-ll}")
93
+ return @log_likelihood
94
+ end
95
+
96
+ def to_s
97
+ sprintf("LogLikelihood(p = %d, q = %d) on params: [%s]",
98
+ @p, @q, @params.join(', '))
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -107,7 +107,7 @@ module Statsample
107
107
  else
108
108
  demeaned_series = self
109
109
  end
110
- n = self.acf.size
110
+ n = (10 * Math.log10(size)).to_i + 1
111
111
  m = self.mean
112
112
  if unbiased
113
113
  d = Array.new(self.size, self.size)
@@ -168,21 +168,28 @@ module Statsample
168
168
  end
169
169
 
170
170
  #=Diff
171
- # Performs a first difference of the series.
172
- #
173
- # The convention is to set the oldest observations (the first ones
174
- # in the series) to nil so that the size of the diffed series is the
175
- # same as the original.
176
- #
171
+ # Performs the difference of the series.
172
+ # Note: The first difference of series is X(t) - X(t-1)
173
+ # But, second difference of series is NOT X(t) - X(t-2)
174
+ # It is the first difference of the first difference
175
+ # => (X(t) - X(t-1)) - (X(t-1) - X(t-2))
176
+ #*Params*:
177
+ #-_max_lags_::integer, (default: 1), number of differences reqd.
177
178
  #*Usage*:
178
179
  #
179
180
  # ts = (1..10).map { rand }.to_ts
180
181
  # # => [0.69, 0.23, 0.44, 0.71, ...]
181
182
  #
182
183
  # ts.diff # => [nil, -0.46, 0.21, 0.27, ...]
183
- #
184
- def diff
185
- self - self.lag
184
+ #*Returns*: Timeseries object
185
+ def diff(max_lags = 1)
186
+ ts = self
187
+ difference = []
188
+ max_lags.times do
189
+ difference = ts - ts.lag
190
+ ts = difference
191
+ end
192
+ difference
186
193
  end
187
194
 
188
195
  #=Moving Average
@@ -78,8 +78,8 @@ module Statsample
78
78
  #Class method
79
79
  #Returns the chain product of two matrices
80
80
  #==Usage:
81
- #Let `a` be 4 * 3 matrix,
82
- #Let `b` be 3 * 3 matrix,
81
+ #Let `a` be 4 * 3 matrix,
82
+ #Let `b` be 3 * 3 matrix,
83
83
  #Let `c` be 3 * 1 matrix,
84
84
  #then `Matrix.chain_dot(a, b, c)`
85
85
  #===*NOTE*: Send the matrices in multiplicative order with proper dimensions
@@ -114,5 +114,38 @@ module Statsample
114
114
  end
115
115
  return Matrix.rows(vectors)
116
116
  end
117
+
118
+ def set_column(i, arr)
119
+ columns = self.column_vectors
120
+ column = columns[i].to_a
121
+ column[0...arr.size] = arr
122
+ columns[i] = column
123
+ return Matrix.columns(columns)
124
+ end
125
+
126
+ def set_row(i, arr)
127
+ #similar implementation as set_column
128
+ #writing and commenting metaprogrammed version
129
+ #Please to give opinion :)
130
+ rows = self.row_vectors
131
+ row = rows[i].to_a
132
+ row[0...arr.size] = arr
133
+ rows[i] = row
134
+ return Matrix.rows(rows)
135
+ end
136
+
137
+ #Metaprogrammed version of set_column, set_row
138
+ # self.class_eval do
139
+ # ["row", "column"].each do |dimension|
140
+ # define_method("set_#{dimension}s") do |i, arr|
141
+ # dims = send("#{dimension}_vectors")
142
+ # dim = dims[i].to_a
143
+ # dim[0...arr.size] = arr
144
+ # dims[i] = dim
145
+ # return Matrix.send("#{dimension}s", dims)
146
+ # end
147
+ # end
148
+ # end
117
149
  end
150
+
118
151
  end
data/test/helper.rb CHANGED
@@ -10,9 +10,9 @@ end
10
10
  require 'minitest/unit'
11
11
  require 'shoulda'
12
12
  require 'shoulda-context'
13
- require 'mocha'
13
+ require 'mocha/setup'
14
14
 
15
- require 'bio-statsample-timeseries'
15
+ #require 'bio-statsample-timeseries'
16
16
 
17
17
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
18
18
  $LOAD_PATH.unshift(File.dirname(__FILE__))
@@ -0,0 +1,106 @@
1
+ require(File.expand_path(File.dirname(__FILE__)+'/helper.rb'))
2
+
3
+ class StatsampleArimaKSTestCase < MiniTest::Unit::TestCase
4
+
5
+ context("AR(0.5) simulation") do
6
+ #include Statsample::TimeSeries
7
+ setup do
8
+ @s = [-1.16025577,0.64758021,0.77158601,0.14989543,2.31358162,3.49213868,1.14826956,0.58169457,-0.30813868,-0.34741084,-1.41175595,0.06040081, -0.78230232,0.86734837,0.95015787,-0.49781397,0.53247330,1.56495187,0.30936619,0.09750217,1.09698829,-0.81315490,-0.79425607,-0.64568547,-1.06460320,1.24647894,0.66695937,1.50284551,1.17631218,1.64082872,1.61462736,0.06443761,-0.17583741,0.83918339,0.46610988,-0.54915270,-0.56417108,-1.27696654,0.89460084,1.49970338,0.24520493,0.26249138,-1.33744834,-0.57725961,1.55819543,1.62143157,0.44421891,-0.74000084 ,0.57866347,3.51189333,2.39135077,1.73046244,1.81783890,0.21454040,0.43520890,-1.42443856,-2.72124685,-2.51313877,-1.20243091,-1.44268002 ,-0.16777305,0.05780661,2.03533992,0.39187242,0.54987983,0.57865693,-0.96592469,-0.93278473,-0.75962671,-0.63216906,1.06776183, 0.17476059 ,0.06635860,0.94906227,2.44498583,-1.04990407,-0.88440073,-1.99838258,-1.12955558,-0.62654882,-1.36589161,-2.67456821,-0.97187696, -0.84431782 ,-0.10051809,0.54239549,1.34622861,1.25598105,0.19707759,3.29286114,3.52423499,1.69146333,-0.10150024,0.45222903,-0.01730516, -0.49828727, -1.18484684,-1.09531773,-1.17190808,0.30207662].to_ts
9
+ end
10
+ context "passed through the Kalman Filter" do
11
+ setup do
12
+ @kf=Statsample::TimeSeries::ARIMA.ks(@s,1,0,0)
13
+ end
14
+ should "return correct object" do
15
+ assert_instance_of Statsample::TimeSeries::Arima::KalmanFilter, @kf
16
+ end
17
+ should "return correct parameters" do
18
+ assert_equal @kf.p,1
19
+ assert_equal @kf.q,0
20
+ assert_equal @kf.i,0
21
+ end
22
+ should "return correct ar estimators" do
23
+ assert_equal @kf.ar.length,1
24
+ assert_in_delta @kf.ar[0], 0.700 #0.564
25
+ end
26
+ should "return correct ma estimators" do
27
+ assert_equal @kf.ma.length,0
28
+ end
29
+ end
30
+ context "passed through the Kalman Filter with AR(0.564)" do
31
+ setup do
32
+ @kf_likehood=Statsample::TimeSeries::Arima::KalmanFilter.log_likelihood([0.564],@s,1,0)
33
+ end
34
+ should "return correct object for log_likehood" do
35
+ assert_instance_of Statsample::TimeSeries::Arima::KF::LogLikelihood, @kf_likehood
36
+ end
37
+ should "return correct log_likehood" do
38
+ assert_in_delta -148.7003, @kf_likehood.log_likelihood
39
+ end
40
+ should "return correct sigma" do
41
+ assert_in_delta 1.137915, @kf_likehood.sigma
42
+ end
43
+ should "return correct AIC value" do
44
+ assert_in_delta 301.44, @kf_likehood.aic, 0.1
45
+ end
46
+
47
+ end
48
+ context "passed through the Kalman Filter with AR(0.2)" do
49
+ setup do
50
+ @kf_likehood=Statsample::TimeSeries::Arima::KalmanFilter.log_likelihood([0.2],@s,1,0)
51
+ end
52
+ should "return correct object for log_likehood" do
53
+ assert_instance_of Statsample::TimeSeries::Arima::KF::LogLikelihood, @kf_likehood
54
+ end
55
+ should "return correct log_likehood" do
56
+ assert_in_delta -66.40337-0.5*@s.size*(Math.log(2*Math::PI)), @kf_likehood.log_likelihood, 0.01
57
+ end
58
+ should "return correct sigma" do
59
+ assert_in_delta 1.378693, @kf_likehood.sigma, 0.01
60
+ end
61
+
62
+ end
63
+ end
64
+
65
+ context("ARMA(1, 1) process") do
66
+ setup do
67
+ @s = [-1.16025577,0.64758021,0.77158601,0.14989543,2.31358162,3.49213868,1.14826956,0.58169457,-0.30813868,-0.34741084,-1.41175595,0.06040081, -0.78230232,0.86734837,0.95015787,-0.49781397,0.53247330,1.56495187,0.30936619,0.09750217,1.09698829,-0.81315490,-0.79425607,-0.64568547,-1.06460320,1.24647894,0.66695937,1.50284551,1.17631218,1.64082872,1.61462736,0.06443761,-0.17583741,0.83918339,0.46610988,-0.54915270,-0.56417108,-1.27696654,0.89460084,1.49970338,0.24520493,0.26249138,-1.33744834,-0.57725961,1.55819543,1.62143157,0.44421891,-0.74000084 ,0.57866347,3.51189333,2.39135077,1.73046244,1.81783890,0.21454040,0.43520890,-1.42443856,-2.72124685,-2.51313877,-1.20243091,-1.44268002 ,-0.16777305,0.05780661,2.03533992,0.39187242,0.54987983,0.57865693,-0.96592469,-0.93278473,-0.75962671,-0.63216906,1.06776183, 0.17476059 ,0.06635860,0.94906227,2.44498583,-1.04990407,-0.88440073,-1.99838258,-1.12955558,-0.62654882,-1.36589161,-2.67456821,-0.97187696, -0.84431782 ,-0.10051809,0.54239549,1.34622861,1.25598105,0.19707759,3.29286114,3.52423499,1.69146333,-0.10150024,0.45222903,-0.01730516, -0.49828727, -1.18484684,-1.09531773,-1.17190808,0.30207662].to_ts
68
+ end
69
+ context "passed through the Kalman Filter" do
70
+ setup do
71
+ @kf = Statsample::TimeSeries::ARIMA.ks(@s, 2, 0, 1)
72
+ end
73
+
74
+ should "return correct parameters" do
75
+ assert_equal @kf.p, 2
76
+ assert_equal @kf.q, 1
77
+ assert_equal @kf.i, 0
78
+ end
79
+ should "return correct AR estimators" do
80
+ assert_equal @kf.ar.length, 2
81
+ assert_in_delta @kf.ar[0], 0.45, 0.01
82
+ assert_in_delta @kf.ar[1], 0.016, 0.01
83
+ end
84
+ should "return correct ma estimators" do
85
+ assert_equal @kf.ma.length, 1
86
+ assert_in_delta @kf.ma[0], 0.18, 0.01
87
+ end
88
+ end
89
+
90
+ context "passed through the LogLikelihood with ARMA([0.45, 0.16, 0.18])" do
91
+ setup do
92
+ @ll = Statsample::TimeSeries::Arima::KF::LogLikelihood.new([0.45, 0.16, 0.18], @s, 2, 1)
93
+ end
94
+ should "return correct log likelihood" do
95
+ assert_in_delta -149.55, @ll.log_likelihood, 0.01
96
+ end
97
+ should "return correct sigma" do
98
+ assert_in_delta 1.14, @ll.sigma, 0.1
99
+ end
100
+ should "return correct AIC value" do
101
+ assert_in_delta 307.11, @ll.aic, 0.01
102
+ end
103
+ end
104
+ end
105
+
106
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bio-statsample-timeseries
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-09-03 00:00:00.000000000 Z
13
+ date: 2013-09-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: statsample
@@ -188,6 +188,22 @@ dependencies:
188
188
  - - ~>
189
189
  - !ruby/object:Gem::Version
190
190
  version: 0.14.0
191
+ - !ruby/object:Gem::Dependency
192
+ name: gsl
193
+ requirement: !ruby/object:Gem::Requirement
194
+ none: false
195
+ requirements:
196
+ - - ! '>='
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ type: :development
200
+ prerelease: false
201
+ version_requirements: !ruby/object:Gem::Requirement
202
+ none: false
203
+ requirements:
204
+ - - ! '>='
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
191
207
  description: Statsample-timeseries is an extension to Statsample. It incorporates
192
208
  helpful timeseries functions and modules like ARMA, ARIMA, acf, pacf, lags etc.
193
209
  email: ankurgel@gmail.com
@@ -216,11 +232,14 @@ files:
216
232
  - features/support/env.rb
217
233
  - lib/bio-statsample-timeseries.rb
218
234
  - lib/bio-statsample-timeseries/arima.rb
235
+ - lib/bio-statsample-timeseries/arima/kalman.rb
236
+ - lib/bio-statsample-timeseries/arima/likelihood.rb
219
237
  - lib/bio-statsample-timeseries/timeseries.rb
220
238
  - lib/bio-statsample-timeseries/timeseries/pacf.rb
221
239
  - lib/bio-statsample-timeseries/utility.rb
222
240
  - test/fixtures/stock_data.csv
223
241
  - test/helper.rb
242
+ - test/test_arima_ks.rb
224
243
  - test/test_arima_simulators.rb
225
244
  - test/test_matrix.rb
226
245
  - test/test_pacf.rb
@@ -241,7 +260,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
241
260
  version: '0'
242
261
  segments:
243
262
  - 0
244
- hash: -122253519
263
+ hash: 68777245
245
264
  required_rubygems_version: !ruby/object:Gem::Requirement
246
265
  none: false
247
266
  requirements: