mirror of
https://github.com/saymrwulf/prophet.git
synced 2026-07-29 20:14:08 +00:00
{rstantools}-based compilation
+ cleans up Stan model compilation by switching over to the rstantools-based workflow (see https://mc-stan.org/rstantools/articles/minimal-rstan-package.html for more info) + minor documentation change: {devtools} -> {remotes}, which is better for end-users + adds RStudio project file which makes it easier for community to get started with contributing to the package
This commit is contained in:
parent
59e374b1ad
commit
25e2b88765
15 changed files with 173 additions and 74 deletions
|
|
@ -2,3 +2,5 @@
|
|||
^libs$
|
||||
^doc$
|
||||
^Meta$
|
||||
^.*\.Rproj$
|
||||
^\.Rproj\.user$
|
||||
|
|
|
|||
54
R/.gitignore
vendored
Normal file
54
R/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
.DS_Store
|
||||
|
||||
# History files
|
||||
.Rhistory
|
||||
.Rapp.history
|
||||
|
||||
# Session Data files
|
||||
.RData
|
||||
|
||||
# User-specific files
|
||||
.Ruserdata
|
||||
|
||||
# Example code in package build process
|
||||
*-Ex.R
|
||||
|
||||
# Output files from R CMD build
|
||||
/*.tar.gz
|
||||
|
||||
# Output files from R CMD check
|
||||
/*.Rcheck/
|
||||
|
||||
# RStudio files
|
||||
.Rproj.user/
|
||||
|
||||
# produced vignettes
|
||||
vignettes/*.html
|
||||
vignettes/*.pdf
|
||||
|
||||
# OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3
|
||||
.httr-oauth
|
||||
|
||||
# knitr and R markdown default cache directories
|
||||
*_cache/
|
||||
/cache/
|
||||
|
||||
# Temporary files created by R markdown
|
||||
*.utf8.md
|
||||
*.knit.md
|
||||
|
||||
# R Environment Variables
|
||||
.Renviron
|
||||
inst/doc
|
||||
|
||||
# Stan
|
||||
exec/*.rda
|
||||
src/*.o
|
||||
src/*.h
|
||||
src/*.cc
|
||||
src/*.cpp
|
||||
src/*.hpp
|
||||
src/prophet.so
|
||||
src/prophet.dll
|
||||
src/init.o
|
||||
|
||||
|
|
@ -12,8 +12,10 @@ Description: Implements a procedure for forecasting time series data based on
|
|||
that have strong seasonal effects and several seasons of historical data.
|
||||
Prophet is robust to missing data and shifts in the trend, and typically
|
||||
handles outliers well.
|
||||
URL: https://github.com/facebook/prophet
|
||||
BugReports: https://github.com/facebook/prophet/issues
|
||||
Depends:
|
||||
R (>= 3.2.3),
|
||||
R (>= 3.4.0),
|
||||
Rcpp (>= 0.12.0),
|
||||
rlang (>= 0.3.0.1)
|
||||
Imports:
|
||||
|
|
@ -22,7 +24,9 @@ Imports:
|
|||
extraDistr,
|
||||
ggplot2,
|
||||
grid,
|
||||
rstan (>= 2.14.0),
|
||||
methods,
|
||||
rstan (>= 2.18.1),
|
||||
rstantools (>= 2.0.0),
|
||||
scales,
|
||||
stats,
|
||||
tidyr (>= 0.6.1),
|
||||
|
|
@ -32,11 +36,16 @@ Suggests:
|
|||
testthat,
|
||||
readr,
|
||||
rmarkdown
|
||||
SystemRequirements: GNU make, C++11
|
||||
Biarch: true
|
||||
License: MIT + file LICENSE
|
||||
URL: https://github.com/facebook/prophet
|
||||
BugReports: https://github.com/facebook/prophet/issues
|
||||
LinkingTo:
|
||||
BH (>= 1.66.0),
|
||||
Rcpp (>= 0.12.0),
|
||||
RcppEigen (>= 0.3.3.3.0),
|
||||
rstan (>= 2.18.1),
|
||||
StanHeaders (>= 2.18.0)
|
||||
LazyData: true
|
||||
RoxygenNote: 7.0.2
|
||||
VignetteBuilder: knitr
|
||||
SystemRequirements: C++11
|
||||
Encoding: UTF-8
|
||||
RoxygenNote: 7.1.0
|
||||
|
|
|
|||
|
|
@ -19,3 +19,4 @@ export(prophet_plot_components)
|
|||
import(Rcpp)
|
||||
import(rlang)
|
||||
importFrom(dplyr,"%>%")
|
||||
useDynLib(prophet, .registration = TRUE)
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ globalVariables(c(
|
|||
#' @importFrom dplyr "%>%"
|
||||
#' @import Rcpp
|
||||
#' @import rlang
|
||||
#' @useDynLib prophet, .registration = TRUE
|
||||
prophet <- function(df = NULL,
|
||||
growth = 'linear',
|
||||
changepoints = NULL,
|
||||
|
|
@ -236,44 +237,6 @@ validate_column_name <- function(
|
|||
}
|
||||
}
|
||||
|
||||
#' Compile Stan model
|
||||
#'
|
||||
#' @return Stan model.
|
||||
#'
|
||||
#' @keywords internal
|
||||
compile_stan_model <- function() {
|
||||
packageStartupMessage('Compiling model (this will take a few minutes...)')
|
||||
packageStartupMessage(
|
||||
'If this is the first time fitting a model since package install, this is normal. ',
|
||||
'You should not see this message more than once after install.'
|
||||
)
|
||||
|
||||
if (.Platform$OS.type == "windows") {
|
||||
dest <- file.path(system.file(package="prophet"), 'libs', .Platform$r_arch)
|
||||
} else {
|
||||
dest <- file.path(system.file(package="prophet"), 'libs')
|
||||
}
|
||||
dir.create(dest, recursive = TRUE, showWarnings = FALSE)
|
||||
|
||||
packageStartupMessage(paste('Writing model to:', dest))
|
||||
packageStartupMessage(paste('Compiling using binary:', R.home('bin')))
|
||||
|
||||
fn <- 'stan/prophet.stan'
|
||||
stan.src <- system.file(fn, package = 'prophet', mustWork = TRUE)
|
||||
model.binary <- file.path(dest, 'prophet_stan_model.RData')
|
||||
|
||||
stanc <- rstan::stanc(stan.src)
|
||||
model.stanm <- rstan::stan_model(
|
||||
stanc_ret = stanc,
|
||||
model_name = 'prophet_model'
|
||||
)
|
||||
save('model.stanm', file = model.binary)
|
||||
packageStartupMessage('------ Model successfully compiled!')
|
||||
packageStartupMessage('You can ignore any compiler warnings above.')
|
||||
assign(".prophet.stan.model", model.stanm, envir = prophet_model_env)
|
||||
return(model.stanm)
|
||||
}
|
||||
|
||||
#' Convert date vector
|
||||
#'
|
||||
#' Convert the date to POSIXct object
|
||||
|
|
@ -365,7 +328,7 @@ setup_dataframe <- function(m, df, initialize_scales = FALSE) {
|
|||
df[[condition.name]] <- as.logical(df[[condition.name]])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
df <- df %>%
|
||||
dplyr::arrange(ds)
|
||||
|
||||
|
|
@ -724,7 +687,7 @@ add_regressor <- function(
|
|||
#' specified, m$seasonality.mode will be used (defaults to 'additive').
|
||||
#' Additive means the seasonality will be added to the trend, multiplicative
|
||||
#' means it will multiply the trend.
|
||||
#'
|
||||
#'
|
||||
#' If condition.name is provided, the dataframe passed to `fit` and `predict`
|
||||
#' should have a column with the specified condition.name containing booleans
|
||||
#' which decides when to apply seasonality.
|
||||
|
|
@ -741,7 +704,7 @@ add_regressor <- function(
|
|||
#'
|
||||
#' @export
|
||||
add_seasonality <- function(
|
||||
m, name, period, fourier.order, prior.scale = NULL, mode = NULL,
|
||||
m, name, period, fourier.order, prior.scale = NULL, mode = NULL,
|
||||
condition.name = NULL
|
||||
) {
|
||||
if (!is.null(m$history)) {
|
||||
|
|
@ -1231,7 +1194,7 @@ fit.prophet <- function(m, df, ...) {
|
|||
if (exists(".prophet.stan.model", where = prophet_model_env)) {
|
||||
model <- get('.prophet.stan.model', envir = prophet_model_env)
|
||||
} else {
|
||||
model <- compile_stan_model()
|
||||
model <- stanmodels$prophet
|
||||
}
|
||||
|
||||
stan_init <- function() {
|
||||
|
|
@ -1280,7 +1243,7 @@ fit.prophet <- function(m, df, ...) {
|
|||
m$params <- m$stan.fit$par
|
||||
n.iteration <- 1
|
||||
}
|
||||
|
||||
|
||||
# Cast the parameters to have consistent form, whether full bayes or MAP
|
||||
for (name in c('delta', 'beta')){
|
||||
m$params[[name]] <- matrix(m$params[[name]], nrow = n.iteration)
|
||||
|
|
@ -1340,7 +1303,7 @@ predict.prophet <- function(object, df = NULL, ...) {
|
|||
} else {
|
||||
intervals <- NULL
|
||||
}
|
||||
|
||||
|
||||
# Drop columns except ds, cap, floor, and trend
|
||||
cols <- c('ds', 'trend')
|
||||
if ('cap' %in% colnames(df)) {
|
||||
|
|
|
|||
25
R/R/stanmodels.R
Normal file
25
R/R/stanmodels.R
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by rstantools. Do not edit by hand.
|
||||
|
||||
# names of stan models
|
||||
stanmodels <- c("prophet")
|
||||
|
||||
# load each stan module
|
||||
Rcpp::loadModule("stan_fit4prophet_mod", what = TRUE)
|
||||
|
||||
# instantiate each stanmodel object
|
||||
stanmodels <- sapply(stanmodels, function(model_name) {
|
||||
# create C++ code for stan model
|
||||
stan_file <- if(dir.exists("stan")) "stan" else file.path("inst", "stan")
|
||||
stan_file <- file.path(stan_file, paste0(model_name, ".stan"))
|
||||
stanfit <- rstan::stanc_builder(stan_file,
|
||||
allow_undefined = TRUE,
|
||||
obfuscate_model_name = FALSE)
|
||||
stanfit$model_cpp <- list(model_cppname = stanfit$model_name,
|
||||
model_cppcode = stanfit$cppcode)
|
||||
# create stanmodel object
|
||||
methods::new(Class = "stanmodel",
|
||||
model_name = stanfit$model_name,
|
||||
model_code = stanfit$model_code,
|
||||
model_cpp = stanfit$model_cpp,
|
||||
mk_cppmodule = function(x) get(paste0("model_", model_name)))
|
||||
})
|
||||
4
R/configure
vendored
Executable file
4
R/configure
vendored
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
# Generated by rstantools. Do not edit by hand.
|
||||
|
||||
#! /bin/sh
|
||||
"${R_HOME}/bin/Rscript" -e "rstantools::rstan_config()"
|
||||
4
R/configure.win
Executable file
4
R/configure.win
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
# Generated by rstantools. Do not edit by hand.
|
||||
|
||||
#! /bin/sh
|
||||
"${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" -e "rstantools::rstan_config()"
|
||||
1
R/inst/include/stan_meta_header.hpp
Normal file
1
R/inst/include/stan_meta_header.hpp
Normal file
|
|
@ -0,0 +1 @@
|
|||
// Insert all #include<foo.hpp> statements here
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
% Generated by roxygen2: do not edit by hand
|
||||
% Please edit documentation in R/prophet.R
|
||||
\name{compile_stan_model}
|
||||
\alias{compile_stan_model}
|
||||
\title{Compile Stan model}
|
||||
\usage{
|
||||
compile_stan_model()
|
||||
}
|
||||
\value{
|
||||
Stan model.
|
||||
}
|
||||
\description{
|
||||
Compile Stan model
|
||||
}
|
||||
\keyword{internal}
|
||||
|
|
@ -4,7 +4,9 @@
|
|||
\name{generated_holidays}
|
||||
\alias{generated_holidays}
|
||||
\title{holidays table}
|
||||
\format{A data frame with five variables: ds, holiday, country, year}
|
||||
\format{
|
||||
A data frame with five variables: ds, holiday, country, year
|
||||
}
|
||||
\usage{
|
||||
generated_holidays
|
||||
}
|
||||
|
|
|
|||
21
R/prophet.Rproj
Normal file
21
R/prophet.Rproj
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
Version: 1.0
|
||||
|
||||
RestoreWorkspace: Default
|
||||
SaveWorkspace: Default
|
||||
AlwaysSaveHistory: Default
|
||||
|
||||
EnableCodeIndexing: Yes
|
||||
UseSpacesForTab: Yes
|
||||
NumSpacesForTab: 2
|
||||
Encoding: UTF-8
|
||||
|
||||
RnwWeave: knitr
|
||||
LaTeX: pdfLaTeX
|
||||
|
||||
AutoAppendNewline: Yes
|
||||
StripTrailingWhitespace: Yes
|
||||
|
||||
BuildType: Package
|
||||
PackageUseDevtools: Yes
|
||||
PackageInstallArgs: --no-multiarch --with-keep.source
|
||||
PackageRoxygenize: rd,collate,namespace
|
||||
15
R/src/Makevars
Normal file
15
R/src/Makevars
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Generated by rstantools. Do not edit by hand.
|
||||
|
||||
STANHEADERS_SRC = $(shell "$(R_HOME)/bin$(R_ARCH_BIN)/Rscript" -e "message()" -e "cat(system.file('include', 'src', package = 'StanHeaders', mustWork = TRUE))" -e "message()" | grep "StanHeaders")
|
||||
|
||||
PKG_CPPFLAGS = -I"../inst/include" -I"$(STANHEADERS_SRC)" -DBOOST_DISABLE_ASSERTS -DEIGEN_NO_DEBUG -DBOOST_MATH_OVERFLOW_ERROR_POLICY=errno_on_error
|
||||
|
||||
CXX_STD = CXX14
|
||||
|
||||
all: $(SHLIB)
|
||||
@if test -e "/usr/bin/install_name_tool" && test -e "/usr/local/clang4/lib/libc++.1.dylib" && test -e "/usr/lib/libc++.1.dylib"; then /usr/bin/install_name_tool -change /usr/local/clang4/lib/libc++.1.dylib /usr/lib/libc++.1.dylib $(SHLIB); fi
|
||||
|
||||
clean:
|
||||
rm -rf *.so *.o
|
||||
|
||||
.phony: all clean
|
||||
14
R/src/Makevars.win
Normal file
14
R/src/Makevars.win
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Generated by rstantools. Do not edit by hand.
|
||||
|
||||
STANHEADERS_SRC = $(shell "$(R_HOME)/bin$(R_ARCH_BIN)/Rscript" -e "message()" -e "cat(system.file('include', 'src', package = 'StanHeaders', mustWork = TRUE))" -e "message()" | grep "StanHeaders")
|
||||
|
||||
PKG_CPPFLAGS = -I"../inst/include" -I"$(STANHEADERS_SRC)" -DBOOST_DISABLE_ASSERTS -DEIGEN_NO_DEBUG
|
||||
|
||||
CXX_STD = CXX14
|
||||
|
||||
all: $(SHLIB)
|
||||
|
||||
clean:
|
||||
RM -rf *.so *.o
|
||||
|
||||
.phony: all clean
|
||||
15
README.md
15
README.md
|
|
@ -21,11 +21,11 @@ Prophet is [open source software](https://code.facebook.com/projects/) released
|
|||
|
||||
## Installation in R
|
||||
|
||||
Prophet is temporarily not on CRAN so you can use the `devtools` package to install it directly from github:
|
||||
Prophet is temporarily not on CRAN so you can use the `devtools` package to install it directly from GitHub:
|
||||
|
||||
```
|
||||
# R
|
||||
> devtools::install_github("facebook/prophet", subdir='R', ref="8306ae3")
|
||||
```R
|
||||
# install.packages("remotes")
|
||||
remotes::install_github("facebook/prophet", subdir = "R")
|
||||
```
|
||||
|
||||
After installation, you can [get started!](https://facebook.github.io/prophet/docs/quick_start.html#r-api)
|
||||
|
|
@ -38,11 +38,10 @@ If you have custom Stan compiler settings, install from source rather than the C
|
|||
|
||||
## Installation in Python
|
||||
|
||||
Prophet is on PyPI, so you can use pip to install it:
|
||||
Prophet is on PyPI, so you can use `pip` to install it:
|
||||
|
||||
```
|
||||
# bash
|
||||
$ pip install fbprophet
|
||||
```bash
|
||||
pip install fbprophet
|
||||
```
|
||||
|
||||
The default dependency that Prophet has is `pystan`. PyStan has its own [installation instructions](http://pystan.readthedocs.io/en/latest/installation_beginner.html). Install pystan with pip before using pip to install fbprophet.
|
||||
|
|
|
|||
Loading…
Reference in a new issue