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 +4 -4
- data/CHANGELOG.md +6 -2
- data/README.md +23 -1
- data/lib/prophet/forecaster.rb +6 -0
- data/lib/prophet/holidays.rb +6 -10
- data/lib/prophet/version.rb +1 -1
- data/lib/prophet.rb +18 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e24dad0631694318db703e420f657e964911071b73e03cd73a6fc4c2d6e16fc
|
4
|
+
data.tar.gz: bcf2a53b3bcacf5461cd0b881bba0d026c7adee88200646f915074c9946711d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdad3069aeaadaa9ac8d339fb6e877942470fd5c8e11652bce50029b0a6de13d0fe383f6a97a343e29138396dec4b1c159e5ee87d229073d2f3eb5c084aa5af2
|
7
|
+
data.tar.gz: 1d54e502621ed4d34c818fe2e0e064578eae948957305300222892f4ee4750418e2471261596568d05795aea31bb4fe4639925da20a1f5db5bd20a0f0b35a66f
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
-
## 0.3.
|
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 (
|
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(
|
231
|
+
m.add_country_holidays("US")
|
210
232
|
m.fit(df)
|
211
233
|
```
|
212
234
|
|
data/lib/prophet/forecaster.rb
CHANGED
@@ -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
|
data/lib/prophet/holidays.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
data/lib/prophet/version.rb
CHANGED
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 =
|
67
|
-
m.
|
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
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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.
|
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-
|
11
|
+
date: 2022-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cmdstan
|