prophet-rb 0.1.1 → 0.2.4

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.
@@ -6,7 +6,7 @@ module Prophet
6
6
  end
7
7
 
8
8
  def make_holidays_df(year_list, country)
9
- holidays_df.where(holidays_df["country"].eq(country) & holidays_df["year"].in(year_list))["ds", "holiday"]
9
+ holidays_df[(holidays_df["country"] == country) & (holidays_df["year"].in?(year_list))][["ds", "holiday"]]
10
10
  end
11
11
 
12
12
  # TODO marshal on installation
@@ -20,7 +20,7 @@ module Prophet
20
20
  holidays["country"] << row["country"]
21
21
  holidays["year"] << row["year"]
22
22
  end
23
- Daru::DataFrame.new(holidays)
23
+ Rover::DataFrame.new(holidays)
24
24
  end
25
25
  end
26
26
  end
data/lib/prophet/plot.rb CHANGED
@@ -8,16 +8,16 @@ module Prophet
8
8
  fig = ax.get_figure
9
9
  end
10
10
  fcst_t = to_pydatetime(fcst["ds"])
11
- ax.plot(to_pydatetime(@history["ds"]), @history["y"].map(&:to_f), "k.")
12
- ax.plot(fcst_t, fcst["yhat"].map(&:to_f), ls: "-", c: "#0072B2")
13
- if fcst.vectors.include?("cap") && plot_cap
14
- ax.plot(fcst_t, fcst["cap"].map(&:to_f), ls: "--", c: "k")
11
+ ax.plot(to_pydatetime(@history["ds"]), @history["y"].to_a, "k.")
12
+ ax.plot(fcst_t, fcst["yhat"].to_a, ls: "-", c: "#0072B2")
13
+ if fcst.include?("cap") && plot_cap
14
+ ax.plot(fcst_t, fcst["cap"].to_a, ls: "--", c: "k")
15
15
  end
16
- if @logistic_floor && fcst.vectors.include?("floor") && plot_cap
17
- ax.plot(fcst_t, fcst["floor"].map(&:to_f), ls: "--", c: "k")
16
+ if @logistic_floor && fcst.include?("floor") && plot_cap
17
+ ax.plot(fcst_t, fcst["floor"].to_a, ls: "--", c: "k")
18
18
  end
19
19
  if uncertainty && @uncertainty_samples
20
- ax.fill_between(fcst_t, fcst["yhat_lower"].map(&:to_f), fcst["yhat_upper"].map(&:to_f), color: "#0072B2", alpha: 0.2)
20
+ ax.fill_between(fcst_t, fcst["yhat_lower"].to_a, fcst["yhat_upper"].to_a, color: "#0072B2", alpha: 0.2)
21
21
  end
22
22
  # Specify formatting to workaround matplotlib issue #12925
23
23
  locator = dates.AutoDateLocator.new(interval_multiples: false)
@@ -33,25 +33,25 @@ module Prophet
33
33
 
34
34
  def plot_components(fcst, uncertainty: true, plot_cap: true, weekly_start: 0, yearly_start: 0, figsize: nil)
35
35
  components = ["trend"]
36
- if @train_holiday_names && fcst.vectors.include?("holidays")
36
+ if @train_holiday_names && fcst.include?("holidays")
37
37
  components << "holidays"
38
38
  end
39
39
  # Plot weekly seasonality, if present
40
- if @seasonalities["weekly"] && fcst.vectors.include?("weekly")
40
+ if @seasonalities["weekly"] && fcst.include?("weekly")
41
41
  components << "weekly"
42
42
  end
43
43
  # Yearly if present
44
- if @seasonalities["yearly"] && fcst.vectors.include?("yearly")
44
+ if @seasonalities["yearly"] && fcst.include?("yearly")
45
45
  components << "yearly"
46
46
  end
47
47
  # Other seasonalities
48
- components.concat(@seasonalities.keys.select { |name| fcst.vectors.include?(name) && !["weekly", "yearly"].include?(name) }.sort)
48
+ components.concat(@seasonalities.keys.select { |name| fcst.include?(name) && !["weekly", "yearly"].include?(name) }.sort)
49
49
  regressors = {"additive" => false, "multiplicative" => false}
50
50
  @extra_regressors.each do |name, props|
51
51
  regressors[props[:mode]] = true
52
52
  end
53
53
  ["additive", "multiplicative"].each do |mode|
54
- if regressors[mode] && fcst.vectors.include?("extra_regressors_#{mode}")
54
+ if regressors[mode] && fcst.include?("extra_regressors_#{mode}")
55
55
  components << "extra_regressors_#{mode}"
56
56
  end
57
57
  end
@@ -97,11 +97,11 @@ module Prophet
97
97
  def add_changepoints_to_plot(ax, fcst, threshold: 0.01, cp_color: "r", cp_linestyle: "--", trend: true)
