bio-statsample-timeseries 0.1.2 → 0.2.0

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/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: