├── .Rbuildignore ├── .git-blame-ignore-revs ├── .github ├── .gitignore ├── CODEOWNERS ├── pull_request_template.md └── workflows │ ├── R-CMD-check.yaml │ ├── doc-preview.yaml │ ├── pkgdown.yaml │ └── pr-commands.yaml ├── .gitignore ├── .lintr ├── DESCRIPTION ├── DEVELOPMENT.md ├── LICENSE ├── LICENSE.md ├── NAMESPACE ├── NEWS.md ├── R ├── arx_classifier.R ├── arx_forecaster.R ├── autoplot.R ├── blueprint-epi_recipe-default.R ├── canned-epipred.R ├── cdc_baseline_forecaster.R ├── check_enough_data.R ├── climatological_forecaster.R ├── compat-purrr.R ├── compat-recipes.R ├── epi_check_training_set.R ├── epi_recipe.R ├── epi_selectors.R ├── epi_shift.R ├── epi_workflow.R ├── epipredict-package.R ├── extract.R ├── extrapolate_quantiles.R ├── flatline.R ├── flatline_forecaster.R ├── flusight_hub_formatter.R ├── frosting.R ├── get_test_data.R ├── import-standalone-purrr.R ├── key_colnames.R ├── layer_add_forecast_date.R ├── layer_add_target_date.R ├── layer_cdc_flatline_quantiles.R ├── layer_naomit.R ├── layer_point_from_distn.R ├── layer_population_scaling.R ├── layer_predict.R ├── layer_predictive_distn.R ├── layer_quantile_distn.R ├── layer_residual_quantiles.R ├── layer_threshold_preds.R ├── layer_unnest.R ├── layers.R ├── make_flatline_reg.R ├── make_grf_quantiles.R ├── make_quantile_reg.R ├── make_smooth_quantile_reg.R ├── model-methods.R ├── pivot_quantiles.R ├── print_epi_step.R ├── print_layer.R ├── quantile_pred-methods.R ├── reexports-tidymodels.R ├── reexports.R ├── step_adjust_latency.R ├── step_climate.R ├── step_epi_naomit.R ├── step_epi_shift.R ├── step_epi_slide.R ├── step_growth_rate.R ├── step_lag_difference.R ├── step_population_scaling.R ├── step_training_window.R ├── tidy.R ├── time_types.R ├── utils-arg.R ├── utils-latency.R ├── utils-misc.R ├── utils-pipe.R ├── weighted_interval_score.R ├── workflow-printing.R └── zzz.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── epipredict.Rproj ├── inst └── other-vignettes │ └── symptom-surveys.Rmd ├── man-roxygen └── step-return.R ├── man ├── Add_model.Rd ├── add_epi_recipe.Rd ├── add_frosting.Rd ├── add_layer.Rd ├── add_shifted_columns.Rd ├── adjust_epi_recipe.Rd ├── adjust_frosting.Rd ├── apply_frosting.Rd ├── arx_args_list.Rd ├── arx_class_args_list.Rd ├── arx_class_epi_workflow.Rd ├── arx_classifier.Rd ├── arx_fcast_epi_workflow.Rd ├── arx_forecaster.Rd ├── augment.epi_workflow.Rd ├── autoplot-epipred.Rd ├── cdc_baseline_args_list.Rd ├── cdc_baseline_forecaster.Rd ├── check_enough_data.Rd ├── check_interminable_latency.Rd ├── clean_f_name.Rd ├── climate_args_list.Rd ├── climatological_forecaster.Rd ├── construct_shift_tibble.Rd ├── count_single_column.Rd ├── dist_quantiles.Rd ├── drop_ignored_keys.Rd ├── epi_recipe.Rd ├── epi_shift_single.Rd ├── epi_slide_wrapper.Rd ├── epi_workflow.Rd ├── epiweek_leap.Rd ├── extract_argument.Rd ├── extract_frosting.Rd ├── extrapolate_quantiles.Rd ├── figures │ ├── lifecycle-archived.svg │ ├── lifecycle-defunct.svg │ ├── lifecycle-deprecated.svg │ ├── lifecycle-experimental.svg │ ├── lifecycle-maturing.svg │ ├── lifecycle-questioning.svg │ ├── lifecycle-soft-deprecated.svg │ ├── lifecycle-stable.svg │ └── lifecycle-superseded.svg ├── fit-epi_workflow.Rd ├── flatline.Rd ├── flatline_args_list.Rd ├── flatline_forecaster.Rd ├── flusight_hub_formatter.Rd ├── forecast.epi_workflow.Rd ├── format_varnames.Rd ├── frosting.Rd ├── get_forecast_date.Rd ├── get_forecast_date_in_layer.Rd ├── get_latency.Rd ├── get_latency_table.Rd ├── get_sign.Rd ├── get_test_data.Rd ├── grf_quantiles.Rd ├── is_epi_recipe.Rd ├── is_epi_workflow.Rd ├── isoweek_leap.Rd ├── layer-processors.Rd ├── layer.Rd ├── layer_add_forecast_date.Rd ├── layer_add_target_date.Rd ├── layer_cdc_flatline_quantiles.Rd ├── layer_naomit.Rd ├── layer_point_from_distn.Rd ├── layer_population_scaling.Rd ├── layer_predict.Rd ├── layer_predictive_distn.Rd ├── layer_quantile_distn.Rd ├── layer_residual_quantiles.Rd ├── layer_threshold.Rd ├── layer_unnest.Rd ├── nested_quantiles.Rd ├── new_epi_recipe_blueprint.Rd ├── pad_to_end.Rd ├── pipe.Rd ├── pivot_quantiles_longer.Rd ├── pivot_quantiles_wider.Rd ├── predict-epi_workflow.Rd ├── quantile.quantile_pred.Rd ├── quantile_reg.Rd ├── reexports.Rd ├── roll_modular_multivec.Rd ├── seq_forward.Rd ├── slather.Rd ├── smooth_quantile_reg.Rd ├── snap.Rd ├── step_adjust_latency.Rd ├── step_adjust_latency_checks.Rd ├── step_climate.Rd ├── step_epi_naomit.Rd ├── step_epi_shift.Rd ├── step_epi_slide.Rd ├── step_growth_rate.Rd ├── step_lag_difference.Rd ├── step_population_scaling.Rd ├── step_training_window.Rd ├── tidy.frosting.Rd ├── update.layer.Rd ├── weighted_interval_score.Rd └── yday_leap.Rd ├── tests ├── testthat.R └── testthat │ ├── _snaps │ ├── arg_is_.md │ ├── arx_args_list.md │ ├── arx_cargs_list.md │ ├── bake-method.md │ ├── check-training-set.md │ ├── check_enough_data.md │ ├── climatological_forecaster.md │ ├── epi_recipe.md │ ├── epi_workflow.md │ ├── extract_argument.md │ ├── flatline_args_list.md │ ├── frosting.md │ ├── get_test_data.md │ ├── layer_add_forecast_date.md │ ├── layer_add_target_date.md │ ├── layer_residual_quantiles.md │ ├── layers.md │ ├── parse_period.md │ ├── parsnip_model_validation.md │ ├── pivot_quantiles.md │ ├── population_scaling.md │ ├── quantile_pred.md │ ├── shuffle.md │ ├── snapshots.md │ ├── step_adjust_latency.md │ ├── step_epi_naomit.md │ ├── step_epi_shift.md │ ├── step_epi_slide.md │ ├── step_growth_rate.md │ ├── step_lag_difference.md │ └── wis-quantile_pred.md │ ├── test-arg_is_.R │ ├── test-arx_args_list.R │ ├── test-arx_cargs_list.R │ ├── test-arx_forecaster.R │ ├── test-bake-method.R │ ├── test-blueprint.R │ ├── test-check-training-set.R │ ├── test-check_enough_data.R │ ├── test-climatological_forecaster.R │ ├── test-epi_recipe.R │ ├── test-epi_shift.R │ ├── test-epi_workflow.R │ ├── test-extract_argument.R │ ├── test-flatline_args_list.R │ ├── test-frosting.R │ ├── test-get_test_data.R │ ├── test-grf_quantiles.R │ ├── test-key_colnames.R │ ├── test-layer_add_forecast_date.R │ ├── test-layer_add_target_date.R │ ├── test-layer_naomit.R │ ├── test-layer_predict.R │ ├── test-layer_residual_quantiles.R │ ├── test-layer_threshold_preds.R │ ├── test-layers.R │ ├── test-parse_period.R │ ├── test-parsnip_model_validation.R │ ├── test-pivot_quantiles.R │ ├── test-population_scaling.R │ ├── test-quantile_pred.R │ ├── test-replace_Inf.R │ ├── test-shuffle.R │ ├── test-snapshots.R │ ├── test-step_adjust_latency.R │ ├── test-step_climate.R │ ├── test-step_epi_naomit.R │ ├── test-step_epi_shift.R │ ├── test-step_epi_slide.R │ ├── test-step_growth_rate.R │ ├── test-step_lag_difference.R │ ├── test-step_training_window.R │ ├── test-target_date_bug.R │ ├── test-utils_latency.R │ └── test-wis-quantile_pred.R └── vignettes ├── .gitignore ├── _common.R ├── articles ├── smooth-qr.Rmd ├── smooth-qr_baseline_preds.rds └── smooth-qr_smooth_preds_list.rds ├── arx-classifier.Rmd ├── backtesting.Rmd ├── epipredict.Rmd ├── panel-data.Rmd ├── preprocessing-and-models.Rmd └── update.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^renv$ 2 | ^renv\.lock$ 3 | ^epipredict\.Rproj$ 4 | ^\.Rproj\.user$ 5 | ^LICENSE\.md$ 6 | ^DEVELOPMENT\.md$ 7 | ^drafts$ 8 | ^\.Rprofile$ 9 | ^man-roxygen$ 10 | ^README\.Rmd$ 11 | ^\.github$ 12 | ^_pkgdown\.yml$ 13 | ^docs$ 14 | ^pkgdown$ 15 | ^musings$ 16 | ^data-raw$ 17 | ^vignettes/articles$ 18 | ^.git-blame-ignore-revs$ 19 | ^DEVELOPMENT\.md$ 20 | ^doc$ 21 | ^Meta$ 22 | ^.lintr$ 23 | ^.venv$ 24 | ^inst/templates$ 25 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # using styler at all 2 | aca7d5e7b66d8bac9d9fbcec3acdb98a087d58fa 3 | f12fcc2bf3fe0a75ba2b10eaaf8a1f1d22486a17 4 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @dajmcdon 2 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Checklist 2 | 3 | Please: 4 | 5 | - [ ] Make sure this PR is against "dev", not "main". 6 | - [ ] Request a review from one of the current epipredict main reviewers: 7 | dajmcdon. 8 | - [ ] Make sure to bump the version number in `DESCRIPTION` and `NEWS.md`. 9 | Always increment the patch version number (the third number), unless you are 10 | making a release PR from dev to main, in which case increment the minor 11 | version number (the second number). 12 | - [ ] Describe changes made in NEWS.md, making sure breaking changes 13 | (backwards-incompatible changes to the documented interface) are noted. 14 | Collect the changes under the next release number (e.g. if you are on 15 | 0.7.2, then write your changes under the 0.8 heading). 16 | - [ ] Consider pinning the `epiprocess` version in the `DESCRIPTION` file if 17 | - You anticipate breaking changes in `epiprocess` soon 18 | - You want to co-develop features in `epipredict` and `epiprocess` 19 | 20 | ### Change explanations for reviewer 21 | 22 | ### Magic GitHub syntax to mark associated Issue(s) as resolved when this is merged into the default branch 23 | 24 | - Resolves #{issue number} 25 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | # 4 | # Created with usethis + edited to use API key. 5 | on: 6 | push: 7 | branches: [main, dev] 8 | pull_request: 9 | branches: [main, dev] 10 | 11 | name: R-CMD-check 12 | 13 | jobs: 14 | R-CMD-check: 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | R_KEEP_PKG_SOURCE: yes 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - uses: r-lib/actions/setup-r@v2 23 | with: 24 | use-public-rspm: true 25 | 26 | - uses: r-lib/actions/setup-r-dependencies@v2 27 | with: 28 | extra-packages: any::rcmdcheck 29 | needs: check 30 | 31 | - uses: r-lib/actions/check-r-package@v2 32 | env: 33 | DELPHI_EPIDATA_KEY: ${{ secrets.SECRET_EPIPREDICT_GHACTIONS_DELPHI_EPIDATA_KEY }} 34 | -------------------------------------------------------------------------------- /.github/workflows/doc-preview.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | issue_comment: 3 | types: [created] 4 | 5 | name: doc-preview.yaml 6 | 7 | permissions: read-all 8 | 9 | jobs: 10 | preview: 11 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'COLLABORATOR' || github.event.comment.author_association == 'CONTRIBUTOR' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/preview-docs') }} 12 | 13 | runs-on: ubuntu-latest 14 | permissions: 15 | # Needed to write a comment on the PR 16 | pull-requests: write 17 | # Needed to read the PR branch 18 | contents: read 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | # Checkout the PR branch 23 | ref: refs/pull/${{ github.event.issue.number }}/head 24 | 25 | - uses: r-lib/actions/setup-pandoc@v2 26 | 27 | - uses: r-lib/actions/setup-r@v2 28 | with: 29 | use-public-rspm: true 30 | 31 | - uses: r-lib/actions/setup-r-dependencies@v2 32 | with: 33 | extra-packages: any::pkgdown, local::. 34 | needs: website 35 | 36 | - name: Build site 37 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 38 | shell: Rscript {0} 39 | 40 | - name: Deploy to Netlify 41 | uses: nwtgck/actions-netlify@v3.0 42 | with: 43 | # Standard config 44 | github-token: ${{ secrets.GITHUB_TOKEN }} 45 | deploy-message: "Deploy from GitHub Actions" 46 | # 'docs/' is the default directory for pkgdown::build_site() 47 | # we add 'dev' because _pkgdown.yml has 'development: mode: devel' 48 | publish-dir: './docs/dev' 49 | # Development deploys only 50 | production-deploy: false 51 | # Enable pull request comment (default) 52 | enable-pull-request-comment: true 53 | # Overwrite the pull request comment with updated link (default) 54 | overwrites-pull-request-comment: true 55 | # Don't deploy to GitHub 56 | enable-github-deployment: false 57 | # Don't update the status of the commit 58 | enable-commit-status: false 59 | # Don't comment on the commit 60 | enable-commit-comment: false 61 | env: 62 | # Netlify credentials (currently from Dmitry's account) 63 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} 64 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} 65 | timeout-minutes: 1 66 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | # 4 | # Modifications: 5 | # * workflow_dispatch added to allow manual triggering of the workflow 6 | # * trigger branches changed 7 | # * API key secrets.SECRET_EPIPREDICT_GHACTIONS_DELPHI_EPIDATA_KEY 8 | on: 9 | push: 10 | branches: [main, dev] 11 | release: 12 | types: [published] 13 | workflow_dispatch: 14 | 15 | name: pkgdown 16 | 17 | jobs: 18 | pkgdown: 19 | # only build docs on the main repository and not forks 20 | if: github.repository_owner == 'cmu-delphi' 21 | runs-on: ubuntu-latest 22 | # Only restrict concurrency for non-PR jobs 23 | concurrency: 24 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 25 | env: 26 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 27 | DELPHI_EPIDATA_KEY: ${{ secrets.SECRET_EPIPREDICT_GHACTIONS_DELPHI_EPIDATA_KEY }} 28 | steps: 29 | - uses: actions/checkout@v4 30 | 31 | - uses: r-lib/actions/setup-pandoc@v2 32 | 33 | - uses: r-lib/actions/setup-r@v2 34 | with: 35 | use-public-rspm: true 36 | 37 | - uses: r-lib/actions/setup-r-dependencies@v2 38 | with: 39 | extra-packages: any::pkgdown, local::., any::cli 40 | needs: website 41 | 42 | - name: Build site 43 | # our versioning system+dev branch doesn't match the requirements for 44 | # develop mode = auto 45 | run: | 46 | target_ref <- "${{ github.event_name == 'pull_request' && github.base_ref || github.ref }}" 47 | override <- if (target_ref == "main" || target_ref == "refs/heads/main") { 48 | list(development = list(mode = "release")) 49 | } else if (target_ref == "dev" || target_ref == "refs/heads/dev") { 50 | list(development = list(mode = "devel")) 51 | } else { 52 | stop("Unexpected target_ref: ", target_ref) 53 | } 54 | pkg <- pkgdown::as_pkgdown(".", override = override) 55 | cli::cli_rule("Cleaning files from old site...") 56 | pkgdown::clean_site(pkg) 57 | pkgdown::build_site(pkg, preview = FALSE, install = FALSE, new_process = FALSE) 58 | pkgdown:::build_github_pages(pkg) 59 | shell: Rscript {0} 60 | 61 | - name: Deploy to GitHub pages 🚀 62 | if: github.event_name != 'pull_request' 63 | uses: JamesIves/github-pages-deploy-action@v4.5.0 64 | with: 65 | clean: false 66 | branch: gh-pages 67 | folder: docs 68 | -------------------------------------------------------------------------------- /.github/workflows/pr-commands.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | name: pr-commands.yaml 8 | 9 | permissions: read-all 10 | 11 | jobs: 12 | document: 13 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'COLLABORATOR' || github.event.comment.author_association == 'CONTRIBUTOR' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }} 14 | name: document 15 | runs-on: ubuntu-latest 16 | env: 17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 18 | permissions: 19 | contents: write 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - uses: r-lib/actions/pr-fetch@v2 24 | with: 25 | repo-token: ${{ secrets.GITHUB_TOKEN }} 26 | 27 | - uses: r-lib/actions/setup-r@v2 28 | with: 29 | use-public-rspm: true 30 | 31 | - uses: r-lib/actions/setup-r-dependencies@v2 32 | with: 33 | extra-packages: any::roxygen2 34 | needs: pr-document 35 | 36 | - name: Document 37 | run: roxygen2::roxygenise() 38 | shell: Rscript {0} 39 | 40 | - name: commit 41 | run: | 42 | git config --local user.name "$GITHUB_ACTOR" 43 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 44 | git add man/\* NAMESPACE 45 | git commit -m 'Document' 46 | 47 | - uses: r-lib/actions/pr-push@v2 48 | with: 49 | repo-token: ${{ secrets.GITHUB_TOKEN }} 50 | 51 | style: 52 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'COLLABORATOR' || github.event.comment.author_association == 'CONTRIBUTOR' || github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }} 53 | name: style 54 | runs-on: ubuntu-latest 55 | env: 56 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 57 | permissions: 58 | contents: write 59 | steps: 60 | - uses: actions/checkout@v4 61 | 62 | - uses: r-lib/actions/pr-fetch@v2 63 | with: 64 | repo-token: ${{ secrets.GITHUB_TOKEN }} 65 | 66 | - uses: r-lib/actions/setup-r@v2 67 | 68 | - name: Install dependencies 69 | run: install.packages("styler") 70 | shell: Rscript {0} 71 | 72 | - name: Style 73 | run: styler::style_pkg() 74 | shell: Rscript {0} 75 | 76 | - name: commit 77 | run: | 78 | git config --local user.name "$GITHUB_ACTOR" 79 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 80 | git add \*.R 81 | git commit -m 'Style' 82 | 83 | - uses: r-lib/actions/pr-push@v2 84 | with: 85 | repo-token: ${{ secrets.GITHUB_TOKEN }} 86 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | docs 6 | inst/doc 7 | .DS_Store 8 | /doc/ 9 | /Meta/ 10 | .Rprofile 11 | renv.lock 12 | renv/ 13 | .Renviron 14 | -------------------------------------------------------------------------------- /.lintr: -------------------------------------------------------------------------------- 1 | linters: linters_with_defaults( 2 | line_length_linter(120), 3 | cyclocomp_linter = NULL, 4 | object_length_linter(length = 40L) 5 | ) 6 | exclusions: list( 7 | "renv", 8 | "venv" 9 | ) 10 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: epipredict 2 | Title: Basic epidemiology forecasting methods 3 | Version: 0.1.15 4 | Authors@R: c( 5 | person("Daniel J.", "McDonald", , "daniel@stat.ubc.ca", role = c("aut", "cre")), 6 | person("Ryan", "Tibshirani", , "ryantibs@cmu.edu", role = "aut"), 7 | person("Dmitry", "Shemetov", , "dshemeto@andrew.cmu.edu", role = "aut"), 8 | person("David", "Weber", , "davidweb@andrew.cmu.edu", role = "aut"), 9 | person("Delphi Research Group", role = c("cph", "fnd")), 10 | person("Logan", "Brooks", role = "aut"), 11 | person("Rachel", "Lobay", role = "aut"), 12 | person("Maggie", "Liu", role = "ctb"), 13 | person("Ken", "Mawer", role = "ctb"), 14 | person("Chloe", "You", role = "ctb"), 15 | person("Jacob", "Bien", role = "ctb") 16 | ) 17 | Description: A forecasting "framework" for creating epidemiological 18 | forecasts from versioned data. The framework is designed to be modular 19 | so that different components can exchanged, enabling a large amount of 20 | flexibility. Some simple baseline models formed from these components 21 | are included. 22 | License: MIT + file LICENSE 23 | URL: https://github.com/cmu-delphi/epipredict/, 24 | https://cmu-delphi.github.io/epipredict 25 | BugReports: https://github.com/cmu-delphi/epipredict/issues/ 26 | Depends: 27 | epidatasets, 28 | parsnip (>= 1.0.0), 29 | R (>= 3.5.0) 30 | Imports: 31 | checkmate, 32 | cli, 33 | dplyr, 34 | epiprocess (>= 0.11.2), 35 | generics, 36 | ggplot2, 37 | glue, 38 | hardhat (>= 1.4.1), 39 | lifecycle, 40 | lubridate, 41 | magrittr, 42 | recipes (>= 1.0.4), 43 | rlang (>= 1.1.0), 44 | stats, 45 | tibble, 46 | tidyr, 47 | tidyselect, 48 | tsibble, 49 | vctrs, 50 | workflows (>= 1.0.0) 51 | Suggests: 52 | data.table, 53 | epidatr (>= 1.0.0), 54 | fs, 55 | grf, 56 | knitr, 57 | poissonreg, 58 | purrr, 59 | quantreg, 60 | ranger, 61 | RcppRoll, 62 | readr, 63 | rmarkdown, 64 | smoothqr, 65 | testthat (>= 3.0.0), 66 | usethis, 67 | xgboost 68 | VignetteBuilder: 69 | knitr 70 | Remotes: 71 | cmu-delphi/delphidocs, 72 | cmu-delphi/epidatasets, 73 | cmu-delphi/epidatr, 74 | cmu-delphi/epiprocess, 75 | dajmcdon/smoothqr 76 | Config/Needs/website: cmu-delphi/delphidocs 77 | Config/testthat/edition: 3 78 | Encoding: UTF-8 79 | Roxygen: list(markdown = TRUE) 80 | RoxygenNote: 7.3.2 81 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2022 2 | COPYRIGHT HOLDER: epipredict authors 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2022 epipredict authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /R/compat-purrr.R: -------------------------------------------------------------------------------- 1 | walk2 <- function(.x, .y, .f, ...) { 2 | map2(.x, .y, .f, ...) 3 | invisible(.x) 4 | } 5 | 6 | map_vec <- function(.x, .f, ...) { 7 | out <- map(.x, .f, ...) 8 | vctrs::list_unchop(out) 9 | } 10 | 11 | map_dfr <- function(.x, .f, ..., .id = NULL) { 12 | .f <- rlang::as_function(.f, env = rlang::global_env()) 13 | res <- map(.x, .f, ...) 14 | bind_rows(res, .id = .id) 15 | } 16 | 17 | map2_dfr <- function(.x, .y, .f, ..., .id = NULL) { 18 | .f <- rlang::as_function(.f, env = rlang::global_env()) 19 | res <- map2(.x, .y, .f, ...) 20 | bind_rows(res, .id = .id) 21 | } 22 | -------------------------------------------------------------------------------- /R/epi_check_training_set.R: -------------------------------------------------------------------------------- 1 | epi_check_training_set <- function(x, rec) { 2 | # Philosophy, allow the model to be fit with warnings, whenever possible. 3 | # If geo_type / time_type of the recipe and training data don't match 4 | # we proceed and warn. 5 | # If other_keys is missing from the training set, there are other issues. 6 | validate_meta_match(x, rec$template, "geo_type", "warn") 7 | validate_meta_match(x, rec$template, "time_type", "warn") 8 | 9 | # There are 3 possibilities. 10 | # 1. template has ok that are in x, but not labelled 11 | # 2. template has ok that are not in x 12 | # 3. x has ok that are not in template. Not a problem. 13 | old_ok <- attr(rec$template, "metadata")$other_keys 14 | new_ok <- attr(x, "metadata")$other_keys 15 | 16 | if (!is.null(old_ok)) { 17 | if (all(old_ok %in% colnames(x))) { # case 1 18 | if (!all(old_ok %in% new_ok)) { 19 | cli_warn(c( 20 | "The recipe specifies additional keys. Because these are available,", 21 | "they are being added to the metadata of the training data." 22 | )) 23 | attr(x, "metadata")$other_keys <- union(new_ok, old_ok) 24 | } 25 | } 26 | missing_ok <- setdiff(old_ok, colnames(x)) 27 | if (length(missing_ok) > 0) { # case 2 28 | cli_abort(c( 29 | "The recipe specifies keys which are not in the training data.", 30 | i = "The training set is missing columns for {missing_ok}." 31 | )) 32 | } 33 | } 34 | x 35 | } 36 | 37 | validate_meta_match <- function(x, template, meta, warn_or_abort = "warn") { 38 | new_meta <- attr(x, "metadata")[[meta]] 39 | old_meta <- attr(template, "metadata")[[meta]] 40 | msg <- c( 41 | "The `{meta}` of the training data appears to be different from that", 42 | "used to construct the recipe. This may result in unexpected consequences.", 43 | i = "Training `{meta}` is '{new_meta}'.", 44 | i = "Originally, it was '{old_meta}'." 45 | ) 46 | if (new_meta != old_meta) { 47 | switch(warn_or_abort, 48 | warn = cli_warn(msg), 49 | abort = cli_abort(msg) 50 | ) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /R/epi_selectors.R: -------------------------------------------------------------------------------- 1 | all_epi_keys <- function() { 2 | union(base_epi_keys(), has_role("key")) 3 | } 4 | 5 | base_epi_keys <- function() { 6 | union(has_role("time_value"), has_role("geo_value")) 7 | } 8 | -------------------------------------------------------------------------------- /R/epi_shift.R: -------------------------------------------------------------------------------- 1 | #' Shift predictors while maintaining grouping and time_value ordering 2 | #' 3 | #' This is a lower-level function. As such it performs no error checking. 4 | #' 5 | #' @param x Data frame. 6 | #' @param shift_val a single integer. Negative values produce leads. 7 | #' @param newname the name for the newly shifted column 8 | #' @param key_cols vector, or `NULL`. Additional grouping vars. 9 | #' 10 | #' @keywords internal 11 | #' 12 | #' @return a list of tibbles 13 | epi_shift_single <- function(x, col, shift_val, newname, key_cols) { 14 | x %>% 15 | select(all_of(c(key_cols, col))) %>% 16 | mutate(time_value = time_value + shift_val) %>% 17 | rename(!!newname := {{ col }}) 18 | } 19 | 20 | #' lags move columns forward to bring the past up to today, while aheads drag 21 | #' the future back to today 22 | #' @keywords internal 23 | get_sign <- function(object) { 24 | if (!is.null(object$prefix)) { 25 | if (object$prefix == "lag_") { 26 | return(1) 27 | } else { 28 | return(-1) 29 | } 30 | } else if (object$method == "extend_lags") { 31 | return(1) 32 | } else { 33 | return(-1) 34 | } 35 | } 36 | 37 | #' backend for both `bake.step_epi_ahead` and `bake.step_epi_lag`, performs the 38 | #' checks missing in `epi_shift_single` 39 | #' @keywords internal 40 | #' @importFrom tidyr expand_grid 41 | #' @importFrom dplyr join_by 42 | add_shifted_columns <- function(new_data, object) { 43 | grid <- object$shift_grid 44 | 45 | if (nrow(object$shift_grid) == 0) { 46 | # we're not shifting any rows, so this is a no-op 47 | return(new_data) 48 | } 49 | ## ensure no name clashes 50 | new_data_names <- colnames(new_data) 51 | intersection <- new_data_names %in% grid$newname 52 | if (any(intersection)) { 53 | cli_abort(c( 54 | "Name collision occured in {.cls {class(object)[1]}}", 55 | "The following variable name{?s} already exist{?s/}: {.val {new_data_names[intersection]}}." 56 | )) 57 | } 58 | ok <- object$keys 59 | shifted <- reduce( 60 | pmap(grid, epi_shift_single, x = new_data, key_cols = ok), 61 | full_join, 62 | by = ok 63 | ) 64 | processed <- new_data %>% 65 | full_join(shifted, by = ok) %>% 66 | group_by(across(all_of(kill_time_value(ok)))) %>% 67 | arrange(time_value) 68 | if (inherits(new_data, "epi_df")) { 69 | processed <- processed %>% 70 | ungroup() %>% 71 | as_epi_df( 72 | as_of = attributes(new_data)$metadata$as_of, 73 | other_keys = attributes(new_data)$metadata$other_keys 74 | ) 75 | } 76 | return(processed) 77 | } 78 | -------------------------------------------------------------------------------- /R/epipredict-package.R: -------------------------------------------------------------------------------- 1 | ## usethis namespace: start 2 | #' @import epiprocess parsnip epidatasets 3 | #' @importFrom checkmate assert_class assert_numeric 4 | #' @importFrom checkmate test_character test_date test_function 5 | #' @importFrom checkmate test_integerish test_logical 6 | #' @importFrom checkmate test_numeric test_scalar 7 | #' @importFrom cli cli_abort cli_warn 8 | #' @importFrom dplyr arrange across all_of any_of bind_cols bind_rows group_by 9 | #' @importFrom dplyr full_join relocate summarise everything 10 | #' @importFrom dplyr inner_join 11 | #' @importFrom dplyr summarize filter mutate select left_join rename ungroup 12 | #' @importFrom epiprocess growth_rate growth_rate_params is_epi_df 13 | #' @importFrom lifecycle deprecated 14 | #' @importFrom magrittr extract2 15 | #' @importFrom rlang := !! %||% as_function global_env set_names !!! caller_arg 16 | #' @importFrom rlang is_logical is_true inject enquo enquos expr sym arg_match 17 | #' @importFrom stats poly predict lm residuals quantile 18 | #' @importFrom tibble as_tibble 19 | ## usethis namespace: end 20 | NULL 21 | -------------------------------------------------------------------------------- /R/extrapolate_quantiles.R: -------------------------------------------------------------------------------- 1 | #' Summarize a distribution with a set of quantiles 2 | #' 3 | #' This function takes a `quantile_pred` vector and returns the same 4 | #' type of object, expanded to include 5 | #' *additional* quantiles computed at `probs`. If you want behaviour more 6 | #' similar to [stats::quantile()], then `quantile(x,...)` may be more 7 | #' appropriate. 8 | #' 9 | #' @param x A vector of class `quantile_pred`. 10 | #' @param probs a vector of probabilities at which to calculate quantiles 11 | #' @param replace_na logical. If `x` contains `NA`'s, these are imputed if 12 | #' possible (if `TRUE`) or retained (if `FALSE`). 13 | #' @param ... additional arguments passed on to the `quantile` method 14 | #' 15 | #' @return a `quantile_pred` vector. Each element 16 | #' of `x` will now have a superset 17 | #' of the original `quantile_values` (the union of those and `probs`). 18 | #' @export 19 | #' 20 | #' @examples 21 | #' dstn <- quantile_pred(rbind(1:4, 8:11), c(.2, .4, .6, .8)) 22 | #' # extra quantiles are appended 23 | #' as_tibble(extrapolate_quantiles(dstn, probs = c(.25, 0.5, .75))) 24 | extrapolate_quantiles <- function(x, probs, replace_na = TRUE, ...) { 25 | UseMethod("extrapolate_quantiles") 26 | } 27 | 28 | #' @export 29 | extrapolate_quantiles.quantile_pred <- function(x, probs, replace_na = TRUE, ...) { 30 | arg_is_lgl_scalar(replace_na) 31 | arg_is_probabilities(probs) 32 | if (is.unsorted(probs)) probs <- sort(probs) 33 | orig_probs <- x %@% "quantile_levels" 34 | orig_values <- as.matrix(x) 35 | 36 | if (!replace_na || !anyNA(orig_values)) { 37 | all_values <- cbind(orig_values, quantile(x, probs, ...)) 38 | } else { 39 | newx <- quantile(x, orig_probs, ...) %>% 40 | hardhat::quantile_pred(orig_probs) 41 | all_values <- cbind(as.matrix(newx), quantile(newx, probs, ...)) 42 | } 43 | all_probs <- c(orig_probs, probs) 44 | dups <- duplicated(all_probs) 45 | all_values <- all_values[, !dups, drop = FALSE] 46 | all_probs <- all_probs[!dups] 47 | o <- order(all_probs) 48 | 49 | hardhat::quantile_pred( 50 | all_values[, o, drop = FALSE], 51 | quantile_levels = all_probs[o] 52 | ) 53 | } 54 | -------------------------------------------------------------------------------- /R/key_colnames.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | key_colnames.recipe <- function(x, ..., exclude = character()) { 3 | geo_key <- x$var_info$variable[x$var_info$role %in% "geo_value"] 4 | time_key <- x$var_info$variable[x$var_info$role %in% "time_value"] 5 | keys <- x$var_info$variable[x$var_info$role %in% "key"] 6 | full_key <- c(geo_key, keys, time_key) %||% character(0L) 7 | full_key[!full_key %in% exclude] 8 | } 9 | 10 | #' @export 11 | key_colnames.epi_workflow <- function(x, ..., exclude = character()) { 12 | # safer to look at the mold than the preprocessor 13 | mold <- hardhat::extract_mold(x) 14 | molded_roles <- mold$extras$roles 15 | extras <- bind_cols(molded_roles$geo_value, molded_roles$key, molded_roles$time_value) 16 | full_key <- names(extras) 17 | if (length(full_key) == 0L) { 18 | # No epikeytime role assignment; infer from all columns: 19 | potential_keys <- c("geo_value", "time_value") 20 | full_key <- potential_keys[potential_keys %in% names(bind_cols(molded_roles))] 21 | } 22 | full_key[!full_key %in% exclude] 23 | } 24 | 25 | kill_time_value <- function(v) { 26 | arg_is_chr(v) 27 | v[v != "time_value"] 28 | } 29 | 30 | epi_keys_only <- function(x, ...) { 31 | kill_time_value(key_colnames(x, ...)) 32 | } 33 | -------------------------------------------------------------------------------- /R/layer_naomit.R: -------------------------------------------------------------------------------- 1 | #' Omit `NA`s from predictions or other columns 2 | #' 3 | #' @param frosting a `frosting` postprocessor 4 | #' @param ... <[`tidy-select`][dplyr::dplyr_tidy_select]> One or more unquoted 5 | #' expressions separated by commas. Variable names can be used as if they 6 | #' were positions in the data frame, so expressions like `x:y` can 7 | #' be used to select a range of variables. Typical usage is `.pred` to remove 8 | #' any rows with `NA` predictions. 9 | #' @param id a random id string 10 | #' 11 | #' @return an updated `frosting` postprocessor 12 | #' @export 13 | #' @examples 14 | #' jhu <- covid_case_death_rates %>% 15 | #' filter(time_value > "2021-11-01", geo_value %in% c("ak", "ca", "ny")) 16 | #' 17 | #' r <- epi_recipe(jhu) %>% 18 | #' step_epi_lag(death_rate, lag = c(0, 7, 14)) %>% 19 | #' step_epi_ahead(death_rate, ahead = 7) 20 | #' 21 | #' wf <- epi_workflow(r, linear_reg()) %>% fit(jhu) 22 | #' 23 | #' f <- frosting() %>% 24 | #' layer_predict() %>% 25 | #' layer_naomit(.pred) 26 | #' 27 | #' wf1 <- wf %>% add_frosting(f) 28 | #' 29 | #' p <- forecast(wf1) 30 | #' p 31 | layer_naomit <- function(frosting, ..., id = rand_id("naomit")) { 32 | arg_is_chr_scalar(id) 33 | add_layer( 34 | frosting, 35 | layer_naomit_new( 36 | terms = enquos(...), 37 | id = id 38 | ) 39 | ) 40 | } 41 | 42 | layer_naomit_new <- function(terms, id) { 43 | layer("naomit", terms = terms, id = id) 44 | } 45 | 46 | #' @export 47 | slather.layer_naomit <- function(object, components, workflow, new_data, ...) { 48 | rlang::check_dots_empty() 49 | exprs <- rlang::expr(c(!!!object$terms)) 50 | pos <- tidyselect::eval_select(exprs, components$predictions) 51 | col_names <- names(pos) 52 | components$predictions <- components$predictions %>% 53 | filter(dplyr::if_any(all_of(col_names), ~ !is.na(.x))) 54 | components 55 | } 56 | 57 | #' @export 58 | print.layer_naomit <- function( 59 | x, width = max(20, options()$width - 30), ...) { 60 | title <- "Removing na predictions from" 61 | print_layer(x$terms, title = title, width = width) 62 | } 63 | -------------------------------------------------------------------------------- /R/layer_predictive_distn.R: -------------------------------------------------------------------------------- 1 | #' Returns predictive distributions 2 | #' 3 | #' `r lifecycle::badge("deprecated")` 4 | #' 5 | #' This function calculates an _approximation_ to a parametric predictive 6 | #' distribution. Predictive distributions from linear models require 7 | #' `x* (X'X)^{-1} x*` 8 | #' along with the degrees of freedom. This function approximates both. It 9 | #' should be reasonably accurate for models fit using `lm` when the new point 10 | #' `x*` isn't too far from the bulk of the data. 11 | #' 12 | #' @param frosting a `frosting` postprocessor 13 | #' @param ... Unused, include for consistency with other layers. 14 | #' @param dist_type Gaussian or Student's t predictive intervals 15 | #' @param truncate Do we truncate the distribution to an interval 16 | #' @param name character. The name for the output column. 17 | #' @param id a random id string 18 | #' 19 | #' @return an updated `frosting` postprocessor with additional columns of the 20 | #' residual quantiles added to the prediction 21 | #' @export 22 | #' 23 | layer_predictive_distn <- function(frosting, 24 | ..., 25 | dist_type = c("gaussian", "student_t"), 26 | truncate = c(-Inf, Inf), 27 | name = ".pred_distn", 28 | id = rand_id("predictive_distn")) { 29 | lifecycle::deprecate_stop("0.1.11", "layer_predictive_distn()", "layer_residual_quantiles()") 30 | } 31 | -------------------------------------------------------------------------------- /R/layer_unnest.R: -------------------------------------------------------------------------------- 1 | #' Unnest prediction list-cols 2 | #' 3 | #' @param frosting a `frosting` postprocessor 4 | #' @param ... <[`tidy-select`][dplyr::dplyr_tidy_select]> One or more unquoted 5 | #' expressions separated by commas. Variable names can be used as if they 6 | #' were positions in the data frame, so expressions like `x:y` can 7 | #' be used to select a range of variables. 8 | #' @param id a random id string 9 | #' 10 | #' @return an updated `frosting` postprocessor 11 | #' @export 12 | layer_unnest <- function(frosting, ..., id = rand_id("unnest")) { 13 | arg_is_chr_scalar(id) 14 | 15 | add_layer( 16 | frosting, 17 | layer_unnest_new( 18 | terms = enquos(...), 19 | id = id 20 | ) 21 | ) 22 | } 23 | 24 | layer_unnest_new <- function(terms, id) { 25 | layer("unnest", terms = terms, id = id) 26 | } 27 | 28 | #' @export 29 | slather.layer_unnest <- 30 | function(object, components, workflow, new_data, ...) { 31 | rlang::check_dots_empty() 32 | exprs <- rlang::expr(c(!!!object$terms)) 33 | pos <- tidyselect::eval_select(exprs, components$predictions) 34 | col_names <- names(pos) 35 | components$predictions <- components$predictions %>% 36 | tidyr::unnest(col_names) 37 | 38 | components 39 | } 40 | 41 | #' @export 42 | print.layer_unnest <- function( 43 | x, width = max(20, options()$width - 30), ...) { 44 | title <- "Unnesting prediction list-cols" 45 | print_layer(x$terms, title = title, width = width) 46 | } 47 | -------------------------------------------------------------------------------- /R/make_flatline_reg.R: -------------------------------------------------------------------------------- 1 | make_flatline_reg <- function() { 2 | parsnip::set_model_engine("linear_reg", "regression", eng = "flatline") 3 | parsnip::set_dependency("linear_reg", eng = "flatline", pkg = "epipredict") 4 | 5 | parsnip::set_fit( 6 | model = "linear_reg", 7 | eng = "flatline", 8 | mode = "regression", 9 | value = list( 10 | interface = "formula", 11 | protect = c("formula", "data"), 12 | func = c(pkg = "epipredict", fun = "flatline"), 13 | defaults = list() 14 | ) 15 | ) 16 | 17 | parsnip::set_encoding( 18 | model = "linear_reg", 19 | eng = "flatline", 20 | mode = "regression", 21 | options = list( 22 | predictor_indicators = "none", 23 | compute_intercept = TRUE, 24 | remove_intercept = TRUE, 25 | allow_sparse_x = FALSE 26 | ) 27 | ) 28 | 29 | parsnip::set_pred( 30 | model = "linear_reg", 31 | eng = "flatline", 32 | mode = "regression", 33 | type = "numeric", 34 | value = list( 35 | pre = NULL, post = NULL, func = c(fun = "predict"), 36 | args = list(object = quote(object$fit), newdata = quote(new_data)) 37 | ) 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /R/print_epi_step.R: -------------------------------------------------------------------------------- 1 | print_epi_step <- function( 2 | tr_obj = NULL, untr_obj = NULL, trained = FALSE, title = NULL, 3 | width = max(20, options()$width - 30), case_weights = NULL, 4 | conjunction = NULL, extra_text = NULL) { 5 | theme_div_id <- cli::cli_div( 6 | theme = list(.pkg = list(`vec-trunc` = Inf, `vec-last` = ", ")) 7 | ) 8 | title <- trimws(title) 9 | trained_text <- dplyr::if_else(trained, "Trained", "") 10 | case_weights_text <- dplyr::case_when( 11 | is.null(case_weights) ~ "", 12 | isTRUE(case_weights) ~ "weighted", 13 | isFALSE(case_weights) ~ "ignored weights" 14 | ) 15 | vline_seperator <- dplyr::if_else(trained_text == "", "", "|") 16 | comma_seperator <- dplyr::if_else( 17 | trained_text != "" && case_weights_text != "", true = ",", false = "" 18 | ) 19 | extra_text <- recipes::format_ch_vec(extra_text) 20 | width_title <- nchar(paste0( 21 | "* ", title, ":", " ", conjunction, " ", extra_text, " ", vline_seperator, 22 | " ", trained_text, " ", comma_seperator, " ", case_weights_text 23 | )) 24 | width_diff <- cli::console_width() * 1 - width_title 25 | if (trained) { 26 | elements <- tr_obj 27 | } else { 28 | elements <- lapply(untr_obj, function(x) { 29 | rlang::expr_deparse(rlang::quo_get_expr(x), width = Inf) 30 | }) 31 | elements <- vctrs::list_unchop(elements, ptype = character()) 32 | } 33 | if (length(elements) == 0L) elements <- "" 34 | 35 | element_print_lengths <- cumsum(nchar(elements)) + 36 | c(0L, cumsum(rep(2L, length(elements) - 1))) + 37 | c(rep(5L, length(elements) - 1), 0L) 38 | first_line <- which(width_diff >= element_print_lengths) 39 | first_line <- unname(first_line) 40 | first_line <- ifelse( 41 | test = identical(first_line, integer(0)), 42 | yes = length(element_print_lengths), 43 | no = max(first_line) 44 | ) 45 | more_dots <- ifelse(first_line == length(elements), "", ", ...") 46 | cli::cli_bullets( 47 | c("\n {title}: \\\n {.pkg {cli::cli_vec(elements[seq_len(first_line)])}}\\\n {more_dots} \\\n {conjunction} \\\n {.pkg {extra_text}} \\\n {vline_seperator} \\\n {.emph {trained_text}}\\\n {comma_seperator} \\\n {.emph {case_weights_text}}\n ") 48 | ) 49 | 50 | cli::cli_end(theme_div_id) 51 | invisible(NULL) 52 | } 53 | -------------------------------------------------------------------------------- /R/print_layer.R: -------------------------------------------------------------------------------- 1 | print_layer <- function( 2 | layer_obj = NULL, title = NULL, width = max(20, options()$width - 30), 3 | conjunction = NULL, extra_text = NULL, ...) { 4 | title <- trimws(title) 5 | width_title <- nchar(paste0("* ", title, ":", " ")) 6 | extra_text <- recipes::format_ch_vec(extra_text) 7 | width_title <- nchar(paste0( 8 | "* ", title, ":", " ", conjunction, " ", extra_text 9 | )) 10 | width_diff <- cli::console_width() * 1 - width_title 11 | elements <- lapply(layer_obj, function(x) { 12 | rlang::expr_deparse(rlang::quo_get_expr(x), width = Inf) 13 | }) 14 | elements <- vctrs::list_unchop(elements, ptype = character()) 15 | if (length(elements) == 0L) elements <- "" 16 | element_print_lengths <- cumsum(nchar(elements)) + 17 | c(0L, cumsum(rep(2L, length(elements) - 1))) + 18 | c(rep(5L, length(elements) - 1), 0L) 19 | first_line <- which(width_diff >= element_print_lengths) 20 | first_line <- unname(first_line) 21 | first_line <- ifelse( 22 | test = identical(first_line, integer(0)), 23 | yes = length(element_print_lengths), 24 | no = max(first_line) 25 | ) 26 | more_dots <- ifelse(first_line == length(elements), "", ", ...") 27 | cli::cli_bullets( 28 | c("\n {title}: \\\n {.pkg {elements[seq_len(first_line)]}}\\\n {more_dots} \\\n {conjunction} \\\n {.pkg {extra_text}}") 29 | ) 30 | 31 | invisible(NULL) 32 | } 33 | -------------------------------------------------------------------------------- /R/reexports-tidymodels.R: -------------------------------------------------------------------------------- 1 | #' @importFrom generics fit 2 | #' @export 3 | generics::fit 4 | 5 | #' @importFrom generics forecast 6 | #' @export 7 | generics::forecast 8 | 9 | #' @importFrom recipes prep 10 | #' @export 11 | recipes::prep 12 | 13 | #' @importFrom recipes bake 14 | #' @export 15 | recipes::bake 16 | 17 | #' @importFrom recipes rand_id 18 | #' @export 19 | recipes::rand_id 20 | 21 | #' @importFrom tibble tibble as_tibble 22 | #' @export 23 | tibble::tibble 24 | 25 | #' @export 26 | tibble::as_tibble 27 | 28 | #' @importFrom generics tidy 29 | #' @export 30 | generics::tidy 31 | 32 | #' @importFrom hardhat quantile_pred extract_quantile_levels 33 | #' @export 34 | hardhat::quantile_pred 35 | 36 | #' @export 37 | hardhat::extract_quantile_levels 38 | -------------------------------------------------------------------------------- /R/reexports.R: -------------------------------------------------------------------------------- 1 | #' @importFrom dplyr filter 2 | #' @export 3 | dplyr::filter 4 | 5 | #' @importFrom dplyr mutate 6 | #' @export 7 | dplyr::mutate 8 | 9 | #' @importFrom dplyr rename 10 | #' @export 11 | dplyr::rename 12 | 13 | #' @importFrom dplyr select 14 | #' @export 15 | dplyr::select 16 | 17 | #' @importFrom epiprocess as_epi_df 18 | #' @export 19 | epiprocess::as_epi_df 20 | 21 | #' @importFrom epiprocess key_colnames 22 | #' @export 23 | epiprocess::key_colnames 24 | 25 | #' @importFrom generics fit 26 | #' @export 27 | generics::fit 28 | 29 | #' @importFrom generics forecast 30 | #' @export 31 | generics::forecast 32 | 33 | #' @importFrom generics tidy 34 | #' @export 35 | generics::tidy 36 | 37 | #' @importFrom recipes prep 38 | #' @export 39 | recipes::prep 40 | 41 | #' @importFrom recipes bake 42 | #' @export 43 | recipes::bake 44 | 45 | #' @importFrom recipes rand_id 46 | #' @export 47 | recipes::rand_id 48 | 49 | #' @importFrom tibble as_tibble 50 | #' @export 51 | tibble::as_tibble 52 | 53 | #' @importFrom tibble tibble 54 | #' @export 55 | tibble::tibble 56 | 57 | #' @importFrom tidyr pivot_longer 58 | #' @export 59 | tidyr::pivot_longer 60 | 61 | #' @importFrom tidyr pivot_wider 62 | #' @export 63 | tidyr::pivot_wider 64 | 65 | #' @importFrom tidyr unnest 66 | #' @export 67 | tidyr::unnest 68 | 69 | #' @importFrom hardhat quantile_pred extract_quantile_levels 70 | #' @export 71 | hardhat::quantile_pred 72 | 73 | #' @export 74 | hardhat::extract_quantile_levels 75 | -------------------------------------------------------------------------------- /R/step_epi_naomit.R: -------------------------------------------------------------------------------- 1 | #' Unified NA omission wrapper function for recipes 2 | #' 3 | #' @param recipe Recipe to be used for omission steps 4 | #' 5 | #' @return Omits NA's from both predictors and outcomes at training time 6 | #' to fit the model. Also only omits associated predictors and not 7 | #' outcomes at prediction time due to lack of response and avoidance 8 | #' of data loss. 9 | #' @export 10 | #' @examples 11 | #' covid_case_death_rates %>% 12 | #' epi_recipe() %>% 13 | #' step_epi_naomit() 14 | step_epi_naomit <- function(recipe) { 15 | stopifnot(inherits(recipe, "recipe")) 16 | recipe %>% 17 | recipes::step_naomit(all_predictors(), skip = FALSE) %>% 18 | recipes::step_naomit(all_outcomes(), skip = TRUE) 19 | } 20 | 21 | #' @export 22 | print.step_naomit <- # not exported from recipes package 23 | function(x, width = max(20, options()$width - 30), ...) { 24 | title <- "Removing rows with NA values in " 25 | recipes::print_step(x$columns, x$terms, x$trained, title, width) 26 | invisible(x) 27 | } 28 | -------------------------------------------------------------------------------- /R/time_types.R: -------------------------------------------------------------------------------- 1 | guess_time_type <- function(time_value) { 2 | # similar to epiprocess:::guess_time_type() but w/o the gap handling 3 | arg_is_scalar(time_value) 4 | if (is.character(time_value)) { 5 | if (nchar(time_value) <= "10") { 6 | new_time_value <- tryCatch( 7 | { 8 | as.Date(time_value) 9 | }, 10 | error = function(e) NULL 11 | ) 12 | } else { 13 | new_time_value <- tryCatch( 14 | { 15 | as.POSIXct(time_value) 16 | }, 17 | error = function(e) NULL 18 | ) 19 | } 20 | if (!is.null(new_time_value)) time_value <- new_time_value 21 | } 22 | if (inherits(time_value, "POSIXct")) { 23 | return("day-time") 24 | } 25 | if (inherits(time_value, "Date")) { 26 | return("day") 27 | } 28 | if (inherits(time_value, "yearweek")) { 29 | return("yearweek") 30 | } 31 | if (inherits(time_value, "yearmonth")) { 32 | return("yearmonth") 33 | } 34 | if (inherits(time_value, "yearquarter")) { 35 | return("yearquarter") 36 | } 37 | if (is.numeric(time_value) && all(time_value == as.integer(time_value)) && 38 | all(time_value >= 1582)) { 39 | return("year") 40 | } 41 | return("custom") 42 | } 43 | 44 | coerce_time_type <- function(x, target_type) { 45 | if (target_type == "year") { 46 | if (is.numeric(x)) { 47 | return(as.integer(x)) 48 | } else { 49 | return(as.POSIXlt(x)$year + 1900L) 50 | } 51 | } 52 | switch(target_type, 53 | "day-time" = as.POSIXct(x), 54 | "day" = as.Date(x), 55 | "week" = as.Date(x), 56 | "yearweek" = tsibble::yearweek(x), 57 | "yearmonth" = tsibble::yearmonth(x), 58 | "yearquarter" = tsibble::yearquarter(x) 59 | ) 60 | } 61 | 62 | validate_date <- function(x, expected, arg = rlang::caller_arg(x), 63 | call = rlang::caller_env()) { 64 | time_type_x <- guess_time_type(x) 65 | ok <- time_type_x == expected 66 | if (!ok) { 67 | cli_abort(c( 68 | "The {.arg {arg}} was given as a {.val {time_type_x}} while the", 69 | `!` = "`time_type` of the training data was {.val {expected}}.", 70 | i = "See {.topic epiprocess::epi_df} for descriptions of these are determined." 71 | ), call = call) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /R/utils-pipe.R: -------------------------------------------------------------------------------- 1 | #' Pipe operator 2 | #' 3 | #' See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. 4 | #' 5 | #' @name %>% 6 | #' @rdname pipe 7 | #' @keywords internal 8 | #' @export 9 | #' @importFrom magrittr %>% 10 | #' @usage lhs \%>\% rhs 11 | #' @param lhs A value or the magrittr placeholder. 12 | #' @param rhs A function call using the magrittr semantics. 13 | #' @return The result of calling `rhs(lhs)`. 14 | NULL 15 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | # ON LOAD ---- 2 | 3 | # The functions below define the model information. These access the model 4 | # environment inside of parsnip so they have to be executed once parsnip has 5 | # been loaded. 6 | 7 | .onLoad <- function(libname, pkgname) { 8 | make_flatline_reg() 9 | make_quantile_reg() 10 | make_smooth_quantile_reg() 11 | make_grf_quantiles() 12 | } 13 | -------------------------------------------------------------------------------- /epipredict.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | ProjectId: a71c2044-10c8-46a9-9702-f4bfc95042c8 3 | 4 | RestoreWorkspace: No 5 | SaveWorkspace: No 6 | AlwaysSaveHistory: Default 7 | 8 | EnableCodeIndexing: Yes 9 | UseSpacesForTab: Yes 10 | NumSpacesForTab: 2 11 | Encoding: UTF-8 12 | 13 | RnwWeave: Sweave 14 | LaTeX: pdfLaTeX 15 | 16 | AutoAppendNewline: Yes 17 | StripTrailingWhitespace: Yes 18 | LineEndingConversion: Posix 19 | 20 | BuildType: Package 21 | PackageUseDevtools: Yes 22 | PackageInstallArgs: --no-multiarch --with-keep.source 23 | PackageRoxygenize: rd,collate,namespace 24 | -------------------------------------------------------------------------------- /man-roxygen/step-return.R: -------------------------------------------------------------------------------- 1 | #' @return An updated version of `recipe` with the new step added to the 2 | #' sequence of any existing operations. 3 | -------------------------------------------------------------------------------- /man/add_epi_recipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/epi_recipe.R 3 | \name{add_epi_recipe} 4 | \alias{add_epi_recipe} 5 | \alias{remove_epi_recipe} 6 | \alias{update_epi_recipe} 7 | \title{Add an \code{epi_recipe} to a workflow} 8 | \usage{ 9 | add_epi_recipe(x, recipe, ..., blueprint = default_epi_recipe_blueprint()) 10 | 11 | remove_epi_recipe(x) 12 | 13 | update_epi_recipe(x, recipe, ..., blueprint = default_epi_recipe_blueprint()) 14 | } 15 | \arguments{ 16 | \item{x}{A \code{workflow} or \code{epi_workflow}} 17 | 18 | \item{recipe}{An epi recipe or recipe} 19 | 20 | \item{...}{Not used} 21 | 22 | \item{blueprint}{A hardhat blueprint used for fine tuning the preprocessing 23 | 24 | \code{\link[=default_epi_recipe_blueprint]{default_epi_recipe_blueprint()}} is used. 25 | 26 | Note that preprocessing done here is separate from preprocessing that 27 | might be done automatically by the underlying model.} 28 | } 29 | \value{ 30 | \code{x}, updated with a new recipe preprocessor. 31 | } 32 | \description{ 33 | Add an \code{epi_recipe} to a workflow 34 | } 35 | \details{ 36 | \code{add_epi_recipe} has the same behaviour as 37 | \code{\link[workflows:add_recipe]{workflows::add_recipe()}} but sets a different 38 | default blueprint to automatically handle \link[epiprocess:epi_df]{epiprocess::epi_df} data. 39 | } 40 | \examples{ 41 | jhu <- covid_case_death_rates \%>\% 42 | filter(time_value > "2021-08-01") 43 | 44 | r <- epi_recipe(jhu) \%>\% 45 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 46 | step_epi_ahead(death_rate, ahead = 7) \%>\% 47 | step_epi_lag(case_rate, lag = c(0, 7, 14)) \%>\% 48 | step_epi_naomit() 49 | 50 | workflow <- epi_workflow() \%>\% 51 | add_epi_recipe(r) 52 | 53 | workflow 54 | 55 | r2 <- epi_recipe(jhu) \%>\% 56 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 57 | step_epi_ahead(death_rate, ahead = 7) 58 | 59 | workflow <- update_epi_recipe(workflow, r2) 60 | 61 | workflow <- remove_epi_recipe(workflow) 62 | 63 | workflow 64 | 65 | } 66 | \seealso{ 67 | \code{\link[workflows:add_recipe]{workflows::add_recipe()}} 68 | \itemize{ 69 | \item \code{add_recipe()} specifies the terms of the model and any preprocessing that 70 | is required through the usage of a recipe. 71 | \item \code{remove_recipe()} removes the recipe as well as any downstream objects 72 | \item \code{update_recipe()} first removes the recipe, then replaces the previous 73 | recipe with the new one. 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /man/add_frosting.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/frosting.R 3 | \name{add_frosting} 4 | \alias{add_frosting} 5 | \alias{remove_frosting} 6 | \alias{update_frosting} 7 | \title{Add frosting to a workflow} 8 | \usage{ 9 | add_frosting(x, frosting, ...) 10 | 11 | remove_frosting(x) 12 | 13 | update_frosting(x, frosting, ...) 14 | } 15 | \arguments{ 16 | \item{x}{A workflow} 17 | 18 | \item{frosting}{A frosting object created using \code{frosting()}.} 19 | 20 | \item{...}{Not used.} 21 | } 22 | \value{ 23 | \code{x}, updated with a new frosting postprocessor 24 | } 25 | \description{ 26 | Add frosting to a workflow 27 | } 28 | \examples{ 29 | jhu <- covid_case_death_rates \%>\% 30 | filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) 31 | r <- epi_recipe(jhu) \%>\% 32 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 33 | step_epi_ahead(death_rate, ahead = 7) 34 | 35 | wf <- epi_workflow(r, linear_reg()) \%>\% fit(jhu) 36 | latest <- jhu \%>\% 37 | filter(time_value >= max(time_value) - 14) 38 | 39 | # Add frosting to a workflow and predict 40 | f <- frosting() \%>\% 41 | layer_predict() \%>\% 42 | layer_naomit(.pred) 43 | wf1 <- wf \%>\% add_frosting(f) 44 | p1 <- predict(wf1, latest) 45 | p1 46 | 47 | # Update frosting in a workflow and predict 48 | f2 <- frosting() \%>\% layer_predict() 49 | wf2 <- wf1 \%>\% update_frosting(f2) 50 | p2 <- predict(wf2, latest) 51 | p2 52 | 53 | # Remove frosting from the workflow and predict 54 | wf3 <- wf2 \%>\% remove_frosting() 55 | p3 <- predict(wf3, latest) 56 | p3 57 | 58 | } 59 | -------------------------------------------------------------------------------- /man/add_layer.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layers.R 3 | \name{add_layer} 4 | \alias{add_layer} 5 | \title{Add layer to a frosting object} 6 | \usage{ 7 | add_layer(frosting, object) 8 | } 9 | \arguments{ 10 | \item{frosting}{a \code{frosting} postprocessor} 11 | 12 | \item{object}{a \code{frosting} layer} 13 | } 14 | \value{ 15 | an updated \code{frosting} postprocessor 16 | } 17 | \description{ 18 | Add layer to a frosting object 19 | } 20 | -------------------------------------------------------------------------------- /man/add_shifted_columns.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/epi_shift.R 3 | \name{add_shifted_columns} 4 | \alias{add_shifted_columns} 5 | \title{backend for both \code{bake.step_epi_ahead} and \code{bake.step_epi_lag}, performs the 6 | checks missing in \code{epi_shift_single}} 7 | \usage{ 8 | add_shifted_columns(new_data, object) 9 | } 10 | \description{ 11 | backend for both \code{bake.step_epi_ahead} and \code{bake.step_epi_lag}, performs the 12 | checks missing in \code{epi_shift_single} 13 | } 14 | \keyword{internal} 15 | -------------------------------------------------------------------------------- /man/adjust_epi_recipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/epi_recipe.R 3 | \name{adjust_epi_recipe} 4 | \alias{adjust_epi_recipe} 5 | \alias{adjust_epi_recipe.epi_workflow} 6 | \alias{adjust_epi_recipe.epi_recipe} 7 | \title{Adjust a step in an \code{epi_workflow} or \code{epi_recipe}} 8 | \usage{ 9 | adjust_epi_recipe( 10 | x, 11 | which_step, 12 | ..., 13 | blueprint = default_epi_recipe_blueprint() 14 | ) 15 | 16 | \method{adjust_epi_recipe}{epi_workflow}( 17 | x, 18 | which_step, 19 | ..., 20 | blueprint = default_epi_recipe_blueprint() 21 | ) 22 | 23 | \method{adjust_epi_recipe}{epi_recipe}( 24 | x, 25 | which_step, 26 | ..., 27 | blueprint = default_epi_recipe_blueprint() 28 | ) 29 | } 30 | \arguments{ 31 | \item{x}{A \code{epi_workflow} or \code{epi_recipe} object} 32 | 33 | \item{which_step}{the number or name of the step to adjust} 34 | 35 | \item{...}{Used to input a parameter adjustment} 36 | 37 | \item{blueprint}{A hardhat blueprint used for fine tuning the preprocessing.} 38 | } 39 | \value{ 40 | \code{x}, updated with the adjustment to the specified \code{epi_recipe} step. 41 | } 42 | \description{ 43 | Make a parameter adjustment to a step in either an 44 | \code{epi_workflow} or \code{epi_recipe} object. 45 | } 46 | \details{ 47 | This function can either adjust a step in a \code{epi_recipe} object 48 | or a step from a \code{epi_recipe} object in an \code{epi_workflow}. The step to be 49 | adjusted is indicated by either the step number or name (if a name is used, 50 | it must be unique). In either case, the argument name and update value 51 | must be inputted as \code{...}. See the examples below for brief 52 | illustrations of the different types of updates. 53 | } 54 | \examples{ 55 | library(workflows) 56 | 57 | jhu <- covid_case_death_rates \%>\% 58 | filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) 59 | r <- epi_recipe(jhu) \%>\% 60 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 61 | step_epi_ahead(death_rate, ahead = 7) \%>\% 62 | step_epi_naomit() 63 | 64 | wf <- epi_workflow(r, parsnip::linear_reg()) \%>\% fit(jhu) 65 | latest <- jhu \%>\% 66 | filter(time_value >= max(time_value) - 14) 67 | 68 | # Adjust `step_epi_ahead` to have an ahead value of 14 69 | # in the `epi_workflow` 70 | # Option 1. Using the step number: 71 | wf2 <- wf \%>\% adjust_epi_recipe(which_step = 2, ahead = 14) 72 | extract_preprocessor(wf2) 73 | # Option 2. Using the step name: 74 | wf3 <- wf \%>\% adjust_epi_recipe(which_step = "step_epi_ahead", ahead = 14) 75 | extract_preprocessor(wf3) 76 | 77 | # Adjust `step_epi_ahead` to have an ahead value of 14 78 | # in the `epi_recipe` 79 | # Option 1. Using the step number 80 | r2 <- r \%>\% adjust_epi_recipe(which_step = 2, ahead = 14) 81 | r2 82 | # Option 2. Using the step name 83 | r3 <- r \%>\% adjust_epi_recipe(which_step = "step_epi_ahead", ahead = 14) 84 | r3 85 | 86 | } 87 | -------------------------------------------------------------------------------- /man/adjust_frosting.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/frosting.R 3 | \name{adjust_frosting} 4 | \alias{adjust_frosting} 5 | \alias{adjust_frosting.epi_workflow} 6 | \alias{adjust_frosting.frosting} 7 | \title{Adjust a layer in an \code{epi_workflow} or \code{frosting}} 8 | \usage{ 9 | adjust_frosting(x, which_layer, ...) 10 | 11 | \method{adjust_frosting}{epi_workflow}(x, which_layer, ...) 12 | 13 | \method{adjust_frosting}{frosting}(x, which_layer, ...) 14 | } 15 | \arguments{ 16 | \item{x}{An \code{epi_workflow} or \code{frosting} object} 17 | 18 | \item{which_layer}{the number or name of the layer to adjust} 19 | 20 | \item{...}{Used to input a parameter adjustment} 21 | } 22 | \value{ 23 | \code{x}, updated with the adjustment to the specified \code{frosting} layer. 24 | } 25 | \description{ 26 | Make a parameter adjustment to a layer in either an 27 | \code{epi_workflow} or \code{frosting} object. 28 | } 29 | \details{ 30 | This function can either adjust a layer in a \code{frosting} object 31 | or a layer from a \code{frosting} object in an \code{epi_workflow}. The layer to be 32 | adjusted is indicated by either the layer number or name (if a name is used, 33 | it must be unique). In either case, the argument name and update value 34 | must be inputted as \code{...}. See the examples below for brief 35 | illustrations of the different types of updates. 36 | } 37 | \examples{ 38 | jhu <- covid_case_death_rates \%>\% 39 | filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) 40 | r <- epi_recipe(jhu) \%>\% 41 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 42 | step_epi_ahead(death_rate, ahead = 7) \%>\% 43 | step_epi_naomit() 44 | 45 | wf <- epi_workflow(r, linear_reg()) \%>\% fit(jhu) 46 | 47 | # in the frosting from the workflow 48 | f1 <- frosting() \%>\% 49 | layer_predict() \%>\% 50 | layer_threshold(.pred) 51 | 52 | wf2 <- wf \%>\% add_frosting(f1) 53 | 54 | # Adjust `layer_threshold` to have an upper bound of 1 55 | # in the `epi_workflow` 56 | # Option 1. Using the layer number: 57 | wf2 <- wf2 \%>\% adjust_frosting(which_layer = 2, upper = 1) 58 | extract_frosting(wf2) 59 | # Option 2. Using the layer name: 60 | wf3 <- wf2 \%>\% adjust_frosting(which_layer = "layer_threshold", upper = 1) 61 | extract_frosting(wf3) 62 | 63 | # Adjust `layer_threshold` to have an upper bound of 5 64 | # in the `frosting` object 65 | # Option 1. Using the layer number: 66 | f2 <- f1 \%>\% adjust_frosting(which_layer = 2, upper = 5) 67 | f2 68 | # Option 2. Using the layer name 69 | f3 <- f1 \%>\% adjust_frosting(which_layer = "layer_threshold", upper = 5) 70 | f3 71 | 72 | } 73 | -------------------------------------------------------------------------------- /man/apply_frosting.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/frosting.R 3 | \name{apply_frosting} 4 | \alias{apply_frosting} 5 | \alias{apply_frosting.default} 6 | \alias{apply_frosting.epi_recipe} 7 | \alias{apply_frosting.epi_workflow} 8 | \title{Apply postprocessing to a fitted workflow} 9 | \usage{ 10 | apply_frosting(workflow, ...) 11 | 12 | \method{apply_frosting}{default}(workflow, components, ...) 13 | 14 | \method{apply_frosting}{epi_workflow}(workflow, components, new_data, type = NULL, opts = list(), ...) 15 | } 16 | \arguments{ 17 | \item{workflow}{An object of class workflow} 18 | 19 | \item{...}{additional arguments passed on to methods} 20 | 21 | \item{components}{a list of components containing model information. These 22 | will be updated and returned by the layer. These should be 23 | \itemize{ 24 | \item \code{mold} - the output of calling \code{hardhat::mold()} on the workflow. This 25 | contains information about the preprocessing, including the recipe. 26 | \item \code{forged} - the output of calling \code{hardhat::forge()} on the workflow. 27 | This should have predictors and outcomes for the \code{new_data}. It will 28 | have three components \code{predictors}, \code{outcomes} (if these were in the 29 | \code{new_data}), and \code{extras} (usually has the rest of the data, including 30 | \code{keys}). 31 | \item \code{keys} - we put the keys (\code{time_value}, \code{geo_value}, and any others) 32 | here for ease. 33 | }} 34 | 35 | \item{new_data}{a data frame containing the new predictors to preprocess 36 | and predict on} 37 | 38 | \item{type, opts}{forwarded (along with \code{...}) to \code{\link[=predict.model_fit]{predict.model_fit()}} and 39 | \code{\link[=slather]{slather()}} for supported layers} 40 | } 41 | \description{ 42 | This function is intended for internal use. It implements postprocessing 43 | inside of the \code{predict()} method for a fitted workflow. 44 | } 45 | -------------------------------------------------------------------------------- /man/arx_class_epi_workflow.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/arx_classifier.R 3 | \name{arx_class_epi_workflow} 4 | \alias{arx_class_epi_workflow} 5 | \title{Create a template \code{arx_classifier} workflow} 6 | \usage{ 7 | arx_class_epi_workflow( 8 | epi_data, 9 | outcome, 10 | predictors, 11 | trainer = parsnip::logistic_reg(), 12 | args_list = arx_class_args_list() 13 | ) 14 | } 15 | \arguments{ 16 | \item{epi_data}{An \code{epi_df} object} 17 | 18 | \item{outcome}{A character (scalar) specifying the outcome (in the 19 | \code{epi_df}). Note that as with \code{\link[=arx_forecaster]{arx_forecaster()}}, this is expected to 20 | be real-valued. Conversion of this data to unordered classes is handled 21 | internally based on the \code{breaks} argument to \code{\link[=arx_class_args_list]{arx_class_args_list()}}. 22 | If discrete classes are already in the \code{epi_df}, it is recommended to 23 | code up a classifier from scratch using \code{\link[=epi_recipe]{epi_recipe()}}.} 24 | 25 | \item{predictors}{A character vector giving column(s) of predictor variables. 26 | This defaults to the \code{outcome}. However, if manually specified, only those variables 27 | specifically mentioned will be used. (The \code{outcome} will not be added.) 28 | By default, equals the outcome. If manually specified, does not add the 29 | outcome variable, so make sure to specify it.} 30 | 31 | \item{trainer}{A \code{{parsnip}} model describing the type of estimation. For 32 | now, we enforce \code{mode = "classification"}. Typical values are 33 | \code{\link[parsnip:logistic_reg]{parsnip::logistic_reg()}} or \code{\link[parsnip:multinom_reg]{parsnip::multinom_reg()}}. More complicated 34 | trainers like \code{\link[parsnip:naive_Bayes]{parsnip::naive_Bayes()}} or \code{\link[parsnip:rand_forest]{parsnip::rand_forest()}} can also 35 | be used. May be \code{NULL} if you'd like to decide later.} 36 | 37 | \item{args_list}{A list of customization arguments to determine 38 | the type of forecasting model. See \code{\link[=arx_class_args_list]{arx_class_args_list()}}.} 39 | } 40 | \value{ 41 | An unfit \code{epi_workflow}. 42 | } 43 | \description{ 44 | This function creates an unfit workflow for use with \code{\link[=arx_classifier]{arx_classifier()}}. 45 | It is useful if you want to make small modifications to that classifier 46 | before fitting and predicting. Supplying a trainer to the function 47 | may alter the returned \code{epi_workflow} object but can be omitted. 48 | } 49 | \examples{ 50 | jhu <- covid_case_death_rates \%>\% 51 | filter(time_value >= as.Date("2021-11-01")) 52 | 53 | arx_class_epi_workflow(jhu, "death_rate", c("case_rate", "death_rate")) 54 | 55 | arx_class_epi_workflow( 56 | jhu, 57 | "death_rate", 58 | c("case_rate", "death_rate"), 59 | trainer = multinom_reg(), 60 | args_list = arx_class_args_list( 61 | breaks = c(-.05, .1), ahead = 14, 62 | horizon = 14, method = "linear_reg" 63 | ) 64 | ) 65 | } 66 | \seealso{ 67 | \code{\link[=arx_classifier]{arx_classifier()}} \code{\link[=arx_class_args_list]{arx_class_args_list()}} 68 | } 69 | -------------------------------------------------------------------------------- /man/arx_fcast_epi_workflow.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/arx_forecaster.R 3 | \name{arx_fcast_epi_workflow} 4 | \alias{arx_fcast_epi_workflow} 5 | \title{Create a template \code{arx_forecaster} workflow} 6 | \usage{ 7 | arx_fcast_epi_workflow( 8 | epi_data, 9 | outcome, 10 | predictors = outcome, 11 | trainer = linear_reg(), 12 | args_list = arx_args_list() 13 | ) 14 | } 15 | \arguments{ 16 | \item{epi_data}{An \code{epi_df} object} 17 | 18 | \item{outcome}{A character (scalar) specifying the outcome (in the 19 | \code{epi_df}).} 20 | 21 | \item{predictors}{A character vector giving column(s) of predictor variables. 22 | This defaults to the \code{outcome}. However, if manually specified, only those variables 23 | specifically mentioned will be used. (The \code{outcome} will not be added.) 24 | By default, equals the outcome. If manually specified, does not add the 25 | outcome variable, so make sure to specify it.} 26 | 27 | \item{trainer}{A \code{{parsnip}} model describing the type of estimation. For 28 | now, we enforce \code{mode = "regression"}. May be \code{NULL} if you'd like to 29 | decide later.} 30 | 31 | \item{args_list}{A list of customization arguments to determine 32 | the type of forecasting model. See \code{\link[=arx_args_list]{arx_args_list()}}.} 33 | } 34 | \value{ 35 | An unfitted \code{epi_workflow}. 36 | } 37 | \description{ 38 | This function creates an unfit workflow for use with \code{\link[=arx_forecaster]{arx_forecaster()}}. 39 | It is useful if you want to make small modifications to that forecaster 40 | before fitting and predicting. Supplying a trainer to the function 41 | may alter the returned \code{epi_workflow} object (e.g., if you intend to 42 | use \code{\link[=quantile_reg]{quantile_reg()}}) but can be omitted. 43 | } 44 | \examples{ 45 | jhu <- covid_case_death_rates \%>\% 46 | filter(time_value >= as.Date("2021-12-01")) 47 | 48 | arx_fcast_epi_workflow( 49 | jhu, "death_rate", 50 | c("case_rate", "death_rate") 51 | ) 52 | 53 | arx_fcast_epi_workflow(jhu, "death_rate", 54 | c("case_rate", "death_rate"), 55 | trainer = quantile_reg(), 56 | args_list = arx_args_list(quantile_levels = 1:9 / 10) 57 | ) 58 | } 59 | \seealso{ 60 | \code{\link[=arx_forecaster]{arx_forecaster()}}, \code{\link[=arx_args_list]{arx_args_list()}} 61 | } 62 | -------------------------------------------------------------------------------- /man/arx_forecaster.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/arx_forecaster.R 3 | \name{arx_forecaster} 4 | \alias{arx_forecaster} 5 | \title{Direct autoregressive forecaster with covariates} 6 | \usage{ 7 | arx_forecaster( 8 | epi_data, 9 | outcome, 10 | predictors = outcome, 11 | trainer = linear_reg(), 12 | args_list = arx_args_list() 13 | ) 14 | } 15 | \arguments{ 16 | \item{epi_data}{An \code{epi_df} object} 17 | 18 | \item{outcome}{A character (scalar) specifying the outcome (in the 19 | \code{epi_df}).} 20 | 21 | \item{predictors}{A character vector giving column(s) of predictor variables. 22 | This defaults to the \code{outcome}. However, if manually specified, only those variables 23 | specifically mentioned will be used. (The \code{outcome} will not be added.) 24 | By default, equals the outcome. If manually specified, does not add the 25 | outcome variable, so make sure to specify it.} 26 | 27 | \item{trainer}{A \code{{parsnip}} model describing the type of estimation. 28 | For now, we enforce \code{mode = "regression"}.} 29 | 30 | \item{args_list}{A list of customization arguments to determine 31 | the type of forecasting model. See \code{\link[=arx_args_list]{arx_args_list()}}.} 32 | } 33 | \value{ 34 | A list with (1) \code{predictions} an \code{epi_df} of predicted values 35 | and (2) \code{epi_workflow}, a list that encapsulates the entire estimation 36 | workflow 37 | } 38 | \description{ 39 | This is an autoregressive forecasting model for 40 | \link[epiprocess:epi_df]{epiprocess::epi_df} data. It does "direct" forecasting, meaning 41 | that it estimates a model for a particular target horizon. 42 | } 43 | \examples{ 44 | jhu <- covid_case_death_rates \%>\% 45 | dplyr::filter(time_value >= as.Date("2021-12-01")) 46 | 47 | out <- arx_forecaster( 48 | jhu, "death_rate", 49 | c("case_rate", "death_rate") 50 | ) 51 | 52 | out <- arx_forecaster(jhu, "death_rate", 53 | c("case_rate", "death_rate"), 54 | trainer = quantile_reg(), 55 | args_list = arx_args_list(quantile_levels = 1:9 / 10) 56 | ) 57 | } 58 | \seealso{ 59 | \code{\link[=arx_fcast_epi_workflow]{arx_fcast_epi_workflow()}}, \code{\link[=arx_args_list]{arx_args_list()}} 60 | } 61 | -------------------------------------------------------------------------------- /man/augment.epi_workflow.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/epi_workflow.R 3 | \name{augment.epi_workflow} 4 | \alias{augment.epi_workflow} 5 | \title{Augment data with predictions} 6 | \usage{ 7 | \method{augment}{epi_workflow}(x, new_data, ...) 8 | } 9 | \arguments{ 10 | \item{x}{A trained epi_workflow} 11 | 12 | \item{new_data}{A epi_df of predictors} 13 | 14 | \item{...}{Arguments passed on to the predict method.} 15 | } 16 | \value{ 17 | new_data with additional columns containing the predicted values 18 | } 19 | \description{ 20 | Augment data with predictions 21 | } 22 | -------------------------------------------------------------------------------- /man/cdc_baseline_forecaster.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cdc_baseline_forecaster.R 3 | \name{cdc_baseline_forecaster} 4 | \alias{cdc_baseline_forecaster} 5 | \title{Predict the future with the most recent value} 6 | \usage{ 7 | cdc_baseline_forecaster( 8 | epi_data, 9 | outcome, 10 | args_list = cdc_baseline_args_list() 11 | ) 12 | } 13 | \arguments{ 14 | \item{epi_data}{An \code{\link[epiprocess:epi_df]{epiprocess::epi_df}}} 15 | 16 | \item{outcome}{A scalar character for the column name we wish to predict.} 17 | 18 | \item{args_list}{A list of additional arguments as created by the 19 | \code{\link[=cdc_baseline_args_list]{cdc_baseline_args_list()}} constructor function.} 20 | } 21 | \value{ 22 | A data frame of point and interval forecasts for all aheads (unique 23 | horizons) for each unique combination of \code{key_vars}. 24 | } 25 | \description{ 26 | This is a simple forecasting model for 27 | \link[epiprocess:epi_df]{epiprocess::epi_df} data. It uses the most recent observation as the 28 | forecast for any future date, and produces intervals by shuffling the quantiles 29 | of the residuals of such a "flatline" forecast and incrementing these 30 | forward over all available training data. 31 | } 32 | \details{ 33 | By default, the predictive intervals are computed separately for each 34 | combination of \code{geo_value} in the \code{epi_data} argument. 35 | 36 | This forecaster is meant to produce exactly the CDC Baseline used for 37 | \href{https://covid19forecasthub.org}{COVID19ForecastHub} 38 | } 39 | \examples{ 40 | library(dplyr) 41 | library(epiprocess) 42 | weekly_deaths <- covid_case_death_rates \%>\% 43 | select(geo_value, time_value, death_rate) \%>\% 44 | left_join(state_census \%>\% select(pop, abbr), by = c("geo_value" = "abbr")) \%>\% 45 | mutate(deaths = pmax(death_rate / 1e5 * pop * 7, 0)) \%>\% 46 | select(-pop, -death_rate) \%>\% 47 | group_by(geo_value) \%>\% 48 | epi_slide(~ sum(.$deaths), .window_size = 7, .new_col_name = "deaths_7dsum") \%>\% 49 | ungroup() \%>\% 50 | filter(weekdays(time_value) == "Saturday") 51 | 52 | cdc <- cdc_baseline_forecaster(weekly_deaths, "deaths_7dsum") 53 | preds <- pivot_quantiles_wider(cdc$predictions, .pred_distn) 54 | 55 | library(ggplot2) 56 | forecast_date <- unique(preds$forecast_date) 57 | four_states <- c("ca", "pa", "wa", "ny") 58 | preds \%>\% 59 | filter(geo_value \%in\% four_states) \%>\% 60 | ggplot(aes(target_date)) + 61 | geom_ribbon(aes(ymin = `0.1`, ymax = `0.9`), fill = blues9[3]) + 62 | geom_ribbon(aes(ymin = `0.25`, ymax = `0.75`), fill = blues9[6]) + 63 | geom_line(aes(y = .pred), color = "orange") + 64 | geom_line( 65 | data = weekly_deaths \%>\% filter(geo_value \%in\% four_states), 66 | aes(x = time_value, y = deaths_7dsum) 67 | ) + 68 | scale_x_date(limits = c(forecast_date - 90, forecast_date + 30)) + 69 | labs(x = "Date", y = "Weekly deaths") + 70 | facet_wrap(~geo_value, scales = "free_y") + 71 | theme_bw() + 72 | geom_vline(xintercept = forecast_date) 73 | } 74 | -------------------------------------------------------------------------------- /man/check_enough_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/check_enough_data.R 3 | \name{check_enough_data} 4 | \alias{check_enough_data} 5 | \title{Check the dataset contains enough data points.} 6 | \usage{ 7 | check_enough_data( 8 | recipe, 9 | ..., 10 | min_observations = NULL, 11 | epi_keys = NULL, 12 | drop_na = TRUE, 13 | role = NA, 14 | trained = FALSE, 15 | skip = TRUE, 16 | id = rand_id("enough_data") 17 | ) 18 | } 19 | \arguments{ 20 | \item{recipe}{A recipe object. The check will be added to the 21 | sequence of operations for this recipe.} 22 | 23 | \item{...}{One or more selector functions to choose variables for this check. 24 | See \code{\link[=selections]{selections()}} for more details. You will usually want to use 25 | \code{\link[recipes:has_role]{recipes::all_predictors()}} and/or \code{\link[recipes:has_role]{recipes::all_outcomes()}} here.} 26 | 27 | \item{min_observations}{The minimum number of data points required for 28 | training. If this is NULL, the total number of predictors will be used.} 29 | 30 | \item{epi_keys}{A character vector of column names on which to group the data 31 | and check threshold within each group. Useful if your forecaster trains 32 | per group (for example, per geo_value).} 33 | 34 | \item{drop_na}{A logical for whether to count NA values as valid rows.} 35 | 36 | \item{role}{Not used by this check since no new variables are 37 | created.} 38 | 39 | \item{trained}{A logical for whether the selectors in \code{...} 40 | have been resolved by \code{\link[=prep]{prep()}}.} 41 | 42 | \item{skip}{A logical. If \code{TRUE}, only training data is checked, while if 43 | \code{FALSE}, both training and predicting data is checked. Technically, this 44 | answers the question "should the check be skipped when the recipe is baked 45 | by \code{\link[=bake]{bake()}}?" While all operations are baked when \code{\link[=prep]{prep()}} is run, some 46 | operations may not be able to be conducted on new data (e.g. processing the 47 | outcome variable(s)). Care should be taken when using \code{skip = TRUE} as it 48 | may affect the computations for subsequent operations.} 49 | 50 | \item{id}{A character string that is unique to this check to identify it.} 51 | } 52 | \description{ 53 | \code{check_enough_data} creates a \emph{specification} of a recipe 54 | operation that will check if variables contain enough data. 55 | } 56 | \details{ 57 | This check will break the \code{prep} and/or bake function if any of the 58 | checked columns have not enough non-NA values. If the check passes, nothing 59 | is changed in the data. It is best used after every other step. 60 | 61 | For checking training data, it is best to set \code{...} to be 62 | \verb{all_predictors(), all_outcomes()}, while for checking prediction data, it 63 | is best to set \code{...} to be \code{all_predictors()} only, with \code{n = 1}. 64 | } 65 | \section{tidy() results}{ 66 | When you \code{\link[=tidy.recipe]{tidy()}} this check, a tibble with column 67 | \code{terms} (the selectors or variables selected) is returned. 68 | } 69 | 70 | \concept{checks} 71 | -------------------------------------------------------------------------------- /man/check_interminable_latency.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-latency.R 3 | \name{check_interminable_latency} 4 | \alias{check_interminable_latency} 5 | \title{warn when the latency is larger than would be reasonable} 6 | \usage{ 7 | check_interminable_latency( 8 | dataset, 9 | latency_table, 10 | target_columns, 11 | forecast_date, 12 | call = caller_env() 13 | ) 14 | } 15 | \arguments{ 16 | \item{dataset}{the epi_df} 17 | 18 | \item{latency_table}{the whole collection of latencies} 19 | 20 | \item{target_columns}{the names of the columns that we're adjusting, and whether its unreasonably latent} 21 | } 22 | \description{ 23 | warn when the latency is larger than would be reasonable 24 | } 25 | \keyword{internal} 26 | -------------------------------------------------------------------------------- /man/clean_f_name.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/step_epi_slide.R 3 | \name{clean_f_name} 4 | \alias{clean_f_name} 5 | \title{Create short function names} 6 | \usage{ 7 | clean_f_name(.f, max_length = 20L) 8 | } 9 | \arguments{ 10 | \item{.f}{a function, character string, or lambda. For example, \code{mean}, 11 | \code{"mean"}, \code{~ mean(.x)} or \verb{\\(x) mean(x, na.rm = TRUE)}.} 12 | 13 | \item{max_length}{integer determining how long names can be} 14 | } 15 | \value{ 16 | a character string of length at most \code{max_length} that 17 | (partially) describes the function. 18 | } 19 | \description{ 20 | Create short function names 21 | } 22 | \examples{ 23 | clean_f_name(mean) 24 | clean_f_name("mean") 25 | clean_f_name(~ mean(.x, na.rm = TRUE)) 26 | clean_f_name(\(x) mean(x, na.rm = TRUE)) 27 | clean_f_name(function(x) mean(x, na.rm = TRUE, trim = 0.2357862)) 28 | } 29 | -------------------------------------------------------------------------------- /man/construct_shift_tibble.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-latency.R 3 | \name{construct_shift_tibble} 4 | \alias{construct_shift_tibble} 5 | \title{create a table of the columns to modify, their shifts, and their prefixes} 6 | \usage{ 7 | construct_shift_tibble(terms_used, recipe, rel_step_type, shift_name) 8 | } 9 | \description{ 10 | create a table of the columns to modify, their shifts, and their prefixes 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/count_single_column.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-latency.R 3 | \name{count_single_column} 4 | \alias{count_single_column} 5 | \title{get the location of the last real value} 6 | \usage{ 7 | count_single_column(col) 8 | } 9 | \arguments{ 10 | \item{col}{the relevant column} 11 | } 12 | \description{ 13 | get the location of the last real value 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/dist_quantiles.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/quantile_pred-methods.R 3 | \name{dist_quantiles} 4 | \alias{dist_quantiles} 5 | \title{A distribution parameterized by a set of quantiles} 6 | \usage{ 7 | dist_quantiles(values, quantile_levels) 8 | } 9 | \arguments{ 10 | \item{values}{A vector (or list of vectors) of values.} 11 | 12 | \item{quantile_levels}{A vector (or list of vectors) of probabilities 13 | corresponding to \code{values}. 14 | 15 | When creating multiple sets of \code{values}/\code{quantile_levels} resulting in 16 | different distributions, the sizes must match. See the examples below.} 17 | } 18 | \value{ 19 | A vector of class \code{"distribution"}. 20 | } 21 | \description{ 22 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 23 | } 24 | \details{ 25 | This function is deprecated. The recommended alternative is 26 | \code{\link[hardhat:quantile_pred]{hardhat::quantile_pred()}}. 27 | } 28 | \keyword{internal} 29 | -------------------------------------------------------------------------------- /man/drop_ignored_keys.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-latency.R 3 | \name{drop_ignored_keys} 4 | \alias{drop_ignored_keys} 5 | \title{given a list named by key columns, remove any matching key values 6 | keys_to_ignore should have the form list(col_name = c("value_to_ignore", "other_value_to_ignore"))} 7 | \usage{ 8 | drop_ignored_keys(training, keys_to_ignore) 9 | } 10 | \description{ 11 | given a list named by key columns, remove any matching key values 12 | keys_to_ignore should have the form list(col_name = c("value_to_ignore", "other_value_to_ignore")) 13 | } 14 | \keyword{internal} 15 | -------------------------------------------------------------------------------- /man/epi_shift_single.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/epi_shift.R 3 | \name{epi_shift_single} 4 | \alias{epi_shift_single} 5 | \title{Shift predictors while maintaining grouping and time_value ordering} 6 | \usage{ 7 | epi_shift_single(x, col, shift_val, newname, key_cols) 8 | } 9 | \arguments{ 10 | \item{x}{Data frame.} 11 | 12 | \item{shift_val}{a single integer. Negative values produce leads.} 13 | 14 | \item{newname}{the name for the newly shifted column} 15 | 16 | \item{key_cols}{vector, or \code{NULL}. Additional grouping vars.} 17 | } 18 | \value{ 19 | a list of tibbles 20 | } 21 | \description{ 22 | This is a lower-level function. As such it performs no error checking. 23 | } 24 | \keyword{internal} 25 | -------------------------------------------------------------------------------- /man/epi_slide_wrapper.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/step_epi_slide.R 3 | \name{epi_slide_wrapper} 4 | \alias{epi_slide_wrapper} 5 | \title{Wrapper to handle epi_slide particulars} 6 | \usage{ 7 | epi_slide_wrapper( 8 | new_data, 9 | .window_size, 10 | .align, 11 | columns, 12 | fns, 13 | fn_names, 14 | group_keys, 15 | name_prefix 16 | ) 17 | } 18 | \arguments{ 19 | \item{fns}{vector of functions, even if it's length 1.} 20 | 21 | \item{group_keys}{the keys to group by. likely \code{epi_keys} (without \code{time_value})} 22 | } 23 | \description{ 24 | This should simplify somewhat in the future when we can run \code{epi_slide} on 25 | columns. Surprisingly, lapply is several orders of magnitude faster than 26 | using roughly equivalent tidy select style. 27 | } 28 | \keyword{internal} 29 | -------------------------------------------------------------------------------- /man/epi_workflow.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/epi_workflow.R 3 | \name{epi_workflow} 4 | \alias{epi_workflow} 5 | \title{Create an epi_workflow} 6 | \usage{ 7 | epi_workflow(preprocessor = NULL, spec = NULL, postprocessor = NULL) 8 | } 9 | \arguments{ 10 | \item{preprocessor}{An optional preprocessor to add to the workflow. One of: 11 | \itemize{ 12 | \item A formula, passed on to \code{\link[workflows:add_formula]{add_formula()}}. 13 | \item A recipe, passed on to \code{\link[workflows:add_recipe]{add_recipe()}}. 14 | \item A \code{\link[workflows:workflow_variables]{workflow_variables()}} object, passed on to \code{\link[workflows:add_variables]{add_variables()}}. 15 | }} 16 | 17 | \item{spec}{An optional parsnip model specification to add to the workflow. 18 | Passed on to \code{\link[workflows:add_model]{add_model()}}.} 19 | 20 | \item{postprocessor}{An optional postprocessor to add to the workflow. 21 | Currently only \code{frosting} is allowed using, \code{add_frosting()}.} 22 | } 23 | \value{ 24 | A new \code{epi_workflow} object. 25 | } 26 | \description{ 27 | This is a container object that unifies preprocessing, fitting, prediction, 28 | and postprocessing for predictive modeling on epidemiological data. It extends 29 | the functionality of a \code{\link[workflows:workflow]{workflows::workflow()}} to handle the typical panel 30 | data structures found in this field. This extension is handled completely 31 | internally, and should be invisible to the user. For all intents and purposes, 32 | this operates exactly like a \code{\link[workflows:workflow]{workflows::workflow()}}. For more details 33 | and numerous examples, see there. 34 | } 35 | \examples{ 36 | jhu <- covid_case_death_rates 37 | 38 | r <- epi_recipe(jhu) \%>\% 39 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 40 | step_epi_ahead(death_rate, ahead = 7) \%>\% 41 | step_epi_lag(case_rate, lag = c(0, 7, 14)) \%>\% 42 | step_epi_naomit() 43 | 44 | wf <- epi_workflow(r, parsnip::linear_reg()) 45 | 46 | wf 47 | } 48 | \seealso{ 49 | workflows::workflow 50 | } 51 | -------------------------------------------------------------------------------- /man/epiweek_leap.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/step_climate.R 3 | \name{epiweek_leap} 4 | \alias{epiweek_leap} 5 | \title{epiweek, but it assigns week 53 the value of 999 instead so it mirrors the assignments in yday_leap} 6 | \usage{ 7 | epiweek_leap(time_value) 8 | } 9 | \description{ 10 | epiweek, but it assigns week 53 the value of 999 instead so it mirrors the assignments in yday_leap 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/extract_argument.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/extract.R 3 | \name{extract_argument} 4 | \alias{extract_argument} 5 | \title{Extract an argument made to a frosting layer or recipe step} 6 | \usage{ 7 | extract_argument(x, name, arg, ...) 8 | } 9 | \arguments{ 10 | \item{x}{an epi_workflow, epi_recipe, frosting, step, or layer object} 11 | 12 | \item{name}{the name of the layer} 13 | 14 | \item{arg}{the name of the argument} 15 | 16 | \item{...}{not used} 17 | } 18 | \value{ 19 | An object originally passed as an argument to a layer or step 20 | } 21 | \description{ 22 | Extract an argument made to a frosting layer or recipe step 23 | } 24 | \examples{ 25 | f <- frosting() \%>\% 26 | layer_predict() \%>\% 27 | layer_residual_quantiles(symmetrize = FALSE) \%>\% 28 | layer_naomit(.pred) 29 | 30 | extract_argument(f, "layer_residual_quantiles", "symmetrize") 31 | } 32 | \keyword{internal} 33 | -------------------------------------------------------------------------------- /man/extract_frosting.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/frosting.R 3 | \name{extract_frosting} 4 | \alias{extract_frosting} 5 | \title{Extract the frosting object from a workflow} 6 | \usage{ 7 | extract_frosting(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{an \code{epi_workflow} object} 11 | 12 | \item{...}{not used} 13 | } 14 | \value{ 15 | a \code{frosting} object 16 | } 17 | \description{ 18 | Extract the frosting object from a workflow 19 | } 20 | -------------------------------------------------------------------------------- /man/extrapolate_quantiles.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/extrapolate_quantiles.R 3 | \name{extrapolate_quantiles} 4 | \alias{extrapolate_quantiles} 5 | \title{Summarize a distribution with a set of quantiles} 6 | \usage{ 7 | extrapolate_quantiles(x, probs, replace_na = TRUE, ...) 8 | } 9 | \arguments{ 10 | \item{x}{A vector of class \code{quantile_pred}.} 11 | 12 | \item{probs}{a vector of probabilities at which to calculate quantiles} 13 | 14 | \item{replace_na}{logical. If \code{x} contains \code{NA}'s, these are imputed if 15 | possible (if \code{TRUE}) or retained (if \code{FALSE}).} 16 | 17 | \item{...}{additional arguments passed on to the \code{quantile} method} 18 | } 19 | \value{ 20 | a \code{quantile_pred} vector. Each element 21 | of \code{x} will now have a superset 22 | of the original \code{quantile_values} (the union of those and \code{probs}). 23 | } 24 | \description{ 25 | This function takes a \code{quantile_pred} vector and returns the same 26 | type of object, expanded to include 27 | \emph{additional} quantiles computed at \code{probs}. If you want behaviour more 28 | similar to \code{\link[stats:quantile]{stats::quantile()}}, then \code{quantile(x,...)} may be more 29 | appropriate. 30 | } 31 | \examples{ 32 | dstn <- quantile_pred(rbind(1:4, 8:11), c(.2, .4, .6, .8)) 33 | # extra quantiles are appended 34 | as_tibble(extrapolate_quantiles(dstn, probs = c(.25, 0.5, .75))) 35 | } 36 | -------------------------------------------------------------------------------- /man/figures/lifecycle-archived.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: archived 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | archived 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-defunct.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: defunct 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | defunct 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-deprecated.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: deprecated 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | deprecated 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-experimental.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: experimental 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | experimental 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-maturing.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: maturing 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | maturing 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-questioning.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: questioning 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | questioning 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-soft-deprecated.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: soft-deprecated 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | soft-deprecated 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-stable.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: stable 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | lifecycle 21 | 22 | 25 | 26 | stable 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /man/figures/lifecycle-superseded.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: superseded 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | superseded 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/fit-epi_workflow.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/epi_workflow.R 3 | \name{fit-epi_workflow} 4 | \alias{fit-epi_workflow} 5 | \alias{fit.epi_workflow} 6 | \title{Fit an \code{epi_workflow} object} 7 | \usage{ 8 | \method{fit}{epi_workflow}(object, data, ..., control = workflows::control_workflow()) 9 | } 10 | \arguments{ 11 | \item{object}{an \code{epi_workflow} object} 12 | 13 | \item{data}{an \code{epi_df} of predictors and outcomes to use when 14 | fitting the \code{epi_workflow}} 15 | 16 | \item{...}{Not used} 17 | 18 | \item{control}{A \code{\link[workflows:control_workflow]{workflows::control_workflow()}} object} 19 | } 20 | \value{ 21 | The \code{epi_workflow} object, updated with a fit parsnip 22 | model in the \code{object$fit$fit} slot. 23 | } 24 | \description{ 25 | This is the \code{fit()} method for an \code{epi_workflow} object that 26 | estimates parameters for a given model from a set of data. 27 | Fitting an \code{epi_workflow} involves two main steps, which are 28 | preprocessing the data and fitting the underlying parsnip model. 29 | } 30 | \examples{ 31 | jhu <- covid_case_death_rates \%>\% 32 | filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) 33 | 34 | r <- epi_recipe(jhu) \%>\% 35 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 36 | step_epi_ahead(death_rate, ahead = 7) 37 | 38 | wf <- epi_workflow(r, parsnip::linear_reg()) \%>\% fit(jhu) 39 | wf 40 | 41 | } 42 | \seealso{ 43 | workflows::fit-workflow 44 | } 45 | -------------------------------------------------------------------------------- /man/flatline.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/flatline.R 3 | \name{flatline} 4 | \alias{flatline} 5 | \title{(Internal) implementation of the flatline forecaster} 6 | \usage{ 7 | flatline(formula, data) 8 | } 9 | \arguments{ 10 | \item{formula}{The lhs should be a single variable. In standard usage, this 11 | would actually be the observed time series shifted forward by the forecast 12 | horizon. The right hand side must contain any keys (locations) for the 13 | panel data separated by plus. The observed time series must come last. 14 | For example 15 | 16 | \if{html}{\out{
}}\preformatted{form <- as.formula(lead7_y ~ state + age + y) 17 | }\if{html}{\out{
}} 18 | 19 | Note that this function doesn't DO the shifting, that has to be done 20 | outside.} 21 | 22 | \item{data}{A data frame containing at least the variables used in the 23 | formula. It must also contain a column \code{time_value} giving the observed 24 | time points.} 25 | } 26 | \value{ 27 | An S3 object of class \code{flatline} with two components: 28 | \itemize{ 29 | \item \code{residuals} - a tibble with all keys and a \code{.resid} column that contains 30 | forecast errors. 31 | \item \code{.pred} - a tibble with all keys and a \code{.pred} column containing only 32 | predictions for future data (the last observed of the outcome for each 33 | combination of keys. 34 | } 35 | } 36 | \description{ 37 | This is an internal function that is used to create a \code{\link[parsnip:linear_reg]{parsnip::linear_reg()}} 38 | model. It has somewhat odd behaviour (see below). 39 | } 40 | \examples{ 41 | tib <- data.frame( 42 | y = runif(100), 43 | expand.grid(k = letters[1:4], j = letters[5:9], time_value = 1:5) 44 | ) \%>\% 45 | dplyr::group_by(k, j) \%>\% 46 | dplyr::mutate(y2 = dplyr::lead(y, 2)) # predict 2 steps ahead 47 | flat <- flatline(y2 ~ j + k + y, tib) # predictions for 20 locations 48 | sum(!is.na(flat$residuals$.resid)) # 100 residuals, but 40 are NA 49 | } 50 | \keyword{internal} 51 | -------------------------------------------------------------------------------- /man/flatline_forecaster.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/flatline_forecaster.R 3 | \name{flatline_forecaster} 4 | \alias{flatline_forecaster} 5 | \title{Predict the future with today's value} 6 | \usage{ 7 | flatline_forecaster(epi_data, outcome, args_list = flatline_args_list()) 8 | } 9 | \arguments{ 10 | \item{epi_data}{An \link[epiprocess:epi_df]{epiprocess::epi_df}} 11 | 12 | \item{outcome}{A scalar character for the column name we wish to predict.} 13 | 14 | \item{args_list}{A list of additional arguments as created by the 15 | \code{\link[=flatline_args_list]{flatline_args_list()}} constructor function.} 16 | } 17 | \value{ 18 | A data frame of point (and optionally interval) forecasts at a single 19 | ahead (unique horizon) for each unique combination of \code{key_vars}. 20 | } 21 | \description{ 22 | This is a simple forecasting model for 23 | \link[epiprocess:epi_df]{epiprocess::epi_df} data. It uses the most recent 24 | observation as the 25 | forecast for any future date, and produces intervals based on the quantiles 26 | of the residuals of such a "flatline" forecast over all available training 27 | data. 28 | } 29 | \details{ 30 | By default, the predictive intervals are computed separately for each 31 | combination of key values (\code{geo_value} + any additional keys) in the 32 | \code{epi_data} argument. 33 | 34 | This forecaster is very similar to that used by the 35 | \href{https://covid19forecasthub.org}{COVID19ForecastHub} 36 | } 37 | \examples{ 38 | jhu <- covid_case_death_rates \%>\% 39 | dplyr::filter(time_value >= as.Date("2021-12-01")) 40 | 41 | out <- flatline_forecaster(jhu, "death_rate") 42 | } 43 | -------------------------------------------------------------------------------- /man/forecast.epi_workflow.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/epi_workflow.R 3 | \name{forecast.epi_workflow} 4 | \alias{forecast.epi_workflow} 5 | \title{Produce a forecast from an epi workflow} 6 | \usage{ 7 | \method{forecast}{epi_workflow}(object, ..., n_recent = NULL, forecast_date = NULL) 8 | } 9 | \arguments{ 10 | \item{object}{An epi workflow.} 11 | 12 | \item{...}{Not used.} 13 | 14 | \item{n_recent}{Integer or NULL. If filling missing data with locf = TRUE, 15 | how far back are we willing to tolerate missing data? Larger values allow 16 | more filling. The default NULL will determine this from the the recipe. For 17 | example, suppose n_recent = 3, then if the 3 most recent observations in any 18 | geo_value are all NA’s, we won’t be able to fill anything, and an error 19 | message will be thrown. (See details.)} 20 | 21 | \item{forecast_date}{By default, this is set to the maximum time_value in x. 22 | But if there is data latency such that recent NA's should be filled, this may 23 | be after the last available time_value.} 24 | } 25 | \value{ 26 | A forecast tibble. 27 | } 28 | \description{ 29 | Produce a forecast from an epi workflow 30 | } 31 | -------------------------------------------------------------------------------- /man/format_varnames.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-misc.R 3 | \name{format_varnames} 4 | \alias{format_varnames} 5 | \title{"Format" a character vector of column/variable names for cli interpolation} 6 | \usage{ 7 | format_varnames(x, empty = "*none*") 8 | } 9 | \arguments{ 10 | \item{x}{\code{chr}; e.g., \code{colnames} of some data frame} 11 | 12 | \item{empty}{string; what should be output if \code{x} is of length 0?} 13 | } 14 | \value{ 15 | \code{chr} 16 | } 17 | \description{ 18 | Designed to give good output if interpolated with cli. Main purpose is to add 19 | backticks around variable names when necessary, and something other than an 20 | empty string if length 0. 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /man/frosting.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/frosting.R 3 | \name{frosting} 4 | \alias{frosting} 5 | \title{Create frosting for postprocessing predictions} 6 | \usage{ 7 | frosting(layers = NULL, requirements = NULL) 8 | } 9 | \arguments{ 10 | \item{layers}{Must be \code{NULL}.} 11 | 12 | \item{requirements}{Must be \code{NULL}.} 13 | } 14 | \value{ 15 | A frosting object. 16 | } 17 | \description{ 18 | This generates a postprocessing container (much like \code{recipes::recipe()}) 19 | to hold steps for postprocessing predictions. 20 | } 21 | \details{ 22 | The arguments are currently placeholders and must be NULL 23 | } 24 | \examples{ 25 | # Toy example to show that frosting can be created and added for postprocessing 26 | f <- frosting() 27 | wf <- epi_workflow() \%>\% add_frosting(f) 28 | 29 | # A more realistic example 30 | jhu <- covid_case_death_rates \%>\% 31 | filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) 32 | 33 | r <- epi_recipe(jhu) \%>\% 34 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 35 | step_epi_ahead(death_rate, ahead = 7) \%>\% 36 | step_epi_naomit() 37 | 38 | wf <- epi_workflow(r, parsnip::linear_reg()) \%>\% fit(jhu) 39 | 40 | f <- frosting() \%>\% 41 | layer_predict() \%>\% 42 | layer_naomit(.pred) 43 | 44 | wf1 <- wf \%>\% add_frosting(f) 45 | 46 | p <- forecast(wf1) 47 | p 48 | } 49 | -------------------------------------------------------------------------------- /man/get_forecast_date.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-latency.R 3 | \name{get_forecast_date} 4 | \alias{get_forecast_date} 5 | \title{Extract the as_of for the forecast date, and make sure there's nothing very off about it.} 6 | \usage{ 7 | get_forecast_date(new_data, info, epi_keys_checked, latency, columns = NULL) 8 | } 9 | \description{ 10 | Extract the as_of for the forecast date, and make sure there's nothing very off about it. 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/get_forecast_date_in_layer.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-latency.R 3 | \name{get_forecast_date_in_layer} 4 | \alias{get_forecast_date_in_layer} 5 | \title{get the target date while in a layer} 6 | \usage{ 7 | get_forecast_date_in_layer(this_recipe, workflow_max_time_value, new_data) 8 | } 9 | \arguments{ 10 | \item{this_recipe}{the recipe to check for \code{step_adjust_latency}} 11 | 12 | \item{workflow_max_time_value}{the \code{max_time} value coming out of the fit 13 | workflow (this will be the maximal time value in a potentially different 14 | dataset)} 15 | 16 | \item{new_data}{the data we're currently working with, from which we'll take 17 | a potentially different max_time_value} 18 | } 19 | \description{ 20 | get the target date while in a layer 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /man/get_latency.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-latency.R 3 | \name{get_latency} 4 | \alias{get_latency} 5 | \title{the latency is also the amount the shift is off by} 6 | \usage{ 7 | get_latency(new_data, forecast_date, column, sign_shift, epi_keys_checked) 8 | } 9 | \arguments{ 10 | \item{sign_shift}{integer. 1 if lag and -1 if ahead. These represent how you 11 | need to shift the data to bring the 3 day lagged value to today.} 12 | } 13 | \description{ 14 | the latency is also the amount the shift is off by 15 | } 16 | \keyword{internal} 17 | -------------------------------------------------------------------------------- /man/get_latency_table.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-latency.R 3 | \name{get_latency_table} 4 | \alias{get_latency_table} 5 | \title{create the latency table 6 | This is a table of column names and the latency adjustment necessary for that column. An example:} 7 | \usage{ 8 | get_latency_table( 9 | training, 10 | columns, 11 | forecast_date, 12 | latency, 13 | sign_shift, 14 | epi_keys_checked, 15 | keys_to_ignore, 16 | info, 17 | terms 18 | ) 19 | } 20 | \description{ 21 | col_name latency 22 | \if{html}{\out{}} \if{html}{\out{}} 23 | 1 case_rate 5 24 | 2 death_rate 5 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /man/get_sign.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/epi_shift.R 3 | \name{get_sign} 4 | \alias{get_sign} 5 | \title{lags move columns forward to bring the past up to today, while aheads drag 6 | the future back to today} 7 | \usage{ 8 | get_sign(object) 9 | } 10 | \description{ 11 | lags move columns forward to bring the past up to today, while aheads drag 12 | the future back to today 13 | } 14 | \keyword{internal} 15 | -------------------------------------------------------------------------------- /man/get_test_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/get_test_data.R 3 | \name{get_test_data} 4 | \alias{get_test_data} 5 | \title{Get test data for prediction based on longest lag period} 6 | \usage{ 7 | get_test_data(recipe, x) 8 | } 9 | \arguments{ 10 | \item{recipe}{A recipe object.} 11 | 12 | \item{x}{An epi_df. The typical usage is to 13 | pass the same data as that used for fitting the recipe.} 14 | } 15 | \value{ 16 | An object of the same type as \code{x} with columns \code{geo_value}, \code{time_value}, any additional 17 | keys, as well other variables in the original dataset. 18 | } 19 | \description{ 20 | Based on the longest lag period in the recipe, 21 | \code{get_test_data()} creates an \link[epiprocess:epi_df]{epi_df} 22 | with columns \code{geo_value}, \code{time_value} 23 | and other variables in the original dataset, 24 | which will be used to create features necessary to produce forecasts. 25 | } 26 | \details{ 27 | The minimum required (recent) data to produce a forecast is equal to 28 | the maximum lag requested (on any predictor) plus the longest horizon 29 | used if growth rate calculations are requested by the recipe. This is 30 | calculated internally. 31 | } 32 | \examples{ 33 | # create recipe 34 | rec <- epi_recipe(covid_case_death_rates) \%>\% 35 | step_epi_ahead(death_rate, ahead = 7) \%>\% 36 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 37 | step_epi_lag(case_rate, lag = c(0, 7, 14)) 38 | get_test_data(recipe = rec, x = covid_case_death_rates) 39 | } 40 | -------------------------------------------------------------------------------- /man/is_epi_recipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/epi_recipe.R 3 | \name{is_epi_recipe} 4 | \alias{is_epi_recipe} 5 | \title{Test for \code{epi_recipe}} 6 | \usage{ 7 | is_epi_recipe(x) 8 | } 9 | \arguments{ 10 | \item{x}{An object.} 11 | } 12 | \value{ 13 | \code{TRUE} if the object inherits from \code{epi_recipe}. 14 | } 15 | \description{ 16 | Test for \code{epi_recipe} 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/is_epi_workflow.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/epi_workflow.R 3 | \name{is_epi_workflow} 4 | \alias{is_epi_workflow} 5 | \title{Test for an \code{epi_workflow}} 6 | \usage{ 7 | is_epi_workflow(x) 8 | } 9 | \arguments{ 10 | \item{x}{An object.} 11 | } 12 | \value{ 13 | \code{TRUE} if the object inherits from \code{epi_workflow}. 14 | } 15 | \description{ 16 | Test for an \code{epi_workflow} 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/isoweek_leap.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/step_climate.R 3 | \name{isoweek_leap} 4 | \alias{isoweek_leap} 5 | \title{isoweek, but it assigns week 53 the value of 999 instead so it mirrors the assignments in yday_leap} 6 | \usage{ 7 | isoweek_leap(time_value) 8 | } 9 | \description{ 10 | isoweek, but it assigns week 53 the value of 999 instead so it mirrors the assignments in yday_leap 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/layer-processors.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/extract.R, R/layers.R 3 | \name{extract_layers} 4 | \alias{extract_layers} 5 | \alias{extract_layers.frosting} 6 | \alias{extract_layers.workflow} 7 | \alias{layer-processors} 8 | \alias{is_layer} 9 | \alias{validate_layer} 10 | \alias{detect_layer} 11 | \alias{detect_layer.frosting} 12 | \alias{detect_layer.workflow} 13 | \title{Extract, validate, or detect layers of frosting} 14 | \usage{ 15 | extract_layers(x, ...) 16 | 17 | \method{extract_layers}{frosting}(x, ...) 18 | 19 | \method{extract_layers}{workflow}(x, ...) 20 | 21 | is_layer(x) 22 | 23 | validate_layer(x, ..., arg = rlang::caller_arg(x), call = caller_env()) 24 | 25 | detect_layer(x, name, ...) 26 | 27 | \method{detect_layer}{frosting}(x, name, ...) 28 | 29 | \method{detect_layer}{workflow}(x, name, ...) 30 | } 31 | \arguments{ 32 | \item{x}{an \code{epi_workflow}, \code{frosting}, or \code{layer} object} 33 | 34 | \item{...}{additional arguments for possible future methods} 35 | 36 | \item{arg}{the name of the input (for error reporting)} 37 | 38 | \item{call}{the environment (for error reporting)} 39 | 40 | \item{name}{a layer name to detect} 41 | } 42 | \value{ 43 | A logical for the validators/detectors or a list of layers for 44 | the extractors 45 | } 46 | \description{ 47 | These functions are mainly internal. They can access and validate 48 | different layers of \code{frosting}. 49 | } 50 | \examples{ 51 | 52 | f <- frosting() \%>\% layer_predict() 53 | wf <- epi_workflow(postprocessor = f) 54 | 55 | is_layer(layer("what_the_what")) 56 | detect_layer(f, "layer_predict") 57 | detect_layer(wf, "layer_predict") 58 | 59 | extract_layers(f) 60 | extract_layers(wf) 61 | } 62 | -------------------------------------------------------------------------------- /man/layer.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layers.R 3 | \name{layer} 4 | \alias{layer} 5 | \title{\code{layer} sets the class of the \code{layer}} 6 | \usage{ 7 | layer(subclass, ..., .prefix = "layer_") 8 | } 9 | \arguments{ 10 | \item{subclass}{A character string for the resulting class. For example, 11 | if \code{subclass = "blah"} the layer object that is returned has class 12 | \code{layer_blah}.} 13 | 14 | \item{...}{All arguments to the operator that should be returned.} 15 | 16 | \item{.prefix}{Prefix to the subclass created.} 17 | } 18 | \value{ 19 | An updated layer with the new class 20 | } 21 | \description{ 22 | \code{layer} sets the class of the \code{layer} 23 | } 24 | \keyword{internal} 25 | -------------------------------------------------------------------------------- /man/layer_naomit.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layer_naomit.R 3 | \name{layer_naomit} 4 | \alias{layer_naomit} 5 | \title{Omit \code{NA}s from predictions or other columns} 6 | \usage{ 7 | layer_naomit(frosting, ..., id = rand_id("naomit")) 8 | } 9 | \arguments{ 10 | \item{frosting}{a \code{frosting} postprocessor} 11 | 12 | \item{...}{<\code{\link[dplyr:dplyr_tidy_select]{tidy-select}}> One or more unquoted 13 | expressions separated by commas. Variable names can be used as if they 14 | were positions in the data frame, so expressions like \code{x:y} can 15 | be used to select a range of variables. Typical usage is \code{.pred} to remove 16 | any rows with \code{NA} predictions.} 17 | 18 | \item{id}{a random id string} 19 | } 20 | \value{ 21 | an updated \code{frosting} postprocessor 22 | } 23 | \description{ 24 | Omit \code{NA}s from predictions or other columns 25 | } 26 | \examples{ 27 | jhu <- covid_case_death_rates \%>\% 28 | filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) 29 | 30 | r <- epi_recipe(jhu) \%>\% 31 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 32 | step_epi_ahead(death_rate, ahead = 7) 33 | 34 | wf <- epi_workflow(r, linear_reg()) \%>\% fit(jhu) 35 | 36 | f <- frosting() \%>\% 37 | layer_predict() \%>\% 38 | layer_naomit(.pred) 39 | 40 | wf1 <- wf \%>\% add_frosting(f) 41 | 42 | p <- forecast(wf1) 43 | p 44 | } 45 | -------------------------------------------------------------------------------- /man/layer_point_from_distn.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layer_point_from_distn.R 3 | \name{layer_point_from_distn} 4 | \alias{layer_point_from_distn} 5 | \title{Converts distributional forecasts to point forecasts} 6 | \usage{ 7 | layer_point_from_distn( 8 | frosting, 9 | ..., 10 | type = c("median", "mean"), 11 | name = NULL, 12 | id = rand_id("point_from_distn") 13 | ) 14 | } 15 | \arguments{ 16 | \item{frosting}{a \code{frosting} postprocessor} 17 | 18 | \item{...}{Unused, include for consistency with other layers.} 19 | 20 | \item{type}{character. Either \code{mean} or \code{median}.} 21 | 22 | \item{name}{character. The name for the output column. The default \code{NULL} 23 | will overwrite the \code{.pred} column, removing the distribution information.} 24 | 25 | \item{id}{a random id string} 26 | } 27 | \value{ 28 | an updated \code{frosting} postprocessor. 29 | } 30 | \description{ 31 | This function adds a postprocessing layer to extract a point forecast from 32 | a distributional forecast. NOTE: With default arguments, this will remove 33 | information, so one should usually call this AFTER \code{layer_quantile_distn()} 34 | or set the \code{name} argument to something specific. 35 | } 36 | \examples{ 37 | jhu <- covid_case_death_rates \%>\% 38 | filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) 39 | 40 | r <- epi_recipe(jhu) \%>\% 41 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 42 | step_epi_ahead(death_rate, ahead = 7) \%>\% 43 | step_epi_naomit() 44 | 45 | wf <- epi_workflow(r, quantile_reg(quantile_levels = c(.25, .5, .75))) \%>\% 46 | fit(jhu) 47 | 48 | f1 <- frosting() \%>\% 49 | layer_predict() \%>\% 50 | layer_quantile_distn() \%>\% # puts the other quantiles in a different col 51 | layer_point_from_distn() \%>\% # mutate `.pred` to contain only a point prediction 52 | layer_naomit(.pred) 53 | wf1 <- wf \%>\% add_frosting(f1) 54 | 55 | p1 <- forecast(wf1) 56 | p1 57 | 58 | f2 <- frosting() \%>\% 59 | layer_predict() \%>\% 60 | layer_point_from_distn() \%>\% # mutate `.pred` to contain only a point prediction 61 | layer_naomit(.pred) 62 | wf2 <- wf \%>\% add_frosting(f2) 63 | 64 | p2 <- forecast(wf2) 65 | p2 66 | } 67 | -------------------------------------------------------------------------------- /man/layer_predictive_distn.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layer_predictive_distn.R 3 | \name{layer_predictive_distn} 4 | \alias{layer_predictive_distn} 5 | \title{Returns predictive distributions} 6 | \usage{ 7 | layer_predictive_distn( 8 | frosting, 9 | ..., 10 | dist_type = c("gaussian", "student_t"), 11 | truncate = c(-Inf, Inf), 12 | name = ".pred_distn", 13 | id = rand_id("predictive_distn") 14 | ) 15 | } 16 | \arguments{ 17 | \item{frosting}{a \code{frosting} postprocessor} 18 | 19 | \item{...}{Unused, include for consistency with other layers.} 20 | 21 | \item{dist_type}{Gaussian or Student's t predictive intervals} 22 | 23 | \item{truncate}{Do we truncate the distribution to an interval} 24 | 25 | \item{name}{character. The name for the output column.} 26 | 27 | \item{id}{a random id string} 28 | } 29 | \value{ 30 | an updated \code{frosting} postprocessor with additional columns of the 31 | residual quantiles added to the prediction 32 | } 33 | \description{ 34 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 35 | } 36 | \details{ 37 | This function calculates an \emph{approximation} to a parametric predictive 38 | distribution. Predictive distributions from linear models require 39 | \verb{x* (X'X)^\{-1\} x*} 40 | along with the degrees of freedom. This function approximates both. It 41 | should be reasonably accurate for models fit using \code{lm} when the new point 42 | \verb{x*} isn't too far from the bulk of the data. 43 | } 44 | -------------------------------------------------------------------------------- /man/layer_quantile_distn.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layer_quantile_distn.R 3 | \name{layer_quantile_distn} 4 | \alias{layer_quantile_distn} 5 | \title{Returns predictive quantiles} 6 | \usage{ 7 | layer_quantile_distn( 8 | frosting, 9 | ..., 10 | quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95), 11 | truncate = c(-Inf, Inf), 12 | name = ".pred_distn", 13 | id = rand_id("quantile_distn") 14 | ) 15 | } 16 | \arguments{ 17 | \item{frosting}{a \code{frosting} postprocessor} 18 | 19 | \item{...}{Unused, include for consistency with other layers.} 20 | 21 | \item{quantile_levels}{a vector of probabilities to extract} 22 | 23 | \item{truncate}{Do we truncate the distribution to an interval} 24 | 25 | \item{name}{character. The name for the output column.} 26 | 27 | \item{id}{a random id string} 28 | } 29 | \value{ 30 | an updated \code{frosting} postprocessor. An additional column of predictive 31 | quantiles will be added to the predictions. 32 | } 33 | \description{ 34 | This function calculates quantiles when the prediction was \emph{distributional}. 35 | } 36 | \details{ 37 | Currently, the only distributional modes/engines are 38 | \itemize{ 39 | \item \code{quantile_reg()} 40 | \item \code{smooth_quantile_reg()} 41 | \item \code{rand_forest(mode = "regression") \%>\% set_engine("grf_quantiles")} 42 | } 43 | 44 | If these engines were used, then this layer will grab out estimated 45 | (or extrapolated) quantiles at the requested quantile values. 46 | } 47 | \examples{ 48 | jhu <- covid_case_death_rates \%>\% 49 | filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) 50 | 51 | r <- epi_recipe(jhu) \%>\% 52 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 53 | step_epi_ahead(death_rate, ahead = 7) \%>\% 54 | step_epi_naomit() 55 | 56 | wf <- epi_workflow(r, quantile_reg(quantile_levels = c(.25, .5, .75))) \%>\% 57 | fit(jhu) 58 | 59 | f <- frosting() \%>\% 60 | layer_predict() \%>\% 61 | layer_quantile_distn() \%>\% 62 | layer_naomit(.pred) 63 | wf1 <- wf \%>\% add_frosting(f) 64 | 65 | p <- forecast(wf1) 66 | p 67 | } 68 | -------------------------------------------------------------------------------- /man/layer_residual_quantiles.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layer_residual_quantiles.R 3 | \name{layer_residual_quantiles} 4 | \alias{layer_residual_quantiles} 5 | \title{Creates predictions based on residual quantiles} 6 | \usage{ 7 | layer_residual_quantiles( 8 | frosting, 9 | ..., 10 | quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95), 11 | symmetrize = TRUE, 12 | by_key = character(0L), 13 | name = ".pred_distn", 14 | id = rand_id("residual_quantiles") 15 | ) 16 | } 17 | \arguments{ 18 | \item{frosting}{a \code{frosting} postprocessor} 19 | 20 | \item{...}{Unused, include for consistency with other layers.} 21 | 22 | \item{quantile_levels}{numeric vector of probabilities with values in (0,1) 23 | referring to the desired quantile. Note that 0.5 will always be included 24 | even if left out by the user.} 25 | 26 | \item{symmetrize}{logical. If \code{TRUE} then interval will be symmetric.} 27 | 28 | \item{by_key}{A character vector of keys to group the residuals by before 29 | calculating quantiles. The default, \code{c()} performs no grouping.} 30 | 31 | \item{name}{character. The name for the output column.} 32 | 33 | \item{id}{a random id string} 34 | } 35 | \value{ 36 | an updated \code{frosting} postprocessor with additional columns of the 37 | residual quantiles added to the prediction 38 | } 39 | \description{ 40 | Creates predictions based on residual quantiles 41 | } 42 | \examples{ 43 | jhu <- covid_case_death_rates \%>\% 44 | filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) 45 | 46 | r <- epi_recipe(jhu) \%>\% 47 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 48 | step_epi_ahead(death_rate, ahead = 7) \%>\% 49 | step_epi_naomit() 50 | 51 | wf <- epi_workflow(r, linear_reg()) \%>\% fit(jhu) 52 | 53 | f <- frosting() \%>\% 54 | layer_predict() \%>\% 55 | layer_residual_quantiles( 56 | quantile_levels = c(0.025, 0.975), 57 | symmetrize = FALSE 58 | ) \%>\% 59 | layer_naomit(.pred) 60 | wf1 <- wf \%>\% add_frosting(f) 61 | 62 | p <- forecast(wf1) 63 | 64 | f2 <- frosting() \%>\% 65 | layer_predict() \%>\% 66 | layer_residual_quantiles( 67 | quantile_levels = c(0.3, 0.7), 68 | by_key = "geo_value" 69 | ) \%>\% 70 | layer_naomit(.pred) 71 | wf2 <- wf \%>\% add_frosting(f2) 72 | 73 | p2 <- forecast(wf2) 74 | } 75 | -------------------------------------------------------------------------------- /man/layer_threshold.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layer_threshold_preds.R 3 | \name{layer_threshold} 4 | \alias{layer_threshold} 5 | \title{Lower and upper thresholds for predicted values} 6 | \usage{ 7 | layer_threshold( 8 | frosting, 9 | ..., 10 | lower = 0, 11 | upper = Inf, 12 | id = rand_id("threshold") 13 | ) 14 | } 15 | \arguments{ 16 | \item{frosting}{a \code{frosting} postprocessor} 17 | 18 | \item{...}{<\code{\link[dplyr:dplyr_tidy_select]{tidy-select}}> One or more unquoted 19 | expressions separated by commas. Variable names can be used as if they 20 | were positions in the data frame, so expressions like \code{x:y} can 21 | be used to select a range of variables. Typical usage is \code{.pred} to 22 | threshold predictions to a range (say, nonnegative).} 23 | 24 | \item{lower}{Lower threshold for the prediction values. That is, any 25 | predictions that are less than this lower bound are set to it. 26 | Default value is \code{0}.} 27 | 28 | \item{upper}{Upper threshold for the prediction values. That is, any 29 | predictions that are greater than this upper bound are set to it. 30 | Default value is \code{Inf}.} 31 | 32 | \item{id}{a random id string} 33 | } 34 | \value{ 35 | an updated \code{frosting} postprocessor 36 | } 37 | \description{ 38 | This postprocessing step is used to set prediction values that are 39 | smaller than the lower threshold or higher than the upper threshold equal 40 | to the threshold values. 41 | } 42 | \examples{ 43 | jhu <- covid_case_death_rates \%>\% 44 | filter(time_value < "2021-03-08", geo_value \%in\% c("ak", "ca", "ar")) 45 | 46 | r <- epi_recipe(jhu) \%>\% 47 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 48 | step_epi_ahead(death_rate, ahead = 7) \%>\% 49 | step_epi_naomit() 50 | wf <- epi_workflow(r, linear_reg()) \%>\% fit(jhu) 51 | 52 | f <- frosting() \%>\% 53 | layer_predict() \%>\% 54 | layer_threshold(.pred, lower = 0.180, upper = 0.310) 55 | wf <- wf \%>\% add_frosting(f) 56 | p <- forecast(wf) 57 | p 58 | } 59 | -------------------------------------------------------------------------------- /man/layer_unnest.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layer_unnest.R 3 | \name{layer_unnest} 4 | \alias{layer_unnest} 5 | \title{Unnest prediction list-cols} 6 | \usage{ 7 | layer_unnest(frosting, ..., id = rand_id("unnest")) 8 | } 9 | \arguments{ 10 | \item{frosting}{a \code{frosting} postprocessor} 11 | 12 | \item{...}{<\code{\link[dplyr:dplyr_tidy_select]{tidy-select}}> One or more unquoted 13 | expressions separated by commas. Variable names can be used as if they 14 | were positions in the data frame, so expressions like \code{x:y} can 15 | be used to select a range of variables.} 16 | 17 | \item{id}{a random id string} 18 | } 19 | \value{ 20 | an updated \code{frosting} postprocessor 21 | } 22 | \description{ 23 | Unnest prediction list-cols 24 | } 25 | -------------------------------------------------------------------------------- /man/nested_quantiles.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pivot_quantiles.R 3 | \name{nested_quantiles} 4 | \alias{nested_quantiles} 5 | \title{Turn a vector of quantile distributions into a list-col} 6 | \usage{ 7 | nested_quantiles(x) 8 | } 9 | \arguments{ 10 | \item{x}{a \code{distribution} containing \code{dist_quantiles}} 11 | } 12 | \value{ 13 | a list-col 14 | } 15 | \description{ 16 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 17 | } 18 | \details{ 19 | This function is deprecated. The recommended alternative is 20 | \code{\link[hardhat:quantile_pred]{hardhat::quantile_pred()}} with \code{\link[tibble:as_tibble]{tibble::as_tibble()}} 21 | } 22 | \examples{ 23 | pred_quantile <- quantile_pred(matrix(rnorm(20), 5), c(.2, .4, .6, .8)) 24 | nested_quantiles(pred_quantile) 25 | 26 | pred_quantile \%>\% 27 | as_tibble() \%>\% 28 | tidyr::nest(.by = .row) \%>\% 29 | dplyr::select(-.row) 30 | 31 | } 32 | -------------------------------------------------------------------------------- /man/pad_to_end.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-latency.R 3 | \name{pad_to_end} 4 | \alias{pad_to_end} 5 | \title{pad every group at the right interval} 6 | \usage{ 7 | pad_to_end(x, groups, end_date, columns_to_complete = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{an epi_df to be filled forward.} 11 | 12 | \item{groups}{the grouping by which to fill forward} 13 | 14 | \item{columns_to_complete}{which columns to apply completion to. By default every non-key column of an epi_df} 15 | } 16 | \description{ 17 | Perform last observation carried forward on a group by group basis. It uses 18 | \code{guess_period} to find the appropriate interval to fill-forward by. It 19 | maintains the grouping structure it recieves. It does \emph{not} fill any 20 | "interior" \code{NA} values occurring in the data beforehand. 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /man/pipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-pipe.R 3 | \name{\%>\%} 4 | \alias{\%>\%} 5 | \title{Pipe operator} 6 | \usage{ 7 | lhs \%>\% rhs 8 | } 9 | \arguments{ 10 | \item{lhs}{A value or the magrittr placeholder.} 11 | 12 | \item{rhs}{A function call using the magrittr semantics.} 13 | } 14 | \value{ 15 | The result of calling \code{rhs(lhs)}. 16 | } 17 | \description{ 18 | See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/pivot_quantiles_longer.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pivot_quantiles.R 3 | \name{pivot_quantiles_longer} 4 | \alias{pivot_quantiles_longer} 5 | \title{Pivot a column containing \code{quantile_pred} longer} 6 | \usage{ 7 | pivot_quantiles_longer(.data, ...) 8 | } 9 | \arguments{ 10 | \item{.data}{A data frame, or a data frame extension such as a tibble or 11 | epi_df.} 12 | 13 | \item{...}{<\code{\link[dplyr:dplyr_tidy_select]{tidy-select}}> One unquoted 14 | expressions separated by commas. Variable names can be used as if they 15 | were positions in the data frame. Note that only one variable 16 | can be selected for this operation.} 17 | } 18 | \value{ 19 | An object of the same class as \code{.data}. 20 | } 21 | \description{ 22 | A column that contains \code{quantile_pred} will be "lengthened" with 23 | the quantile levels serving as 1 column and the values as another. If 24 | multiple columns are selected, these will be prefixed with the column name. 25 | } 26 | \examples{ 27 | d1 <- quantile_pred(rbind(1:3, 2:4), 1:3 / 4) 28 | d2 <- quantile_pred(rbind(2:4, 3:5), 2:4 / 5) 29 | tib <- tibble(g = c("a", "b"), d1 = d1, d2 = d2) 30 | 31 | pivot_quantiles_longer(tib, "d1") 32 | pivot_quantiles_longer(tib, dplyr::ends_with("1")) 33 | pivot_quantiles_longer(tib, d2) 34 | } 35 | -------------------------------------------------------------------------------- /man/pivot_quantiles_wider.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pivot_quantiles.R 3 | \name{pivot_quantiles_wider} 4 | \alias{pivot_quantiles_wider} 5 | \title{Pivot a column containing \code{quantile_pred} wider} 6 | \usage{ 7 | pivot_quantiles_wider(.data, ...) 8 | } 9 | \arguments{ 10 | \item{.data}{A data frame, or a data frame extension such as a tibble or 11 | epi_df.} 12 | 13 | \item{...}{<\code{\link[dplyr:dplyr_tidy_select]{tidy-select}}> One unquoted 14 | expressions separated by commas. Variable names can be used as if they 15 | were positions in the data frame. Note that only one variable 16 | can be selected for this operation.} 17 | } 18 | \value{ 19 | An object of the same class as \code{.data} 20 | } 21 | \description{ 22 | Any selected columns that contain \code{quantile_pred} will be "widened" with 23 | the "taus" (quantile) serving as names and the values in the data frame. 24 | When pivoting multiple columns, the original column name will be used as 25 | a prefix. 26 | } 27 | \examples{ 28 | d1 <- quantile_pred(rbind(1:3, 2:4), 1:3 / 4) 29 | d2 <- quantile_pred(rbind(2:4, 3:5), 2:4 / 5) 30 | tib <- tibble(g = c("a", "b"), d1 = d1, d2 = d2) 31 | 32 | pivot_quantiles_wider(tib, "d1") 33 | pivot_quantiles_wider(tib, dplyr::ends_with("2")) 34 | pivot_quantiles_wider(tib, d2) 35 | } 36 | -------------------------------------------------------------------------------- /man/quantile.quantile_pred.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/quantile_pred-methods.R 3 | \name{quantile.quantile_pred} 4 | \alias{quantile.quantile_pred} 5 | \title{Quantiles from a distribution} 6 | \usage{ 7 | \method{quantile}{quantile_pred}( 8 | x, 9 | probs = seq(0, 1, 0.25), 10 | na.rm = FALSE, 11 | lower = -Inf, 12 | upper = Inf, 13 | middle = c("cubic", "linear"), 14 | ... 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{numeric vector whose sample quantiles are wanted, or an 19 | object of a class for which a method has been defined (see also 20 | \sQuote{details}). \code{\link{NA}} and \code{NaN} values are not 21 | allowed in numeric vectors unless \code{na.rm} is \code{TRUE}.} 22 | 23 | \item{probs}{numeric vector of probabilities with values in 24 | \eqn{[0,1]}. (Values up to \samp{2e-14} outside that 25 | range are accepted and moved to the nearby endpoint.)} 26 | 27 | \item{na.rm}{logical; if true, any \code{\link{NA}} and \code{NaN}'s 28 | are removed from \code{x} before the quantiles are computed.} 29 | 30 | \item{lower}{Scalar. Optional lower bound.} 31 | 32 | \item{upper}{Scalar. Optional upper bound.} 33 | 34 | \item{middle}{Controls how extrapolation to "interior" probabilities is 35 | performed. "cubic" attempts to use \code{\link[stats:splinefun]{stats::splinefun()}} while "linear" 36 | uses \code{\link[stats:approxfun]{stats::approx()}}. The "linear" method is used as a fallback if 37 | "cubic" should fail for some reason.} 38 | 39 | \item{...}{unused} 40 | } 41 | \value{ 42 | a matrix with one row for each entry in \code{x} and one column for each 43 | value in \code{probs} 44 | } 45 | \description{ 46 | Given a \link[hardhat:quantile_pred]{hardhat::quantile_pred} object, users may wish to compute additional 47 | \code{quantile_levels} that are not part of the object. This function attempts 48 | to estimate these quantities under some assumptions. Interior probabilities, 49 | those contained within existing probabilities are interpolated in a manner 50 | controled by the \code{middle} argument. Those outside existing probabilities 51 | are extrapolated under the assumption that the tails of the distribution 52 | decays exponentially. Optionally, one may constrain \emph{all} quantiles to be 53 | within some support (say, \verb{[0, Inf)}). 54 | } 55 | \examples{ 56 | qp <- quantile_pred(matrix(1:8, nrow = 2, byrow = TRUE), 1:4 / 5) 57 | quantile(qp) 58 | quantile(qp, lower = 0) 59 | quantile(qp, probs = 0.5) 60 | quantile(qp, probs = 1:9 / 10) 61 | } 62 | \seealso{ 63 | \code{\link[=extrapolate_quantiles]{extrapolate_quantiles()}} 64 | } 65 | -------------------------------------------------------------------------------- /man/quantile_reg.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/make_quantile_reg.R 3 | \name{quantile_reg} 4 | \alias{quantile_reg} 5 | \title{Quantile regression} 6 | \usage{ 7 | quantile_reg( 8 | mode = "regression", 9 | engine = "rq", 10 | quantile_levels = c(0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95), 11 | method = "br" 12 | ) 13 | } 14 | \arguments{ 15 | \item{mode}{A single character string for the type of model. 16 | The only possible value for this model is "regression".} 17 | 18 | \item{engine}{Character string naming the fitting function. Currently, only 19 | "rq" and "grf" are supported.} 20 | 21 | \item{quantile_levels}{A scalar or vector of values in (0, 1) to determine which 22 | quantiles to estimate (default is the set 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95).} 23 | 24 | \item{method}{A fitting method used by \code{\link[quantreg:rq]{quantreg::rq()}}. See the 25 | documentation for a list of options.} 26 | } 27 | \description{ 28 | \code{quantile_reg()} generates a quantile regression model \emph{specification} for 29 | the \href{https://www.tidymodels.org/}{tidymodels} framework. Currently, the 30 | only supported engines are "rq", which uses \code{\link[quantreg:rq]{quantreg::rq()}}. 31 | Quantile regression is also possible by combining \code{\link[parsnip:rand_forest]{parsnip::rand_forest()}} 32 | with the \code{grf} engine. See \link{grf_quantiles}. 33 | } 34 | \examples{ 35 | library(quantreg) 36 | tib <- data.frame(y = rnorm(100), x1 = rnorm(100), x2 = rnorm(100)) 37 | rq_spec <- quantile_reg(quantile_levels = c(.2, .8)) \%>\% set_engine("rq") 38 | ff <- rq_spec \%>\% fit(y ~ ., data = tib) 39 | predict(ff, new_data = tib) 40 | } 41 | \seealso{ 42 | \code{\link[=fit.model_spec]{fit.model_spec()}}, \code{\link[=set_engine]{set_engine()}} 43 | } 44 | -------------------------------------------------------------------------------- /man/reexports.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/autoplot.R, R/reexports-tidymodels.R, 3 | % R/reexports.R 4 | \docType{import} 5 | \name{reexports} 6 | \alias{reexports} 7 | \alias{autoplot} 8 | \alias{fit} 9 | \alias{forecast} 10 | \alias{prep} 11 | \alias{bake} 12 | \alias{rand_id} 13 | \alias{tibble} 14 | \alias{as_tibble} 15 | \alias{tidy} 16 | \alias{quantile_pred} 17 | \alias{extract_quantile_levels} 18 | \alias{filter} 19 | \alias{mutate} 20 | \alias{rename} 21 | \alias{select} 22 | \alias{as_epi_df} 23 | \alias{key_colnames} 24 | \alias{pivot_longer} 25 | \alias{pivot_wider} 26 | \alias{unnest} 27 | \title{Objects exported from other packages} 28 | \keyword{internal} 29 | \description{ 30 | These objects are imported from other packages. Follow the links 31 | below to see their documentation. 32 | 33 | \describe{ 34 | \item{dplyr}{\code{\link[dplyr]{filter}}, \code{\link[dplyr]{mutate}}, \code{\link[dplyr]{rename}}, \code{\link[dplyr]{select}}} 35 | 36 | \item{epiprocess}{\code{\link[epiprocess:epi_df]{as_epi_df}}, \code{\link[epiprocess]{key_colnames}}} 37 | 38 | \item{generics}{\code{\link[generics]{fit}}, \code{\link[generics]{fit}}, \code{\link[generics]{forecast}}, \code{\link[generics]{forecast}}, \code{\link[generics]{tidy}}, \code{\link[generics]{tidy}}} 39 | 40 | \item{ggplot2}{\code{\link[ggplot2]{autoplot}}} 41 | 42 | \item{hardhat}{\code{\link[hardhat:quantile_pred]{extract_quantile_levels}}, \code{\link[hardhat:quantile_pred]{extract_quantile_levels}}, \code{\link[hardhat]{quantile_pred}}, \code{\link[hardhat]{quantile_pred}}} 43 | 44 | \item{recipes}{\code{\link[recipes]{bake}}, \code{\link[recipes]{bake}}, \code{\link[recipes]{prep}}, \code{\link[recipes]{prep}}, \code{\link[recipes]{rand_id}}, \code{\link[recipes]{rand_id}}} 45 | 46 | \item{tibble}{\code{\link[tibble]{as_tibble}}, \code{\link[tibble]{as_tibble}}, \code{\link[tibble]{tibble}}, \code{\link[tibble]{tibble}}} 47 | 48 | \item{tidyr}{\code{\link[tidyr]{pivot_longer}}, \code{\link[tidyr]{pivot_wider}}, \code{\link[tidyr]{unnest}}} 49 | }} 50 | 51 | -------------------------------------------------------------------------------- /man/roll_modular_multivec.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/step_climate.R 3 | \name{roll_modular_multivec} 4 | \alias{roll_modular_multivec} 5 | \title{group col by .idx values and sum windows around each .idx value} 6 | \usage{ 7 | roll_modular_multivec(col, .idx, weights, aggr, window_size, modulus) 8 | } 9 | \arguments{ 10 | \item{col}{the list of values indexed by \code{.idx}} 11 | 12 | \item{.idx}{the relevant periodic part of time value, e.g. the week number} 13 | 14 | \item{weights}{how much to weigh each particular datapoint} 15 | 16 | \item{aggr}{the aggregation function, probably Quantile, mean or median} 17 | 18 | \item{window_size}{the number of .idx entries before and after to include in 19 | the aggregation} 20 | 21 | \item{modulus}{the maximum value of \code{.idx}} 22 | } 23 | \description{ 24 | group col by .idx values and sum windows around each .idx value 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /man/seq_forward.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-latency.R 3 | \name{seq_forward} 4 | \alias{seq_forward} 5 | \title{seq, but returns null if from is larger} 6 | \usage{ 7 | seq_forward(from, to, by) 8 | } 9 | \description{ 10 | seq, but returns null if from is larger 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/slather.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layers.R 3 | \name{slather} 4 | \alias{slather} 5 | \title{Spread a layer of frosting on a fitted workflow} 6 | \usage{ 7 | slather(object, components, workflow, new_data, ...) 8 | } 9 | \arguments{ 10 | \item{object}{a workflow with \code{frosting} postprocessing steps} 11 | 12 | \item{components}{a list of components containing model information. These 13 | will be updated and returned by the layer. These should be 14 | \itemize{ 15 | \item \code{mold} - the output of calling \code{hardhat::mold()} on the workflow. This 16 | contains information about the preprocessing, including the recipe. 17 | \item \code{forged} - the output of calling \code{hardhat::forge()} on the workflow. 18 | This should have predictors and outcomes for the \code{new_data}. It will 19 | have three components \code{predictors}, \code{outcomes} (if these were in the 20 | \code{new_data}), and \code{extras} (usually has the rest of the data, including 21 | \code{keys}). 22 | \item \code{keys} - we put the keys (\code{time_value}, \code{geo_value}, and any others) 23 | here for ease. 24 | }} 25 | 26 | \item{workflow}{an object of class workflow} 27 | 28 | \item{new_data}{a data frame containing the new predictors to preprocess 29 | and predict on} 30 | 31 | \item{...}{additional arguments used by methods. Currently unused.} 32 | } 33 | \value{ 34 | The \code{components} list. In the same format after applying any updates. 35 | } 36 | \description{ 37 | Slathering frosting means to implement a postprocessing layer. When 38 | creating a new postprocessing layer, you must implement an S3 method 39 | for this function 40 | } 41 | -------------------------------------------------------------------------------- /man/snap.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layer_threshold_preds.R 3 | \name{snap} 4 | \alias{snap} 5 | \title{restrict various objects to the interval [lower, upper]} 6 | \usage{ 7 | snap(x, lower, upper, ...) 8 | } 9 | \arguments{ 10 | \item{x}{the object to restrict} 11 | 12 | \item{lower}{numeric, the lower bound} 13 | 14 | \item{upper}{numeric, the upper bound} 15 | 16 | \item{...}{unused} 17 | } 18 | \description{ 19 | restrict various objects to the interval [lower, upper] 20 | } 21 | \keyword{internal} 22 | -------------------------------------------------------------------------------- /man/step_adjust_latency_checks.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-latency.R 3 | \name{step_adjust_latency_checks} 4 | \alias{step_adjust_latency_checks} 5 | \title{checks: the recipe type, whether a previous step is the relevant epi_shift, 6 | that either \code{fixed_latency} or \code{fixed_forecast_date} is non-null, and that 7 | \code{fixed_latency} only references columns that exist at the time of the step 8 | inclusion} 9 | \usage{ 10 | step_adjust_latency_checks( 11 | id, 12 | method, 13 | recipe, 14 | fixed_latency, 15 | fixed_forecast_date, 16 | call = caller_env() 17 | ) 18 | } 19 | \description{ 20 | checks: the recipe type, whether a previous step is the relevant epi_shift, 21 | that either \code{fixed_latency} or \code{fixed_forecast_date} is non-null, and that 22 | \code{fixed_latency} only references columns that exist at the time of the step 23 | inclusion 24 | } 25 | \keyword{internal} 26 | -------------------------------------------------------------------------------- /man/step_epi_naomit.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/step_epi_naomit.R 3 | \name{step_epi_naomit} 4 | \alias{step_epi_naomit} 5 | \title{Unified NA omission wrapper function for recipes} 6 | \usage{ 7 | step_epi_naomit(recipe) 8 | } 9 | \arguments{ 10 | \item{recipe}{Recipe to be used for omission steps} 11 | } 12 | \value{ 13 | Omits NA's from both predictors and outcomes at training time 14 | to fit the model. Also only omits associated predictors and not 15 | outcomes at prediction time due to lack of response and avoidance 16 | of data loss. 17 | } 18 | \description{ 19 | Unified NA omission wrapper function for recipes 20 | } 21 | \examples{ 22 | covid_case_death_rates \%>\% 23 | epi_recipe() \%>\% 24 | step_epi_naomit() 25 | } 26 | -------------------------------------------------------------------------------- /man/step_lag_difference.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/step_lag_difference.R 3 | \name{step_lag_difference} 4 | \alias{step_lag_difference} 5 | \title{Calculate a lagged difference} 6 | \usage{ 7 | step_lag_difference( 8 | recipe, 9 | ..., 10 | role = "predictor", 11 | horizon = 7, 12 | prefix = "lag_diff_", 13 | skip = FALSE, 14 | id = rand_id("lag_diff") 15 | ) 16 | } 17 | \arguments{ 18 | \item{recipe}{A recipe object. The step will be added to the 19 | sequence of operations for this recipe.} 20 | 21 | \item{...}{One or more selector functions to choose variables 22 | for this step. See \code{\link[recipes:selections]{recipes::selections()}} for more details.} 23 | 24 | \item{role}{For model terms created by this step, what analysis role should 25 | they be assigned? \code{lag} is default a predictor while \code{ahead} is an outcome.} 26 | 27 | \item{horizon}{Scalar or vector. Time period(s) over which to calculate 28 | differences.} 29 | 30 | \item{prefix}{A character string that will be prefixed to the new column.} 31 | 32 | \item{skip}{A logical. Should the step be skipped when the 33 | recipe is baked by \code{\link[=bake]{bake()}}? While all operations are baked 34 | when \code{\link[=prep]{prep()}} is run, some operations may not be able to be 35 | conducted on new data (e.g. processing the outcome variable(s)). 36 | Care should be taken when using \code{skip = TRUE} as it may affect 37 | the computations for subsequent operations.} 38 | 39 | \item{id}{A unique identifier for the step} 40 | } 41 | \value{ 42 | An updated version of \code{recipe} with the new step added to the 43 | sequence of any existing operations. 44 | } 45 | \description{ 46 | \code{step_lag_difference()} creates a \emph{specification} of a recipe step 47 | that will generate one or more new columns of derived data. 48 | } 49 | \examples{ 50 | r <- epi_recipe(covid_case_death_rates) \%>\% 51 | step_lag_difference(case_rate, death_rate, horizon = c(7, 14)) \%>\% 52 | step_epi_naomit() 53 | r 54 | 55 | r \%>\% 56 | prep(covid_case_death_rates) \%>\% 57 | bake(new_data = NULL) 58 | } 59 | \seealso{ 60 | Other row operation steps: 61 | \code{\link{step_adjust_latency}()}, 62 | \code{\link{step_epi_lag}()}, 63 | \code{\link{step_growth_rate}()} 64 | } 65 | \concept{row operation steps} 66 | -------------------------------------------------------------------------------- /man/step_training_window.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/step_training_window.R 3 | \name{step_training_window} 4 | \alias{step_training_window} 5 | \title{Limits the size of the training window to the most recent observations} 6 | \usage{ 7 | step_training_window( 8 | recipe, 9 | role = NA, 10 | n_recent = 50, 11 | epi_keys = NULL, 12 | id = rand_id("training_window") 13 | ) 14 | } 15 | \arguments{ 16 | \item{recipe}{A recipe object. The step will be added to the 17 | sequence of operations for this recipe.} 18 | 19 | \item{role}{For model terms created by this step, what analysis role should 20 | they be assigned? \code{lag} is default a predictor while \code{ahead} is an outcome.} 21 | 22 | \item{n_recent}{An integer value that represents the number of most recent 23 | observations that are to be kept in the training window per key 24 | The default value is 50.} 25 | 26 | \item{epi_keys}{An optional character vector for specifying "key" variables 27 | to group on. The default, \code{NULL}, ensures that every key combination is 28 | limited.} 29 | 30 | \item{id}{A unique identifier for the step} 31 | } 32 | \value{ 33 | An updated version of \code{recipe} with the new step added to the 34 | sequence of any existing operations. 35 | } 36 | \description{ 37 | \code{step_training_window} creates a \emph{specification} of a recipe step that 38 | limits the size of the training window to the \code{n_recent} most recent 39 | observations in \code{time_value} per group, where the groups are formed 40 | based on the remaining \code{epi_keys}. 41 | } 42 | \details{ 43 | Note that \code{step_epi_lead()} and \code{step_epi_lag()} should come 44 | after any filtering step. 45 | } 46 | \examples{ 47 | tib <- tibble( 48 | x = 1:10, 49 | y = 1:10, 50 | time_value = rep(seq(as.Date("2020-01-01"), by = 1, length.out = 5), 2), 51 | geo_value = rep(c("ca", "hi"), each = 5) 52 | ) \%>\% 53 | as_epi_df() 54 | 55 | epi_recipe(y ~ x, data = tib) \%>\% 56 | step_training_window(n_recent = 3) \%>\% 57 | prep(tib) \%>\% 58 | bake(new_data = NULL) 59 | 60 | epi_recipe(y ~ x, data = tib) \%>\% 61 | step_epi_naomit() \%>\% 62 | step_training_window(n_recent = 3) \%>\% 63 | prep(tib) \%>\% 64 | bake(new_data = NULL) 65 | } 66 | -------------------------------------------------------------------------------- /man/tidy.frosting.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidy.R 3 | \name{tidy.frosting} 4 | \alias{tidy.frosting} 5 | \title{Tidy the result of a frosting object} 6 | \usage{ 7 | \method{tidy}{frosting}(x, number = NA, id = NA, ...) 8 | } 9 | \arguments{ 10 | \item{x}{A \code{frosting} or \code{layer} object} 11 | 12 | \item{number}{An integer or \code{NA}. If missing, and \code{id} is not provided, 13 | the return value is a list of the operations in the frosting. 14 | If a number is given, a \code{tidy} method is executed for that operation 15 | in the frosting (if it exists). \code{number} must not be provided if 16 | \code{id} is.} 17 | 18 | \item{id}{A character string or \code{NA}. If missing and \code{number} is not provided, 19 | the return value is a list of the operations in the frosting. 20 | If a character string is given, a \code{tidy} method is executed for that 21 | operation in the frosting (if it exists). \code{id} must not be provided 22 | if \code{number} is.} 23 | 24 | \item{...}{Not currently used.} 25 | } 26 | \value{ 27 | A tibble with columns that vary depending on what 28 | \code{tidy} method is executed. When \code{number}, and \code{id} are \code{NA}, a 29 | tibble with columns \code{number} (the operation iteration), 30 | \code{operation} ("layer"), 31 | \code{type} (the method, e.g. "predict", "naomit"), and a character column \code{id}. 32 | } 33 | \description{ 34 | \code{tidy} will return a data frame that contains information 35 | regarding a frosting or operation within the frosting (when a \code{tidy} 36 | method for the operation exists). Note that this is a modified 37 | version of the \code{tidy} method for a recipe. 38 | } 39 | \examples{ 40 | jhu <- covid_case_death_rates \%>\% 41 | filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) 42 | 43 | r <- epi_recipe(jhu) \%>\% 44 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 45 | step_epi_ahead(death_rate, ahead = 7) \%>\% 46 | step_epi_naomit() 47 | 48 | wf <- epi_workflow(r, parsnip::linear_reg()) \%>\% fit(jhu) 49 | latest <- get_test_data(recipe = r, x = jhu) 50 | 51 | f <- frosting() \%>\% 52 | layer_predict() \%>\% 53 | layer_naomit(.pred) 54 | 55 | tidy(f) 56 | 57 | } 58 | -------------------------------------------------------------------------------- /man/update.layer.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layers.R 3 | \name{update.layer} 4 | \alias{update.layer} 5 | \title{Update post-processing \code{layer}} 6 | \usage{ 7 | \method{update}{layer}(object, ...) 8 | } 9 | \arguments{ 10 | \item{object}{A post-processing \code{layer}.} 11 | 12 | \item{...}{Key-value pairs where the keys match up with names of elements 13 | in the layer, and the values are the new values to update the layer with.} 14 | } 15 | \description{ 16 | This \code{layer} method for \code{update()} takes named arguments as \code{...} whose values 17 | will replace the elements of the same name in the actual post-processing layer. 18 | Analogous to \code{update.step()} from the \code{recipes} package. 19 | } 20 | \examples{ 21 | jhu <- covid_case_death_rates \%>\% 22 | filter(time_value > "2021-11-01", geo_value \%in\% c("ak", "ca", "ny")) 23 | r <- epi_recipe(jhu) \%>\% 24 | step_epi_lag(death_rate, lag = c(0, 7, 14)) \%>\% 25 | step_epi_ahead(death_rate, ahead = 7) \%>\% 26 | step_epi_naomit() 27 | wf <- epi_workflow(r, linear_reg()) \%>\% fit(jhu) 28 | latest <- jhu \%>\% filter(time_value >= max(time_value) - 14) 29 | 30 | # Specify a `forecast_date` that is greater than or equal to `as_of` date 31 | f <- frosting() \%>\% 32 | layer_predict() \%>\% 33 | layer_add_forecast_date(forecast_date = "2022-05-31") \%>\% 34 | layer_naomit(.pred) 35 | 36 | wf1 <- wf \%>\% add_frosting(f) 37 | 38 | p1 <- predict(wf1, latest) 39 | p1 40 | 41 | # Update forecast date 42 | f$layers[[2]] <- update(f$layers[[2]], forecast_date = "2021-06-01") 43 | 44 | # Need to still update workflow if only update a layer in frosting 45 | wf2 <- wf \%>\% add_frosting(f) 46 | wf2$post # Check that wf1 has update 47 | p1 <- predict(wf2, latest) 48 | p1 49 | } 50 | -------------------------------------------------------------------------------- /man/yday_leap.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/step_climate.R 3 | \name{yday_leap} 4 | \alias{yday_leap} 5 | \title{a function that assigns Feb 29th to 999, and aligns all other dates the same 6 | number in the year, regardless of whether it's a leap year} 7 | \usage{ 8 | yday_leap(time_value) 9 | } 10 | \description{ 11 | a function that assigns Feb 29th to 999, and aligns all other dates the same 12 | number in the year, regardless of whether it's a leap year 13 | } 14 | \keyword{internal} 15 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(epipredict) 3 | library(parsnip) 4 | library(workflows) 5 | library(dplyr) 6 | 7 | 8 | test_check("epipredict") 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/arx_cargs_list.md: -------------------------------------------------------------------------------- 1 | # arx_class_args checks inputs 2 | 3 | Code 4 | arx_class_args_list(ahead = c(0, 4)) 5 | Condition 6 | Error in `arx_class_args_list()`: 7 | ! `ahead` must be a scalar. 8 | 9 | --- 10 | 11 | Code 12 | arx_class_args_list(n_training = c(28, 65)) 13 | Condition 14 | Error in `arx_class_args_list()`: 15 | ! `n_training` must be a scalar. 16 | 17 | --- 18 | 19 | Code 20 | arx_class_args_list(ahead = -1) 21 | Condition 22 | Error in `arx_class_args_list()`: 23 | ! `ahead` must be a non-negative integer. 24 | 25 | --- 26 | 27 | Code 28 | arx_class_args_list(ahead = 1.5) 29 | Condition 30 | Error in `arx_class_args_list()`: 31 | ! `ahead` must be a non-negative integer. 32 | 33 | --- 34 | 35 | Code 36 | arx_class_args_list(n_training = -1) 37 | Condition 38 | Error in `arx_class_args_list()`: 39 | ! `n_training` must be a strictly positive number. 40 | 41 | --- 42 | 43 | Code 44 | arx_class_args_list(n_training = 1.5) 45 | Condition 46 | Error in `arx_class_args_list()`: 47 | ! `n_training` must be a positive integer. 48 | 49 | --- 50 | 51 | Code 52 | arx_class_args_list(lags = c(-1, 0)) 53 | Condition 54 | Error in `arx_class_args_list()`: 55 | ! `lags` must be non-negative integers. 56 | 57 | --- 58 | 59 | Code 60 | arx_class_args_list(lags = list(c(1:5, 6.5), 2:8)) 61 | Condition 62 | Error in `arx_class_args_list()`: 63 | ! `lags` must be non-negative integers. 64 | 65 | --- 66 | 67 | Code 68 | arx_class_args_list(target_date = "2022-01-01") 69 | Condition 70 | Error in `arx_class_args_list()`: 71 | ! `target_date` must be a date. 72 | 73 | --- 74 | 75 | Code 76 | arx_class_args_list(n_training_min = "de") 77 | Condition 78 | Error in `arx_class_args_list()`: 79 | ! `...` must be empty. 80 | x Problematic argument: 81 | * n_training_min = "de" 82 | 83 | --- 84 | 85 | Code 86 | arx_class_args_list(epi_keys = 1) 87 | Condition 88 | Error in `arx_class_args_list()`: 89 | ! `...` must be empty. 90 | x Problematic argument: 91 | * epi_keys = 1 92 | 93 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/bake-method.md: -------------------------------------------------------------------------------- 1 | # bake method works in all cases 2 | 3 | Code 4 | bake(prep(r, edf), NULL, composition = "matrix") 5 | Condition 6 | Error in `juice()`: 7 | ! `data` must only contain numeric columns. 8 | i These columns aren't numeric: "geo_value" and "time_value". 9 | 10 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/check-training-set.md: -------------------------------------------------------------------------------- 1 | # training set validation works 2 | 3 | Code 4 | validate_meta_match(t1, template, "geo_type", "abort") 5 | Condition 6 | Error in `validate_meta_match()`: 7 | ! The `geo_type` of the training data appears to be different from that 8 | used to construct the recipe. This may result in unexpected consequences. 9 | i Training `geo_type` is 'county'. 10 | i Originally, it was 'state'. 11 | 12 | --- 13 | 14 | Code 15 | epi_check_training_set(t4, rec) 16 | Condition 17 | Error in `epi_check_training_set()`: 18 | ! The recipe specifies keys which are not in the training data. 19 | i The training set is missing columns for missing_col. 20 | 21 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/check_enough_data.md: -------------------------------------------------------------------------------- 1 | # check_enough_data works on pooled data 2 | 3 | Code 4 | epi_recipe(toy_epi_df) %>% check_enough_data(x, y, min_observations = 2 * n + 1, 5 | drop_na = FALSE) %>% prep(toy_epi_df) 6 | Condition 7 | Error in `check_enough_data_core()`: 8 | ! The following columns don't have enough data to train: x and y. 9 | 10 | --- 11 | 12 | Code 13 | epi_recipe(toy_epi_df) %>% check_enough_data(x, y, min_observations = 2 * n - 1, 14 | drop_na = TRUE) %>% prep(toy_epi_df) 15 | Condition 16 | Error in `check_enough_data_core()`: 17 | ! The following columns don't have enough data to train: x. 18 | 19 | # check_enough_data works on unpooled data 20 | 21 | Code 22 | epi_recipe(toy_epi_df) %>% check_enough_data(x, y, min_observations = n + 1, 23 | epi_keys = "geo_value", drop_na = FALSE) %>% prep(toy_epi_df) 24 | Condition 25 | Error in `check_enough_data_core()`: 26 | ! The following columns don't have enough data to train: x and y. 27 | 28 | --- 29 | 30 | Code 31 | epi_recipe(toy_epi_df) %>% check_enough_data(x, y, min_observations = 2 * n - 3, 32 | epi_keys = "geo_value", drop_na = TRUE) %>% prep(toy_epi_df) 33 | Condition 34 | Error in `check_enough_data_core()`: 35 | ! The following columns don't have enough data to train: x and y. 36 | 37 | # check_enough_data only checks train data when skip = FALSE 38 | 39 | Code 40 | forecaster %>% predict(new_data = toy_test_data %>% filter(time_value > 41 | "2020-01-08")) 42 | Condition 43 | Error in `check_enough_data_core()`: 44 | ! The following columns don't have enough data to predict: x. 45 | 46 | # check_enough_data works with all_predictors() downstream of constructed terms 47 | 48 | Code 49 | epi_recipe(toy_epi_df) %>% step_epi_lag(x, lag = c(1, 2)) %>% check_enough_data( 50 | all_predictors(), y, min_observations = 2 * n - 4) %>% prep(toy_epi_df) 51 | Condition 52 | Error in `check_enough_data_core()`: 53 | ! The following columns don't have enough data to train: no single column, but the combination of lag_1_x, lag_2_x, y. 54 | 55 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/climatological_forecaster.md: -------------------------------------------------------------------------------- 1 | # climate args list validates properly 2 | 3 | Code 4 | climate_args_list(forecast_date = 12345) 5 | Condition 6 | Error in `climate_args_list()`: 7 | ! `forecast_date` must be a date. 8 | 9 | --- 10 | 11 | Code 12 | climate_args_list(forecast_date = as.Date(c("2021-01-10", "2024-01-22"))) 13 | Condition 14 | Error in `climate_args_list()`: 15 | ! `forecast_date` must be a scalar. 16 | 17 | --- 18 | 19 | Code 20 | climate_args_list(forecast_horizon = 1.3) 21 | Condition 22 | Error in `climate_args_list()`: 23 | ! `forecast_horizon` must be a integer. 24 | 25 | --- 26 | 27 | Code 28 | climate_args_list(window_size = -1) 29 | Condition 30 | Error in `climate_args_list()`: 31 | ! `window_size` must be a non-negative integer. 32 | 33 | --- 34 | 35 | Code 36 | climate_args_list(window_size = 2.5) 37 | Condition 38 | Error in `climate_args_list()`: 39 | ! `window_size` must be a non-negative integer. 40 | 41 | --- 42 | 43 | Code 44 | climate_args_list(window_size = 1:3) 45 | Condition 46 | Error in `climate_args_list()`: 47 | ! `window_size` must be a scalar. 48 | 49 | --- 50 | 51 | Code 52 | climate_args_list(quantile_levels = -1) 53 | Condition 54 | Error in `climate_args_list()`: 55 | ! `quantile_levels` must lie in [0, 1]. 56 | 57 | --- 58 | 59 | Code 60 | climate_args_list(quantile_levels = 1.3) 61 | Condition 62 | Error in `climate_args_list()`: 63 | ! `quantile_levels` must lie in [0, 1]. 64 | 65 | --- 66 | 67 | Code 68 | climate_args_list(symmetrize = 2.5) 69 | Condition 70 | Error in `climate_args_list()`: 71 | ! `symmetrize` must be of type . 72 | 73 | --- 74 | 75 | Code 76 | climate_args_list(symmetrize = c(TRUE, TRUE)) 77 | Condition 78 | Error in `climate_args_list()`: 79 | ! `symmetrize` must be a scalar. 80 | 81 | --- 82 | 83 | Code 84 | climate_args_list(nonneg = 2.5) 85 | Condition 86 | Error in `climate_args_list()`: 87 | ! `nonneg` must be of type . 88 | 89 | --- 90 | 91 | Code 92 | climate_args_list(nonneg = c(TRUE, TRUE)) 93 | Condition 94 | Error in `climate_args_list()`: 95 | ! `nonneg` must be a scalar. 96 | 97 | --- 98 | 99 | Code 100 | climate_args_list(quantile_by_key = TRUE) 101 | Condition 102 | Error in `climate_args_list()`: 103 | ! `quantile_by_key` must be of type . 104 | 105 | --- 106 | 107 | Code 108 | climate_args_list(quantile_by_key = 2:3) 109 | Condition 110 | Error in `climate_args_list()`: 111 | ! `quantile_by_key` must be of type . 112 | 113 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/epi_recipe.md: -------------------------------------------------------------------------------- 1 | # epi_recipe produces error if not an epi_df 2 | 3 | Code 4 | epi_recipe(tib) 5 | Condition 6 | Error in `UseMethod()`: 7 | ! no applicable method for 'epi_recipe' applied to an object of class "c('tbl_df', 'tbl', 'data.frame')" 8 | 9 | --- 10 | 11 | Code 12 | epi_recipe(y ~ x, tib) 13 | Condition 14 | Error in `epi_recipe()`: 15 | ! `epi_recipe()` has been called with a non- object. Use `recipe()` instead. 16 | 17 | --- 18 | 19 | Code 20 | epi_recipe(m) 21 | Condition 22 | Error in `UseMethod()`: 23 | ! no applicable method for 'epi_recipe' applied to an object of class "c('matrix', 'array', 'character')" 24 | 25 | # add/update/adjust/remove epi_recipe works as intended 26 | 27 | Code 28 | workflows::extract_preprocessor(wf)$steps 29 | Condition 30 | Error in `workflows::extract_preprocessor()`: 31 | ! The workflow does not have a preprocessor. 32 | 33 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/epi_workflow.md: -------------------------------------------------------------------------------- 1 | # model can be added/updated/removed from epi_workflow 2 | 3 | Code 4 | extract_spec_parsnip(wf) 5 | Condition 6 | Error in `extract_spec_parsnip()`: 7 | ! The workflow does not have a model spec. 8 | 9 | # forecast method errors when workflow not fit 10 | 11 | Code 12 | forecast(wf) 13 | Condition 14 | Error in `forecast()`: 15 | ! You cannot `forecast()` a that has not been trained. 16 | i Please use `fit()` before forecasting. 17 | 18 | # fit method does not silently drop the class 19 | 20 | Code 21 | epi_recipe(y ~ x, data = tbl) 22 | Condition 23 | Error in `epi_recipe()`: 24 | ! `epi_recipe()` has been called with a non- object. Use `recipe()` instead. 25 | 26 | --- 27 | 28 | Code 29 | ewf_erec_edf %>% fit(tbl) 30 | Condition 31 | Error in `if (new_meta != old_meta) ...`: 32 | ! argument is of length zero 33 | 34 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/extract_argument.md: -------------------------------------------------------------------------------- 1 | # layer argument extractor works 2 | 3 | Code 4 | extract_argument(f$layers[[1]], "uhoh", "bubble") 5 | Condition 6 | Error in `extract_argument()`: 7 | ! Requested "uhoh" not found. This is a(n) . 8 | 9 | --- 10 | 11 | Code 12 | extract_argument(f$layers[[1]], "layer_predict", "bubble") 13 | Condition 14 | Error in `extract_argument()`: 15 | ! Requested argument "bubble" not found in "layer_predict". 16 | 17 | --- 18 | 19 | Code 20 | extract_argument(f, "layer_thresh", "quantile_levels") 21 | Condition 22 | Error in `extract_argument()`: 23 | ! frosting object does not contain a "layer_thresh". 24 | 25 | --- 26 | 27 | Code 28 | extract_argument(epi_workflow(), "layer_residual_quantiles", "quantile_levels") 29 | Condition 30 | Error in `extract_frosting()`: 31 | ! The epi_workflow does not have a postprocessor. 32 | 33 | --- 34 | 35 | Code 36 | extract_argument(wf, "layer_predict", c("type", "opts")) 37 | Condition 38 | Error in `FUN()`: 39 | ! `arg` must be a scalar of type . 40 | 41 | # recipe argument extractor works 42 | 43 | Code 44 | extract_argument(r$steps[[1]], "uhoh", "bubble") 45 | Condition 46 | Error in `extract_argument()`: 47 | ! Requested "uhoh" not found. This is a . 48 | 49 | --- 50 | 51 | Code 52 | extract_argument(r$steps[[1]], "step_epi_lag", "bubble") 53 | Condition 54 | Error in `extract_argument()`: 55 | ! Requested argument "bubble" not found in "step_epi_lag". 56 | 57 | --- 58 | 59 | Code 60 | extract_argument(r, "step_lightly", "quantile_levels") 61 | Condition 62 | Error in `extract_argument()`: 63 | ! recipe object does not contain a "step_lightly". 64 | 65 | --- 66 | 67 | Code 68 | extract_argument(epi_workflow(), "step_epi_lag", "lag") 69 | Condition 70 | Error in `extract_argument()`: 71 | ! The workflow must have a recipe preprocessor. 72 | 73 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/frosting.md: -------------------------------------------------------------------------------- 1 | # frosting validators / constructors work 2 | 3 | Code 4 | wf %>% add_postprocessor(list()) 5 | Condition 6 | Error: 7 | ! `postprocessor` must be a frosting object. 8 | 9 | # frosting can be created/added/updated/adjusted/removed 10 | 11 | Code 12 | frosting(layers = 1:5) 13 | Condition 14 | Error in `frosting()`: 15 | ! Currently, no arguments to `frosting()` are allowed to be non-null. 16 | 17 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/get_test_data.md: -------------------------------------------------------------------------------- 1 | # expect insufficient training data error 2 | 3 | Code 4 | get_test_data(recipe = r, x = covid_case_death_rates) 5 | Condition 6 | Error in `get_test_data()`: 7 | ! You supplied insufficient recent data for this recipe. 8 | ! You need at least 367 days of data, 9 | ! but `x` contains only 365. 10 | 11 | # expect error that geo_value or time_value does not exist 12 | 13 | Code 14 | get_test_data(recipe = r, x = wrong_epi_df) 15 | Condition 16 | Error in `get_test_data()`: 17 | ! `x` must be an `epi_df`. 18 | 19 | # NA fill behaves as desired 20 | 21 | Code 22 | get_test_data(r, df, "A") 23 | Condition 24 | Error in `get_test_data()`: 25 | ! `fill_locf` must be of type . 26 | 27 | --- 28 | 29 | Code 30 | get_test_data(r, df, TRUE, -3) 31 | Condition 32 | Error in `get_test_data()`: 33 | ! `n_recent` must be a positive integer. 34 | 35 | --- 36 | 37 | Code 38 | get_test_data(r, df2, TRUE) 39 | Condition 40 | Error in `if (recipes::is_trained(recipe)) ...`: 41 | ! argument is of length zero 42 | 43 | # forecast date behaves 44 | 45 | Code 46 | get_test_data(r, df, TRUE, forecast_date = 9) 47 | Condition 48 | Error in `get_test_data()`: 49 | ! `forecast_date` must be the same class as `x$time_value`. 50 | 51 | --- 52 | 53 | Code 54 | get_test_data(r, df, TRUE, forecast_date = 9L) 55 | Condition 56 | Error in `get_test_data()`: 57 | ! `forecast_date` must be no earlier than `max(x$time_value)` 58 | 59 | --- 60 | 61 | Code 62 | get_test_data(r, df, forecast_date = 9L) 63 | Condition 64 | Error in `get_test_data()`: 65 | ! `forecast_date` must be no earlier than `max(x$time_value)` 66 | 67 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/layer_add_forecast_date.md: -------------------------------------------------------------------------------- 1 | # layer validation works 2 | 3 | Code 4 | layer_add_forecast_date(f, c("2022-05-31", "2022-05-31")) 5 | Condition 6 | Error in `layer_add_forecast_date()`: 7 | ! `forecast_date` must be a scalar. 8 | 9 | --- 10 | 11 | Code 12 | layer_add_forecast_date(f, "2022-05-31", id = 2) 13 | Condition 14 | Error in `layer_add_forecast_date()`: 15 | ! `id` must be a scalar of type . 16 | 17 | --- 18 | 19 | Code 20 | layer_add_forecast_date(f, "2022-05-31", id = c("a", "b")) 21 | Condition 22 | Error in `layer_add_forecast_date()`: 23 | ! `id` must be a scalar of type . 24 | 25 | # forecast date works for daily 26 | 27 | Code 28 | predict(wf1, latest_yearly) 29 | Condition 30 | Error: 31 | ! Can't convert `data$time_value` to match type of `time_value` . 32 | 33 | --- 34 | 35 | Code 36 | predict(wf3, latest) 37 | Condition 38 | Error in `layer_add_forecast_date()`: 39 | ! The `forecast_date` was given as a "year" while the 40 | ! `time_type` of the training data was "day". 41 | i See `?epiprocess::epi_df` for descriptions of these are determined. 42 | 43 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/layer_add_target_date.md: -------------------------------------------------------------------------------- 1 | # target date works for daily and yearly 2 | 3 | Code 4 | predict(wf1, latest_bad) 5 | Condition 6 | Error: 7 | ! Can't convert `data$time_value` to match type of `time_value` . 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/layer_residual_quantiles.md: -------------------------------------------------------------------------------- 1 | # Errors when used with a classifier 2 | 3 | Code 4 | forecast(wf) 5 | Condition 6 | Error in `grab_residuals()`: 7 | ! For meaningful residuals, the predictor should be a regression model. 8 | 9 | # flatline_forecaster correctly errors when n_training < ahead 10 | 11 | Code 12 | flatline_forecaster(jhu, "death_rate", args_list = flatline_args_list(ahead = 10, 13 | n_training = 9)) 14 | Condition 15 | Error in `slather()`: 16 | ! Residual quantiles could not be calculated due to missing residuals. 17 | i This may be due to `n_train` < `ahead` in your . 18 | 19 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/layers.md: -------------------------------------------------------------------------------- 1 | # A layer can be updated in frosting 2 | 3 | Code 4 | update(f$layers[[1]], lower = 100) 5 | Condition 6 | Error in `update()`: 7 | ! The step you are trying to update, `layer_predict()`, does not have the lower field. 8 | 9 | --- 10 | 11 | Code 12 | update(f$layers[[3]], lower = 100) 13 | Condition 14 | Error in `f$layers[[3]]`: 15 | ! subscript out of bounds 16 | 17 | --- 18 | 19 | Code 20 | update(f$layers[[2]], bad_param = 100) 21 | Condition 22 | Error in `update()`: 23 | ! The step you are trying to update, `layer_threshold()`, does not have the bad_param field. 24 | 25 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/parse_period.md: -------------------------------------------------------------------------------- 1 | # parse_period works 2 | 3 | Code 4 | parse_period(c(1, 2)) 5 | Condition 6 | Error in `parse_period()`: 7 | ! `x` must be a scalar. 8 | 9 | --- 10 | 11 | Code 12 | parse_period(c(1.3)) 13 | Condition 14 | Error in `parse_period()`: 15 | ! rlang::is_integerish(x) is not TRUE 16 | 17 | --- 18 | 19 | Code 20 | parse_period("1 year") 21 | Condition 22 | Error in `parse_period()`: 23 | ! incompatible timespan in `aheads`. 24 | 25 | --- 26 | 27 | Code 28 | parse_period("2 weeks later") 29 | Condition 30 | Error in `parse_period()`: 31 | ! incompatible timespan in `aheads`. 32 | 33 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/parsnip_model_validation.md: -------------------------------------------------------------------------------- 1 | # forecaster can validate parsnip model 2 | 3 | Code 4 | get_parsnip_mode(l) 5 | Condition 6 | Error in `get_parsnip_mode()`: 7 | ! `trainer` must be a `parsnip` model. 8 | i This trainer has class: . 9 | 10 | --- 11 | 12 | Code 13 | is_classification(l) 14 | Condition 15 | Error in `get_parsnip_mode()`: 16 | ! `trainer` must be a `parsnip` model. 17 | i This trainer has class: . 18 | 19 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/pivot_quantiles.md: -------------------------------------------------------------------------------- 1 | # quantile pivotting wider behaves 2 | 3 | Code 4 | pivot_quantiles_wider(tib, a) 5 | Condition 6 | Error in `pivot_quantiles_wider()`: 7 | ! `a` is not <`quantile_pred`>. Cannot pivot it. 8 | 9 | --- 10 | 11 | Code 12 | pivot_quantiles_wider(tib, d1, d2) 13 | Condition 14 | Error in `pivot_quantiles_wider()`: 15 | ! Only one column can be pivotted. Can not pivot all of: `d1` and `d2`. 16 | 17 | --- 18 | 19 | Code 20 | pivot_quantiles_longer(tib, d1, d2) 21 | Condition 22 | Error in `pivot_quantiles_longer()`: 23 | ! Only one column can be pivotted. Can not pivot all of: `d1` and `d2`. 24 | 25 | # quantile pivotting longer behaves 26 | 27 | Code 28 | pivot_quantiles_longer(tib, a) 29 | Condition 30 | Error in `pivot_quantiles_longer()`: 31 | ! `a` is not <`quantile_pred`>. Cannot pivot it. 32 | 33 | --- 34 | 35 | Code 36 | pivot_quantiles_longer(tib, d1, d2) 37 | Condition 38 | Error in `pivot_quantiles_longer()`: 39 | ! Only one column can be pivotted. Can not pivot all of: `d1` and `d2`. 40 | 41 | # nested_quantiles is deprecated, but works where possible 42 | 43 | Code 44 | d <- dist_quantiles(list(1:4, 2:5), 1:4 / 5) 45 | Condition 46 | Warning: 47 | `dist_quantiles()` was deprecated in epipredict 0.1.11. 48 | i Please use `hardhat::quantile_pred()` instead. 49 | 50 | --- 51 | 52 | Code 53 | o <- nested_quantiles(d) 54 | Condition 55 | Warning: 56 | `nested_quantiles()` was deprecated in epipredict 0.1.11. 57 | i Please use `hardhat::quantile_pred()` instead. 58 | 59 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/population_scaling.md: -------------------------------------------------------------------------------- 1 | # expect error if `by` selector does not match 2 | 3 | Code 4 | wf <- epi_workflow(r, parsnip::linear_reg()) %>% fit(jhu) %>% add_frosting(f) 5 | Condition 6 | Error in `hardhat::validate_column_names()`: 7 | ! The required column "a" is missing. 8 | 9 | --- 10 | 11 | Code 12 | forecast(wf) 13 | Condition 14 | Error in `hardhat::validate_column_names()`: 15 | ! The required column "nothere" is missing. 16 | 17 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/quantile_pred.md: -------------------------------------------------------------------------------- 1 | # arithmetic works on quantiles 2 | 3 | Code 4 | sum(dstn) 5 | Condition 6 | Error in `vec_math()`: 7 | ! `sum()` is not a supported operation for . 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/shuffle.md: -------------------------------------------------------------------------------- 1 | # shuffle works 2 | 3 | Code 4 | shuffle(matrix(NA, 2, 2)) 5 | Condition 6 | Error in `shuffle()`: 7 | ! is.vector(x) is not TRUE 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/step_adjust_latency.md: -------------------------------------------------------------------------------- 1 | # printing step_adjust_latency results in expected output 2 | 3 | Code 4 | r5 5 | Message 6 | 7 | -- Epi Recipe ------------------------------------------------------------------ 8 | 9 | -- Inputs 10 | Number of variables by role 11 | raw: 2 12 | geo_value: 1 13 | time_value: 1 14 | 15 | -- Operations 16 | 1. Adj. extend_lags: has_role("raw") latency TBD at train time 17 | 2. Lagging: death_rate by 0, 6, 11 18 | 3. Lagging: case_rate by 1, 5 19 | 4. Leading: death_rate by 7 20 | 21 | --- 22 | 23 | Code 24 | prep(r5, real_x) 25 | Message 26 | 27 | -- Epi Recipe ------------------------------------------------------------------ 28 | 29 | -- Inputs 30 | Number of variables by role 31 | raw: 2 32 | geo_value: 1 33 | time_value: 1 34 | 35 | -- Training information 36 | Training data contained 200 data points and no incomplete rows. 37 | 38 | -- Operations 39 | 1. Adj. extend_lags: case_rate death_rate w/ forecast date 2021-07-24 | Trained 40 | 2. Lagging: death_rate by 5, 11, 16, (lat adj) | Trained 41 | 3. Lagging: case_rate by 6, 10, (lat adj) | Trained 42 | 4. Leading: death_rate by 7 | Trained 43 | 44 | --- 45 | 46 | Code 47 | r6 48 | Message 49 | 50 | -- Epi Recipe ------------------------------------------------------------------ 51 | 52 | -- Inputs 53 | Number of variables by role 54 | raw: 2 55 | geo_value: 1 56 | time_value: 1 57 | 58 | -- Operations 59 | 1. Lagging: death_rate by 0, 7, 14 60 | 2. Adj. extend_ahead: has_role("raw") latency TBD at train time 61 | 3. Leading: death_rate by 7 62 | 63 | --- 64 | 65 | Code 66 | prep(r6, covid_case_death_rates) 67 | Message 68 | 69 | -- Epi Recipe ------------------------------------------------------------------ 70 | 71 | -- Inputs 72 | Number of variables by role 73 | raw: 2 74 | geo_value: 1 75 | time_value: 1 76 | 77 | -- Training information 78 | Training data contained 20496 data points and no incomplete rows. 79 | 80 | -- Operations 81 | 1. Lagging: death_rate by 0, 7, 14 | Trained 82 | 2. Adj. extend_ahead: case_rate, ... w/ forecast date 2023-03-10 | Trained 83 | 3. Leading: death_rate by -441, (lat adj) | Trained 84 | 85 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/step_epi_naomit.md: -------------------------------------------------------------------------------- 1 | # Argument must be a recipe 2 | 3 | Code 4 | step_epi_naomit(x) 5 | Condition 6 | Error in `step_epi_naomit()`: 7 | ! inherits(recipe, "recipe") is not TRUE 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/step_epi_shift.md: -------------------------------------------------------------------------------- 1 | # Values for ahead and lag must be integer values 2 | 3 | Code 4 | r1 <- epi_recipe(x) %>% step_epi_ahead(death_rate, ahead = 3.6) %>% 5 | step_epi_lag(death_rate, lag = 1.9) 6 | Condition 7 | Error in `step_epi_lag()`: 8 | ! `lag` must be a non-negative integer. 9 | 10 | # A negative lag value should should throw an error 11 | 12 | Code 13 | r2 <- epi_recipe(x) %>% step_epi_ahead(death_rate, ahead = 7) %>% step_epi_lag( 14 | death_rate, lag = -7) 15 | Condition 16 | Error in `step_epi_lag()`: 17 | ! `lag` must be a non-negative integer. 18 | 19 | # A nonpositive ahead value should throw an error 20 | 21 | Code 22 | r3 <- epi_recipe(x) %>% step_epi_ahead(death_rate, ahead = -7) %>% step_epi_lag( 23 | death_rate, lag = 7) 24 | 25 | # Values for ahead and lag cannot be duplicates 26 | 27 | Code 28 | slm_fit(r4) 29 | Condition 30 | Error in `add_shifted_columns()`: 31 | ! Name collision occured in 32 | The following variable name already exists: "lag_7_death_rate". 33 | 34 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/step_lag_difference.md: -------------------------------------------------------------------------------- 1 | # step_lag_difference validates arguments 2 | 3 | Code 4 | step_lag_difference(r) 5 | Condition 6 | Error in `step_lag_difference()`: 7 | ! This recipe step can only operate on an . 8 | 9 | --- 10 | 11 | Code 12 | step_lag_difference(r, value, role = 1) 13 | Condition 14 | Error in `step_lag_difference()`: 15 | ! `role` must be of type . 16 | 17 | --- 18 | 19 | Code 20 | step_lag_difference(r, value, horizon = 0) 21 | Condition 22 | Error in `step_lag_difference()`: 23 | ! `horizon` must be a positive integer. 24 | 25 | --- 26 | 27 | Code 28 | step_lag_difference(r, value, prefix = letters[1:2]) 29 | Condition 30 | Error in `step_lag_difference()`: 31 | ! `prefix` must be a scalar of type . 32 | 33 | --- 34 | 35 | Code 36 | step_lag_difference(r, value, id = letters[1:2]) 37 | Condition 38 | Error in `step_lag_difference()`: 39 | ! `id` must be a scalar of type . 40 | 41 | --- 42 | 43 | Code 44 | step_lag_difference(r, value, prefix = letters[1:2]) 45 | Condition 46 | Error in `step_lag_difference()`: 47 | ! `prefix` must be a scalar of type . 48 | 49 | --- 50 | 51 | Code 52 | step_lag_difference(r, value, prefix = 1) 53 | Condition 54 | Error in `step_lag_difference()`: 55 | ! `prefix` must be a scalar of type . 56 | 57 | --- 58 | 59 | Code 60 | step_lag_difference(r, value, id = 1) 61 | Condition 62 | Error in `step_lag_difference()`: 63 | ! `id` must be a scalar of type . 64 | 65 | --- 66 | 67 | Code 68 | step_lag_difference(r, value, skip = 1) 69 | Condition 70 | Error in `step_lag_difference()`: 71 | ! `skip` must be a scalar of type . 72 | 73 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/wis-quantile_pred.md: -------------------------------------------------------------------------------- 1 | # wis dispatches and produces the correct values 2 | 3 | Code 4 | weighted_interval_score(1:10, 10) 5 | Condition 6 | Error in `UseMethod()`: 7 | ! no applicable method for 'weighted_interval_score' applied to an object of class "c('integer', 'numeric')" 8 | 9 | --- 10 | 11 | Code 12 | weighted_interval_score(quantile_pred(rbind(1:4, 8:11), 1:4 / 5), 1:3) 13 | Condition 14 | Error in `weighted_interval_score.quantile_pred()`: 15 | ! Assertion on 'actual' failed: Must have length 2, but has length 3. 16 | 17 | -------------------------------------------------------------------------------- /tests/testthat/test-arx_cargs_list.R: -------------------------------------------------------------------------------- 1 | test_that("arx_class_args checks inputs", { 2 | expect_s3_class(arx_class_args_list(), c("arx_class", "alist")) 3 | expect_snapshot(error = TRUE, arx_class_args_list(ahead = c(0, 4))) 4 | expect_snapshot(error = TRUE, arx_class_args_list(n_training = c(28, 65))) 5 | 6 | expect_snapshot(error = TRUE, arx_class_args_list(ahead = -1)) 7 | expect_snapshot(error = TRUE, arx_class_args_list(ahead = 1.5)) 8 | expect_snapshot(error = TRUE, arx_class_args_list(n_training = -1)) 9 | expect_snapshot(error = TRUE, arx_class_args_list(n_training = 1.5)) 10 | expect_snapshot(error = TRUE, arx_class_args_list(lags = c(-1, 0))) 11 | expect_snapshot(error = TRUE, arx_class_args_list(lags = list(c(1:5, 6.5), 2:8))) 12 | 13 | 14 | expect_snapshot(error = TRUE, arx_class_args_list(target_date = "2022-01-01")) 15 | expect_identical( 16 | arx_class_args_list(target_date = as.Date("2022-01-01"))$target_date, 17 | as.Date("2022-01-01") 18 | ) 19 | 20 | expect_snapshot(error = TRUE, arx_class_args_list(n_training_min = "de")) 21 | expect_snapshot(error = TRUE, arx_class_args_list(epi_keys = 1)) 22 | 23 | expect_warning(arx_class_args_list( 24 | forecast_date = as.Date("2022-01-01"), 25 | target_date = as.Date("2022-01-03"), 26 | ahead = 1L 27 | )) 28 | }) 29 | -------------------------------------------------------------------------------- /tests/testthat/test-arx_forecaster.R: -------------------------------------------------------------------------------- 1 | train_data <- epidatasets::cases_deaths_subset 2 | test_that("arx_forecaster warns if forecast date beyond the implicit one", { 3 | bad_date <- max(train_data$time_value) + 300 4 | expect_warning( 5 | arx1 <- arx_forecaster( 6 | train_data, 7 | "death_rate_7d_av", 8 | c("death_rate_7d_av", "case_rate_7d_av"), 9 | args_list = (arx_args_list(forecast_date = bad_date)) 10 | ), 11 | class = "epipredict__arx_forecaster__forecast_date_defaulting" 12 | ) 13 | }) 14 | 15 | test_that("arx_forecaster errors if forecast date, target date, and ahead are inconsistent", { 16 | max_date <- max(train_data$time_value) 17 | expect_error( 18 | arx1 <- arx_forecaster( 19 | train_data, 20 | "death_rate_7d_av", 21 | c("death_rate_7d_av", "case_rate_7d_av"), 22 | args_list = (arx_args_list(ahead = 5, target_date = max_date, forecast_date = max_date)) 23 | ), 24 | class = "epipredict__arx_args__inconsistent_target_ahead_forecaste_date" 25 | ) 26 | }) 27 | 28 | test_that("warns if there's not enough data to predict", { 29 | edf <- tibble( 30 | geo_value = "ct", 31 | time_value = seq(as.Date("2020-10-01"), as.Date("2023-05-31"), by = "day"), 32 | ) %>% 33 | mutate(value = seq_len(nrow(.)) + rnorm(nrow(.))) %>% 34 | # Oct to May (flu season, ish) only: 35 | filter(!dplyr::between(as.POSIXlt(time_value)$mon + 1L, 6L, 9L)) %>% 36 | # and actually, pretend we're around mid-October 2022: 37 | filter(time_value <= as.Date("2022-10-12")) %>% 38 | as_epi_df(as_of = as.Date("2022-10-12")) 39 | edf %>% filter(time_value > "2022-08-01") 40 | 41 | expect_error( 42 | edf %>% arx_forecaster("value"), 43 | class = "epipredict__not_enough_data" 44 | ) 45 | }) 46 | -------------------------------------------------------------------------------- /tests/testthat/test-bake-method.R: -------------------------------------------------------------------------------- 1 | test_that("bake method works in all cases", { 2 | edf <- covid_case_death_rates %>% 3 | filter(time_value > "2021-11-01", geo_value %in% c("ak", "ca", "ny")) 4 | r <- epi_recipe(edf) %>% 5 | step_epi_lag(death_rate, lag = c(0, 7, 14)) %>% 6 | step_epi_ahead(death_rate, ahead = 7) 7 | 8 | r2 <- epi_recipe(edf) %>% 9 | step_epi_lag(death_rate, lag = c(0, 7, 14)) %>% 10 | step_epi_ahead(death_rate, ahead = 7) %>% 11 | step_epi_naomit() 12 | 13 | b_null <- bake(prep(r, edf), NULL) 14 | b_train <- bake(prep(r, edf), edf) 15 | expect_s3_class(b_null, "epi_df") 16 | expect_identical(b_null, b_train) 17 | 18 | b_baked <- bake(prep(r2, edf), edf) # leaves rows with NA in the response 19 | # doesn't (because we "juice", so skip doesn't apply) 20 | b_juiced <- bake(prep(r2, edf), NULL) 21 | expect_equal(nrow(b_juiced), sum(complete.cases(b_train))) 22 | expect_equal(nrow(b_baked), sum(complete.cases(b_train)) + 3 * 7) 23 | 24 | # check that the {recipes} behaves 25 | expect_s3_class(bake(prep(r, edf), NULL, composition = "tibble"), "tbl_df") 26 | expect_s3_class(bake(prep(r, edf), NULL, composition = "data.frame"), "data.frame") 27 | # can't be a matrix because time_value/geo_value aren't numeric 28 | expect_snapshot(error = TRUE, bake(prep(r, edf), NULL, composition = "matrix")) 29 | }) 30 | -------------------------------------------------------------------------------- /tests/testthat/test-blueprint.R: -------------------------------------------------------------------------------- 1 | test_that("epi_recipe blueprint keeps the class, mold works", { 2 | bp <- new_default_epi_recipe_blueprint() 3 | expect_length(class(bp), 5L) 4 | expect_s3_class(bp, "default_epi_recipe_blueprint") 5 | expect_s3_class(refresh_blueprint(bp), "default_epi_recipe_blueprint") 6 | 7 | jhu <- covid_case_death_rates 8 | # expect_s3_class(er_check_is_data_like(jhu), "epi_df") 9 | 10 | r <- epi_recipe(jhu) %>% 11 | step_epi_lag(death_rate, lag = c(0, 7, 14)) %>% 12 | step_epi_ahead(death_rate, ahead = 7) %>% 13 | step_naomit(all_predictors()) %>% 14 | step_naomit(all_outcomes(), skip = TRUE) 15 | 16 | mm <- mold_epi_recipe_default_clean(bp, jhu) 17 | expect_s3_class(mm$blueprint, "default_epi_recipe_blueprint") 18 | expect_s3_class(mm$data, "epi_df") 19 | 20 | bp <- hardhat:::update_blueprint(bp, recipe = r) 21 | run_mm <- run_mold(bp, data = jhu) 22 | expect_false(is.factor(run_mm$extras$roles$geo_value$geo_value)) 23 | }) 24 | -------------------------------------------------------------------------------- /tests/testthat/test-check-training-set.R: -------------------------------------------------------------------------------- 1 | test_that("training set validation works", { 2 | template <- epidatasets::cases_deaths_subset[1, ] 3 | rec <- list(template = template) 4 | t1 <- template 5 | 6 | expect_silent(validate_meta_match(template, template, "geo_type", "blah")) 7 | expect_silent(validate_meta_match(template, template, "time_type", "blah")) 8 | attr(t1, "metadata")$geo_type <- "county" 9 | expect_warning(validate_meta_match(t1, template, "geo_type"), "county") 10 | expect_snapshot(error = TRUE, validate_meta_match(t1, template, "geo_type", "abort")) 11 | 12 | 13 | expect_identical(template, epi_check_training_set(template, rec)) 14 | expect_warning(epi_check_training_set(t1, rec), "county") 15 | attr(t1, "metadata")$time_type <- "weekly" 16 | expect_warning( 17 | expect_warning(epi_check_training_set(t1, rec), "county"), 18 | "weekly" 19 | ) 20 | t2 <- template 21 | attr(t2, "metadata")$other_keys <- "cases" 22 | expect_silent(epi_check_training_set(t2, rec)) 23 | rec$template <- t2 24 | t3 <- template 25 | expect_warning(t4 <- epi_check_training_set(t3, rec)) 26 | expect_identical(rec$template, t4) 27 | attr(rec$template, "metadata")$other_keys <- "missing_col" 28 | expect_snapshot(error = TRUE, epi_check_training_set(t4, rec)) 29 | }) 30 | -------------------------------------------------------------------------------- /tests/testthat/test-climatological_forecaster.R: -------------------------------------------------------------------------------- 1 | test_that("climate args list validates properly", { 2 | expect_s3_class(climate_args_list(), c("climate_fcast", "alist")) 3 | expect_s3_class( 4 | climate_args_list(forecast_date = as.Date("2021-01-10")), 5 | c("climate_fcast", "alist") 6 | ) 7 | expect_snapshot(error = TRUE, climate_args_list(forecast_date = 12345)) 8 | expect_snapshot( 9 | error = TRUE, 10 | climate_args_list(forecast_date = as.Date(c("2021-01-10", "2024-01-22"))) 11 | ) 12 | expect_silent(climate_args_list(forecast_horizon = 1L)) 13 | expect_silent(climate_args_list(forecast_horizon = -1:4)) 14 | expect_snapshot(error = TRUE, climate_args_list(forecast_horizon = 1.3)) 15 | expect_snapshot(error = TRUE, climate_args_list(window_size = -1)) 16 | expect_snapshot(error = TRUE, climate_args_list(window_size = 2.5)) 17 | expect_snapshot(error = TRUE, climate_args_list(window_size = 1:3)) 18 | expect_snapshot(error = TRUE, climate_args_list(quantile_levels = -1)) 19 | expect_snapshot(error = TRUE, climate_args_list(quantile_levels = 1.3)) 20 | expect_snapshot(error = TRUE, climate_args_list(symmetrize = 2.5)) 21 | expect_snapshot(error = TRUE, climate_args_list(symmetrize = c(TRUE, TRUE))) 22 | expect_snapshot(error = TRUE, climate_args_list(nonneg = 2.5)) 23 | expect_snapshot(error = TRUE, climate_args_list(nonneg = c(TRUE, TRUE))) 24 | expect_snapshot(error = TRUE, climate_args_list(quantile_by_key = TRUE)) 25 | expect_snapshot(error = TRUE, climate_args_list(quantile_by_key = 2:3)) 26 | }) 27 | 28 | test_that("climatological_forecaster works as expected", { 29 | single_yr <- seq(as.Date("2020-01-01"), as.Date("2020-12-31"), by = "1 day") 30 | x <- tibble( 31 | time_value = rep(single_yr, times = 2L), 32 | geo_value = rep(c("reg1", "reg2"), each = length(single_yr)), 33 | y = rep(c(1:183, 184:2), times = 2L) 34 | ) %>% 35 | as_epi_df(as_of = max(single_yr)) 36 | clim_forecast <- climatological_forecaster(x, "y", args_list = climate_args_list(time_type = "day")) 37 | preds <- clim_forecast$predictions %>% 38 | mutate( 39 | quant_med = median(.pred_distn) 40 | ) 41 | expect_equal(preds$.pred, preds$quant_med) 42 | 43 | expected_res <- tibble( 44 | geo_value = rep(c("reg1", "reg2"), 5), 45 | forecast_date = as.Date("2020-12-31"), 46 | target_date = c( 47 | rep(as.Date("2020-12-31"), 2), rep(as.Date("2021-01-01"), 2), rep(as.Date("2021-01-02"), 2), rep(as.Date("2021-01-03"), 2), rep(as.Date("2021-01-04"), 2) 48 | ), 49 | .pred = c(rep(3, 8), rep(4, 2)) 50 | ) 51 | expect_equal(preds %>% select(geo_value, forecast_date, target_date, .pred), expected_res) 52 | }) 53 | -------------------------------------------------------------------------------- /tests/testthat/test-epi_shift.R: -------------------------------------------------------------------------------- 1 | test_that("epi shift single works, renames", { 2 | tib <- tibble( 3 | x = 1:5, y = 1:5, 4 | time_value = seq(as.Date("2020-01-01"), by = 1, length.out = 5), 5 | geo_value = "ca" 6 | ) %>% epiprocess::as_epi_df() 7 | ess <- epi_shift_single(tib, "x", 1, "test", key_colnames(tib)) 8 | expect_named(ess, c("geo_value", "time_value", "test")) 9 | expect_equal(ess$time_value, tib$time_value + 1) 10 | }) 11 | -------------------------------------------------------------------------------- /tests/testthat/test-extract_argument.R: -------------------------------------------------------------------------------- 1 | test_that("layer argument extractor works", { 2 | f <- frosting() %>% 3 | layer_predict() %>% 4 | layer_residual_quantiles(quantile_levels = c(0.0275, 0.975), symmetrize = FALSE) %>% 5 | layer_naomit(.pred) 6 | 7 | expect_snapshot(error = TRUE, extract_argument(f$layers[[1]], "uhoh", "bubble")) 8 | expect_snapshot(error = TRUE, extract_argument(f$layers[[1]], "layer_predict", "bubble")) 9 | expect_identical( 10 | extract_argument(f$layers[[2]], "layer_residual_quantiles", "quantile_levels"), 11 | c(0.0275, 0.5, 0.9750) 12 | ) 13 | 14 | expect_snapshot(error = TRUE, extract_argument(f, "layer_thresh", "quantile_levels")) 15 | expect_identical( 16 | extract_argument(f, "layer_residual_quantiles", "quantile_levels"), 17 | c(0.0275, 0.5, 0.9750) 18 | ) 19 | 20 | wf <- epi_workflow(postprocessor = f) 21 | expect_snapshot(error = TRUE, extract_argument(epi_workflow(), "layer_residual_quantiles", "quantile_levels")) 22 | expect_identical( 23 | extract_argument(wf, "layer_residual_quantiles", "quantile_levels"), 24 | c(0.0275, 0.5, 0.9750) 25 | ) 26 | 27 | expect_snapshot(error = TRUE, extract_argument(wf, "layer_predict", c("type", "opts"))) 28 | }) 29 | 30 | test_that("recipe argument extractor works", { 31 | jhu <- covid_case_death_rates %>% 32 | dplyr::filter(time_value > "2021-08-01") %>% 33 | dplyr::arrange(geo_value, time_value) 34 | 35 | r <- epi_recipe(jhu) %>% 36 | step_epi_lag(death_rate, lag = c(0, 7, 14)) %>% 37 | step_epi_ahead(death_rate, ahead = 7) %>% 38 | step_epi_lag(case_rate, lag = c(0, 7, 14)) %>% 39 | step_naomit(all_predictors()) %>% 40 | # below, `skip` means we don't do this at predict time 41 | step_naomit(all_outcomes(), skip = TRUE) 42 | 43 | 44 | expect_snapshot(error = TRUE, extract_argument(r$steps[[1]], "uhoh", "bubble")) 45 | expect_snapshot(error = TRUE, extract_argument(r$steps[[1]], "step_epi_lag", "bubble")) 46 | expect_identical(extract_argument(r$steps[[2]], "step_epi_ahead", "ahead"), 7L) 47 | 48 | 49 | expect_snapshot(error = TRUE, extract_argument(r, "step_lightly", "quantile_levels")) 50 | expect_identical( 51 | extract_argument(r, "step_epi_lag", "lag"), 52 | list(c(0L, 7L, 14L), c(0L, 7L, 14L)) 53 | ) 54 | 55 | wf <- epi_workflow(preprocessor = r) 56 | expect_snapshot(error = TRUE, extract_argument(epi_workflow(), "step_epi_lag", "lag")) 57 | expect_identical( 58 | extract_argument(wf, "step_epi_lag", "lag"), 59 | list(c(0L, 7L, 14L), c(0L, 7L, 14L)) 60 | ) 61 | }) 62 | -------------------------------------------------------------------------------- /tests/testthat/test-flatline_args_list.R: -------------------------------------------------------------------------------- 1 | test_that("flatline_args_list checks inputs", { 2 | expect_s3_class(flatline_args_list(), c("flat_fcast", "alist")) 3 | expect_snapshot(error = TRUE, flatline_args_list(ahead = c(0, 4))) 4 | expect_snapshot(error = TRUE, flatline_args_list(n_training = c(28, 65))) 5 | 6 | expect_snapshot(error = TRUE, flatline_args_list(ahead = -1)) 7 | expect_snapshot(error = TRUE, flatline_args_list(ahead = 1.5)) 8 | expect_snapshot(error = TRUE, flatline_args_list(n_training = -1)) 9 | expect_snapshot(error = TRUE, flatline_args_list(n_training = 1.5)) 10 | expect_snapshot(error = TRUE, flatline_args_list(lags = c(-1, 0))) 11 | expect_snapshot(error = TRUE, flatline_args_list(lags = list(c(1:5, 6.5), 2:8))) 12 | 13 | expect_snapshot(error = TRUE, flatline_args_list(symmetrize = 4)) 14 | expect_snapshot(error = TRUE, flatline_args_list(nonneg = 4)) 15 | 16 | expect_snapshot(error = TRUE, flatline_args_list(quantile_levels = -.1)) 17 | expect_snapshot(error = TRUE, flatline_args_list(quantile_levels = 1.1)) 18 | expect_type(flatline_args_list(quantile_levels = NULL), "list") 19 | 20 | expect_snapshot(error = TRUE, flatline_args_list(target_date = "2022-01-01")) 21 | expect_identical( 22 | flatline_args_list(target_date = as.Date("2022-01-01"))$target_date, 23 | as.Date("2022-01-01") 24 | ) 25 | 26 | expect_snapshot(error = TRUE, flatline_args_list(n_training_min = "de")) 27 | expect_snapshot(error = TRUE, flatline_args_list(epi_keys = 1)) 28 | 29 | # Detect mismatched ahead and target_date - forecast_date difference 30 | expect_warning(flatline_args_list( 31 | forecast_date = as.Date("2022-01-01"), 32 | target_date = as.Date("2022-01-03"), 33 | ahead = 1L 34 | )) 35 | }) 36 | -------------------------------------------------------------------------------- /tests/testthat/test-key_colnames.R: -------------------------------------------------------------------------------- 1 | test_that("Extracts keys from a recipe; roles are NA, giving an empty vector", { 2 | expect_equal(key_colnames(recipe(covid_case_death_rates)), character(0L)) 3 | }) 4 | 5 | test_that("key_colnames extracts time_value and geo_value, but not raw", { 6 | my_recipe <- epi_recipe(covid_case_death_rates) %>% 7 | step_epi_ahead(death_rate, ahead = 7) %>% 8 | step_epi_lag(death_rate, lag = c(0, 7, 14)) %>% 9 | step_epi_lag(case_rate, lag = c(0, 7, 14)) %>% 10 | step_epi_naomit() 11 | 12 | expect_identical(key_colnames(my_recipe), c("geo_value", "time_value")) 13 | 14 | my_workflow <- epi_workflow() %>% 15 | add_epi_recipe(my_recipe) %>% 16 | add_model(linear_reg()) %>% 17 | fit(data = covid_case_death_rates) 18 | 19 | expect_identical(key_colnames(my_workflow), c("geo_value", "time_value")) 20 | 21 | # `exclude =` works: 22 | expect_identical(key_colnames(my_workflow, exclude = "geo_value"), c("time_value")) 23 | }) 24 | 25 | test_that("key_colnames extracts additional keys when they are present", { 26 | my_data <- tibble::tibble( 27 | geo_value = rep(c("ca", "fl", "pa"), each = 3), 28 | time_value = rep(seq(as.Date("2020-06-01"), as.Date("2020-06-03"), 29 | by = "day" 30 | ), length.out = length(geo_value)), 31 | pol = rep(c("blue", "swing", "swing"), each = 3), # extra key 32 | state = rep(c("ca", "fl", "pa"), each = 3), # extra key 33 | value = 1:length(geo_value) + 0.01 * rnorm(length(geo_value)) 34 | ) %>% 35 | as_epi_df( 36 | other_keys = c("state", "pol") 37 | ) 38 | 39 | expect_identical( 40 | key_colnames(my_data), 41 | c("geo_value", "state", "pol", "time_value") 42 | ) 43 | 44 | my_recipe <- epi_recipe(my_data) %>% 45 | step_epi_ahead(value, ahead = 7) %>% 46 | step_epi_naomit() 47 | 48 | # order of the additional keys may be different 49 | expect_equal(key_colnames(my_recipe), c("geo_value", "state", "pol", "time_value")) 50 | 51 | my_workflow <- epi_workflow(my_recipe, linear_reg()) %>% fit(my_data) 52 | 53 | # order of the additional keys may be different 54 | expect_equal(key_colnames(my_workflow), c("geo_value", "state", "pol", "time_value")) 55 | 56 | # `exclude =` works: 57 | expect_equal(key_colnames(my_workflow, exclude = c("time_value", "pol")), c("geo_value", "state")) 58 | }) 59 | -------------------------------------------------------------------------------- /tests/testthat/test-layer_naomit.R: -------------------------------------------------------------------------------- 1 | jhu <- covid_case_death_rates %>% 2 | dplyr::filter(time_value > "2021-11-01", geo_value %in% c("ak", "ca", "ny")) 3 | 4 | r <- epi_recipe(jhu) %>% 5 | step_epi_lag(death_rate, lag = c(0, 7, 14, 30)) %>% 6 | step_epi_ahead(death_rate, ahead = 7) %>% 7 | recipes::step_naomit(all_predictors()) %>% 8 | recipes::step_naomit(all_outcomes(), skip = TRUE) 9 | 10 | wf <- epipredict::epi_workflow(r, parsnip::linear_reg()) %>% parsnip::fit(jhu) 11 | 12 | latest <- get_test_data(recipe = r, x = jhu) %>% # 93 x 4 13 | dplyr::arrange(geo_value, time_value) 14 | latest[1:10, 4] <- NA # 10 rows have NA 15 | 16 | 17 | test_that("Removing NA after predict", { 18 | f <- frosting() %>% 19 | layer_predict() %>% 20 | layer_naomit(.pred) 21 | 22 | wf1 <- wf %>% add_frosting(f) 23 | 24 | expect_silent(p <- predict(wf1, latest)) 25 | expect_s3_class(p, "epi_df") 26 | expect_equal(nrow(p), 2L) # ak is NA so removed 27 | expect_named(p, c("geo_value", "time_value", ".pred")) 28 | }) 29 | -------------------------------------------------------------------------------- /tests/testthat/test-layer_threshold_preds.R: -------------------------------------------------------------------------------- 1 | jhu <- covid_case_death_rates %>% 2 | dplyr::filter(time_value < "2021-03-08", geo_value %in% c("ak", "ca", "ar")) 3 | r <- epi_recipe(jhu) %>% 4 | step_epi_lag(death_rate, lag = c(0, 7, 14)) %>% 5 | step_epi_ahead(death_rate, ahead = 7) %>% 6 | step_epi_naomit() 7 | 8 | wf <- epi_workflow(r, parsnip::linear_reg()) %>% fit(jhu) 9 | latest <- jhu %>% 10 | dplyr::filter(time_value >= max(time_value) - 14) 11 | 12 | test_that("Default pred_lower and pred_upper work as intended", { 13 | f <- frosting() %>% 14 | layer_predict() %>% 15 | layer_threshold(.pred) %>% 16 | layer_naomit(.pred) 17 | wf1 <- wf %>% add_frosting(f) 18 | 19 | expect_silent(p <- predict(wf1, latest)) 20 | expect_equal(ncol(p), 3L) 21 | expect_s3_class(p, "epi_df") 22 | expect_equal(nrow(p), 3L) 23 | expect_equal(round(p$.pred, digits = 3), c(0.179, 0, 0.765)) 24 | # expect_named(p, c("time_value", "geo_value", ".pred")) 25 | expect_named(p, c("geo_value", "time_value", ".pred")) 26 | }) 27 | 28 | test_that("Specified pred_lower and pred_upper work as intended", { 29 | f <- frosting() %>% 30 | layer_predict() %>% 31 | layer_threshold(.pred, lower = 0.180, upper = 0.31) %>% 32 | layer_naomit(.pred) 33 | wf2 <- wf %>% add_frosting(f) 34 | 35 | expect_silent(p <- predict(wf2, latest)) 36 | expect_equal(ncol(p), 3L) 37 | expect_s3_class(p, "epi_df") 38 | expect_equal(nrow(p), 3L) 39 | expect_equal(round(p$.pred, digits = 3), c(0.180, 0.180, 0.310)) 40 | expect_named(p, c("geo_value", "time_value", ".pred")) 41 | }) 42 | 43 | test_that("thresholds additional columns", { 44 | f <- frosting() %>% 45 | layer_predict() %>% 46 | layer_residual_quantiles(quantile_levels = c(.1, .9)) %>% 47 | layer_threshold(.pred, .pred_distn, lower = 0.180, upper = 0.31) %>% 48 | layer_naomit(.pred) 49 | 50 | wf2 <- wf %>% add_frosting(f) 51 | 52 | expect_silent(p <- predict(wf2, latest)) 53 | expect_equal(ncol(p), 4L) 54 | expect_s3_class(p, "epi_df") 55 | expect_equal(nrow(p), 3L) 56 | expect_equal(round(p$.pred, digits = 3), c(0.180, 0.180, 0.310)) 57 | expect_named(p, c("geo_value", "time_value", ".pred", ".pred_distn")) 58 | p <- p %>% 59 | pivot_quantiles_longer(.pred_distn) 60 | expect_equal( 61 | round(p$.pred_distn_value, digits = 3), 62 | c(0.180, 0.180, 0.31, 0.180, .18, .18, .31, 0.310, .31) 63 | ) 64 | expect_equal(p$.pred_distn_quantile_level, rep(c(.1, 0.5, .9), times = 3)) 65 | }) 66 | -------------------------------------------------------------------------------- /tests/testthat/test-layers.R: -------------------------------------------------------------------------------- 1 | test_that("A layer can be updated in frosting", { 2 | # Modify lower in `layer_threshold` 3 | f <- frosting() %>% 4 | layer_predict() %>% 5 | layer_threshold(.pred) 6 | fold <- f 7 | expect_equal(class(f), "frosting") 8 | expect_equal(length(f$layers), 2) 9 | expect_equal(f$layers[[2]]$lower, 0) 10 | f$layers[[2]] <- update(f$layers[[2]], lower = 100) 11 | expect_equal(length(f$layers), 2) 12 | expect_equal(f$layers[[1]], fold$layers[[1]]) 13 | expect_equal(f$layers[[2]]$lower, 100) 14 | expect_snapshot(error = TRUE, update(f$layers[[1]], lower = 100)) 15 | expect_snapshot(error = TRUE, update(f$layers[[3]], lower = 100)) 16 | expect_snapshot(error = TRUE, update(f$layers[[2]], bad_param = 100)) 17 | }) 18 | -------------------------------------------------------------------------------- /tests/testthat/test-parse_period.R: -------------------------------------------------------------------------------- 1 | test_that("parse_period works", { 2 | expect_snapshot(error = TRUE, parse_period(c(1, 2))) 3 | expect_snapshot(error = TRUE, parse_period(c(1.3))) 4 | expect_snapshot(error = TRUE, parse_period("1 year")) 5 | expect_snapshot(error = TRUE, parse_period("2 weeks later")) 6 | expect_identical(parse_period(1), 1L) 7 | expect_identical(parse_period("1 day"), 1L) 8 | expect_identical(parse_period("1 days"), 1L) 9 | expect_identical(parse_period("1 week"), 7L) 10 | expect_identical(parse_period("1 weeks"), 7L) 11 | expect_identical(parse_period("2 weeks"), 14L) 12 | }) 13 | -------------------------------------------------------------------------------- /tests/testthat/test-parsnip_model_validation.R: -------------------------------------------------------------------------------- 1 | test_that("forecaster can validate parsnip model", { 2 | l <- list() 3 | trainer1 <- parsnip::linear_reg() 4 | trainer2 <- parsnip::logistic_reg() 5 | trainer3 <- parsnip::rand_forest() 6 | 7 | expect_snapshot(error = TRUE, get_parsnip_mode(l)) 8 | expect_equal(get_parsnip_mode(trainer1), "regression") 9 | expect_equal(get_parsnip_mode(trainer2), "classification") 10 | expect_equal(get_parsnip_mode(trainer3), "unknown") 11 | 12 | expect_snapshot(error = TRUE, is_classification(l)) 13 | expect_true(is_regression(trainer1)) 14 | expect_false(is_classification(trainer1)) 15 | expect_true(is_classification(trainer2)) 16 | expect_false(is_regression(trainer2)) 17 | expect_true(is_regression(trainer3)) 18 | expect_true(is_classification(trainer3)) 19 | }) 20 | -------------------------------------------------------------------------------- /tests/testthat/test-pivot_quantiles.R: -------------------------------------------------------------------------------- 1 | test_that("quantile pivotting wider behaves", { 2 | tib <- tibble::tibble(a = 1:5, b = 6:10) 3 | expect_snapshot(error = TRUE, pivot_quantiles_wider(tib, a)) 4 | 5 | d1 <- quantile_pred(rbind(1:3, 2:4), 1:3 / 4) 6 | d2 <- quantile_pred(rbind(2:4, 3:5), 2:4 / 5) 7 | tib <- tibble(g = c("a", "b"), d1 = d1, d2 = d2) 8 | 9 | # too many columns 10 | expect_snapshot(error = TRUE, pivot_quantiles_wider(tib, d1, d2)) 11 | expect_snapshot(error = TRUE, pivot_quantiles_longer(tib, d1, d2)) 12 | 13 | 14 | expect_length(pivot_quantiles_wider(tib, d1), 5L) 15 | expect_length(pivot_quantiles_wider(tib, tidyselect::ends_with("1")), 5L) 16 | expect_equal(vctrs::vec_size(pivot_quantiles_longer(tib, d2)), 6L) 17 | }) 18 | 19 | test_that("pivotting wider still works if there are duplicates", { 20 | # previously this would produce a warning if pivotted because the 21 | # two rows of the result are identical 22 | tb <- tibble(.pred = quantile_pred(rbind(1:3, 1:3), c(.1, .5, .9))) 23 | res <- tibble(`0.1` = c(1, 1), `0.5` = c(2, 2), `0.9` = c(3, 3)) 24 | expect_equal(tb %>% pivot_quantiles_wider(.pred), res) 25 | res_longer <- tibble( 26 | .pred_value = rep(1:3, 2), 27 | .pred_quantile_level = rep(c(0.1, 0.5, 0.9), 2) 28 | ) 29 | expect_equal(tb %>% pivot_quantiles_longer(.pred), res_longer) 30 | }) 31 | 32 | 33 | test_that("quantile pivotting longer behaves", { 34 | tib <- tibble::tibble(a = 1:5, b = 6:10) 35 | expect_snapshot(error = TRUE, pivot_quantiles_longer(tib, a)) 36 | 37 | d1 <- quantile_pred(rbind(1:3, 2:4), 1:3 / 4) 38 | d2 <- quantile_pred(rbind(2:4, 3:5), 2:4 / 5) 39 | tib <- tibble(g = c("a", "b"), d1 = d1, d2 = d2) 40 | 41 | # too many columns 42 | expect_snapshot(error = TRUE, pivot_quantiles_longer(tib, d1, d2)) 43 | 44 | # different quantiles 45 | expect_length(pivot_quantiles_longer(tib, d1), 4L) 46 | expect_identical(nrow(pivot_quantiles_longer(tib, d1)), 6L) 47 | expect_identical(pivot_quantiles_longer(tib, d1)$d1_value, c(1:3, 2:4)) 48 | }) 49 | 50 | test_that("nested_quantiles is deprecated, but works where possible", { 51 | expect_snapshot(d <- dist_quantiles(list(1:4, 2:5), 1:4 / 5)) 52 | expect_snapshot(o <- nested_quantiles(d)) 53 | res <- as_tibble(hardhat::quantile_pred( 54 | matrix(c(1:4, 2:5), nrow = 2, byrow = TRUE), 1:4 / 5 55 | )) 56 | expect_identical(o |> mutate(.row = dplyr::row_number()) |> unnest(data), res) 57 | }) 58 | -------------------------------------------------------------------------------- /tests/testthat/test-replace_Inf.R: -------------------------------------------------------------------------------- 1 | test_that("replace_inf works", { 2 | x <- 1:5 3 | x[3] <- Inf # converts to double 4 | expect_identical(vec_replace_inf(x, 3), as.double(1:5)) 5 | df <- tibble( 6 | geo_value = letters[1:5], time_value = 1:5, 7 | v1 = 1:5, v2 = c(1, 2, Inf, -Inf, NA) 8 | ) 9 | 10 | suppressPackageStartupMessages(library(dplyr)) 11 | ok <- c("geo_value", "time_value") 12 | df2 <- df %>% mutate(across(!all_of(ok), ~ vec_replace_inf(.x, NA))) 13 | expect_identical(df[, 1:3], df2[, 1:3]) 14 | expect_identical(df2$v2, c(1, 2, NA, NA, NA)) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test-shuffle.R: -------------------------------------------------------------------------------- 1 | test_that("shuffle works", { 2 | expect_snapshot(error = TRUE, shuffle(matrix(NA, 2, 2))) 3 | expect_length(shuffle(1:10), 10L) 4 | expect_identical(sort(shuffle(1:10)), 1:10) 5 | }) 6 | -------------------------------------------------------------------------------- /tests/testthat/test-step_epi_naomit.R: -------------------------------------------------------------------------------- 1 | suppressPackageStartupMessages(library(dplyr)) 2 | suppressPackageStartupMessages(library(parsnip)) 3 | suppressPackageStartupMessages(library(workflows)) 4 | 5 | # Random generated dataset 6 | x <- tibble( 7 | geo_value = rep("nowhere", 200), 8 | time_value = as.Date("2021-01-01") + 0:199, 9 | case_rate = 1:200, 10 | death_rate = 1:200 11 | ) %>% 12 | epiprocess::as_epi_df() 13 | 14 | # Preparing the datasets to be used for comparison 15 | r <- epi_recipe(x) %>% 16 | step_epi_ahead(death_rate, ahead = 7) %>% 17 | step_epi_lag(death_rate, lag = c(0, 7, 14)) 18 | 19 | test_that("Argument must be a recipe", { 20 | expect_snapshot(error = TRUE, step_epi_naomit(x)) 21 | }) 22 | 23 | z1 <- step_epi_naomit(r) 24 | z2 <- r %>% 25 | step_naomit(all_predictors(), skip = FALSE) %>% 26 | step_naomit(all_outcomes(), skip = TRUE) 27 | 28 | # Checks the behaviour of a step function, omitting the quosure and id that 29 | # differ from one another, even with identical behaviour 30 | behav <- function(recipe, step_num) recipe$steps[[step_num]][-1][-5] 31 | # Checks the class type of an object 32 | step_class <- function(recipe, step_num) class(recipe$steps[step_num]) 33 | 34 | test_that("Check that both functions behave the same way", { 35 | expect_identical(behav(z1, 3), behav(z2, 3)) 36 | expect_identical(behav(z1, 4), behav(z2, 4)) 37 | expect_identical(step_class(z1, 3), step_class(z2, 3)) 38 | expect_identical(step_class(z1, 4), step_class(z2, 4)) 39 | }) 40 | -------------------------------------------------------------------------------- /tests/testthat/test-step_epi_shift.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(epiprocess) 3 | library(parsnip) 4 | library(workflows) 5 | 6 | # Random generated dataset 7 | x <- tibble( 8 | geo_value = rep("place", 200), 9 | time_value = as.Date("2021-01-01") + 0:199, 10 | case_rate = sqrt(1:200) + atan(0.1 * 1:200) + sin(5 * 1:200) + 1, 11 | death_rate = atan(0.1 * 1:200) + cos(5 * 1:200) + 1 12 | ) %>% 13 | as_epi_df() 14 | 15 | slm_fit <- function(recipe, data = x) { 16 | epi_workflow() %>% 17 | add_epi_recipe(recipe) %>% 18 | add_model(linear_reg()) %>% 19 | fit(data = data) 20 | } 21 | 22 | test_that("Values for ahead and lag must be integer values", { 23 | expect_snapshot( 24 | error = TRUE, 25 | r1 <- epi_recipe(x) %>% 26 | step_epi_ahead(death_rate, ahead = 3.6) %>% 27 | step_epi_lag(death_rate, lag = 1.9) 28 | ) 29 | }) 30 | 31 | test_that("A negative lag value should should throw an error", { 32 | expect_snapshot( 33 | error = TRUE, 34 | r2 <- epi_recipe(x) %>% 35 | step_epi_ahead(death_rate, ahead = 7) %>% 36 | step_epi_lag(death_rate, lag = -7) 37 | ) 38 | }) 39 | 40 | test_that("A nonpositive ahead value should throw an error", { 41 | expect_snapshot( 42 | error = FALSE, 43 | r3 <- epi_recipe(x) %>% 44 | step_epi_ahead(death_rate, ahead = -7) %>% 45 | step_epi_lag(death_rate, lag = 7) 46 | ) 47 | }) 48 | 49 | test_that("Values for ahead and lag cannot be duplicates", { 50 | r4 <- epi_recipe(x) %>% 51 | step_epi_ahead(death_rate, ahead = 7) %>% 52 | step_epi_lag(death_rate, lag = 7) %>% 53 | step_epi_lag(death_rate, lag = 7) 54 | expect_snapshot(error = TRUE, slm_fit(r4)) 55 | }) 56 | 57 | test_that("Check that epi_lag shifts applies the shift", { 58 | r5 <- epi_recipe(x) %>% 59 | step_epi_ahead(death_rate, ahead = 7) %>% 60 | step_epi_lag(death_rate, lag = c(0, 7, 14)) 61 | 62 | # Two steps passed here 63 | expect_equal(length(r5$steps), 2) 64 | fit5 <- slm_fit(r5) 65 | 66 | # Should have four predictors, including the intercept 67 | expect_equal(length(fit5$fit$fit$fit$coefficients), 4) 68 | }) 69 | 70 | test_that("Shifting nothing is a no-op", { 71 | expect_no_error(noop <- epi_recipe(x) %>% step_epi_ahead(ahead = 3) %>% prep(x) %>% bake(x)) 72 | expect_equal(noop, x) 73 | }) 74 | -------------------------------------------------------------------------------- /tests/testthat/test-target_date_bug.R: -------------------------------------------------------------------------------- 1 | # These tests address #290: 2 | # https://github.com/cmu-delphi/epipredict/issues/290 3 | 4 | library(dplyr) 5 | train <- epidatasets::cases_deaths_subset |> 6 | filter(time_value >= as.Date("2021-10-01")) |> 7 | select(geo_value, time_value, cr = case_rate_7d_av, dr = death_rate_7d_av) 8 | ngeos <- n_distinct(train$geo_value) 9 | 10 | test_that("flatline determines target_date where forecast_date exists", { 11 | flat <- flatline_forecaster( 12 | train, "dr", 13 | args_list = flatline_args_list( 14 | forecast_date = as.Date("2021-12-31"), 15 | target_date = as.Date("2022-01-01"), 16 | ahead = 1L 17 | ) 18 | ) 19 | # previously, if target_date existed, it could be 20 | # erroneously incremented by the ahead 21 | expect_identical( 22 | flat$predictions$target_date, 23 | rep(as.Date("2022-01-01"), ngeos) 24 | ) 25 | expect_identical( 26 | flat$predictions$forecast_date, 27 | rep(as.Date("2021-12-31"), ngeos) 28 | ) 29 | expect_true(all(!is.na(flat$predictions$.pred_distn))) 30 | expect_true(all(!is.na(flat$predictions$.pred))) 31 | }) 32 | 33 | test_that("arx_forecaster determines target_date where forecast_date exists", { 34 | arx <- arx_forecaster( 35 | train, "dr", c("dr", "cr"), 36 | args_list = arx_args_list( 37 | forecast_date = as.Date("2021-12-31"), 38 | target_date = as.Date("2022-01-01"), 39 | ahead = 1L 40 | ) 41 | ) 42 | # previously, if target_date existed, it could be 43 | # erroneously incremented by the ahead 44 | expect_identical( 45 | arx$predictions$target_date, 46 | rep(as.Date("2022-01-01"), ngeos) 47 | ) 48 | expect_identical( 49 | arx$predictions$forecast_date, 50 | rep(as.Date("2021-12-31"), ngeos) 51 | ) 52 | expect_true(all(!is.na(arx$predictions$.pred_distn))) 53 | expect_true(all(!is.na(arx$predictions$.pred))) 54 | }) 55 | 56 | test_that("arx_classifier determines target_date where forecast_date exists", { 57 | arx <- arx_classifier( 58 | train, "dr", c("dr"), 59 | trainer = parsnip::boost_tree(mode = "classification", trees = 5), 60 | args_list = arx_class_args_list( 61 | forecast_date = as.Date("2021-12-31"), 62 | target_date = as.Date("2022-01-01"), 63 | ahead = 1L 64 | ) 65 | ) 66 | # previously, if target_date existed, it could be 67 | # erroneously incremented by the ahead 68 | expect_identical( 69 | arx$predictions$target_date, 70 | rep(as.Date("2022-01-01"), ngeos) 71 | ) 72 | expect_identical( 73 | arx$predictions$forecast_date, 74 | rep(as.Date("2021-12-31"), ngeos) 75 | ) 76 | expect_true(all(!is.na(arx$predictions$.pred_class))) 77 | }) 78 | -------------------------------------------------------------------------------- /tests/testthat/test-wis-quantile_pred.R: -------------------------------------------------------------------------------- 1 | test_that("wis dispatches and produces the correct values", { 2 | tau <- c(.2, .4, .6, .8) 3 | q1 <- 1:4 4 | q2 <- 8:11 5 | wis_one_pred <- function(q, tau, actual) { 6 | 2 * mean(pmax(tau * (actual - q), (1 - tau) * (q - actual)), na.rm = TRUE) 7 | } 8 | actual <- 5 9 | expected <- c(wis_one_pred(q1, tau, actual), wis_one_pred(q2, tau, actual)) 10 | 11 | dstn <- quantile_pred(rbind(q1, q2), tau) 12 | expect_equal(weighted_interval_score(dstn, actual), expected) 13 | 14 | # works with a single dstn 15 | q <- sort(10 * rexp(23)) 16 | tau0 <- c(.01, .025, 1:19 / 20, .975, .99) 17 | dst <- quantile_pred(rbind(q), tau0) 18 | expect_equal(weighted_interval_score(dst, 10), wis_one_pred(q, tau0, 10)) 19 | 20 | # returns NA when expected 21 | dst <- quantile_pred(rbind(rep(NA, 3)), c(.2, .5, .95)) 22 | expect_true(is.na(weighted_interval_score(dst, 10))) 23 | expect_equal( 24 | weighted_interval_score(dstn, c(NA, actual)), 25 | c(NA, wis_one_pred(q2, tau, actual)) 26 | ) 27 | 28 | # errors for non quantile_pred 29 | expect_snapshot(error = TRUE, weighted_interval_score(1:10, 10)) 30 | 31 | # errors if sizes don't match 32 | expect_snapshot(error = TRUE, weighted_interval_score( 33 | quantile_pred(rbind(1:4, 8:11), 1:4 / 5), # length 2 34 | 1:3 35 | )) 36 | 37 | #' # Missing value behaviours 38 | dstn <- quantile_pred(rbind(c(1, 2, NA, 4)), 1:4 / 5) 39 | expect_equal(weighted_interval_score(dstn, 2.5), 0.5) 40 | expect_equal(weighted_interval_score(dstn, 2.5, c(2, 4, 5, 6, 8) / 10), 0.4) 41 | expect_equal( 42 | weighted_interval_score(dstn, 3, na_handling = "drop"), 43 | 2 / 3 44 | ) 45 | expect_equal( 46 | weighted_interval_score(dstn, 2.5, c(2, 4, 5, 6, 8) / 10, na_handling = "drop"), 47 | 0.4 48 | ) 49 | expect_true(is.na( 50 | weighted_interval_score(dstn, 2.5, na_handling = "propagate") 51 | )) 52 | expect_true(is.na( 53 | weighted_interval_score( 54 | quantile_pred(rbind(1:4), 1:4 / 5), 2.5, 1:9 / 10, 55 | na_handling = "fail" 56 | ) 57 | )) 58 | }) 59 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *_cache/ 3 | *.R 4 | !_common.R 5 | -------------------------------------------------------------------------------- /vignettes/_common.R: -------------------------------------------------------------------------------- 1 | knitr::opts_chunk$set( 2 | digits = 3, 3 | comment = "#>", 4 | collapse = TRUE, 5 | cache = TRUE, 6 | dev.args = list(bg = "transparent"), 7 | dpi = 300, 8 | cache.lazy = FALSE, 9 | out.width = "90%", 10 | fig.align = "center", 11 | fig.width = 9, 12 | fig.height = 6 13 | ) 14 | ggplot2::theme_set(ggplot2::theme_bw()) 15 | options( 16 | dplyr.print_min = 6, 17 | dplyr.print_max = 6, 18 | pillar.max_footer_lines = 2, 19 | pillar.min_chars = 15, 20 | stringr.view_n = 6, 21 | pillar.bold = TRUE, 22 | width = 77 23 | ) 24 | -------------------------------------------------------------------------------- /vignettes/articles/smooth-qr_baseline_preds.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmu-delphi/epipredict/0e86519e0151a0930015b0ffcabd890da39bb272/vignettes/articles/smooth-qr_baseline_preds.rds -------------------------------------------------------------------------------- /vignettes/articles/smooth-qr_smooth_preds_list.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cmu-delphi/epipredict/0e86519e0151a0930015b0ffcabd890da39bb272/vignettes/articles/smooth-qr_smooth_preds_list.rds --------------------------------------------------------------------------------