statsample-timeseries 0.0.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2aa5a74001152045a97547f2341b4a03f23ed408
4
+ data.tar.gz: 9f1c370a27c0b3ffb99d13f0d96eb6bfc6ca93bc
5
+ SHA512:
6
+ metadata.gz: 75272189f0b3f8f242820dc5693d335abb8d160d9322c36f7e82372d282ad2f7368ddb5fbedea0ebb2afd6bab21559651f8faaf224a02d462758131cd48098e5
7
+ data.tar.gz: ca16839c93757d521eb4322640b425fb0672187fa4c05d8adc6ed741fcc74271e5d67d074898a757a1814ff2c45d4a3e86e32d4a540d5cb16fc98b7504f7c8d7
@@ -0,0 +1,19 @@
1
+ # rcov generated
2
+ coverage
3
+ coverage.data
4
+
5
+ # rdoc generated
6
+ rdoc
7
+
8
+ # yard generated
9
+ doc
10
+ .yardoc
11
+
12
+ # bundler
13
+ .bundle
14
+
15
+ # jeweler generated
16
+ pkg
17
+
18
+ Gemfile.lock
19
+ *.gem
@@ -1,13 +1,16 @@
1
1
  language: ruby
2
+
2
3
  rvm:
3
- - 1.9.2
4
- - 1.9.3
5
4
  - 2.0.0
6
- - jruby-19mode # JRuby in 1.9 mode
7
- - rbx-19mode
8
- # - 1.8.7
9
- # - jruby-18mode # JRuby in 1.8 mode
10
- # - rbx-18mode
11
-
12
- # uncomment this line if your project needs to run something other than `rake`:
13
- # script: bundle exec rspec spec
5
+ - 2.1.0
6
+ - 2.2.1
7
+
8
+ script: "bundle exec rake test"
9
+
10
+ install:
11
+ - gem install bundler
12
+ - bundle install
13
+
14
+ before_install:
15
+ - sudo apt-get update -qq
16
+ - sudo apt-get install -y libgsl0-dev
data/Gemfile CHANGED
@@ -1,21 +1,2 @@
1
- source "http://rubygems.org"
2
-
3
- gem 'statsample', '=1.2.0'
4
-
5
- # Add dependencies required to use your gem here.
6
- # Example:
7
- gem "activesupport", "= 3.2.10"
8
-
9
- # Add dependencies to develop your gem here.
10
- # Include everything needed to run rake, tests, features, etc.
11
- group :development do
12
- gem "shoulda", ">= 0"
13
- gem "rdoc", "~> 3.12"
14
- gem "minitest", "~> 4.7.5"
15
- gem "cucumber", ">= 0"
16
- gem "bundler", "~> 1.3.5"
17
- gem "jeweler", "~> 1.8.4"
18
- gem "bio", ">= 1.4.2"
19
- gem "rdoc", "~> 3.12"
20
- gem 'mocha', '~> 0.14.0'
21
- end
1
+ source "https://rubygems.org"
2
+ gemspec
@@ -0,0 +1,4 @@
1
+ # 0.1.0
2
+
3
+ * Statsample-timeseries now dependents on the latest statsample (2) and uses daru for data containers.
4
+ * Removed redundant dependency on cucumber and migrated relevant cucumber tests to Test::Unit.
@@ -9,7 +9,7 @@ You *must* read the Contributor Agreement before contributing code to the SciRub
9
9
 
10
10
  -----
11
11
 
12
- Copyright (c) 2010 - 2013, Ruby Science Foundation
12
+ Copyright (c) 2013, Ankur Goel and Ruby Science Foundation
13
13
  All rights reserved.
14
14
 
15
15
  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
