ts 1.0.0 → 1.0.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.
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