stl-rb 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +15 -1
  4. data/lib/stl/version.rb +1 -1
  5. data/lib/stl.rb +95 -31
  6. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 27deddcf999b886ec030e044a3875bf175918d6ca417cc3eca23490402526d98
4
- data.tar.gz: 9876b7bfde1681a95c1b80b2c9072545d75d967cef1b48dccbff3111f77eb848
3
+ metadata.gz: 8c050d95d79bc0c5d644257c5cb5130d595dd7fe18c691b0e71eed7ecfef7a0d
4
+ data.tar.gz: 7c644155be7b848965299b62423e03ffa05bf17143fd76ca804bc5e4b36c03b2
5
5
  SHA512:
6
- metadata.gz: 4675511aa5679abe804a1c53d7914cf236a4e2045dd2cc52211a81a810ec657ce98a520fc89c87b121d0439e1c2e49a0f15233ad6f9c6f3c4143cb3f9db668ab
7
- data.tar.gz: 95bdd4d19dd9ebf24acbc0980af10a9438fafbfdf2037140b3a19d3da6bd0fffa55c11356c1d8a0983e06ab08985af9ba79a3a2dfc5c5dd167a53ceb86e8499f
6
+ metadata.gz: 47a0248efdeb721218a9b5e1642e3e0b28735cb2692085c9ebc8f879d1cbc26bf2eb615611627d4a3873d9efda63da81fe214853eaae9901f74bddfc4bfac3e1
7
+ data.tar.gz: ef7bbb4ba3039a1f2703875165047dc87e4ad3bdfad5f3050f7faa3478560ca022735f226f171355394ef7e87edfd545dfa79f437026b4db336286e0592e6d47
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.1.1 (2021-10-20)
2
+
3
+ - Added `plot` method
4
+
1
5
  ## 0.1.0 (2021-10-16)
2
6
 
3
7
  - First release
data/README.md CHANGED
@@ -34,7 +34,7 @@ series = User.group_by_day(:created_at).count
34
34
  Stl.decompose(series, period: 7)
35
35
  ```
36
36
 
37
- Series can also be an array without times (the index is returned)
37
+ Series can also be an array without times
38
38
 
39
39
  ```ruby
40
40
  series = [100, 150, 136, ...]
@@ -70,6 +70,20 @@ Stl.decompose(
70
70
  )
