diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 1947ea3..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index b811cc6..fa262d0 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -1,20 +1,12 @@ -# NOTE: This workflow is overkill for most R packages -# check-standard.yaml is likely a better choice -# usethis::use_github_action("check-standard") will install it. -# -# For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag. -# https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: schedule: - cron: '0 0 1 * *' push: - branches: - - main - - master + branches: [main, master] pull_request: - branches: - - main - - master + branches: [main, master] name: R-CMD-check @@ -28,78 +20,32 @@ jobs: fail-fast: false matrix: config: - - {os: macOS-latest, r: 'release'} + - {os: macos-latest, r: 'release'} - {os: windows-latest, r: 'release'} - # - {os: windows-latest, r: '3.6'} - - {os: ubuntu-18.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", http-user-agent: "R/4.0.0 (ubuntu-18.04) R (4.0.0 x86_64-pc-linux-gnu x86_64 linux-gnu) on GitHub Actions" } - - {os: ubuntu-18.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} - # - {os: ubuntu-18.04, r: 'oldrel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} - # - {os: ubuntu-18.04, r: '3.6', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest"} + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release'} + - {os: ubuntu-latest, r: 'oldrel-1'} env: - RSPM: ${{ matrix.config.rspm }} GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-r@v1 - id: install-r + - uses: r-lib/actions/setup-pandoc@v2 + + - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true - - uses: r-lib/actions/setup-pandoc@v1 - - - name: Install pak and query dependencies - run: | - install.packages("pak", repos = "https://r-lib.github.io/p/pak/dev/") - saveRDS(pak::pkg_deps("local::.", dependencies = TRUE), ".github/r-depends.rds") - shell: Rscript {0} - - - name: Restore R package cache - uses: actions/cache@v2 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - path: ${{ env.R_LIBS_USER }} - key: ${{ matrix.config.os }}-${{ steps.install-r.outputs.installed-r-version }}-1-${{ hashFiles('.github/r-depends.rds') }} - restore-keys: ${{ matrix.config.os }}-${{ steps.install-r.outputs.installed-r-version }}-1- - - - name: Install system dependencies - if: runner.os == 'Linux' - run: | - pak::local_system_requirements(execute = TRUE) - pak::pkg_system_requirements("rcmdcheck", execute = TRUE) - shell: Rscript {0} - - - name: Install dependencies - run: | - pak::local_install_dev_deps(upgrade = TRUE) - pak::pkg_install("rcmdcheck") - shell: Rscript {0} - - - name: Session info - run: | - options(width = 100) - pkgs <- installed.packages()[, "Package"] - sessioninfo::session_info(pkgs, include_base = TRUE) - shell: Rscript {0} - - - name: Check - env: - _R_CHECK_CRAN_INCOMING_: false - run: | - options(crayon.enabled = TRUE) - rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check") - shell: Rscript {0} - - - name: Show testthat output - if: always() - run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true - shell: bash + extra-packages: any::rcmdcheck + needs: check - - name: Upload check results - if: failure() - uses: actions/upload-artifact@main + - uses: r-lib/actions/check-r-package@v2 with: - name: ${{ matrix.config.os }}-r${{ matrix.config.r }}-results - path: check + upload-snapshots: true diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 3eb8dd9..ed7650c 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -1,57 +1,48 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: - branches: - - main - - master + branches: [main, master] + pull_request: + branches: [main, master] + release: + types: [published] + workflow_dispatch: name: pkgdown jobs: pkgdown: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest + # Only restrict concurrency for non-PR jobs + concurrency: + group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} env: - RSPM: https://packagemanager.rstudio.com/cran/__linux__/bionic/latest GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - + permissions: + contents: write steps: - - uses: actions/checkout@v2 - - - uses: r-lib/actions/setup-r@v1 - id: install-r + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-pandoc@v1 - - - name: Install pak and query dependencies - run: | - install.packages("pak", repos = "https://r-lib.github.io/p/pak/dev/") - saveRDS(pak::pkg_deps("local::.", dependencies = TRUE), ".github/r-depends.rds") - shell: Rscript {0} + - uses: r-lib/actions/setup-pandoc@v2 - - name: Restore R package cache - uses: actions/cache@v2 + - uses: r-lib/actions/setup-r@v2 with: - path: ${{ env.R_LIBS_USER }} - key: ubuntu-18.04-${{ steps.install-r.outputs.installed-r-version }}-1-${{ hashFiles('.github/r-depends.rds') }} - restore-keys: ubuntu-18.04-${{ steps.install-r.outputs.installed-r-version }}-1- + use-public-rspm: true - - name: Install system dependencies - if: runner.os == 'Linux' - run: | - pak::local_system_requirements(execute = TRUE) - pak::pkg_system_requirements("pkgdown", execute = TRUE) - shell: Rscript {0} + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::pkgdown, local::. + needs: website - - name: Install dependencies - run: | - pak::local_install_dev_deps(upgrade = TRUE) - pak::pkg_install("pkgdown") + - name: Build site + run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) shell: Rscript {0} - - name: Install package - run: R CMD INSTALL . - - - name: Build and deploy pkgdown site - run: | - git config --local user.name "$GITHUB_ACTOR" - git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" - Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)' + - name: Deploy to GitHub pages 🚀 + if: github.event_name != 'pull_request' + uses: JamesIves/github-pages-deploy-action@v4.4.1 + with: + clean: false + branch: gh-pages + folder: docs diff --git a/.github/workflows/pr-commands.yaml b/.github/workflows/pr-commands.yaml index e5edf9f..71f335b 100644 --- a/.github/workflows/pr-commands.yaml +++ b/.github/workflows/pr-commands.yaml @@ -1,55 +1,79 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: issue_comment: types: [created] + name: Commands + jobs: document: - if: startsWith(github.event.comment.body, '/document') + if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }} name: document - runs-on: macOS-latest + runs-on: ubuntu-latest env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 - - uses: r-lib/actions/pr-fetch@v1 + - uses: actions/checkout@v3 + + - uses: r-lib/actions/pr-fetch@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: r-lib/actions/setup-r@v1 - - name: Install dependencies - run: Rscript -e 'install.packages(c("remotes", "roxygen2"))' -e 'remotes::install_deps(dependencies = TRUE)' + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::roxygen2 + needs: pr-document + - name: Document - run: Rscript -e 'roxygen2::roxygenise()' + run: roxygen2::roxygenise() + shell: Rscript {0} + - name: commit run: | - git config --local user.email "actions@github.com" - git config --local user.name "GitHub Actions" + git config --local user.name "$GITHUB_ACTOR" + git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" git add man/\* NAMESPACE git commit -m 'Document' - - uses: r-lib/actions/pr-push@v1 + + - uses: r-lib/actions/pr-push@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} + style: - if: startsWith(github.event.comment.body, '/style') + if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }} name: style - runs-on: macOS-latest + runs-on: ubuntu-latest env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 - - uses: r-lib/actions/pr-fetch@v1 + - uses: actions/checkout@v3 + + - uses: r-lib/actions/pr-fetch@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - - uses: r-lib/actions/setup-r@v1 + + - uses: r-lib/actions/setup-r@v2 + - name: Install dependencies - run: Rscript -e 'install.packages("styler")' + run: install.packages("styler") + shell: Rscript {0} + - name: Style - run: Rscript -e 'styler::style_pkg()' + run: styler::style_pkg() + shell: Rscript {0} + - name: commit run: | - git config --local user.email "actions@github.com" - git config --local user.name "GitHub Actions" + git config --local user.name "$GITHUB_ACTOR" + git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" git add \*.R git commit -m 'Style' - - uses: r-lib/actions/pr-push@v1 + + - uses: r-lib/actions/pr-push@v2 with: repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 965cd84..27d4528 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -1,54 +1,50 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: - branches: - - main - - master + branches: [main, master] pull_request: - branches: - - main - - master + branches: [main, master] name: test-coverage jobs: test-coverage: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest env: - RSPM: https://packagemanager.rstudio.com/cran/__linux__/bionic/latest GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-r@v1 - id: install-r - - - name: Install pak and query dependencies - run: | - install.packages("pak", repos = "https://r-lib.github.io/p/pak/dev/") - saveRDS(pak::pkg_deps("local::.", dependencies = TRUE), ".github/r-depends.rds") - shell: Rscript {0} + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true - - name: Restore R package cache - uses: actions/cache@v2 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - path: ${{ env.R_LIBS_USER }} - key: ubuntu-18.04-${{ steps.install-r.outputs.installed-r-version }}-1-${{ hashFiles('.github/r-depends.rds') }} - restore-keys: ubuntu-18.04-${{ steps.install-r.outputs.installed-r-version }}-1- + extra-packages: any::covr + needs: coverage - - name: Install system dependencies - if: runner.os == 'Linux' + - name: Test coverage run: | - pak::local_system_requirements(execute = TRUE) - pak::pkg_system_requirements("covr", execute = TRUE) + covr::codecov( + quiet = FALSE, + clean = FALSE, + install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") + ) shell: Rscript {0} - - name: Install dependencies + - name: Show testthat output + if: always() run: | - pak::local_install_dev_deps(upgrade = TRUE) - pak::pkg_install("covr") - shell: Rscript {0} + ## -------------------------------------------------------------------- + find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash - - name: Test coverage - run: covr::codecov() - shell: Rscript {0} + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v3 + with: + name: coverage-test-failures + path: ${{ runner.temp }}/package diff --git a/.gitignore b/.gitignore index c833a2c..86fa0f8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .RData .Ruserdata inst/doc +.DS_Store diff --git a/DESCRIPTION b/DESCRIPTION index 9b71ca1..f79a2d1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: modeltime.ensemble Type: Package Title: Ensemble Algorithms for Time Series Forecasting with Modeltime -Version: 1.0.3 +Version: 1.0.3.9000 Authors@R: c( person("Matt", "Dancho", email = "mdancho@business-science.io", role = c("aut", "cre")), person("Business Science", role = "cph") @@ -11,7 +11,7 @@ Description: weighted averaging, and stacking. These techniques are popular methods to improve forecast accuracy and stability. Refer to papers such as "Machine-Learning Models for Sales Time Series Forecasting" Pavlyshenko, B.M. (2019) . -URL: https://github.com/business-science/modeltime.ensemble +URL: https://business-science.github.io/modeltime.ensemble/, https://github.com/business-science/modeltime.ensemble BugReports: https://github.com/business-science/modeltime.ensemble/issues License: MIT + file LICENSE Encoding: UTF-8 @@ -22,7 +22,7 @@ Depends: Imports: tune (>= 0.1.2), rsample, - yardstick, + yardstick, workflows (>= 0.2.1), parsnip (>= 0.1.6), recipes (>= 0.1.15), @@ -31,7 +31,6 @@ Imports: dplyr (>= 1.0.0), tidyr, purrr, - glue, stringr, rlang (>= 0.1.2), cli, @@ -41,25 +40,18 @@ Imports: parallel, doParallel, foreach, -Suggests: +Suggests: gt, - crayon, dials, glmnet, - progressr, utils, - roxygen2, earth, testthat, tidymodels, xgboost, - tidyverse, lubridate, knitr, - rmarkdown, - covr, - qpdf, - remotes + rmarkdown RoxygenNote: 7.2.3 VignetteBuilder: knitr Roxygen: list(markdown = TRUE) diff --git a/NEWS.md b/NEWS.md index 17f9c2a..197d8e0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,5 @@ +# modeltime.ensemble (development version) + # modeltime.ensemble 1.0.3 - Resubmit to CRAN (following timetk archival) diff --git a/R/ensemble_average.R b/R/ensemble_average.R index eef0008..cf020b5 100644 --- a/R/ensemble_average.R +++ b/R/ensemble_average.R @@ -26,7 +26,7 @@ #' library(tidymodels) #' library(modeltime) #' library(modeltime.ensemble) -#' library(tidyverse) +#' library(dplyr) #' library(timetk) #' #' # Make an ensemble from a Modeltime Table @@ -89,14 +89,12 @@ print.mdl_time_ensemble_avg <- function(x, ...) { print(cli::rule("Modeltime Ensemble", width = min(65, cli::console_width()))) if (x$parameters$type == "mean") { - msg <- glue::glue("Ensemble of {x$n_models} Models (MEAN)") + msg <- cli::format_inline("Ensemble of {x$n_models} Models (MEAN)") } else { - msg <- glue::glue("Ensemble of {x$n_models} Models (MEDIAN)") + msg <- cli::format_inline("Ensemble of {x$n_models} Models (MEDIAN)") } - print(msg) - - cli::cat_line() + cat(msg, "\n\n") print(x$model_tbl) diff --git a/R/ensemble_model_spec.R b/R/ensemble_model_spec.R index 843fcdb..c3f0726 100644 --- a/R/ensemble_model_spec.R +++ b/R/ensemble_model_spec.R @@ -83,7 +83,7 @@ #' library(tidymodels) #' library(modeltime) #' library(modeltime.ensemble) -#' library(tidyverse) +#' library(dplyr) #' library(timetk) #' #' # Step 1: Make resample predictions for submodels @@ -146,7 +146,7 @@ ensemble_model_spec <- function(object, if (rlang::is_missing(model_spec)) rlang::abort("'model_spec' must be provided. Try creating a model_spec using parsnip or modeltime models.") if (!inherits(model_spec, "model_spec")) rlang::abort("'model_spec' must be a `model_spec` object. Try creating a model_spec using parsnip or modeltime models.") - if (is.null(model_spec$engine)) rlang::abort("'model_spec' does not have an engine set. Try setting an engine using `parsnip::set_engine()`.") + if (is.null(model_spec$engine)) cli::cli_abort("'model_spec' does not have an engine set. Try setting an engine using {.fn parsnip::set_engine}.") if (nrow(object) < 2) rlang::abort("An ensemble requires two or more models in the Modeltime Table.") @@ -213,11 +213,9 @@ print.mdl_time_ensemble_model_spec <- function(x, ...) { print(cli::rule("Modeltime Ensemble", width = min(65, cli::console_width()))) desc <- x$fit$fit %>% modeltime::get_model_description() - msg <- glue::glue("Ensemble of {x$n_models} Models ({stringr::str_c(desc, ' STACK')})") + msg <- cli::format_inline("Ensemble of {x$n_models} Models ({stringr::str_c(desc, ' STACK')})") - print(msg) - - cli::cat_line() + cat(msg, "\n\n") print(x$model_tbl) diff --git a/R/ensemble_weighted.R b/R/ensemble_weighted.R index 6c2431b..3bd20b0 100644 --- a/R/ensemble_weighted.R +++ b/R/ensemble_weighted.R @@ -27,7 +27,7 @@ #' library(tidymodels) #' library(modeltime) #' library(modeltime.ensemble) -#' library(tidyverse) +#' library(dplyr) #' library(timetk) #' #' # Make an ensemble from a Modeltime Table @@ -117,11 +117,9 @@ print.mdl_time_ensemble_wt <- function(x, ...) { print(cli::rule("Modeltime Ensemble", width = min(65, cli::console_width()))) - msg <- glue::glue("Ensemble of {x$n_models} Models (WEIGHTED)") + msg <- cli::format_inline("Ensemble of {x$n_models} Models (WEIGHTED)") - print(msg) - - cli::cat_line() + cat(msg, "\n\n") print(dplyr::left_join(x$model_tbl, x$fit$loadings_tbl, by = ".model_id")) diff --git a/R/nested_ensemble_average.R b/R/nested_ensemble_average.R index a4e8f39..7022745 100644 --- a/R/nested_ensemble_average.R +++ b/R/nested_ensemble_average.R @@ -336,7 +336,7 @@ ensemble_nested_average_parallel <- function(object, utils::capture.output() %>% stringr::str_remove("Time difference of ") - if (control$verbose) cli::cli_inform(stringr::str_glue("Finished in: {time_elapsed}.")) + if (control$verbose) cli::cli_inform("Finished in: {time_elapsed}.") # STRUCTURE ---- diff --git a/R/tibble-type_sum.R b/R/tibble-type_sum.R index f7de535..3e32b66 100644 --- a/R/tibble-type_sum.R +++ b/R/tibble-type_sum.R @@ -2,7 +2,7 @@ #' @importFrom tibble type_sum #' @export type_sum.mdl_time_ensemble <- function(x) { - glue::glue("ensemble [{x$n_models}]") + cli::cli_text("ensemble [{x$n_models}]") } diff --git a/README.Rmd b/README.Rmd index b869bb3..96b2526 100644 --- a/README.Rmd +++ b/README.Rmd @@ -23,8 +23,9 @@ knitr::opts_chunk$set( [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/modeltime.ensemble)](https://cran.r-project.org/package=modeltime.ensemble) ![](http://cranlogs.r-pkg.org/badges/modeltime.ensemble?color=brightgreen) ![](http://cranlogs.r-pkg.org/badges/grand-total/modeltime.ensemble?color=brightgreen) -[![R-CMD-check](https://github.com/business-science/modeltime.ensemble/workflows/R-CMD-check/badge.svg)](https://github.com/business-science/modeltime.ensemble/actions) +[![R-CMD-check](https://github.com/business-science/modeltime.ensemble/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/business-science/modeltime.ensemble/actions/workflows/R-CMD-check.yaml) [![Codecov test coverage](https://codecov.io/gh/business-science/modeltime.ensemble/branch/master/graph/badge.svg)](https://app.codecov.io/gh/business-science/modeltime.ensemble?branch=master) + @@ -64,7 +65,7 @@ Load the following libraries. library(tidymodels) library(modeltime) library(modeltime.ensemble) -library(tidyverse) +library(dplyr) library(timetk) ``` diff --git a/README.md b/README.md index 9dfcf4b..48e8105 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,13 @@ -[![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version/modeltime.ensemble)](https://cran.r-project.org/package=modeltime.ensemble) +[![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/modeltime.ensemble)](https://cran.r-project.org/package=modeltime.ensemble) ![](http://cranlogs.r-pkg.org/badges/modeltime.ensemble?color=brightgreen) ![](http://cranlogs.r-pkg.org/badges/grand-total/modeltime.ensemble?color=brightgreen) -[![R-CMD-check](https://github.com/business-science/modeltime.ensemble/workflows/R-CMD-check/badge.svg)](https://github.com/business-science/modeltime.ensemble/actions) +[![R-CMD-check](https://github.com/business-science/modeltime.ensemble/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/business-science/modeltime.ensemble/actions/workflows/R-CMD-check.yaml) [![Codecov test coverage](https://codecov.io/gh/business-science/modeltime.ensemble/branch/master/graph/badge.svg)](https://app.codecov.io/gh/business-science/modeltime.ensemble?branch=master) + > Ensemble Algorithms for Time Series Forecasting with Modeltime @@ -51,7 +52,7 @@ Load the following libraries. library(tidymodels) library(modeltime) library(modeltime.ensemble) -library(tidyverse) +library(dplyr) library(timetk) ``` @@ -80,7 +81,7 @@ ensemble_fit <- m750_models %>% ensemble_fit #> ── Modeltime Ensemble ─────────────────────────────────────────── -#> Ensemble of 3 Models (MEAN) +#> Ensemble of 3 Models (MEAN) #> #> # Modeltime Table #> # A tibble: 3 × 3 @@ -130,23 +131,23 @@ The modeltime ecosystem is growing Modeltime is part of a **growing ecosystem** of Modeltime forecasting packages. -- [Modeltime (Machine - Learning)](https://business-science.github.io/modeltime/) +- [Modeltime (Machine + Learning)](https://business-science.github.io/modeltime/) -- [Modeltime H2O - (AutoML)](https://business-science.github.io/modeltime.h2o/) +- [Modeltime H2O + (AutoML)](https://business-science.github.io/modeltime.h2o/) -- [Modeltime GluonTS (Deep - Learning)](https://business-science.github.io/modeltime.gluonts/) +- [Modeltime GluonTS (Deep + Learning)](https://business-science.github.io/modeltime.gluonts/) -- [Modeltime Ensemble (Blending - Forecasts)](https://business-science.github.io/modeltime.ensemble/) +- [Modeltime Ensemble (Blending + Forecasts)](https://business-science.github.io/modeltime.ensemble/) -- [Modeltime Resample - (Backtesting)](https://business-science.github.io/modeltime.resample/) +- [Modeltime Resample + (Backtesting)](https://business-science.github.io/modeltime.resample/) -- [Timetk (Feature Engineering, Data Wrangling, Time Series - Visualization)](https://business-science.github.io/timetk/) +- [Timetk (Feature Engineering, Data Wrangling, Time Series + Visualization)](https://business-science.github.io/timetk/) ## Take the High-Performance Forecasting Course @@ -176,17 +177,17 @@ Series Forecasting Course**](https://university.business-science.io/p/ds4b-203-r-high-performance-time-series-forecasting). You will learn: -- **Time Series Machine Learning** (cutting-edge) with `Modeltime` - - 30+ Models (Prophet, ARIMA, XGBoost, Random Forest, & many more) -- **Deep Learning** with `GluonTS` (Competition Winners) -- **Time Series Preprocessing**, Noise Reduction, & Anomaly Detection -- **Feature engineering** using lagged variables & external regressors -- **Hyperparameter Tuning** -- **Time series cross-validation** -- **Ensembling** Multiple Machine Learning & Univariate Modeling - Techniques (Competition Winner) -- **Scalable Forecasting** - Forecast 1000+ time series in parallel -- and more. +- **Time Series Machine Learning** (cutting-edge) with `Modeltime` - 30+ + Models (Prophet, ARIMA, XGBoost, Random Forest, & many more) +- **Deep Learning** with `GluonTS` (Competition Winners) +- **Time Series Preprocessing**, Noise Reduction, & Anomaly Detection +- **Feature engineering** using lagged variables & external regressors +- **Hyperparameter Tuning** +- **Time series cross-validation** +- **Ensembling** Multiple Machine Learning & Univariate Modeling + Techniques (Competition Winner) +- **Scalable Forecasting** - Forecast 1000+ time series in parallel +- and more.

