Class: TS
Overview
TS
Utility class for [timestamp, number] tuples, where periodicity is not guaranteed.
Constant Summary collapse
- Version =
"1.0.2"
Instance Attribute Summary collapse
-
#data ⇒ Object
readonly
Returns the value of attribute data.
Instance Method Summary collapse
-
#after(time) ⇒ Object
give the timeseries with values after time
time
the time boundary. -
#before(time) ⇒ Object
give the timeseries with values before time
time
the time boundary. -
#each ⇒ Object
see Enumerable.
-
#initialize(data) ⇒ TS
constructor
data
an array of [timestamp/time, number] tuples. -
#map ⇒ Object
map the [time,value] tuples into other [time,value] tuples.
-
#mean ⇒ Object
get the mean value.
-
#nearest(time) ⇒ Object
find the nearest idx for a given time using a fuzzy binary search.
-
#projected_time(value) ⇒ Object
Estimate the time for a given value.
-
#projected_value(time) ⇒ Object
Project the value at a given time using the regresion.
-
#regression ⇒ Object
Run a regression on the series.
-
#size ⇒ Object
The number of elements in the set.
-
#slice(t1, t2) ⇒ Object
slice a timeseries by timestamps
t1
start timet2
end time. -
#sma(size) ⇒ Object
run a simple moving average, and return a new TS instance
size
the size of the window. -
#stats ⇒ Object
generate some statistics from the values of the series returns { :num => …, :min => …, :max => …, :sum => …, :mean => …, :stddev => …, }.
-
#stddev ⇒ Object
get the standard deviation of the values.
-
#time_at(idx) ⇒ Object
fetch the time at a given index
idx
the array index of the data. -
#timestamps ⇒ Object
get the timestamp series.
-
#value_at(idx) ⇒ Object
fetch the value at a given index
idx
the array index of the data. -
#values ⇒ Object
get the value series.
Constructor Details
#initialize(data) ⇒ TS
data
an array of [timestamp/time, number] tuples
16 17 18 19 20 21 22 |
# File 'lib/ts.rb', line 16 def initialize data if data.nil? raise "Cannot instantiate timeseries without data" end @data = data end |
Instance Attribute Details
#data ⇒ Object (readonly)
Returns the value of attribute data.
13 14 15 |
# File 'lib/ts.rb', line 13 def data @data end |
Instance Method Details
#after(time) ⇒ Object
give the timeseries with values after time time
the time boundary
124 125 126 127 128 129 130 131 |
# File 'lib/ts.rb', line 124 def after time idx = nearest(time) if time_at(idx) <= time idx += 1 end TS.new(@data[idx..-1]) end |
#before(time) ⇒ Object
give the timeseries with values before time time
the time boundary
135 136 137 138 139 140 141 142 |
# File 'lib/ts.rb', line 135 def before time idx = nearest(time) if time_at(idx) < time idx += 1 end TS.new(@data[0..idx-1]) end |
#each ⇒ Object
see Enumerable
30 31 32 |
# File 'lib/ts.rb', line 30 def each @data.each { |v| yield *v } end |
#map ⇒ Object
map the [time,value] tuples into other [time,value] tuples
35 36 37 |
# File 'lib/ts.rb', line 35 def map TS.new(@data.map { |v| yield *v }) end |
#mean ⇒ Object
get the mean value
92 93 94 |
# File 'lib/ts.rb', line 92 def mean stats[:mean] end |
#nearest(time) ⇒ Object
find the nearest idx for a given time using a fuzzy binary search
158 159 160 |
# File 'lib/ts.rb', line 158 def nearest time bsearch time, 0, size - 1 end |
#projected_time(value) ⇒ Object
Estimate the time for a given value. Assumes a fairly linear model.
x = (y - b) / m
value
the timestamp of the value you wish to predict
218 219 220 |
# File 'lib/ts.rb', line 218 def projected_time value (value - regression[:y_intercept]) / regression[:slope] end |
#projected_value(time) ⇒ Object
Project the value at a given time using the regresion
y = mx + b
time
the timestamp of the value you wish to predict
208 209 210 |
# File 'lib/ts.rb', line 208 def projected_value time regression[:slope] * time + regression[:y_intercept] end |
#regression ⇒ Object
Run a regression on the series. Useful for weak projections and testing if your project is accurate (r2 =~ 1)
returns
:r2 => ...,
:slope => ...,
:y_intercept => ...
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/ts.rb', line 180 def regression return @regression if @regression times, values = @data.transpose t_mean = times.reduce(:+) / size v_mean = values.reduce(:+) / size slope = (0..size - 1).inject(0.0) { |sum, n| sum + (times[n] - t_mean) * (values[n] - v_mean) } / times.inject(0.0) { |sum, n| sum + (n - t_mean) ** 2 } r = slope * (_stddev(times) / _stddev(values)) @regression = { :r2 => r * r, :slope => slope, :y_intercept => v_mean - (slope * t_mean) } end |
#size ⇒ Object
The number of elements in the set
25 26 27 |
# File 'lib/ts.rb', line 25 def size @data.size end |
#slice(t1, t2) ⇒ Object
slice a timeseries by timestamps t1
start time t2
end time
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/ts.rb', line 104 def slice t1, t2 idx1 = nearest(t1) idx2 = nearest(t2) # don't include a value not in range if time_at(idx1) < t1 idx1 += 1 end # slice goes up to, but doesn't include, so only # add if the nearest is less than if time_at(idx2) < t2 idx2 += 1 end TS.new(@data[idx1..idx2]) end |
#sma(size) ⇒ Object
run a simple moving average, and return a new TS instance size
the size of the window
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/ts.rb', line 41 def sma size buf = [] sum = 0 map { |t, v| buf << v sum += v if buf.size > size sum -= buf.shift end [t, sum / buf.size] } end |
#stats ⇒ Object
generate some statistics from the values of the series returns
:num => ...,
:min => ...,
:max => ...,
:sum => ...,
:mean => ...,
:stddev => ...,
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/ts.rb', line 66 def stats return @stats if @stats min = Float::MAX max = Float::MIN sum = 0.0 sum2 = 0.0 each { |time, val| min = val if val < min max = val if val > max sum += val sum2 += val ** 2 } @stats = { :num => size, :min => min, :max => max, :sum => sum, :mean => sum / size, :stddev => Math.sqrt((sum2 / size) - ((sum / size) ** 2)) } end |
#stddev ⇒ Object
get the standard deviation of the values
97 98 99 |
# File 'lib/ts.rb', line 97 def stddev stats[:stddev] end |
#time_at(idx) ⇒ Object
fetch the time at a given index idx
the array index of the data
152 153 154 |
# File 'lib/ts.rb', line 152 def time_at idx @data[idx].first end |
#timestamps ⇒ Object
get the timestamp series
163 164 165 |
# File 'lib/ts.rb', line 163 def @data.transpose.first end |
#value_at(idx) ⇒ Object
fetch the value at a given index idx
the array index of the data
146 147 148 |
# File 'lib/ts.rb', line 146 def value_at idx @data[idx].last end |
#values ⇒ Object
get the value series
168 169 170 |
# File 'lib/ts.rb', line 168 def values @data.transpose.last end |