stl-rb 0.1.0 → 0.1.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 (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