Become the Time Series Expert for your organization. diff --git a/_pkgdown.yml b/_pkgdown.yml index ef0d781..6e894fc 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -77,7 +77,6 @@ reference: - "ensemble_average" - "ensemble_weighted" - "ensemble_model_spec" - - "modeltime_fit_resamples" - title: Nested Ensemble Forecasting desc: Make ensembles with the nested forecasting workflow contents: diff --git a/man/ensemble_average.Rd b/man/ensemble_average.Rd index 598b3ef..3858aa9 100644 --- a/man/ensemble_average.Rd +++ b/man/ensemble_average.Rd @@ -36,7 +36,7 @@ underlying models forecast at each timestamp library(tidymodels) library(modeltime) library(modeltime.ensemble) -library(tidyverse) +library(dplyr) library(timetk) # Make an ensemble from a Modeltime Table diff --git a/man/ensemble_model_spec.Rd b/man/ensemble_model_spec.Rd index 41589fd..5b1556c 100644 --- a/man/ensemble_model_spec.Rd +++ b/man/ensemble_model_spec.Rd @@ -103,7 +103,7 @@ up parallelization using \code{tune} via one of the backends such as library(tidymodels) library(modeltime) library(modeltime.ensemble) -library(tidyverse) +library(dplyr) library(timetk) # Step 1: Make resample predictions for submodels diff --git a/man/ensemble_weighted.Rd b/man/ensemble_weighted.Rd index c4d4348..aec1df4 100644 --- a/man/ensemble_weighted.Rd +++ b/man/ensemble_weighted.Rd @@ -34,7 +34,7 @@ The weighted method uses uses \code{loadings} by applying a library(tidymodels) library(modeltime) library(modeltime.ensemble) -library(tidyverse) +library(dplyr) library(timetk) # Make an ensemble from a Modeltime Table diff --git a/modeltime.ensemble.Rproj b/modeltime.ensemble.Rproj index c690b7c..09608cf 100644 --- a/modeltime.ensemble.Rproj +++ b/modeltime.ensemble.Rproj @@ -19,3 +19,7 @@ BuildType: Package PackageUseDevtools: Yes PackageInstallArgs: --no-multiarch --with-keep.source PackageRoxygenize: rd,collate,namespace + +UseNativePipeOperator: No + +SpellingDictionary: en_US diff --git a/tests/testthat.R b/tests/testthat.R index b8b7c35..bfb81a2 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -8,11 +8,9 @@ library(modeltime.resample) # Model dependencies library(xgboost) -library(earth) library(glmnet) # Core Packages -library(tidyverse) library(timetk) library(lubridate) diff --git a/tests/testthat/test-conf_by_id.R b/tests/testthat/test-conf_by_id.R index ccae134..b278545 100644 --- a/tests/testthat/test-conf_by_id.R +++ b/tests/testthat/test-conf_by_id.R @@ -8,12 +8,10 @@ test_that("Accuracy & CI by ID", { library(tidymodels) library(timetk) library(modeltime) - library(tidyverse) # Data data <- walmart_sales_weekly %>% - select(id, Date, Weekly_Sales) %>% - set_names(c("ID", "date", "value")) + dplyr::select(ID = id, date = Date, value = Weekly_Sales) splits <- data %>% time_series_split(assess = "3 months", cumulative = TRUE) diff --git a/tests/testthat/test-ensemble_average.R b/tests/testthat/test-ensemble_average.R index 100fff8..b42479f 100644 --- a/tests/testthat/test-ensemble_average.R +++ b/tests/testthat/test-ensemble_average.R @@ -54,7 +54,7 @@ m750_models_2 <- modeltime_table( # Median ---- test_that("ensemble_average(type = 'median')", { - testthat::skip_on_cran() + skip_on_cran() ensemble_fit_median <- m750_models_2 %>% ensemble_average(type = "median") diff --git a/tests/testthat/test-ensemble_model_spec.R b/tests/testthat/test-ensemble_model_spec.R index ff42a0f..9f86728 100644 --- a/tests/testthat/test-ensemble_model_spec.R +++ b/tests/testthat/test-ensemble_model_spec.R @@ -50,7 +50,7 @@ m750_models_2 <- modeltime_table( # SETUP ---- -testthat::test_that("ensemble_model_spec", { +test_that("ensemble_model_spec", { skip_on_cran() diff --git a/tests/testthat/test-nested-ensembles.R b/tests/testthat/test-nested-ensembles.R index 881b5c6..237d075 100644 --- a/tests/testthat/test-nested-ensembles.R +++ b/tests/testthat/test-nested-ensembles.R @@ -1,11 +1,10 @@ context("TEST: nested ensembles") # 1- SEQUENTIAL ---- -testthat::test_that("Nested Ensembles Work - sequential", { +test_that("Nested Ensembles Work - sequential", { data_tbl <- walmart_sales_weekly %>% - select(id, Date, Weekly_Sales) %>% - set_names(c("id", "date", "value")) %>% + select(id, date = Date, value = Weekly_Sales) %>% filter(id %in% c("1_1", "1_3")) nested_data_tbl <- data_tbl %>% @@ -59,7 +58,7 @@ testthat::test_that("Nested Ensembles Work - sequential", { # EXPECT WARNING DUE TO BAD MODEL ---- - testthat::expect_warning({ + expect_warning({ nested_modeltime_tbl <- modeltime_nested_fit( # Nested data nested_data = nested_data_tbl, @@ -86,7 +85,7 @@ testthat::test_that("Nested Ensembles Work - sequential", { model_table <- nested_ensemble_1_tbl %>% extract_nested_modeltime_table() - testthat::expect_equal( + expect_equal( model_table$.model_desc[4], "ENSEMBLE (MEAN): 2 MODELS" ) @@ -94,10 +93,7 @@ testthat::test_that("Nested Ensembles Work - sequential", { extract_nested_test_accuracy() %>% filter(.model_desc == "ENSEMBLE (MEAN): 2 MODELS") - testthat::expect_is( - model_accuracy %>% pull(mae), - "numeric" - ) + expect_type(model_accuracy$mae, "double") # Weighted Ensemble ---- @@ -115,15 +111,8 @@ testthat::test_that("Nested Ensembles Work - sequential", { extract_nested_modeltime_table(1) %>% pluck(".model", 5, "fit", "loadings_tbl") - testthat::expect_is( - loadings_tbl$.loadings, - "numeric" - ) - - testthat::expect_equal( - length(loadings_tbl$.loadings), - 2 - ) + expect_type(loadings_tbl$.loadings, "double") + expect_length(loadings_tbl$.loadings, 2) # * TEST LOADINGS TOO SHORT ---- nested_ensemble_2_tbl <- nested_ensemble_1_tbl %>% @@ -139,15 +128,8 @@ testthat::test_that("Nested Ensembles Work - sequential", { extract_nested_modeltime_table(1) %>% pluck(".model", 5, "fit", "loadings_tbl") - testthat::expect_is( - loadings_tbl$.loadings, - "numeric" - ) - - testthat::expect_equal( - length(loadings_tbl$.loadings), - 1 - ) + expect_type(loadings_tbl$.loadings, "double") + expect_length(loadings_tbl$.loadings, 1) # CHECK METRICS @@ -166,7 +148,7 @@ testthat::test_that("Nested Ensembles Work - sequential", { mutate(check = max(c_across(model_1:model_2))) %>% ungroup() - testthat::expect_equivalent(metrics_rsq$model_5, metrics_rsq$check) + expect_equal(metrics_rsq$model_5, metrics_rsq$check, check.attributes = FALSE) @@ -196,21 +178,20 @@ testthat::test_that("Nested Ensembles Work - sequential", { mutate(check = min(c_across(model_1:model_2))) %>% ungroup() - testthat::expect_equivalent(metrics_rmse$model_5, metrics_rmse$check) + expect_equal(metrics_rmse$model_5, metrics_rmse$check, check.attributes = FALSE) }) # 2. PARALLEL ---- -testthat::test_that("Nested Ensembles Work - parallel", { +test_that("Nested Ensembles Work - parallel", { - testthat::skip_on_cran() + skip_on_cran() parallel_start(2) data_tbl <- walmart_sales_weekly %>% - select(id, Date, Weekly_Sales) %>% - set_names(c("id", "date", "value")) %>% + select(id, date = Date, value = Weekly_Sales) %>% filter(id %in% c("1_1", "1_3")) nested_data_tbl <- data_tbl %>% @@ -264,7 +245,7 @@ testthat::test_that("Nested Ensembles Work - parallel", { # EXPECT WARNING DUE TO BAD MODEL ---- - testthat::expect_warning({ + expect_warning({ nested_modeltime_tbl <- modeltime_nested_fit( # Nested data nested_data = nested_data_tbl, @@ -291,7 +272,7 @@ testthat::test_that("Nested Ensembles Work - parallel", { model_table <- nested_ensemble_1_tbl %>% extract_nested_modeltime_table() - testthat::expect_equal( + expect_equal( model_table$.model_desc[4], "ENSEMBLE (MEAN): 2 MODELS" ) @@ -299,10 +280,7 @@ testthat::test_that("Nested Ensembles Work - parallel", { extract_nested_test_accuracy() %>% filter(.model_desc == "ENSEMBLE (MEAN): 2 MODELS") - testthat::expect_is( - model_accuracy %>% pull(mae), - "numeric" - ) + expect_type(model_accuracy$mae, "double") # Weighted Ensemble ---- @@ -320,15 +298,8 @@ testthat::test_that("Nested Ensembles Work - parallel", { extract_nested_modeltime_table(1) %>% pluck(".model", 5, "fit", "loadings_tbl") - testthat::expect_is( - loadings_tbl$.loadings, - "numeric" - ) - - testthat::expect_equal( - length(loadings_tbl$.loadings), - 2 - ) + expect_type(loadings_tbl$.loadings, "double") + expect_length(loadings_tbl$.loadings, 2) # * TEST LOADINGS TOO SHORT ---- nested_ensemble_2_tbl <- nested_ensemble_1_tbl %>% @@ -344,15 +315,8 @@ testthat::test_that("Nested Ensembles Work - parallel", { extract_nested_modeltime_table(1) %>% pluck(".model", 5, "fit", "loadings_tbl") - testthat::expect_is( - loadings_tbl$.loadings, - "numeric" - ) - - testthat::expect_equal( - length(loadings_tbl$.loadings), - 1 - ) + expect_type(loadings_tbl$.loadings, "double") + expect_length(loadings_tbl$.loadings, 1) # CHECK METRICS @@ -371,7 +335,7 @@ testthat::test_that("Nested Ensembles Work - parallel", { mutate(check = max(c_across(model_1:model_2))) %>% ungroup() - testthat::expect_equivalent(metrics_rsq$model_5, metrics_rsq$check) + expect_equal(metrics_rsq$model_5, metrics_rsq$check, check.attributes = FALSE) @@ -401,7 +365,7 @@ testthat::test_that("Nested Ensembles Work - parallel", { mutate(check = min(c_across(model_1:model_2))) %>% ungroup() - testthat::expect_equivalent(metrics_rmse$model_5, metrics_rmse$check) + expect_equal(metrics_rmse$model_5, metrics_rmse$check, check.attributes = FALSE) parallel_stop() diff --git a/tests/testthat/test-panel-data.R b/tests/testthat/test-panel-data.R index 23b2bf2..0c80077 100644 --- a/tests/testthat/test-panel-data.R +++ b/tests/testthat/test-panel-data.R @@ -59,14 +59,14 @@ test_that("ensemble_average(): Forecast Jumbled", { modeltime_calibrate(data_set) expect_equal(calibration_tbl$.type, c("Test")) - expect_true(all(c(".type", ".calibration_data") %in% names(calibration_tbl))) + expect_contains(names(calibration_tbl), c(".type", ".calibration_data")) expect_equal(nrow(data_set), calibration_tbl %>% pluck(".calibration_data", 1) %>% nrow()) # Accuracy accuracy_tbl <- calibration_tbl %>% modeltime_accuracy() - expect_true(all(!is.na(accuracy_tbl$mae))) + expect_false(anyNA(accuracy_tbl$mae)) expect_true(all(is.double(accuracy_tbl$mae))) expect_true(accuracy_tbl$mae < 500) @@ -122,14 +122,14 @@ test_that("ensemble_weighted(): Forecast Jumbled", { modeltime_calibrate(data_set) expect_equal(calibration_tbl$.type, c("Test")) - expect_true(all(c(".type", ".calibration_data") %in% names(calibration_tbl))) + expect_contains(names(calibration_tbl), c(".type", ".calibration_data")) expect_equal(nrow(data_set), calibration_tbl %>% pluck(".calibration_data", 1) %>% nrow()) # Accuracy accuracy_tbl <- calibration_tbl %>% modeltime_accuracy() - expect_true(all(!is.na(accuracy_tbl$mae))) + expect_false(anyNA(accuracy_tbl$mae)) expect_true(all(is.double(accuracy_tbl$mae))) expect_true(accuracy_tbl$mae < 400) @@ -195,14 +195,14 @@ test_that("ensemble_model_spec(): Forecast Jumbled", { modeltime_calibrate(data_set, quiet = FALSE) expect_equal(calibration_tbl$.type, c("Test")) - expect_true(all(c(".type", ".calibration_data") %in% names(calibration_tbl))) + expect_contains(names(calibration_tbl), c(".type", ".calibration_data")) expect_equal(nrow(data_set), calibration_tbl %>% pluck(".calibration_data", 1) %>% nrow()) # Accuracy accuracy_tbl <- calibration_tbl %>% modeltime_accuracy() - expect_true(all(!is.na(accuracy_tbl$mae))) + expect_false(anyNA(accuracy_tbl$mae)) expect_true(all(is.double(accuracy_tbl$mae))) # * Forecast ---- diff --git a/tests/testthat/test-recursive.R b/tests/testthat/test-recursive.R index 7ec70f8..07257cd 100644 --- a/tests/testthat/test-recursive.R +++ b/tests/testthat/test-recursive.R @@ -4,7 +4,7 @@ context("TEST: RECURSIVE ENSEMBLES") # SINGLE / RECIPE / PARSNIP ---- test_that("recursive ensemble 1 - single / recipe / parsnip", { - + skip_if_not_installed("earth") FORECAST_HORIZON <- 24 m750_extended <- m750 %>% @@ -23,10 +23,10 @@ test_that("recursive ensemble 1 - single / recipe / parsnip", { m750_lagged <- recipe_lag %>% prep() %>% juice() train_data <- m750_lagged %>% - drop_na() + tidyr::drop_na() future_data <- m750_lagged %>% - filter(is.na(value)) + dplyr::filter(is.na(value)) # * Recursive Modeling ---- @@ -75,7 +75,7 @@ test_that("recursive ensemble 1 - single / recipe / parsnip", { # * Modeltime Refit ---- - retrain_tbl <- m750_lagged %>% dplyr::slice(1:200) %>% drop_na() + retrain_tbl <- m750_lagged %>% dplyr::slice(1:200) %>% tidyr::drop_na() future_tbl <- m750_lagged %>% dplyr::slice(201:224) refit_tbl <- modeltime_table( @@ -108,7 +108,7 @@ test_that("recursive ensemble 1 - single / recipe / parsnip", { # PANEL / FUNCTION / PARSNIP & WORKFLOW ---- test_that("recursive ensemble 2 - panel / function / parsnip + workflow", { - + skip_if_not_installed("earth") # Jumble the data to make sure it forecasts properly FORECAST_HORIZON <- 24 @@ -132,10 +132,10 @@ test_that("recursive ensemble 2 - panel / function / parsnip + workflow", { lag_transformer_grouped() train_data <- m4_lags %>% - drop_na() + tidyr::drop_na() future_data <- m4_lags %>% - filter(is.na(value)) + dplyr::filter(is.na(value)) # * Recursive Modeling ---- @@ -186,7 +186,7 @@ test_that("recursive ensemble 2 - panel / function / parsnip + workflow", { ) %>% modeltime_forecast( new_data = future_data, - actual_data = m4_lags %>% drop_na(), + actual_data = tidyr::drop_na(m4_lags), keep_data = TRUE ) @@ -214,7 +214,7 @@ test_that("recursive ensemble 2 - panel / function / parsnip + workflow", { forecast_refit_tbl <- refit_tbl %>% modeltime_forecast( new_data = future_data, - actual_data = m4_lags %>% drop_na(), + actual_data = tidyr::drop_na(m4_lags), keep_data = TRUE ) diff --git a/vignettes/getting-started-with-modeltime-ensemble.Rmd b/vignettes/getting-started-with-modeltime-ensemble.Rmd index 785e19c..9754d6d 100644 --- a/vignettes/getting-started-with-modeltime-ensemble.Rmd +++ b/vignettes/getting-started-with-modeltime-ensemble.Rmd @@ -42,7 +42,7 @@ Note that `modeltime.ensemble` has capabilities for more sophisticated model ens Load libraries to complete this short tutorial. -```{r setup} +```r # Time Series ML library(tidymodels) library(modeltime) @@ -55,6 +55,19 @@ library(timetk) interactive <- FALSE ``` +```{r setup, include=FALSE,echo=FALSE} +# Time Series ML +library(tidymodels) +library(modeltime) +library(modeltime.ensemble) + +# Core +library(dplyr) +library(timetk) + +interactive <- FALSE +``` + ## Collect the Data We'll use the `m750` dataset that comes with `modeltime.ensemble`. We can visualize the dataset. diff --git a/vignettes/nested-ensembles.Rmd b/vignettes/nested-ensembles.Rmd index 69f3795..040b7c4 100644 --- a/vignettes/nested-ensembles.Rmd +++ b/vignettes/nested-ensembles.Rmd @@ -60,7 +60,7 @@ Load the following libraries. library(tidymodels) library(modeltime) library(modeltime.ensemble) -library(tidyverse) +library(dplyr) library(timetk) library(gt) ``` @@ -71,8 +71,7 @@ Read in the Walmart Sales Weekly data (comes with `timetk`). ```{r} data_tbl <- walmart_sales_weekly %>% - select(id, Date, Weekly_Sales) %>% - set_names(c("id", "date", "value")) %>% + select(id, date = Date, value = Weekly_Sales) %>% filter(id %in% c("1_1", "1_3")) data_tbl @@ -217,8 +216,8 @@ tab_style_by_group <- function(object, ..., style) { style = style, locations = cells_body( rows = .[["_data"]] %>% - rowid_to_column("rowid") %>% - group_by(!! grp_col) %>% + tibble::rowid_to_column("rowid") %>% + group_by(!!grp_col) %>% filter(...) %>% ungroup() %>% pull(rowid) diff --git a/vignettes/recursive-ensembles.Rmd b/vignettes/recursive-ensembles.Rmd index ae0fc98..df96114 100644 --- a/vignettes/recursive-ensembles.Rmd +++ b/vignettes/recursive-ensembles.Rmd @@ -51,10 +51,9 @@ First, we need to load the necessary libraries: library(modeltime.ensemble) library(modeltime) library(tidymodels) -library(earth) library(glmnet) library(xgboost) -library(tidyverse) +library(dplyr) library(lubridate) library(timetk) ``` @@ -91,7 +90,7 @@ We divide the data set into training dataset and future dataset: ```{r} train_data <- m750_lagged %>% filter(!is.na(value)) %>% - drop_na() + tidyr::drop_na() future_data <- m750_lagged %>% filter(is.na(value)) @@ -104,7 +103,7 @@ Next, we are going to create two models that we will then join into an ensemble. In a real scenario, we would typically do a pre-selection work where we would analyze more models and keep those with better performance to make the ensemble. -```{r} +```{r,eval=rlang::is_installed("earth")} model_fit_lm <- linear_reg() %>% set_engine("lm") %>% fit(value ~ ., data = train_data %>% select(-id)) @@ -204,7 +203,7 @@ We split into training data and future data. ```{r} train_data <- m4_lags %>% - drop_na() + tidyr::drop_na() future_data <- m4_lags %>% filter(is.na(value))