Prophet.rb
Ruby版时间序列预测库,移植自Prophet
支持:
- 多重季节性
- 线性和非线性增长
- 节假日和特殊事件
并能优雅地处理缺失数据
安装
在应用的Gemfile中添加以下行:
gem "prophet-rb"
简单API
预测
获取时间序列的未来预测
series = {
Date.parse("2020-01-01") => 100,
Date.parse("2020-01-02") => 150,
Date.parse("2020-01-03") => 136,
# ...
}
Prophet.forecast(series)
指定返回的预测数量
Prophet.forecast(series, count: 3)
与Groupdate配合使用效果很好
series = User.group_by_day(:created_at).count
Prophet.forecast(series)
支持高级API选项
Prophet.forecast(series, growth: "logistic", weekly_seasonality: false)
异常检测
检测时间序列中的异常
Prophet.anomalies(series)
指定不确定性区间的宽度(减小以获得更多异常)
Prophet.anomalies(series, interval_width: 0.99)
同样支持高级API选项
Prophet.anomalies(series, growth: "logistic", weekly_seasonality: false)
高级API
查看Prophet文档以获取所有功能的详细说明。高级API遵循Python API并支持相同的功能。它使用Rover处理数据框。
高级快速入门
创建包含ds
和y
列的数据框 - 这里有一个示例可供使用
df = Rover.read_csv("example_wp_log_peyton_manning.csv")
df.head
ds | y |
---|---|
2007-12-10 | 9.59076113 |
2007-12-11 | 8.51959031 |
2007-12-12 | 8.18367658 |
2007-12-13 | 8.07246736 |
2007-12-14 | 7.89357207 |
拟合模型
m = Prophet.new
m.fit(df)
创建包含未来日期ds
列的数据框
future = m.make_future_dataframe(periods: 365)
future.tail
ds |
---|
2017-01-15 |
2017-01-16 |
2017-01-17 |
2017-01-18 |
2017-01-19 |
进行预测
forecast = m.predict(future)
forecast[["ds", "yhat", "yhat_lower", "yhat_upper"]].tail
ds | yhat | yhat_lower | yhat_upper |
---|---|---|---|
2017-01-15 | 8.21192840 | 7.52526442 | 8.92389960 |
2017-01-16 | 8.53696359 | 7.79124970 | 9.22620028 |
2017-01-17 | 8.32439891 | 7.62482699 | 9.04719328 |
2017-01-18 | 8.15702395 | 7.40079968 | 8.91301650 |
2017-01-19 | 8.16900433 | 7.45673678 | 8.83486188 |
绘图
要进行绘图,请安装matplotlib gem。
绘制预测图
m.plot(forecast).savefig("forecast.png")
绘制组件图
m.plot_components(forecast).savefig("components.png")
饱和预测
预测逻辑增长而非线性增长
df = Rover.read_csv("example_wp_log_R.csv")
df["cap"] = 8.5
m = Prophet.new(growth: "logistic")
m.fit(df)
future = m.make_future_dataframe(periods: 1826)
future["cap"] = 8.5
forecast = m.predict(future)
饱和最小值
df["y"] = 10 - df["y"]
df["cap"] = 6
df["floor"] = 1.5
future["cap"] = 6
future["floor"] = 1.5
m = Prophet.new(growth: "logistic")
m.fit(df)
forecast = m.predict(future)
趋势变点
绘制变点
fig = m.plot(forecast)
m.add_changepoints_to_plot(fig.gca, forecast)
调整趋势灵活性
m = Prophet.new(changepoint_prior_scale: 0.5)
指定变点位置
m = Prophet.new(changepoints: ["2014-01-01"])
节假日和特殊事件
创建包含holiday
和ds
列的数据框。包括过去数据中的所有出现以及你想预测的未来出现。
playoffs = Rover::DataFrame.new({
"holiday" => "playoff",
"ds" => [
"2008-01-13", "2009-01-03", "2010-01-16",
"2010-01-24", "2010-02-07", "2011-01-08",
"2013-01-12", "2014-01-12", "2014-01-19",
"2014-02-02", "2015-01-11", "2016-01-17",
"2016-01-24", "2016-02-07"
],
"lower_window" => 0,
"upper_window" => 1
})
superbowls = Rover::DataFrame.new({
"holiday" => "superbowl",
"ds" => ["2010-02-07", "2014-02-02", "2016-02-07"],
"lower_window" => 0,
"upper_window" => 1
})
holidays = playoffs.concat(superbowls)
m = Prophet.new(holidays: holidays)
m.fit(df)
添加特定国家的节假日
m = Prophet.new
m.add_country_holidays("US")
m.fit(df)
指定自定义季节性
m = Prophet.new(weekly_seasonality: false)
m.add_seasonality(name: "monthly", period: 30.5, fourier_order: 5)
forecast = m.fit(df).predict(future)
指定额外的回归变量
nfl_sunday = lambda do |ds|
date = ds.respond_to?(:to_date) ? ds.to_date : Date.parse(ds)
date.wday == 0 && (date.month > 8 || date.month < 2) ? 1 : 0
end
df["nfl_sunday"] = df["ds"].map(&nfl_sunday)
m = Prophet.new
m.add_regressor("nfl_sunday")
m.fit(df)
future["nfl_sunday"] = future["ds"].map(&nfl_sunday)
forecast = m.predict(future)
乘法季节性
指定乘法季节性
df = Rover.read_csv("example_air_passengers.csv")
m = Prophet.new(seasonality_mode: "multiplicative")
m.fit(df)
future = m.make_future_dataframe(periods: 50, freq: "MS")
forecast = m.predict(future)
添加季节性和回归变量时指定模式
m = Prophet.new(seasonality_mode: "multiplicative")
m.add_seasonality(name: "quarterly", period: 91.25, fourier_order: 8, mode: "additive")
m.add_regressor("regressor", mode: "additive")
不确定性区间
指定不确定性区间的宽度(默认为80%)
Prophet.new(interval_width: 0.95)
获取季节性的不确定性
Prophet.new(mcmc_samples: 300)
异常值
移除异常值
df = Rover.read_csv("example_wp_log_R_outliers1.csv")
df["y"][(df["ds"] > "2010-01-01") & (df["ds"] < "2011-01-01")] = Float::NAN
m = Prophet.new.fit(df)
非日常数据
次日数据
df = Rover.read_csv("example_yosemite_temps.csv")
m = Prophet.new(changepoint_prior_scale: 0.01).fit(df)
future = m.make_future_dataframe(periods: 300, freq: "H")
forecast = m.predict(future)
诊断
交叉验证
df_cv = Prophet::Diagnostics.cross_validation(m, initial: "730 days", period: "180 days", horizon: "365 days")
自定义切点
cutoffs = ["2013-02-15", "2013-08-15", "2014-02-15"].map { |v| Time.parse("#{v} 00:00:00 UTC") }
df_cv2 = Prophet::Diagnostics.cross_validation(m, cutoffs: cutoffs, horizon: "365 days")
获取性能指标
df_p = Prophet::Diagnostics.performance_metrics(df_cv)
绘制交叉验证指标图
Prophet::Plot.plot_cross_validation_metric(df_cv, metric: "mape")
超参数调优
param_grid = {
changepoint_prior_scale: [0.001, 0.01, 0.1, 0.5],
seasonality_prior_scale: [0.01, 0.1, 1.0, 10.0]
}
# 生成所有参数组合
all_params = param_grid.values[0].product(*param_grid.values[1..-1]).map { |v| param_grid.keys.zip(v).to_h }
rmses = [] # 在此存储每组参数的RMSE
# 使用交叉验证评估所有参数
all_params.each do |params|
m = Prophet.new(**params).fit(df) # 使用给定参数拟合模型
df_cv = Prophet::Diagnostics.cross_validation(m, cutoffs: cutoffs, horizon: "30 days")
df_p = Prophet::Diagnostics.performance_metrics(df_cv, rolling_window: 1)
rmses << df_p["rmse"][0]
end
# 找出最佳参数
tuning_results = Rover::DataFrame.new(all_params)
tuning_results["rmse"] = rmses
p tuning_results
其他主题
保存模型
File.write("model.json", m.to_json)
加载模型
m = Prophet.from_json(File.read("model.json"))
使用与Python相同的格式,因此模型可以在两种语言中保存和加载
平坦趋势
m = Prophet.new(growth: "flat")
更新已拟合的模型
def stan_init(m)
res = {}
["k", "m", "sigma_obs"].each do |pname|
res[pname] = m.params[pname][0, true][0]
end
["delta", "beta"].each do |pname|
res[pname] = m.params[pname][0, true]
end
res
end
df = Rover.read_csv("example_wp_log_peyton_manning.csv")
df1 = df[df["ds"] <= "2016-01-19"] # 除最后一天外的所有数据
m1 = Prophet.new.fit(df1) # 使用除最后一天外的所有数据拟合的模型
m2 = Prophet.new.fit(df) # 添加最后一天,从头开始拟合
m2 = Prophet.new.fit(df, init: stan_init(m1)) # 添加最后一天,从m1热启动
资源
致谢
该库是从Prophet Python库移植而来,并使用相同的许可证。
历史
查看更新日志
贡献
我们鼓励每个人都参与改进这个项目。以下是一些您可以帮助的方式:
要开始开发,请执行以下操作:
git clone https://github.com/ankane/prophet-ruby.git
cd prophet-ruby
bundle install
bundle exec rake vendor:all
bundle exec rake test