prophet-rb 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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