98
98
  artists = []
99
99
  if trend
100
- artists << ax.plot(to_pydatetime(fcst["ds"]), fcst["trend"].map(&:to_f), c: cp_color)
100
+ artists << ax.plot(to_pydatetime(fcst["ds"]), fcst["trend"].to_a, c: cp_color)
101
101
  end
102
102
  signif_changepoints =
103
103
  if @changepoints.size > 0
104
- (@params["delta"].mean(axis: 0, nan: true).abs >= threshold).mask(@changepoints)
104
+ (@params["delta"].mean(axis: 0, nan: true).abs >= threshold).mask(@changepoints.to_numo)
105
105
  else
106
106
  []
107
107
  end
@@ -120,15 +120,15 @@ module Prophet
120
120
  ax = fig.add_subplot(111)
121
121
  end
122
122
  fcst_t = to_pydatetime(fcst["ds"])
123
- artists += ax.plot(fcst_t, fcst[name].map(&:to_f), ls: "-", c: "#0072B2")
124
- if fcst.vectors.include?("cap") && plot_cap
125
- artists += ax.plot(fcst_t, fcst["cap"].map(&:to_f), ls: "--", c: "k")
123
+ artists += ax.plot(fcst_t, fcst[name].to_a, ls: "-", c: "#0072B2")
124
+ if fcst.include?("cap") && plot_cap
125
+ artists += ax.plot(fcst_t, fcst["cap"].to_a, ls: "--", c: "k")
126
126
  end
127
- if @logistic_floor && fcst.vectors.include?("floor") && plot_cap
128
- ax.plot(fcst_t, fcst["floor"].map(&:to_f), ls: "--", c: "k")
127
+ if @logistic_floor && fcst.include?("floor") && plot_cap
128
+ ax.plot(fcst_t, fcst["floor"].to_a, ls: "--", c: "k")
129
129
  end
130
130
  if uncertainty && @uncertainty_samples
131
- artists += [ax.fill_between(fcst_t, fcst[name + "_lower"].map(&:to_f), fcst[name + "_upper"].map(&:to_f), color: "#0072B2", alpha: 0.2)]
131
+ artists += [ax.fill_between(fcst_t, fcst[name + "_lower"].to_a, fcst[name + "_upper"].to_a, color: "#0072B2", alpha: 0.2)]
132
132
  end
133
133
  # Specify formatting to workaround matplotlib issue #12925
134
134
  locator = dates.AutoDateLocator.new(interval_multiples: false)
@@ -145,17 +145,17 @@ module Prophet
145
145
  end
146
146
 
147
147
  def seasonality_plot_df(ds)
148
- df_dict = {"ds" => ds, "cap" => [1.0] * ds.size, "floor" => [0.0] * ds.size}
148
+ df_dict = {"ds" => ds, "cap" => 1.0, "floor" => 0.0}
149
149
  @extra_regressors.each_key do |name|
150
- df_dict[name] = [0.0] * ds.size
150
+ df_dict[name] = 0.0
151
151
  end
152
152
  # Activate all conditional seasonality columns
153
153
  @seasonalities.values.each do |props|
154
154
  if props[:condition_name]
155
- df_dict[props[:condition_name]] = [true] * ds.size
155
+ df_dict[props[:condition_name]] = true
156
156
  end
157
157
  end
158
- df = Daru::DataFrame.new(df_dict)
158
+ df = Rover::DataFrame.new(df_dict)
159
159
  df = setup_dataframe(df)
160
160
  df
161
161
  end
@@ -172,9 +172,9 @@ module Prophet
172
172
  df_w = seasonality_plot_df(days)
173
173
  seas = predict_seasonal_components(df_w)
174
174
  days = days.map { |v| v.strftime("%A") }
175
- artists += ax.plot(days.size.times.to_a, seas[name].map(&:to_f), ls: "-", c: "#0072B2")
175
+ artists += ax.plot(days.size.times.to_a, seas[name].to_a, ls: "-", c: "#0072B2")
176
176
  if uncertainty && @uncertainty_samples
177
- artists += [ax.fill_between(days.size.times.to_a, seas[name + "_lower"].map(&:to_f), seas[name + "_upper"].map(&:to_f), color: "#0072B2", alpha: 0.2)]
177
+ artists += [ax.fill_between(days.size.times.to_a, seas[name + "_lower"].to_a, seas[name + "_upper"].to_a, color: "#0072B2", alpha: 0.2)]
178
178
  end
179
179
  ax.grid(true, which: "major", c: "gray", ls: "-", lw: 1, alpha: 0.2)
180
180
  ax.set_xticks(days.size.times.to_a)
@@ -198,9 +198,9 @@ module Prophet
198
198
  days = 365.times.map { |i| start + i + yearly_start }
