ts 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/lib/ts.rb +68 -9
  4. data/test/test_ts.rb +15 -1
  5. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 28be043c878e154e056aca129a35fb9a2c225e1d
4
- data.tar.gz: 9f6582a2e8298dcabfe7103daeedb37eec3fd2ee
3
+ metadata.gz: 22f6b0505160ceb7fe7c019d4c101aacbd35039c
4
+ data.tar.gz: 76a7f282ebfd76d98e430708d0a78ada36b4ad59
5
5
  SHA512:
6
- metadata.gz: 79d5dbdade0dd0c12f9213a34f6f4f36dbe84252874d04e9189da4bb6c9e74bfe25e6ccf7e95b3b13304426518e3da815b9c683afc3c45e904a4e4b1329bb2f3
7
- data.tar.gz: e285a9dcc3389ff35de9891cd4dbef0af18d72a05f1ebe5a6f6ae179547f741007be9518a46c74fc05760bba0fe91af5298c5a96cd41f915d30e26ec51dc7212
6
+ metadata.gz: cadb0aea96d5b5614455f618ca3759f6446e0dae53ece7259d851a2fbe7aa0bbef94675d2eb7ffaea53413f3468b2388aef59acae307c87c3beb72e3831dc9f0
7
+ data.tar.gz: d77c9c1418a81bf0415a33b9cc0d664c8cfa32137065ee2446f3d2cccbb28f105a24d1b3647f4c4502ed4a15b3fe0182eadae22dadef8575b7fc87060b5be3d6
data/.gitignore CHANGED
@@ -0,0 +1 @@
1
+ *.gem
data/lib/ts.rb CHANGED
@@ -6,7 +6,7 @@
6
6
  #
7
7
  class TS
8
8
 
9
- Version = "1.0.0"
9
+ Version = "1.0.1"
10
10
 
11
11
  include Enumerable
12
12
 
@@ -36,6 +36,33 @@ class TS
36
36
  TS.new(@data.map { |v| yield *v })
37
37
  end
38
38
 
39
+ # run a simple moving average, and return a new TS instance
40
+ # +size+ the size of the window
41
+ def sma size
42
+ buf = []
43
+ sum = 0
44
+
45
+ map { |t, v|
46
+ buf << v
47
+ sum += v
48
+
49
+ if buf.size > size
50
+ sum -= buf.shift
51
+ end
52
+
53
+ [t, sum / buf.size]
54
+ }
55
+ end
56
+
57
+ # generate some statistics from the values of the series
58
+ # returns {
59
+ # :num => ...,
60
+ # :min => ...,
61
+ # :max => ...,
62
+ # :sum => ...,
63
+ # :mean => ...,
64
+ # :stddev => ...,
65
+ # }
39
66
  def stats
40
67
  return @stats if @stats
41
68
 
@@ -47,8 +74,8 @@ class TS
47
74
  each { |time, val|
48
75
  min = val if val < min
49
76
  max = val if val > max
50
- sum = sum + val
51
- sum2 = sum2 + val ** 2
77
+ sum += val
78
+ sum2 += val ** 2
52
79
  }
53
80
 