71
71
  ```
72
72
 
73
+ ## Plotting
74
+
75
+ Add [Vega](https://github.com/ankane/vega) to your application’s Gemfile:
76
+
77
+ ```ruby
78
+ gem 'vega'
79
+ ```
80
+
81
+ And use:
82
+
83
+ ```ruby
84
+ Stl.plot(series, decompose_result)
85
+ ```
86
+
73
87
  ## Credits
74
88
 
75
89
  This library was ported from the [Fortran implementation](https://www.netlib.org/a/stl).
data/lib/stl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Stl
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/lib/stl.rb CHANGED
@@ -5,38 +5,102 @@ require "stl/ext"
5
5
  require "stl/version"
6
6
 
7
7
  module Stl
8
- def self.decompose(
9
- series, period:,
10
- seasonal_length: nil, trend_length: nil, low_pass_length: nil,
11
- seasonal_degree: nil, trend_degree: nil, low_pass_degree: nil,
12
- seasonal_jump: nil, trend_jump: nil, low_pass_jump: nil,
13
- inner_loops: nil, outer_loops: nil, robust: false
14
- )
15
- params = StlParams.new
16
-
17
- params.seasonal_length(seasonal_length) unless seasonal_length.nil?
18
- params.trend_length(trend_length) unless trend_length.nil?
19
- params.low_pass_length(low_pass_length) unless low_pass_length.nil?
20
-
21
- params.seasonal_degree(seasonal_degree) unless seasonal_degree.nil?
22
- params.trend_degree(trend_degree) unless trend_degree.nil?
23
- params.low_pass_degree(low_pass_degree) unless low_pass_degree.nil?
24
-
25
- params.seasonal_jump(seasonal_jump) unless seasonal_jump.nil?
26
- params.trend_jump(trend_jump) unless trend_jump.nil?
27
- params.low_pass_jump(low_pass_jump) unless low_pass_jump.nil?
28
-
29
- params.inner_loops(inner_loops) unless inner_loops.nil?
30
- params.outer_loops(outer_loops) unless outer_loops.nil?
31
- params.robust(robust) unless robust.nil?
32
-
33
- if series.is_a?(Hash)
34
- sorted = series.sort_by { |k, _| k }
35
- y = sorted.map(&:last)
36
- else
37
- y = series
8
+ class << self
9
+ def decompose(
10
+ series, period:,
11
+ seasonal_length: nil, trend_length: nil, low_pass_length: nil,
12
+ seasonal_degree: nil, trend_degree: nil, low_pass_degree: nil,
13
+ seasonal_jump: nil, trend_jump: nil, low_pass_jump: nil,
14
+ inner_loops: nil, outer_loops: nil, robust: false
15
+ )
16
+ params = StlParams.new
17
+
18
+ params.seasonal_length(seasonal_length) unless seasonal_length.nil?
19
+ params.trend_length(trend_length) unless trend_length.nil?
20
+ params.low_pass_length(low_pass_length) unless low_pass_length.nil?
21
+
22
+ params.seasonal_degree(seasonal_degree) unless seasonal_degree.nil?
23
+ params.trend_degree(trend_degree) unless trend_degree.nil?
24
+ params.low_pass_degree(low_pass_degree) unless low_pass_degree.nil?
25
+
26
+ params.seasonal_jump(seasonal_jump) unless seasonal_jump.nil?
27
+ params.trend_jump(trend_jump) unless trend_jump.nil?
28
+ params.low_pass_jump(low_pass_jump) unless low_pass_jump.nil?
29
+
30
+ params.inner_loops(inner_loops) unless inner_loops.nil?
31
+ params.outer_loops(outer_loops) unless outer_loops.nil?
32
+ params.robust(robust) unless robust.nil?
33
+
34
+ if series.is_a?(Hash)
35
+ sorted = series.sort_by { |k, _| k }
36
+ y = sorted.map(&:last)
37
+ else
38
+ y = series
39
+ end
40
+
41
+ params.fit(y, period, outer_loops.nil? ? robust : outer_loops > 0)
42
+ end
43
+
44
+ def plot(series, result)
45
+ require "vega"
46
+
47
+ data =
48
+ if series.is_a?(Hash)
49
+ series.sort_by { |k, _| k }.map.with_index do |s, i|
50
+ {
51
+ x: iso8601(s[0]),
52
+ series: s[1],
53
+ seasonal: result[:seasonal][i],
54
+ trend: result[:trend][i],
55
+ remainder: result[:remainder][i]
56
+ }
57
+ end
58
+ else
59
+ series.map.with_index do |v, i|
60
+ {
61
+ x: i,
62
+ series: v,
63
+ seasonal: result[:seasonal][i],
64
+ trend: result[:trend][i],
65
+ remainder: result[:remainder][i]
66
+ }
67
+ end
68
+ end
69
+
70
+ if series.is_a?(Hash)
71
+ x = {field: "x", type: "temporal"}
72
+ x["scale"] = {type: "utc"} if series.keys.first.is_a?(Date)
73
+ else
74
+ x = {field: "x", type: "quantitative"}
75
+ end
76
+ x[:axis] = {title: nil, labelFontSize: 12}
77
+
78
+ charts =
79
+ ["series", "seasonal", "trend", "remainder"].map do |field|
80
+ {
81
+ mark: {type: "line"},
82
+ encoding: {
83
+ x: x,
84
+ y: {field: field, type: "quantitative", scale: {zero: false}, axis: {labelFontSize: 12}}
85
+ },
86
+ width: "container",
87
+ height: 100
88
+ }
89
+ end
90
+
91
+ Vega.lite
92
+ .data(data)
93
+ .vconcat(charts)
38
94
  end
39
95
 
40
- params.fit(y, period, outer_loops.nil? ? robust : outer_loops > 0)
96
+ private
97
+
98
+ def iso8601(v)
99
+ if v.is_a?(Date)
100
+ v.strftime("%Y-%m-%d")
101
+ else
102
+ v.strftime("%Y-%m-%dT%H:%M:%S.%L%z")
103
+ end
104
+ end
41
105
  end
42
106
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stl-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-16 00:00:00.000000000 Z
11
+ date: 2021-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rice