199
199
  df_y = seasonality_plot_df(days)
200
200
  seas = predict_seasonal_components(df_y)
201
- artists += ax.plot(to_pydatetime(df_y["ds"]), seas[name].map(&:to_f), ls: "-", c: "#0072B2")
201
+ artists += ax.plot(to_pydatetime(df_y["ds"]), seas[name].to_a, ls: "-", c: "#0072B2")
202
202
  if uncertainty && @uncertainty_samples
203
- artists += [ax.fill_between(to_pydatetime(df_y["ds"]), seas[name + "_lower"].map(&:to_f), seas[name + "_upper"].map(&:to_f), color: "#0072B2", alpha: 0.2)]
203
+ artists += [ax.fill_between(to_pydatetime(df_y["ds"]), seas[name + "_lower"].to_a, seas[name + "_upper"].to_a, color: "#0072B2", alpha: 0.2)]
204
204
  end
205
205
  ax.grid(true, which: "major", c: "gray", ls: "-", lw: 1, alpha: 0.2)
206
206
  months = dates.MonthLocator.new((1..12).to_a, bymonthday: 1, interval: 2)
@@ -231,9 +231,9 @@ module Prophet
231
231
  days = plot_points.times.map { |i| Time.at(start + i * step).utc }
232
232
  df_y = seasonality_plot_df(days)
233
233
  seas = predict_seasonal_components(df_y)
234
- artists += ax.plot(to_pydatetime(df_y["ds"]), seas[name].map(&:to_f), ls: "-", c: "#0072B2")
234
+ artists += ax.plot(to_pydatetime(df_y["ds"]), seas[name].to_a, ls: "-", c: "#0072B2")
235
235
  if uncertainty && @uncertainty_samples
236
- artists += [ax.fill_between(to_pydatetime(df_y["ds"]), seas[name + "_lower"].map(&:to_f), seas[name + "_upper"].map(&:to_f), color: "#0072B2", alpha: 0.2)]
236
+ artists += [ax.fill_between(to_pydatetime(df_y["ds"]), seas[name + "_lower"].to_a, seas[name + "_upper"].to_a, color: "#0072B2", alpha: 0.2)]
237
237
  end
238
238
  ax.grid(true, which: "major", c: "gray", ls: "-", lw: 1, alpha: 0.2)
239
239
  step = (finish - start) / (7 - 1).to_f
@@ -281,7 +281,7 @@ module Prophet
281
281
 
282
282
  def to_pydatetime(v)
283
283
  datetime = PyCall.import_module("datetime")
284
- v.map { |v| datetime.datetime.utcfromtimestamp(v.to_i) }
284
+ v.map { |v| datetime.datetime.utcfromtimestamp(v.to_i) }.to_a
285
285
  end
286
286
  end
287
287
  end
@@ -127,7 +127,7 @@ module Prophet
127
127
  stan_data["t_change"] = stan_data["t_change"].to_a
128
128
  stan_data["s_a"] = stan_data["s_a"].to_a
129
129
  stan_data["s_m"] = stan_data["s_m"].to_a
130
- stan_data["X"] = stan_data["X"].to_matrix.to_a
130
+ stan_data["X"] = stan_data["X"].to_numo.to_a
131
131
  stan_init["delta"] = stan_init["delta"].to_a
132
132
  stan_init["beta"] = stan_init["beta"].to_a
133
133
  [stan_init, stan_data]
@@ -1,3 +1,3 @@
1
1
  module Prophet
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.4"
3
3
  end
@@ -73,6 +73,15 @@ functions {
73
73
  ) {
74
74
  return (k + A * delta) .* t + (m + A * (-t_change .* delta));
75
75
  }
76
+
77
+ // Flat trend function
78
+
79
+ vector flat_trend(
80
+ real m,
81
+ int T
82
+ ) {
83
+ return rep_vector(m, T);
84
+ }
76
85
  }
77
86
 