54
81
  @stats = {
@@ -104,10 +131,14 @@ class TS
104
131
  TS.new(@data[0..idx-1])
105
132
  end
106
133
 
134
+ # fetch the value at a given index
135
+ # +idx+ the array index of the data
107
136
  def value_at idx
108
137
  @data[idx].last
109
138
  end
110
139
 
140
+ # fetch the time at a given index
141
+ # +idx+ the array index of the data
111
142
  def time_at idx
112
143
  @data[idx].first
113
144
  end
@@ -118,15 +149,24 @@ class TS
118
149
  bsearch time, 0, size - 1
119
150
  end
120
151
 
152
+ # get the timestamp series
121
153
  def timestamps
122
154
  @data.transpose.first
123
155
  end
124
156
 
157
+ # get the value series
125
158
  def values
126
159
  @data.transpose.last
127
160
  end
128
161
 
129
- # Run a regression and calculate r, r2, the slope, and intercept
162
+ # Run a regression on the series. Useful for weak projections
163
+ # and testing if your project is accurate (r2 =~ 1)
164
+ #
165
+ # returns {
166
+ # :r2 => ...,
167
+ # :slope => ...,
168
+ # :y_intercept => ...
169
+ # }
130
170
  def regression
131
171
  return @regression if @regression
132
172
 
@@ -135,22 +175,40 @@ class TS
135
175
  t_mean = times.reduce(:+) / size
136
176
  v_mean = values.reduce(:+) / size
137
177
 
138
- slope = (0..size - 1).inject(0) { |sum, n|
178
+ slope = (0..size - 1).inject(0.0) { |sum, n|
139
179
  sum + (times[n] - t_mean) * (values[n] - v_mean)
140
- } / times.inject { |sum, n|
180
+ } / times.inject(0.0) { |sum, n|
141
181
  sum + (n - t_mean) ** 2
142
182
  }
143
183
 
144
- # now r2
145
184
  r = slope * (stddev(times) / stddev(values))
146
185
 
147
186
  @regression = {
148
- :r2 => r ** 2,
187
+ :r2 => r * r,
149
188
  :slope => slope,
150
189
  :y_intercept => v_mean - (slope * t_mean)
151
190
  }
152
191
  end
153
192
 
193
+ # Project the value at a given time using the regresion
194
+ #
195
+ # y = mx + b
196
+ #
197
+ # +time+ the timestamp of the value you wish to predict
198
+ def projected_value time
199
+ regression[:slope] * time + regression[:y_intercept]
200
+ end
201
+
202
+ # Estimate the time for a given value. Assumes a fairly linear
203
+ # model.
204
+ #
205
+ # x = (y - b) / m
206
+ #
207
+ # +value+ the timestamp of the value you wish to predict
208
+ def projected_time value
209
+ (value - regression[:y_intercept]) / regression[:slope]
210
+ end
211
+
154
212
  private
155
213
 
156
214
  # Find the nearest index for a given time (fuzzy search)
@@ -169,6 +227,7 @@ class TS
169
227
  end
170
228
  end
171
229
 
230
+ # calculate the std deviation of the 1d data set
172
231
  def stddev data
173
232
  sum = 0.0
174
233
  sum2 = 0.0
@@ -176,7 +235,7 @@ class TS
176
235
  sum += v
177
236
  sum2 += v ** 2
178
237
  }
179
- Math.sqrt(sum2 / data.size - (sum / data.size) ** 2)
238
+ Math.sqrt((sum2 / data.size) - ((sum / data.size) ** 2))
180
239
  end
181
240
 
182
241
  end
@@ -50,11 +50,25 @@ class TSTest < Test::Unit::TestCase
50
50
  def test_regression
51
51
  assert_in_delta 0.001, @ts.regression[:slope], 0.001
52
52
  assert_in_delta 1.0, @ts.regression[:r2], 0.01
53
- assert_in_delta -1.5, @ts.regression[:y_intercept], 0.1
53
+ assert_in_delta 0.0, @ts.regression[:y_intercept], 0.1
54
54
  end
55
55
 
56
56
  def test_collect
57
57
  assert @ts.map { |t, v| [t, v * 2] }.stats[:min] == 2
58
58
  end
59
59
 
60
+ def test_sma
61
+ assert_equal [2000, 2], @ts.data[1]
62
+ assert_equal [2000, 1.5], @ts.sma(7).data[1]
63
+ end
64
+
65
+ def test_projection
66
+ assert_equal 5000, @ts.projected_value(5000000)
67
+ end
68
+
69
+ def test_projection_time
70
+ assert_equal 5000000, @ts.projected_time(5000)
71
+ assert_equal -1000, @ts.projected_time(-1)
72
+ end
73
+
60
74
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ts
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Simpson