prophet-rb 0.3.1 → 0.3.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0656a4f1c6761438bfd9e6eeaed0bc30547cd10e794cdf2d12d208309fd57fd5
4
- data.tar.gz: 8e6e1304ae81f33ac648a93bb287f9f206be2d800a40cbc82fffe295a285546d
3
+ metadata.gz: 3e24dad0631694318db703e420f657e964911071b73e03cd73a6fc4c2d6e16fc
4
+ data.tar.gz: bcf2a53b3bcacf5461cd0b881bba0d026c7adee88200646f915074c9946711d3
5
5
  SHA512:
6
- metadata.gz: 9954683d0197627894eb1727690bf6007f05e94e896783f70ca66c4dff748a00829e68478ab155a30dcfbc971c4646032b046e58d7cc01bf0e38be98b851c504
7
- data.tar.gz: 145e6f2974f79ba8cfe0836d7d71f39924b7f4800f73a776d9c17e3f10b7aa3e889ef82a8b9c30795df51b5c13f0fd189ca83fe7d841215572d6cc857301ddc9
6
+ metadata.gz: bdad3069aeaadaa9ac8d339fb6e877942470fd5c8e11652bce50029b0a6de13d0fe383f6a97a343e29138396dec4b1c159e5ee87d229073d2f3eb5c084aa5af2
7
+ data.tar.gz: 1d54e502621ed4d34c818fe2e0e064578eae948957305300222892f4ee4750418e2471261596568d05795aea31bb4fe4639925da20a1f5db5bd20a0f0b35a66f
data/CHANGELOG.md CHANGED
@@ -1,8 +1,12 @@
1
- ## 0.3.1 (2021-04-28)
1
+ ## 0.3.2 (2022-05-15)
2
+
3
+ - Added advanced API options to `forecast` and `anomalies` methods
4
+
5
+ ## 0.3.1 (2022-04-28)
2
6
 
3
7
  - Improved error message for missing columns
4
8
 
5
- ## 0.3.0 (2021-04-24)
9
+ ## 0.3.0 (2022-04-24)
6
10
 
7
11
  - Switched to precompiled models
8
12
  - Dropped support for Ruby < 2.7
data/README.md CHANGED
@@ -22,6 +22,8 @@ gem "prophet-rb"
22
22
 
23
23
  ## Simple API
24
24
 
25
+ ### Forecasting
26
+
25
27
  Get future predictions for a time series
26
28
 
27
29
  ```ruby
@@ -48,12 +50,32 @@ series = User.group_by_day(:created_at).count
48
50
  Prophet.forecast(series)
49
51
  ```
50
52
 