78
87
  data {
@@ -86,7 +95,7 @@ data {
86
95
  matrix[T,K] X; // Regressors
87
96
  vector[K] sigmas; // Scale on seasonality prior
88
97
  real<lower=0> tau; // Scale on changepoints prior
89
- int trend_indicator; // 0 for linear, 1 for logistic
98
+ int trend_indicator; // 0 for linear, 1 for logistic, 2 for flat
90
99
  vector[K] s_a; // Indicator of additive features
91
100
  vector[K] s_m; // Indicator of multiplicative features
92
101
  }
@@ -104,6 +113,17 @@ parameters {
104
113
  vector[K] beta; // Regressor coefficients
105
114
  }
106
115
 
116
+ transformed parameters {
117
+ vector[T] trend;
118
+ if (trend_indicator == 0) {
119
+ trend = linear_trend(k, m, delta, t, A, t_change);
120
+ } else if (trend_indicator == 1) {
121
+ trend = logistic_trend(k, m, delta, t, cap, A, t_change, S);
122
+ } else if (trend_indicator == 2) {
123
+ trend = flat_trend(m, T);
124
+ }
125
+ }
126
+
107
127
  model {
108
128
  //priors
109
129
  k ~ normal(0, 5);
@@ -113,19 +133,10 @@ model {
113
133
  beta ~ normal(0, sigmas);
114
134
 
115
135
  // Likelihood
116
- if (trend_indicator == 0) {
117
- y ~ normal(
118
- linear_trend(k, m, delta, t, A, t_change)
119
- .* (1 + X * (beta .* s_m))
120
- + X * (beta .* s_a),
121
- sigma_obs
122
- );
123
- } else if (trend_indicator == 1) {
124
- y ~ normal(
125
- logistic_trend(k, m, delta, t, cap, A, t_change, S)
126
- .* (1 + X * (beta .* s_m))
127
- + X * (beta .* s_a),
128
- sigma_obs
129
- );
130
- }
136
+ y ~ normal(
137
+ trend
138
+ .* (1 + X * (beta .* s_m))
139
+ + X * (beta .* s_a),
140
+ sigma_obs
141
+ );
131
142
  }
@@ -47,7 +47,7 @@ functions {
47
47
  }
48
48
  return gamma;
49
49
  }
50
-
50
+
51
51
  real[] logistic_trend(
52
52
  real k,
53
53
  real m,
@@ -94,6 +94,17 @@ functions {
94
94
  }
95
95
  return Y;
96
96
  }
97
+
98
+ // Flat trend function
99
+
100
+ real[] flat_trend(
101
+ real m,
102
+ int T
103
+ ) {
104
+ return rep_array(m, T);
105
+ }
106
+
107
+
97
108
  }
98
109
 
99
110
  data {
@@ -107,7 +118,7 @@ data {
107
118
  real X[T,K]; // Regressors
108
119
  vector[K] sigmas; // Scale on seasonality prior
109
120
  real<lower=0> tau; // Scale on changepoints prior
110
- int trend_indicator; // 0 for linear, 1 for logistic
121
+ int trend_indicator; // 0 for linear, 1 for logistic, 2 for flat
111
122
  real s_a[K]; // Indicator of additive features
112
123
  real s_m[K]; // Indicator of multiplicative features
113
124
  }
@@ -135,6 +146,8 @@ transformed parameters {
135
146
  trend = linear_trend(k, m, delta, t, A, t_change, S, T);
136
147
  } else if (trend_indicator == 1) {
137
148
  trend = logistic_trend(k, m, delta, t, cap, A, t_change, S, T);
149
+ } else if (trend_indicator == 2){
150
+ trend = flat_trend(m, T);
138
151
  }
139
152
 
140
153
  for (i in 1:K) {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prophet-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-10 00:00:00.000000000 Z
11
+ date: 2021-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cmdstan
@@ -24,106 +24,36 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.1.2
27
- - !ruby/object:Gem::Dependency
28
- name: daru
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: numo-narray
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - ">="
46
32
  - !ruby/object:Gem::Version
47
- version: '0'
33
+ version: 0.9.1.7
48
34
  type: :runtime
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
38
  - - ">="
53
39
  - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rake
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
40
+ version: 0.9.1.7
83
41
  - !ruby/object:Gem::Dependency
84
- name: minitest
42
+ name: rover-df
85
43
  requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '5'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '5'
97
- - !ruby/object:Gem::Dependency
98
- name: matplotlib
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
44
  requirements:
108
45
  - - ">="
109
46
  - !ruby/object:Gem::Version
110
47
  version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: ruby-prof
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
48
+ type: :runtime
119
49
  prerelease: false
120
50
  version_requirements: !ruby/object:Gem::Requirement
121
51
  requirements:
122
52
  - - ">="
123
53
  - !ruby/object:Gem::Version
124
54
  version: '0'
125
- description:
126
- email: andrew@chartkick.com
55
+ description:
56
+ email: andrew@ankane.org
127
57
  executables: []
128
58
  extensions:
129
59
  - ext/prophet/extconf.rb
@@ -148,7 +78,7 @@ homepage: https://github.com/ankane/prophet
148
78
  licenses:
149
79
  - MIT
150
80
  metadata: {}
151
- post_install_message:
81
+ post_install_message:
152
82
  rdoc_options: []
153
83
  require_paths:
154
84
  - lib
@@ -163,8 +93,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
163
93
  - !ruby/object:Gem::Version
164
94
  version: '0'
165
95
  requirements: []
166
- rubygems_version: 3.1.2
167
- signing_key:
96
+ rubygems_version: 3.2.3
97
+ signing_key:
168
98
  specification_version: 4
169
99
  summary: Time series forecasting for Ruby
170
100
  test_files: []