@@ -0,0 +1,62 @@
1
+ # statsample-timeseries
2
+
3
+ {<img
4
+ src="https://secure.travis-ci.org/SciRuby/statsample-timeseries.png"
5
+ />}[http://travis-ci.org/#!/SciRuby/statsample-timeseries]
6
+
7
+ Statsample-Timeseries is an extension to [Statsample](https://github.com/sciruby/statsample), a suite for advanced statistics with Ruby.
8
+
9
+ ## Description
10
+
11
+ Statsample-Timeseries is extension of Statsample, and incorporates helpful time series functions, estimation techniques, and modules, such as:
12
+
13
+ * ACF
14
+ * PACF
15
+ * ARIMA
16
+ * Kalman Filter
17
+ * Log Likelihood
18
+ * Autocovariances
19
+ * Moving Averages
20
+
21
+ Statsample-Timeseries is part of the [SciRuby project](http://sciruby.com).
22
+
23
+ ## Dependency
24
+
25
+ Please install [rb-gsl]() which is a Ruby wrapper over GNU Scientific Library.
26
+ It enables us to use various minimization techniques during estimations.
27
+
28
+ ## Installation
29
+
30
+ `gem install statsample-timeseries`
31
+
32
+ ## Usage
33
+
34
+ To use the library:
35
+
36
+ `require 'statsample-timeseries'`
37
+
38
+ See [Ankur's blog posts](http://ankurgoel.com) for explanations and examples.
39
+
40
+ ## Documentation
41
+
42
+ The API doc is [online](http://rubygems.org/gems/statsample-timeseries). For more code examples see also the test files in the source tree.
43
+
44
+ ## Contributing
45
+
46
+ * Fork the project.
47
+ * Create your feature branch
48
+ * Add/Modify code.
49
+ * Write equivalent documentation and *tests*.
50
+ * Run `rake test` to verify that all tests pass.
51
+ * Push your branch.
52
+ * Pull request. :)
53
+
54
+ ## Project home page
55
+
56
+ For information on the source tree, documentation, issues and how to contribute, see [http://github.com/SciRuby/statsample-timeseries](git@github.com:SciRuby/statsample-timeseries.git).
57
+
58
+ == Copyright
59
+
60
+ Copyright (c) 2013 Ankur Goel and the Ruby Science Foundation. See LICENSE.txt for further details.
61
+
62
+ Statsample is (c) 2009-2013 Claudio Bustos and the Ruby Science Foundation.
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
1
  # encoding: utf-8
2
+ require 'rake'
3
+ require 'bundler/gem_tasks'
2
4
 
3
- require 'rubygems'
5
+ # Setup the necessary gems, specified in the gemspec.
4
6
  require 'bundler'
5
7
  begin
6
8
  Bundler.setup(:default, :development)
@@ -9,20 +11,16 @@ rescue Bundler::BundlerError => e
9
11
  $stderr.puts "Run `bundle install` to install missing gems"
10
12
  exit e.status_code
11
13
  end
12
- require 'rake'
13
14
 
14
- require 'jeweler'
15
- Jeweler::Tasks.new do |gem|
16
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
- gem.name = "statsample-timeseries"
18
- gem.homepage = "http://github.com/AnkurGel/statsample-timeseries"
19
- gem.summary = %Q{TimeSeries modules for Statsample}
20
- gem.description = %Q{Statsample-timeseries is an extension to Statsample. It incorporates helpful timeseries functions and modules like ARMA, ARIMA, acf, pacf, lags etc.}
21
- gem.email = "ankurgel@gmail.com"
22
- gem.authors = ["Ankur Goel", "Claudio Bustos"]
23
- # dependencies defined in Gemfile
15
+ desc "Open IRB with statsample-timeseries loaded."
16
+ task :console do
17
+ require 'irb'
18
+ require 'irb/completion'
19
+ $:.unshift File.expand_path("../lib", __FILE__)
20
+ require 'statsample-timeseries'
21
+ ARGV.clear
22
+ IRB.start
24
23
  end
25
- Jeweler::RubygemsDotOrgTasks.new
26
24
 
27
25
  require 'rake/testtask'
28
26
  Rake::TestTask.new(:test) do |test|
@@ -31,14 +29,11 @@ Rake::TestTask.new(:test) do |test|
31
29
  test.verbose = true
32
30
  end
33
31
 
34
- require 'cucumber/rake/task'
35
- Cucumber::Rake::Task.new(:features)
36
-
37
32
  task :default => :test
38
33
 
39
34
  require 'rdoc/task'
40
35
  Rake::RDocTask.new do |rdoc|
41
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
36
+ version = Statsample::TimeSeries::VERSION
42
37
 
43
38
  rdoc.rdoc_dir = 'rdoc'
44
39
  rdoc.title = "statsample-timeseries #{version}"
@@ -1,18 +1,8 @@
1
- # Please require your code below, respecting the naming conventions in the
2
- # bioruby directory tree.
3
- #
4
- # For example, say you have a plugin named bio-plugin, the only uncommented
5
- # line in this file would be
6
- #
7
- # require 'bio/bio-plugin/plugin'
8
- #
9
- # In this file only require other files. Avoid other source code.
10
-
11
1
  require 'statsample'
12
- require_relative 'statsample-timeseries/timeseries.rb'
2
+ require 'statsample-timeseries/version'
3
+
4
+ require_relative 'statsample-timeseries/daru_monkeys.rb'
13
5
  require_relative 'statsample-timeseries/arima.rb'
14
6
  require_relative 'statsample-timeseries/arima/kalman'
15
7
  require_relative 'statsample-timeseries/arima/likelihood'
16
8
  require_relative 'statsample-timeseries/utility.rb'
17
-
18
-
@@ -1,4 +1,3 @@
1
- #require 'debugger'
2
1
  require 'statsample-timeseries/arima/kalman'
3
2
  require 'statsample-timeseries/arima/likelihood'
4
3
  module Statsample
@@ -10,31 +9,31 @@ module Statsample
10
9
  Statsample::TimeSeries::ARIMA.new
11
10
  end
12
11
 
13
- class ARIMA < Statsample::Vector
14
- include Statsample::TimeSeries
12
+ class ARIMA
15
13
 
16
14
  #= Kalman filter on ARIMA model
17
- #== Params
15
+ # == Arguments
18
16
  #
19
17
  #* *ts*: timeseries object
20
18
  #* *p*: AR order
21
19
  #* *i*: Integerated part order
22
20
  #* *q*: MA order
23
21
  #
24
- #== Usage
25
- # ts = (1..100).map { rand }.to_ts
26
- # k_obj = Statsample::TimeSeries::ARIMA.ks(ts, 2, 1, 1)
27
- # k_obj.ar
28
- # #=> AR's phi coefficients
29
- # k_obj.ma
30
- # #=> MA's theta coefficients
22
+ # == Usage
23
+ #
24
+ # ts = (1..100).map { rand }.to_ts
25
+ # k_obj = Statsample::TimeSeries::ARIMA.ks(ts, 2, 1, 1)
26
+ # k_obj.ar
27
+ # #=> AR's phi coefficients
28
+ # k_obj.ma
29
+ # #=> MA's theta coefficients
31
30
  #
32
31
  #== Returns
33
- #Kalman filter object
32
+ # Kalman filter object
34
33
  def self.ks(ts, p, i, q)
35
34
  #prototype
36
35
  if i > 0
37
- ts = ts.diff(i).reject { |x| x.nil? }.to_ts
36
+ ts = ts.diff(i).reject { |x| x.nil? }
38
37
  end
39
38
  if Statsample.has_gsl?
40
39
  filter = Arima::KalmanFilter.new(ts, p, i, q)
@@ -49,14 +48,15 @@ module Statsample
49
48
  #http://en.wikipedia.org/wiki/Autoregressive_model#Definition
50
49
  #For finding parameters(to fit), we will use either Yule-walker
51
50
  #or Burg's algorithm(more efficient)
51
+ raise NotImplementedError
52
52
  end
53
53
 
54
- #Converts a linear array into a Statsample vector
54
+ # Converts a linear array into a Daru vector
55
55
  #== Parameters
56
56
  #
57
- #* *arr*: Array which has to be converted in Statsample vector
57
+ #* *arr*: Array which has to be converted to Daru vector
58
58
  def create_vector(arr)
59
- Statsample::Vector.new(arr, :scale)
59
+ Daru::Vector.new(arr)
60
60
  end
61
61
 
62
62
  #=Yule Walker
@@ -70,7 +70,7 @@ module Statsample
70
70
  #==Returns
71
71
  #phi and sigma vectors
72
72
  def yule_walker(ts, n, k)
73
- phi, sigma = Pacf::Pacf.yule_walker(ts, k)
73
+ phi, sigma = Statsample::TimeSeries::Pacf.yule_walker(ts, k)
74
74
  return phi, sigma
75
75
  #return ar_sim(n, phi, sigma)
76
76
  end
@@ -89,22 +89,23 @@ module Statsample
89
89
  intermediate = Pacf::Pacf.levinson_durbin(ts, k)
90
90
  phi, sigma = intermediate[1], intermediate[0]
91
91
  return phi, sigma
92
- #return ar_sim(n, phi, sigma)
93
92
  end
94
93
 
95
94
  #=Autoregressive Simulator
96
95
  #Simulates an autoregressive AR(p) model with specified number of
97
96
  #observations(n), with phi number of values for order p and sigma.
98
97
  #
99
- #==Analysis:
100
- # [http://ankurgoel.com/blog/2013/07/20/ar-ma-arma-acf-pacf-visualizations/](http://ankurgoel.com/blog/2013/07/20/ar-ma-arma-acf-pacf-visualizations/)
98
+ # == Analysis
101
99
  #
102
- #==Parameters:
100
+ # http://ankurgoel.com/blog/2013/07/20/ar-ma-arma-acf-pacf-visualizations/
101
+ #
102
+ # == Parameters
103
103
  #* *n*: integer, number of observations
104
104
  #* *phi* :array of phi values, e.g: [0.35, 0.213] for p = 2
105
105
  #* *sigma*: float, sigma value for error generalization
106
106
  #
107
- #==Usage
107
+ # == Usage
108
+ #
108
109
  # ar = ARIMA.new
109
110
  # ar.ar_sim(1500, [0.3, 0.9], 0.12)
110
111
  # # => AR(2) autoregressive series of 1500 values
@@ -127,14 +128,13 @@ module Statsample
127
128
  11.upto(n+11) do |i|
128
129
  if i <= phi.size
129
130
  #dependent on previous accumulation of x
130
- backshifts = create_vector(x[0...i].reverse)
131
+ backshifts = x[0...i].reverse
131
132
  else
132
133
  #dependent on number of phi size/order
133
- backshifts = create_vector(x[(i - phi.size)...i].reverse)
134
+ backshifts = x[(i - phi.size)...i].reverse
134
135
  end
135
- parameters = create_vector(phi[0...backshifts.size])
136
-
137
- summation = (backshifts * parameters).inject(:+)
136
+ parameters = phi[0...backshifts.size]
137
+ summation = (backshifts.map.with_index { |e,i| e*parameters[i] }).inject(:+)
138
138
  x[i] = summation + err_nor.call()
139
139
  end
140
140
  x - buffer
@@ -144,70 +144,74 @@ module Statsample
144
144
  #Simulates a moving average model with specified number of
145
145
  #observations(n), with theta values for order k and sigma
146
146
  #
147
- #==Parameters
147
+ # == Parameters
148
148
  #* *n*: integer, number of observations
149
149
  #* *theta*: array of floats, e.g: [0.23, 0.732], must be < 1
150
150
  #* *sigma*: float, sigma value for whitenoise error
151
151
  #
152
- #==Usage
153
- # ar = ARIMA.new
154
- # ar.ma_sim(1500, [0.23, 0.732], 0.27)
152
+ # == Usage
153
+ # ar = ARIMA.new
154
+ # ar.ma_sim(1500, [0.23, 0.732], 0.27)
155
155
  #
156
- #==Returns
157
- #Array of generated MA(q) model
156
+ # == Returns
157
+ # Array of generated MA(q) model
158
+ #
159
+ # == Notes
160
+ # n is number of observations (eg: 1000). theta are the model parameters
161
+ # containting q values. q is the order of MA
158
162
  def ma_sim(n, theta, sigma)
159
- #n is number of observations (eg: 1000)
160
- #theta are the model parameters containting q values
161
- #q is the order of MA
162
- mean = theta.to_ts.mean()
163
+ q = theta.size
164
+ mean = theta.inject(:+) / q
163
165
  whitenoise_gen = Distribution::Normal.rng(0, sigma)
164
166
  x = Array.new(n, 0)
165
- q = theta.size
166
167
  noise_arr = (n+1).times.map { whitenoise_gen.call() }
167
168
 
168
169
  1.upto(n) do |i|
169
170
  #take care that noise vector doesn't try to index -ve value:
170
171
  if i <= q
171
- noises = create_vector(noise_arr[0..i].reverse)
172
+ noises = noise_arr[0..i].reverse
172
173
  else
173
- noises = create_vector(noise_arr[(i-q)..i].reverse)
174
+ noises = noise_arr[(i-q)..i].reverse
174
175
  end
175
- weights = create_vector([1] + theta[0...noises.size - 1])
176
+ weights = [1] + theta[0...noises.size - 1]
176
177
 
177
- summation = (weights * noises).inject(:+)
178
+ summation = weights.map.with_index { |e,i| e*noises[i] }.inject(:+)
178
179
  x[i] = mean + summation
179
180
  end
181
+
180
182
  x
181
183
  end
182
184
 
183
185
  #=ARMA(Autoregressive and Moving Average) Simulator
184
- #ARMA is represented by:
185
- #http://upload.wikimedia.org/math/2/e/d/2ed0485927b4370ae288f1bc1fe2fc8b.png
186
- #This simulates the ARMA model against p, q and sigma.
187
- #If p = 0, then model is pure MA(q),
188
- #If q = 0, then model is pure AR(p),
189
- #otherwise, model is ARMA(p, q) represented by above.
186
+ # ARMA is represented by:
187
+ # http://upload.wikimedia.org/math/2/e/d/2ed0485927b4370ae288f1bc1fe2fc8b.png
188
+ # This simulates the ARMA model against p, q and sigma.
189
+ # If p = 0, then model is pure MA(q),
190
+ # If q = 0, then model is pure AR(p),
191
+ # otherwise, model is ARMA(p, q) represented by above.
190
192
  #
191
- #==Detailed analysis:
192
- # [http://ankurgoel.com/blog/2013/07/20/ar-ma-arma-acf-pacf-visualizations/](http://ankurgoel.com/blog/2013/07/20/ar-ma-arma-acf-pacf-visualizations/)
193
+ # == Detailed analysis:
194
+ #
195
+ # http://ankurgoel.com/blog/2013/07/20/ar-ma-arma-acf-pacf-visualizations/
196
+ #
197
+ # == Parameters
193
198
  #
194
- #==Parameters
195
199
  #* *n*: integer, number of observations
196
200
  #* *p*: array, contains p number of phi values for AR(p) process
197
201
  #* *q*: array, contains q number of theta values for MA(q) process
198
202
  #* *sigma*: float, sigma value for whitenoise error generation
199
203
  #
200
- #==Usage
201
- # ar = ARIMA.new
202
- # ar.arma_sim(1500, [0.3, 0.272], [0.8, 0.317], 0.92)
204
+ # == Usage
203
205
  #
204
- #==Returns
205
- #array of generated ARMA model values
206
+ # ar = ARIMA.new
207
+ # ar.arma_sim(1500, [0.3, 0.272], [0.8, 0.317], 0.92)
208
+ #
209
+ # == Returns
210
+ #
211
+ # array of generated ARMA model values
206
212
  def arma_sim(n, p, q, sigma)
207
213
  #represented by :
208
214
  #http://upload.wikimedia.org/math/2/e/d/2ed0485927b4370ae288f1bc1fe2fc8b.png
209
-
210
-
211
215
  whitenoise_gen = Distribution::Normal.rng(0, sigma)
212
216
  noise_arr = (n+11).times.map { whitenoise_gen.call() }
213
217
 
@@ -216,35 +220,29 @@ module Statsample
216
220
 
217
221
  11.upto(n+11) do |i|
218
222
  if i <= p.size
219
- backshifts = create_vector(x[0...i].reverse)
223
+ backshifts = x[0...i].reverse
220
224
  else
221
- backshifts = create_vector(x[(i - p.size)...i].reverse)
225
+ backshifts = x[(i - p.size)...i].reverse
222
226
  end
223
- parameters = create_vector(p[0...backshifts.size])
224
-
225
- ar_summation = (backshifts * parameters).inject(:+)
227
+ parameters = p[0...backshifts.size]
228
+ ar_summation = backshifts.map.with_index { |e,i| e*parameters[i] }.inject(:+)
226
229
 
227
230
  if i <= q.size
228
- noises = create_vector(noise_arr[0..i].reverse)
231
+ noises = noise_arr[0..i].reverse
229
232
  else
230
- noises = create_vector(noise_arr[(i-q.size)..i].reverse)
233
+ noises = noise_arr[(i-q.size)..i].reverse
231
234
  end
232
- weights = create_vector([1] + q[0...noises.size - 1])
233
-
234
- ma_summation = (weights * noises).inject(:+)
235
-
235
+ weights = [1] + q[0...noises.size - 1]
236
+ ma_summation = (weights.map.with_index { |e,i| e*noises[i] }).inject(:+)
236
237
  x[i] = ar_summation + ma_summation
237
238
  end
238
239
  x - buffer
239
240
  end
240
241
 
241
- #=Hannan-Rissanen for ARMA fit
242
+ # Hannan-Rissanen for ARMA fit
242
243
  def self.hannan(ts, p, q, k)
243
- start_params = create_vector(Array.new(p+q+k, 0))
244
- ts_dup = ts.dup
245
-
244
+ raise NotImplementedError
246
245
  end
247
246
  end
248
-
249
247
  end
250
248
  end