53
+ And supports [advanced API](#advanced-api) options
54
+
55
+ ```ruby
56
+ Prophet.forecast(series, growth: "logistic", weekly_seasonality: false)
57
+ ```
58
+
59
+ ### Anomaly Detection
60
+
51
61
  Detect anomalies in a time series
52
62
 
53
63
  ```ruby
54
64
  Prophet.anomalies(series)
55
65
  ```
56
66
 
67
+ Specify the width of uncertainty intervals (decrease for more anomalies)
68
+
69
+ ```ruby
70
+ Prophet.anomalies(series, interval_width: 0.99)
71
+ ```
72
+
73
+ Also supports [advanced API](#advanced-api) options
74
+
75
+ ```ruby
76
+ Prophet.anomalies(series, growth: "logistic", weekly_seasonality: false)
77
+ ```
78
+
57
79
  ## Advanced API
58
80
 
59
81
  Check out the [Prophet documentation](https://facebook.github.io/prophet/docs/quick_start.html) for a great explanation of all of the features. The advanced API follows the Python API and supports the same features. It uses [Rover](https://github.com/ankane/rover) for data frames.
@@ -206,7 +228,7 @@ Add country-specific holidays
206
228
 
207
229
  ```ruby
208
230
  m = Prophet.new
209
- m.add_country_holidays(country_name: "US")
231
+ m.add_country_holidays("US")
210
232
  m.fit(df)
211
233
  ```
212
234
 
@@ -386,6 +386,12 @@ module Prophet
386
386
 
387
387
  def add_country_holidays(country_name)
388
388
  raise Error, "Country holidays must be added prior to model fitting." if @history
389
+
390
+ # Fix for previously documented keyword argument
391
+ if country_name.is_a?(Hash) && country_name[:country_name]
392
+ country_name = country_name[:country_name]
393
+ end
394
+
389
395
  # Validate names.
390
396
  get_holiday_names(country_name).each do |name|
391
397
  # Allow merging with existing holidays
@@ -2,25 +2,21 @@ module Prophet
2
2
  module Holidays
3
3
  def get_holiday_names(country)
4
4
  years = (1995..2045).to_a
5
- make_holidays_df(years, country)["holiday"].uniq
5
+ holiday_names = make_holidays_df(years, country)["holiday"].uniq
6
+ # TODO raise error in 0.4.0
7
+ logger.warn "Holidays in #{country} are not currently supported"
8
+ holiday_names
6
9
  end
7
10
 
8
11
  def make_holidays_df(year_list, country)
9
12
  holidays_df[(holidays_df["country"] == country) & (holidays_df["year"].in?(year_list))][["ds", "holiday"]]
10
13
  end
11
14
 
12
- # TODO marshal on installation
15
+ # TODO improve performance
13
16
  def holidays_df
14
17
  @holidays_df ||= begin
15
- holidays = {"ds" => [], "holiday" => [], "country" => [], "year" => []}
16
18
  holidays_file = File.expand_path("../../data-raw/generated_holidays.csv", __dir__)
17
- CSV.foreach(holidays_file, headers: true, converters: [:date, :numeric]) do |row|
18
- holidays["ds"] << row["ds"]
19
- holidays["holiday"] << row["holiday"]
20
- holidays["country"] << row["country"]
21
- holidays["year"] << row["year"]
22
- end
23
- Rover::DataFrame.new(holidays)
19
+ Rover.read_csv(holidays_file, converters: [:date, :numeric])
24
20
  end
25
21
  end
26
22
  end
@@ -1,3 +1,3 @@
1
1
  module Prophet
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.2"
3
3
  end
data/lib/prophet.rb CHANGED
@@ -21,9 +21,12 @@ module Prophet
21
21
  Forecaster.new(**kwargs)
22
22
  end
23
23
 
24
- def self.forecast(series, count: 10)
24
+ def self.forecast(series, count: 10, country_holidays: nil, cap: nil, verbose: false, **options)
25
25
  raise ArgumentError, "Series must have at least 10 data points" if series.size < 10
26
26
 
27
+ # error early on unknown keywords
28
+ m = Prophet.new(**options)
29
+
27
30
  # check type to determine output format
28
31
  # check for before converting to time
29
32
  keys = series.keys
@@ -62,12 +65,14 @@ module Prophet
62
65
 
63
66
  # use series, not times, so dates are handled correctly
64
67
  df = Rover::DataFrame.new({"ds" => series.keys, "y" => series.values})
68
+ df["cap"] = cap if cap
65
69
 
66
- m = Prophet.new
67
- m.logger.level = ::Logger::FATAL # no logging
70
+ m.logger.level = ::Logger::FATAL unless verbose
71
+ m.add_country_holidays(country_holidays) if country_holidays
68
72
  m.fit(df)
69
73
 
70
74
  future = m.make_future_dataframe(periods: count, include_history: false, freq: freq)
75
+ future["cap"] = cap if cap
71
76
  forecast = m.predict(future)
72
77
  result = forecast[["ds", "yhat"]].to_a
73
78
 
@@ -84,11 +89,17 @@ module Prophet
84
89
  result.map { |v| [v["ds"], v["yhat"]] }.to_h
85
90
  end
86
91
 
87
- def self.anomalies(series)
88
- df = Rover::DataFrame.new(series.map { |k, v| {"ds" => k, "y" => v} })
89
- m = Prophet.new(interval_width: 0.99)
90
- m.logger.level = ::Logger::FATAL # no logging
92
+ # TODO better name for interval_width
93
+ # TODO DRY with forecast method
94
+ def self.anomalies(series, interval_width: 0.99, country_holidays: nil, cap: nil, verbose: false, **options)
95
+ df = Rover::DataFrame.new({"ds" => series.keys, "y" => series.values})
96
+ df["cap"] = cap if cap
97
+
98
+ m = Prophet.new(interval_width: interval_width, **options)
99
+ m.logger.level = ::Logger::FATAL unless verbose
100
+ m.add_country_holidays(country_holidays) if country_holidays
91
101
  m.fit(df)
102
+
92
103
  forecast = m.predict(df)
93
104
  # filter df["ds"] to ensure dates/times in same format as input
94
105
  df["ds"][(df["y"] < forecast["yhat_lower"]) | (df["y"] > forecast["yhat_upper"])].to_a
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.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-28 00:00:00.000000000 Z
11
+ date: 2022-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cmdstan