├── air.toml ├── .github ├── .gitignore ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── bug_report.md │ └── feature_request.md ├── workflows │ ├── lock.yaml │ ├── pkgdown.yaml │ ├── format-suggest.yaml │ ├── test-coverage.yaml │ ├── R-CMD-check.yaml │ └── pr-commands.yaml ├── SUPPORT.md ├── CONTRIBUTING.md └── CODE_OF_CONDUCT.md ├── vignettes ├── .gitignore └── articles │ ├── .gitignore │ ├── template-biochemists.R │ └── examples.Rmd ├── .covrignore ├── .gitignore ├── LICENSE ├── R ├── reexports.R ├── data.R ├── zzz.R ├── poissonreg-package.R ├── poisson_reg-stan.R ├── tidy.R ├── poisson_reg-glmnet.R └── poisson_reg-data.R ├── data └── seniors.rda ├── man ├── figures │ └── logo.png ├── reexports.Rd ├── rmd │ └── example.Rmd ├── seniors.Rd ├── tidy_zip.Rd ├── predict_raw._fishnet.Rd └── poissonreg-package.Rd ├── tests ├── testthat.R ├── spelling.R └── testthat │ ├── helpers.R │ ├── test-tidy.R │ ├── test-poisson_reg-glm.R │ ├── test-poisson_reg.R │ ├── test-poisson_reg-hurdle.R │ ├── test-poisson_reg-zeroinfl.R │ ├── _snaps │ └── poisson_reg.md │ └── test-poisson_reg-glmnet.R ├── .vscode ├── extensions.json └── settings.json ├── man-roxygen ├── spec-references.R └── spec-details.R ├── inst └── WORDLIST ├── codecov.yml ├── cran-comments.md ├── .Rbuildignore ├── poissonreg.Rproj ├── _pkgdown.yml ├── NAMESPACE ├── LICENSE.md ├── DESCRIPTION ├── NEWS.md ├── README.Rmd └── README.md /air.toml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /vignettes/articles/.gitignore: -------------------------------------------------------------------------------- 1 | /.quarto/ 2 | -------------------------------------------------------------------------------- /.covrignore: -------------------------------------------------------------------------------- 1 | R/poisson_reg_data.R 2 | R/0_imports.R 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .DS_Store 3 | .Rhistory 4 | docs 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2025 2 | COPYRIGHT HOLDER: poissonreg authors 3 | -------------------------------------------------------------------------------- /R/reexports.R: -------------------------------------------------------------------------------- 1 | #' @importFrom generics tidy 2 | #' @export 3 | generics::tidy 4 | -------------------------------------------------------------------------------- /data/seniors.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidymodels/poissonreg/HEAD/data/seniors.rda -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidymodels/poissonreg/HEAD/man/figures/logo.png -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(poissonreg) 3 | 4 | test_check("poissonreg") 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Posit.air-vscode" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /man-roxygen/spec-references.R: -------------------------------------------------------------------------------- 1 | #' @references \url{https://www.tidymodels.org}, [_Tidy Models with R_](https://www.tmwr.org/) 2 | -------------------------------------------------------------------------------- /tests/spelling.R: -------------------------------------------------------------------------------- 1 | if (requireNamespace("spelling", quietly = TRUE)) { 2 | spelling::spell_check_test( 3 | vignettes = TRUE, 4 | error = FALSE, 5 | skip_on_cran = TRUE 6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[r]": { 3 | "editor.formatOnSave": true, 4 | "editor.defaultFormatter": "Posit.air-vscode" 5 | }, 6 | "[quarto]": { 7 | "editor.formatOnSave": true, 8 | "editor.defaultFormatter": "quarto.quarto" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | Agresti 2 | CMD 3 | Codecov 4 | Jackman 5 | Keras 6 | Kleiber 7 | Lifecycle 8 | ORCID 9 | PBC 10 | RStudio 11 | Zeileis 12 | doi 13 | funder 14 | glm 15 | glmnet 16 | jss 17 | poisson 18 | pscl 19 | reprex 20 | rstanarm 21 | stan 22 | tibble 23 | tibbles 24 | tidymodels 25 | zeroinfl 26 | -------------------------------------------------------------------------------- /man-roxygen/spec-details.R: -------------------------------------------------------------------------------- 1 | #' @details 2 | #' This function only defines what _type_ of model is being fit. Once an engine 3 | #' is specified, the _method_ to fit the model is also defined. 4 | #' 5 | #' The model is not trained or fit until the [fit.model_spec()] function is used 6 | #' with the data. 7 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - name: Help 3 | url: https://www.tidymodels.org/help/ 4 | about: "Check out options for getting help on tidymodels.org" 5 | - name: Discussion 6 | url: https://rstd.io/tidymodels-community 7 | about: "For discussions about tidymodels, post on Posit Community" 8 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## R CMD check results 2 | 3 | 0 errors | 0 warnings | 0 note 4 | 5 | ## Submission 1.0.1 6 | 7 | This is a patch release to produce valid HTML5 for the documentation. 8 | 9 | ## Submission 1.0.0 10 | 11 | This release marks a **change in maintainer** from Max Kuhn 12 | to Hannah Frick . 13 | -------------------------------------------------------------------------------- /vignettes/articles/template-biochemists.R: -------------------------------------------------------------------------------- 1 | #' We'll model the number of articles published by graduate students in biochemistry Ph.D. programs. 2 | 3 | #+ results = "hide", messages = FALSE 4 | library(tidymodels) 5 | library(poissonreg) 6 | tidymodels_prefer() 7 | 8 | data(bioChemists, package = "pscl") 9 | 10 | biochemists_train <- bioChemists[-c(1:5), ] 11 | biochemists_test <- bioChemists[1:5, ] 12 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^fishy\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^README\.Rmd$ 5 | ^cran-comments\.md$ 6 | ^\.github$ 7 | ^codecov\.yml$ 8 | ^poissonreg\.Rproj$ 9 | ^\.Rhistory$ 10 | ^docs$ 11 | ^\.covrignore$ 12 | ^CODE_OF_CONDUCT\.md$ 13 | ^_pkgdown\.yml$ 14 | ^man-roxygen$ 15 | ^pkgdown$ 16 | ^CRAN-SUBMISSION$ 17 | ^vignettes/articles$ 18 | ^[\.]?air\.toml$ 19 | ^\.vscode$ 20 | ^[.]?air[.]toml$ 21 | -------------------------------------------------------------------------------- /man/reexports.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reexports.R 3 | \docType{import} 4 | \name{reexports} 5 | \alias{reexports} 6 | \alias{tidy} 7 | \title{Objects exported from other packages} 8 | \keyword{internal} 9 | \description{ 10 | These objects are imported from other packages. Follow the links 11 | below to see their documentation. 12 | 13 | \describe{ 14 | \item{generics}{\code{\link[generics]{tidy}}} 15 | }} 16 | 17 | -------------------------------------------------------------------------------- /R/data.R: -------------------------------------------------------------------------------- 1 | #' Alcohol, Cigarette, and Marijuana Use for High School Seniors 2 | #' 3 | #' @details Data are from Table 7.3 of Agresti (2007). The first three columns 4 | #' make up data from a 3-way contingency table. 5 | #' 6 | #' @name seniors 7 | #' @aliases seniors 8 | #' @docType data 9 | #' @return \item{seniors}{a tibble} 10 | #' 11 | #' @source Agresti, A (2007). _An Introduction to Categorical Data Analysis_. 12 | #' 13 | #' @keywords datasets 14 | #' @examples 15 | #' data(seniors) 16 | #' str(seniors) 17 | NULL 18 | -------------------------------------------------------------------------------- /poissonreg.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | LineEndingConversion: Posix 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | # nocov start 2 | 3 | # ------------------------------------------------------------------------------ 4 | 5 | # The functions below define the model information. These access the model 6 | # environment inside of parsnip so they have to be executed once parsnip has 7 | # been loaded. 8 | 9 | .onLoad <- function(libname, pkgname) { 10 | make_poisson_reg_glm() 11 | make_poisson_reg_hurdle() 12 | make_poisson_reg_zeroinfl() 13 | make_poisson_reg_glmnet() 14 | make_poisson_reg_stan() 15 | } 16 | 17 | # nocov end 18 | -------------------------------------------------------------------------------- /tests/testthat/helpers.R: -------------------------------------------------------------------------------- 1 | # a helper to sanitize the environment of quosures so that 2 | # expect_snapshot results are reproducible 3 | clear_quosure_environment <- function(x) { 4 | if (rlang::is_quosure(x)) { 5 | x <- rlang::quo_set_env(x, rlang::empty_env()) 6 | } 7 | 8 | x 9 | } 10 | 11 | # a helper to express the idiom of translating, subsetting out the 12 | # generated args, and snapshotting them 13 | translate_args <- function(x) { 14 | x |> 15 | translate() |> 16 | purrr::pluck("method", "fit", "args") |> 17 | purrr::map(clear_quosure_environment) 18 | } 19 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://poissonreg.tidymodels.org/ 2 | 3 | template: 4 | package: tidytemplate 5 | bootstrap: 5 6 | bslib: 7 | danger: "#CA225E" 8 | primary: "#CA225E" 9 | includes: 10 | in_header: | 11 | 12 | 13 | 14 | development: 15 | mode: auto 16 | 17 | figures: 18 | fig.width: 8 19 | fig.height: 5.75 20 | -------------------------------------------------------------------------------- /man/rmd/example.Rmd: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | Let's fit a model to the data from Agresti (2007) Table 7.6: 4 | 5 | ```{r, message = FALSE} 6 | library(poissonreg) 7 | library(tidymodels) 8 | tidymodels_prefer() 9 | 10 | log_lin_fit <- 11 | # Define the model 12 | poisson_reg() |> 13 | # Choose an engine for fitting. The default is 'glm' so 14 | # this next line is not strictly needed: 15 | set_engine("glm") |> 16 | # Fit the model to the data: 17 | fit(count ~ (.)^2, data = seniors) 18 | 19 | log_lin_fit 20 | ``` 21 | 22 | The different engines for the model that are provided by this package are: 23 | 24 | ```{r} 25 | show_engines("poisson_reg") 26 | ``` 27 | -------------------------------------------------------------------------------- /man/seniors.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{seniors} 5 | \alias{seniors} 6 | \title{Alcohol, Cigarette, and Marijuana Use for High School Seniors} 7 | \source{ 8 | Agresti, A (2007). \emph{An Introduction to Categorical Data Analysis}. 9 | } 10 | \value{ 11 | \item{seniors}{a tibble} 12 | } 13 | \description{ 14 | Alcohol, Cigarette, and Marijuana Use for High School Seniors 15 | } 16 | \details{ 17 | Data are from Table 7.3 of Agresti (2007). The first three columns 18 | make up data from a 3-way contingency table. 19 | } 20 | \examples{ 21 | data(seniors) 22 | str(seniors) 23 | } 24 | \keyword{datasets} 25 | -------------------------------------------------------------------------------- /man/tidy_zip.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tidy.R 3 | \name{tidy_zip} 4 | \alias{tidy_zip} 5 | \alias{tidy.zeroinfl} 6 | \alias{tidy.hurdle} 7 | \title{Turn zero-inflated model results into a tidy tibble} 8 | \usage{ 9 | \method{tidy}{zeroinfl}(x, type = "count", ...) 10 | 11 | \method{tidy}{hurdle}(x, type = "count", ...) 12 | } 13 | \arguments{ 14 | \item{x}{A \code{hurdle} or \code{zeroinfl} model object.} 15 | 16 | \item{type}{A character string for which model coefficients to return: 17 | "all", "count", or "zero".} 18 | 19 | \item{...}{Not currently used.} 20 | } 21 | \value{ 22 | A tibble 23 | } 24 | \description{ 25 | Turn zero-inflated model results into a tidy tibble 26 | } 27 | -------------------------------------------------------------------------------- /tests/testthat/test-tidy.R: -------------------------------------------------------------------------------- 1 | test_that("hurdle", { 2 | library(pscl) 3 | data("bioChemists", package = "pscl") 4 | hurd <- hurdle(art ~ fem | ment, data = bioChemists) 5 | summ <- summary(hurd) 6 | 7 | expect_no_error(counts <- tidy(hurd)) 8 | expect_no_error(zeros <- tidy(hurd, "zero")) 9 | expect_no_error(both <- tidy(hurd, "all")) 10 | 11 | expect_equal( 12 | unname(summ$coefficients$count[, "Estimate"]), 13 | counts$estimate 14 | ) 15 | expect_equal( 16 | unname(summ$coefficients$zero[, "Estimate"]), 17 | zeros$estimate 18 | ) 19 | expect_equal( 20 | c( 21 | unname(summ$coefficients$count[, "Estimate"]), 22 | unname(summ$coefficients$zero[, "Estimate"]) 23 | ), 24 | both$estimate 25 | ) 26 | }) 27 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(multi_predict,"_fishnet") 4 | S3method(predict,"_fishnet") 5 | S3method(predict_numeric,"_fishnet") 6 | S3method(predict_raw,"_fishnet") 7 | S3method(tidy,hurdle) 8 | S3method(tidy,zeroinfl) 9 | export(tidy) 10 | import(parsnip) 11 | importFrom(dplyr,arrange) 12 | importFrom(dplyr,as_tibble) 13 | importFrom(dplyr,full_join) 14 | importFrom(generics,tidy) 15 | importFrom(purrr,map) 16 | importFrom(purrr,map_lgl) 17 | importFrom(rlang,enquo) 18 | importFrom(rlang,enquos) 19 | importFrom(rlang,expr) 20 | importFrom(stats,predict) 21 | importFrom(stats,quantile) 22 | importFrom(stats,sd) 23 | importFrom(stats,setNames) 24 | importFrom(tibble,as_tibble) 25 | importFrom(tibble,is_tibble) 26 | importFrom(tibble,tibble) 27 | importFrom(tidyr,gather) 28 | -------------------------------------------------------------------------------- /R/poissonreg-package.R: -------------------------------------------------------------------------------- 1 | #' parsnip methods for Poisson regression 2 | #' 3 | #' \pkg{poissonreg} offers a function to fit model to count data using Poisson 4 | #' generalized linear models or via different methods for zero-inflated Poisson 5 | #' (ZIP) models. 6 | #' 7 | #' The model function works with the tidymodels infrastructure so that the model 8 | #' can be resampled, tuned, tided, etc. 9 | #' 10 | #' @includeRmd man/rmd/example.Rmd 11 | #' @keywords internal 12 | "_PACKAGE" 13 | 14 | ## usethis namespace: start 15 | ##' @import parsnip 16 | #' @importFrom rlang enquo expr enquos 17 | #' @importFrom purrr map_lgl map 18 | #' @importFrom tibble is_tibble as_tibble tibble 19 | #' @importFrom stats predict sd setNames quantile 20 | ## usethis namespace: end 21 | NULL 22 | 23 | utils::globalVariables( 24 | c(".pred", "group", "level", "new_data", "object") 25 | ) 26 | -------------------------------------------------------------------------------- /R/poisson_reg-stan.R: -------------------------------------------------------------------------------- 1 | organize_stan_interval <- function(results, object, interval_type = "conf") { 2 | interval_type <- rlang::arg_match(interval_type, c("conf", "pred")) 3 | if (interval_type == "conf") { 4 | lvl <- object$spec$method$pred$conf_int$extras$level 5 | add_standard_error <- object$spec$method$pred$conf_int$extras$std_error 6 | } else { 7 | lvl <- object$spec$method$pred$pred_int$extras$level 8 | add_standard_error <- object$spec$method$pred$pred_int$extras$std_error 9 | } 10 | res <- 11 | tibble( 12 | .pred_lower = parsnip::convert_stan_interval( 13 | results, 14 | level = lvl 15 | ), 16 | .pred_upper = parsnip::convert_stan_interval( 17 | results, 18 | level = lvl, 19 | lower = FALSE 20 | ), 21 | ) 22 | if (add_standard_error) { 23 | res$.std_error <- apply(results, 2, sd, na.rm = TRUE) 24 | } 25 | res 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2025 poissonreg 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 | -------------------------------------------------------------------------------- /man/predict_raw._fishnet.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/poisson_reg-glmnet.R 3 | \name{predict_raw._fishnet} 4 | \alias{predict_raw._fishnet} 5 | \alias{multi_predict._fishnet} 6 | \title{Model predictions across many sub-models} 7 | \usage{ 8 | \method{predict_raw}{`_fishnet`}(object, new_data, opts = list(), ...) 9 | 10 | \method{multi_predict}{`_fishnet`}(object, new_data, type = NULL, penalty = NULL, ...) 11 | } 12 | \arguments{ 13 | \item{object}{A \code{model_fit} object.} 14 | 15 | \item{new_data}{A rectangular data object, such as a data frame.} 16 | 17 | \item{opts}{A list of options..} 18 | 19 | \item{...}{Optional arguments to pass to \code{predict.model_fit(type = "raw")} 20 | such as \code{type}.} 21 | 22 | \item{penalty}{A numeric vector of penalty values.} 23 | } 24 | \value{ 25 | A tibble with the same number of rows as the data being predicted. 26 | There is a list-column named \code{.pred} that contains tibbles with 27 | multiple rows per sub-model. 28 | } 29 | \description{ 30 | For some models, predictions can be made on sub-models in the model object. 31 | } 32 | \keyword{internal} 33 | -------------------------------------------------------------------------------- /tests/testthat/test-poisson_reg-glm.R: -------------------------------------------------------------------------------- 1 | test_that("glm execution", { 2 | glm_spec <- poisson_reg() |> set_engine("glm") 3 | ctrl <- control_parsnip(verbosity = 1, catch = FALSE) 4 | 5 | expect_no_error( 6 | fit(glm_spec, count ~ ., data = seniors, control = ctrl) 7 | ) 8 | expect_no_error( 9 | fit_xy(glm_spec, x = seniors[, 1:3], y = seniors$count, control = ctrl) 10 | ) 11 | }) 12 | 13 | test_that("glm prediction", { 14 | glm_spec <- poisson_reg() |> set_engine("glm") 15 | ctrl <- control_parsnip(verbosity = 1, catch = FALSE) 16 | 17 | glm_fit <- glm(count ~ ., data = seniors, family = "poisson") 18 | glm_pred <- unname(predict(glm_fit, seniors[1:3, 1:3], type = "response")) 19 | 20 | res_xy <- fit_xy( 21 | glm_spec, 22 | x = seniors[, 1:3], 23 | y = seniors$count, 24 | control = ctrl 25 | ) 26 | 27 | expect_equal( 28 | predict(res_xy, seniors[1:3, 1:3])$.pred, 29 | glm_pred 30 | ) 31 | 32 | res_form <- fit( 33 | glm_spec, 34 | count ~ ., 35 | data = seniors, 36 | control = ctrl 37 | ) 38 | expect_equal( 39 | predict(res_form, seniors[1:3, ])$.pred, 40 | glm_pred 41 | ) 42 | }) 43 | -------------------------------------------------------------------------------- /.github/workflows/lock.yaml: -------------------------------------------------------------------------------- 1 | name: 'Lock Threads' 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | 7 | jobs: 8 | lock: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: dessant/lock-threads@v2 12 | with: 13 | github-token: ${{ github.token }} 14 | issue-lock-inactive-days: '14' 15 | # issue-exclude-labels: '' 16 | # issue-lock-labels: 'outdated' 17 | issue-lock-comment: > 18 | This issue has been automatically locked. If you believe you have 19 | found a related problem, please file a new issue (with a reprex: 20 | ) and link to this issue. 21 | issue-lock-reason: '' 22 | pr-lock-inactive-days: '14' 23 | # pr-exclude-labels: 'wip' 24 | pr-lock-labels: '' 25 | pr-lock-comment: > 26 | This pull request has been automatically locked. If you believe you 27 | have found a related problem, please file a new issue (with a reprex: 28 | ) and link to this issue. 29 | pr-lock-reason: '' 30 | # process-only: 'issues' 31 | -------------------------------------------------------------------------------- /R/tidy.R: -------------------------------------------------------------------------------- 1 | tidy_mat <- function(x, type) { 2 | ret <- tibble::as_tibble(x, rownames = "term") 3 | colnames(ret) <- c("term", "estimate", "std.error", "statistic", "p.value") 4 | ret$type <- type 5 | dplyr::relocate(ret, type, .after = "term") 6 | } 7 | 8 | .tidy <- function(x, type = "count", ...) { 9 | type <- rlang::arg_match0(type, c("count", "zero", "all"), "type") 10 | x <- summary(x) 11 | if (type == "count") { 12 | res <- tidy_mat(x$coefficients$count, "count") 13 | } else if (type == "zero") { 14 | res <- tidy_mat(x$coefficients$zero, "zero") 15 | } else { 16 | res <- 17 | dplyr::bind_rows( 18 | tidy_mat(x$coefficients$count, "count"), 19 | tidy_mat(x$coefficients$zero, "zero") 20 | ) 21 | } 22 | res 23 | } 24 | 25 | 26 | #' Turn zero-inflated model results into a tidy tibble 27 | #' 28 | #' @param x A `hurdle` or `zeroinfl` model object. 29 | #' @param type A character string for which model coefficients to return: 30 | #' "all", "count", or "zero". 31 | #' @param ... Not currently used. 32 | #' @return A tibble 33 | #' 34 | #' @name tidy_zip 35 | #' @export 36 | tidy.zeroinfl <- .tidy 37 | 38 | #' @export 39 | #' @rdname tidy_zip 40 | tidy.hurdle <- .tidy 41 | -------------------------------------------------------------------------------- /tests/testthat/test-poisson_reg.R: -------------------------------------------------------------------------------- 1 | # this tests primary and engine args here rather than in parsnip because 2 | # it requires the engines to be loaded 3 | 4 | test_that("arguments", { 5 | basic <- poisson_reg() 6 | penalty <- poisson_reg(penalty = 1) 7 | mixture <- poisson_reg(penalty = 1, mixture = 0.128) 8 | mixture_tune <- poisson_reg(penalty = 1, mixture = tune()) 9 | 10 | expect_snapshot(translate_args(basic)) 11 | expect_snapshot(translate_args(penalty |> set_engine("glmnet"))) 12 | expect_snapshot( 13 | translate_args( 14 | penalty |> set_engine("glmnet", path_values = 4:2) 15 | ) 16 | ) 17 | expect_snapshot(translate_args(mixture |> set_engine("glmnet"))) 18 | expect_snapshot(translate_args(mixture_tune |> set_engine("glmnet"))) 19 | }) 20 | 21 | 22 | test_that('check_args() works', { 23 | skip_if_not_installed("parsnip", "1.2.1.9001") 24 | 25 | expect_snapshot( 26 | error = TRUE, 27 | { 28 | spec <- poisson_reg(mixture = -1) |> 29 | set_engine("glm") |> 30 | set_mode("regression") 31 | fit(spec, gear ~ ., data = mtcars) 32 | } 33 | ) 34 | 35 | expect_snapshot( 36 | error = TRUE, 37 | { 38 | spec <- poisson_reg(penalty = -1) |> 39 | set_engine("glm") |> 40 | set_mode("regression") 41 | fit(spec, gear ~ ., data = mtcars) 42 | } 43 | ) 44 | }) 45 | -------------------------------------------------------------------------------- /.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 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | release: 8 | types: [published] 9 | workflow_dispatch: 10 | 11 | name: pkgdown.yaml 12 | 13 | permissions: read-all 14 | 15 | jobs: 16 | pkgdown: 17 | runs-on: ubuntu-latest 18 | # Only restrict concurrency for non-PR jobs 19 | concurrency: 20 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 21 | env: 22 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 23 | permissions: 24 | contents: write 25 | steps: 26 | - uses: actions/checkout@v4 27 | 28 | - uses: r-lib/actions/setup-pandoc@v2 29 | 30 | - uses: r-lib/actions/setup-r@v2 31 | with: 32 | use-public-rspm: true 33 | 34 | - uses: r-lib/actions/setup-r-dependencies@v2 35 | with: 36 | extra-packages: any::pkgdown, local::. 37 | needs: website 38 | 39 | - name: Build site 40 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 41 | shell: Rscript {0} 42 | 43 | - name: Deploy to GitHub pages 🚀 44 | if: github.event_name != 'pull_request' 45 | uses: JamesIves/github-pages-deploy-action@v4.5.0 46 | with: 47 | clean: false 48 | branch: gh-pages 49 | folder: docs 50 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: poissonreg 2 | Title: Model Wrappers for Poisson Regression 3 | Version: 1.0.1.9001 4 | Authors@R: c( 5 | person("Max", "Kuhn", , "max@posit.co", role = "aut", 6 | comment = c(ORCID = "0000-0003-2402-136X")), 7 | person("Hannah", "Frick", , "hannah@posit.co", role = c("aut", "cre"), 8 | comment = c(ORCID = "0000-0002-6049-5258")), 9 | person("Posit Software, PBC", role = c("cph", "fnd"), 10 | comment = c(ROR = "03wc8by49")) 11 | ) 12 | Description: Bindings for Poisson regression models for use with the 13 | 'parsnip' package. Models include simple generalized linear models, 14 | Bayesian models, and zero-inflated Poisson models (Zeileis, Kleiber, 15 | and Jackman (2008) ). 16 | License: MIT + file LICENSE 17 | URL: https://github.com/tidymodels/poissonreg, 18 | https://poissonreg.tidymodels.org/ 19 | BugReports: https://github.com/tidymodels/poissonreg/issues 20 | Depends: 21 | parsnip (>= 0.2.0), 22 | R (>= 4.1) 23 | Imports: 24 | dplyr, 25 | generics, 26 | purrr, 27 | rlang, 28 | stats, 29 | tibble, 30 | tidyr 31 | Suggests: 32 | covr, 33 | glmnet, 34 | pscl, 35 | rstanarm, 36 | spelling, 37 | testthat (>= 3.0.0) 38 | Config/Needs/website: 39 | tidymodels, 40 | tidyverse/tidytemplate 41 | Config/testthat/edition: 3 42 | Config/usethis/last-upkeep: 2025-04-24 43 | Encoding: UTF-8 44 | Language: en-US 45 | LazyData: true 46 | Roxygen: list(markdown = TRUE) 47 | RoxygenNote: 7.3.2 48 | -------------------------------------------------------------------------------- /.github/workflows/format-suggest.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/posit-dev/setup-air/tree/main/examples 2 | 3 | on: 4 | # Using `pull_request_target` over `pull_request` for elevated `GITHUB_TOKEN` 5 | # privileges, otherwise we can't set `pull-requests: write` when the pull 6 | # request comes from a fork, which is our main use case (external contributors). 7 | # 8 | # `pull_request_target` runs in the context of the target branch (`main`, usually), 9 | # rather than in the context of the pull request like `pull_request` does. Due 10 | # to this, we must explicitly checkout `ref: ${{ github.event.pull_request.head.sha }}`. 11 | # This is typically frowned upon by GitHub, as it exposes you to potentially running 12 | # untrusted code in a context where you have elevated privileges, but they explicitly 13 | # call out the use case of reformatting and committing back / commenting on the PR 14 | # as a situation that should be safe (because we aren't actually running the untrusted 15 | # code, we are just treating it as passive data). 16 | # https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/ 17 | pull_request_target: 18 | 19 | name: format-suggest.yaml 20 | 21 | jobs: 22 | format-suggest: 23 | name: format-suggest 24 | runs-on: ubuntu-latest 25 | 26 | permissions: 27 | # Required to push suggestion comments to the PR 28 | pull-requests: write 29 | 30 | steps: 31 | - uses: actions/checkout@v4 32 | with: 33 | ref: ${{ github.event.pull_request.head.sha }} 34 | 35 | - name: Install 36 | uses: posit-dev/setup-air@v1 37 | 38 | - name: Format 39 | run: air format . 40 | 41 | - name: Suggest 42 | uses: reviewdog/action-suggester@v1 43 | with: 44 | level: error 45 | fail_level: error 46 | tool_name: air 47 | -------------------------------------------------------------------------------- /tests/testthat/test-poisson_reg-hurdle.R: -------------------------------------------------------------------------------- 1 | test_that("hurdle execution", { 2 | skip_if_not_installed("pscl") 3 | skip_on_cran() 4 | 5 | data("bioChemists", package = "pscl", envir = rlang::current_env()) 6 | 7 | hurdle_spec <- poisson_reg() |> set_engine("hurdle") 8 | ctrl <- control_parsnip(verbosity = 1, catch = FALSE) 9 | 10 | expect_no_error( 11 | fit(hurdle_spec, art ~ ., data = bioChemists, control = ctrl) 12 | ) 13 | expect_no_error( 14 | res <- fit_xy( 15 | hurdle_spec, 16 | x = bioChemists[, 2:6], 17 | y = bioChemists$art, 18 | control = ctrl 19 | ) 20 | ) 21 | 22 | expect_false(has_multi_predict(res)) 23 | expect_equal(multi_predict_args(res), NA_character_) 24 | }) 25 | 26 | test_that("hurdle prediction", { 27 | skip_if_not_installed("pscl") 28 | skip_on_cran() 29 | 30 | data("bioChemists", package = "pscl", envir = rlang::current_env()) 31 | 32 | hurdle_spec <- poisson_reg() |> set_engine("hurdle") 33 | quiet_ctrl <- control_parsnip(verbosity = 0, catch = TRUE) 34 | 35 | hurdle_pred <- c( 36 | 2.00569689955261, 37 | 1.29916133671851, 38 | 1.30005204940495, 39 | 1.43756150261801, 40 | 2.37677697507562 41 | ) 42 | 43 | res_xy <- fit_xy( 44 | hurdle_spec, 45 | x = bioChemists[, 2:6], 46 | y = bioChemists$art, 47 | control = quiet_ctrl 48 | ) 49 | 50 | expect_equal( 51 | predict(res_xy, bioChemists[1:5, 2:6])$.pred, 52 | hurdle_pred, 53 | tolerance = 0.001 54 | ) 55 | 56 | form_pred <- c( 57 | 1.83402584880366, 58 | 1.45332695575065, 59 | 1.43412114470316, 60 | 1.58891378718055, 61 | 1.855682964733 62 | ) 63 | 64 | res_form <- fit( 65 | hurdle_spec, 66 | art ~ . | 1, 67 | data = bioChemists, 68 | control = quiet_ctrl 69 | ) 70 | 71 | expect_equal( 72 | predict(res_form, bioChemists[1:5, ])$.pred, 73 | form_pred, 74 | tolerance = 0.001 75 | ) 76 | }) 77 | -------------------------------------------------------------------------------- /tests/testthat/test-poisson_reg-zeroinfl.R: -------------------------------------------------------------------------------- 1 | test_that("zeroinfl execution", { 2 | skip_if_not_installed("pscl") 3 | skip_on_cran() 4 | 5 | data("bioChemists", package = "pscl", envir = rlang::current_env()) 6 | 7 | zeroinfl_spec <- poisson_reg() |> set_engine("zeroinfl") 8 | ctrl <- control_parsnip(verbosity = 1, catch = FALSE) 9 | 10 | expect_no_error( 11 | fit(zeroinfl_spec, art ~ ., data = bioChemists, control = ctrl) 12 | ) 13 | expect_no_error( 14 | res <- fit_xy( 15 | zeroinfl_spec, 16 | x = bioChemists[, 2:6], 17 | y = bioChemists$art, 18 | control = ctrl 19 | ) 20 | ) 21 | 22 | expect_false(has_multi_predict(res)) 23 | expect_equal(multi_predict_args(res), NA_character_) 24 | }) 25 | 26 | test_that("zeroinfl prediction", { 27 | skip_if_not_installed("pscl") 28 | skip_on_cran() 29 | 30 | data("bioChemists", package = "pscl", envir = rlang::current_env()) 31 | 32 | zeroinfl_spec <- poisson_reg() |> set_engine("zeroinfl") 33 | quiet_ctrl <- control_parsnip(verbosity = 0, catch = TRUE) 34 | 35 | zeroinfl_pred <- c( 36 | 2.03795552288294, 37 | 1.32312378302603, 38 | 1.30870432888435, 39 | 1.43998196151274, 40 | 2.36323310634688 41 | ) 42 | 43 | res_xy <- fit_xy( 44 | zeroinfl_spec, 45 | x = bioChemists[, 2:6], 46 | y = bioChemists$art, 47 | control = quiet_ctrl 48 | ) 49 | 50 | expect_equal( 51 | predict(res_xy, bioChemists[1:5, 2:6])$.pred, 52 | zeroinfl_pred, 53 | tolerance = 0.001 54 | ) 55 | 56 | form_pred <- c( 57 | 1.95901387152585, 58 | 1.33126661829735, 59 | 1.33699534952439, 60 | 1.51045647275656, 61 | 2.05706336705877 62 | ) 63 | 64 | res_form <- fit( 65 | zeroinfl_spec, 66 | art ~ . | 1, 67 | data = bioChemists, 68 | control = quiet_ctrl 69 | ) 70 | expect_equal( 71 | predict(res_form, bioChemists[1:5, ])$.pred, 72 | form_pred, 73 | tolerance = 0.001 74 | ) 75 | }) 76 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # poissonreg (development version) 2 | 3 | * Predictions via `multi_predict()` for glmnet models now correctly default to mean counts instead of the linear predictor (#89). 4 | 5 | * Predictions for a single observation now work for `poisson_reg()` with the `"glmnet"` engine (#48). 6 | 7 | * Removed the now obsolete registration of the `predict_raw()` generic as it is now exported from parsnip (#52). 8 | 9 | * Removed the unused internal `s3_register()` function (#53). 10 | 11 | * Tests on the model specification have been updated to the current testing pattern in parsnip and other extension packages (#55). 12 | 13 | * The `predict()` method for the `"glmnet"` engine now checks the penalty value via `parsnip::.check_glmnet_penalty_predict()` instead of a copied version of the function (#57). 14 | 15 | * Moved imports and declaration of global variables into the standard place (#59). 16 | 17 | * Tests are now self-contained (#60). 18 | 19 | * Predictions of type `"conf_int"` for the `"stan"` engine now use the function suggested by rstanarm (#86). 20 | 21 | * Removed obsolete check on supplying `newdata` as an argument to `predict()` or `multi_predict()` (#87). 22 | 23 | 24 | # poissonreg 1.0.1 25 | 26 | * Update to the .Rd files to generate valid HTML5 27 | 28 | 29 | # poissonreg 1.0.0 30 | 31 | * Changes for using case weights with parsnip 1.0.0. 32 | 33 | 34 | # poissonreg 0.2.0 35 | 36 | * Model definition functions (e.g. `poisson_reg()`) were moved to the parsnip package. 37 | 38 | 39 | # poissonreg 0.1.1 40 | 41 | * A default engine of `glm` was added for `poisson_reg()`. 42 | 43 | * Added `tidy()` methods for `pscl::hurdle()` and `pscl::zeroinfl()`. 44 | 45 | 46 | # poissonreg 0.1.0 47 | 48 | * Work-around for a `glmnet` bug where different column order will silently produce incorrect predictions. 49 | 50 | * `multi_predict()` was enabled. 51 | 52 | * Updates to go along with new version of `parsnip`. 53 | 54 | 55 | # poissonreg 0.0.1 56 | 57 | * Added a `NEWS.md` file to track changes to the package. 58 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.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 | push: 5 | branches: [main, master] 6 | pull_request: 7 | 8 | name: test-coverage.yaml 9 | 10 | permissions: read-all 11 | 12 | jobs: 13 | test-coverage: 14 | runs-on: ubuntu-latest 15 | env: 16 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - uses: r-lib/actions/setup-r@v2 22 | with: 23 | use-public-rspm: true 24 | 25 | - uses: r-lib/actions/setup-r-dependencies@v2 26 | with: 27 | extra-packages: any::covr, any::xml2 28 | needs: coverage 29 | 30 | - name: Test coverage 31 | run: | 32 | cov <- covr::package_coverage( 33 | quiet = FALSE, 34 | clean = FALSE, 35 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 36 | ) 37 | print(cov) 38 | covr::to_cobertura(cov) 39 | shell: Rscript {0} 40 | 41 | - uses: codecov/codecov-action@v5 42 | with: 43 | # Fail if error if not on PR, or if on PR and token is given 44 | fail_ci_if_error: ${{ github.event_name != 'pull_request' || secrets.CODECOV_TOKEN }} 45 | files: ./cobertura.xml 46 | plugins: noop 47 | disable_search: true 48 | token: ${{ secrets.CODECOV_TOKEN }} 49 | 50 | - name: Show testthat output 51 | if: always() 52 | run: | 53 | ## -------------------------------------------------------------------- 54 | find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true 55 | shell: bash 56 | 57 | - name: Upload test results 58 | if: failure() 59 | uses: actions/upload-artifact@v4 60 | with: 61 | name: coverage-test-failures 62 | path: ${{ runner.temp }}/package 63 | -------------------------------------------------------------------------------- /.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 | # NOTE: This workflow is overkill for most R packages and 5 | # check-standard.yaml is likely a better choice. 6 | # usethis::use_github_action("check-standard") will install it. 7 | on: 8 | push: 9 | branches: [main, master] 10 | pull_request: 11 | 12 | name: R-CMD-check.yaml 13 | 14 | permissions: read-all 15 | 16 | jobs: 17 | R-CMD-check: 18 | runs-on: ${{ matrix.config.os }} 19 | 20 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | config: 26 | - {os: macos-latest, r: 'release'} 27 | 28 | - {os: windows-latest, r: 'release'} 29 | # use 4.0 or 4.1 to check with rtools40's older compiler 30 | - {os: windows-latest, r: 'oldrel-4'} 31 | 32 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 33 | - {os: ubuntu-latest, r: 'release'} 34 | - {os: ubuntu-latest, r: 'oldrel-1'} 35 | - {os: ubuntu-latest, r: 'oldrel-2'} 36 | - {os: ubuntu-latest, r: 'oldrel-3'} 37 | - {os: ubuntu-latest, r: 'oldrel-4'} 38 | 39 | env: 40 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 41 | R_KEEP_PKG_SOURCE: yes 42 | 43 | steps: 44 | - uses: actions/checkout@v4 45 | 46 | - uses: r-lib/actions/setup-pandoc@v2 47 | 48 | - uses: r-lib/actions/setup-r@v2 49 | with: 50 | r-version: ${{ matrix.config.r }} 51 | http-user-agent: ${{ matrix.config.http-user-agent }} 52 | use-public-rspm: true 53 | 54 | - uses: r-lib/actions/setup-r-dependencies@v2 55 | with: 56 | extra-packages: any::rcmdcheck 57 | needs: check 58 | 59 | - uses: r-lib/actions/check-r-package@v2 60 | with: 61 | upload-snapshots: true 62 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 63 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Bug Report" 3 | about: Submit a bug report to help us improve tidymodels 4 | --- 5 | 6 | ### Tips for a helpful bug report: 7 | 8 | * Please include a **minimal reproducible example,** a reprex, to demonstrate the bug. If you've never heard of a reprex before, start by reading "[What is a reprex](https://github.com/tidyverse/reprex#what-is-a-reprex)" and following the advice there. If we can't reproduce a bug, we can't fit it. 9 | 10 | * Here is a good example bug report: [#46](https://github.com/tidymodels/tune/issues/46) 11 | 12 | * We don't want you to use confidential data; you can use a dataset from [modeldata](https://modeldata.tidymodels.org/reference/index.html), blind the data, or simulate other data to demonstrate your bug. The functions [`caret::twoClassSim()`](https://www.rdocumentation.org/packages/caret/versions/6.0-84/topics/SLC14_1) or [`caret::SLC14_1()`](https://www.rdocumentation.org/packages/caret/versions/6.0-84/topics/SLC14_1) might be good tools to simulate data for you. 13 | 14 | * Unless the problem is explicitly about parallel processing, please run sequentially. _Even if_ it is about parallel processing, please make sure that it runs sequentially first. 15 | 16 | * Use `set.seed()` to ensure any randomness in your code is reproducible. 17 | 18 | * Please check or to see if someone has already reported the same problem (see: [Yihui's Rule](https://yihui.name/en/2017/08/so-gh-email/)). 19 | 20 | * You might need to install these packages to create a reproducible example or share session info: 21 | 22 | ```r 23 | install.packages(c("reprex", "sessioninfo"), repos = "http://cran.r-project.org") 24 | ``` 25 | 26 | When you are ready to file the bug 🐛 report, please delete everything above this line: 27 | < -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> 28 | 29 | ## The problem 30 | 31 | I'm having trouble with ... 32 | 33 | ## Reproducible example 34 | 35 | ```r 36 | ## copy your code to the clipboard and run: 37 | reprex::reprex(si = TRUE) 38 | ``` 39 | 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Feature Request" 3 | about: Suggest a change or new feature in tidymodels 4 | --- 5 | 6 | ### Tips for a helpful feature request: 7 | 8 | * See our [contributing guidelines](https://github.com/tidymodels/tidymodels/blob/master/.github/CONTRIBUTING.md) and [development guide](https://www.tidymodels.org/contribute/) for more on design goals and how to contribute. 9 | 10 | * Please include a **minimal reproducible example,** a reprex, to demonstrate your feature idea when appropriate. If you've never heard of a reprex before, start by reading "[What is a reprex](https://github.com/tidyverse/reprex#what-is-a-reprex)" and following the advice there. A reproducible example can be effective at demonstrating the case for a new feature. 11 | 12 | * We don't want you to use confidential data; you can use a dataset from [modeldata](https://modeldata.tidymodels.org/reference/index.html), blind the data, or simulate other data to demonstrate your bug. The functions [`caret::twoClassSim()`](https://www.rdocumentation.org/packages/caret/versions/6.0-84/topics/SLC14_1) or [`caret::SLC14_1()`](https://www.rdocumentation.org/packages/caret/versions/6.0-84/topics/SLC14_1) might be good tools to simulate data for you. 13 | 14 | * Unless the feature is explicitly about parallel processing, please run sequentially. _Even if_ it is about parallel processing, please make sure that it runs sequentially first. 15 | 16 | * Use `set.seed()` to ensure any randomness in your code is reproducible. 17 | 18 | * Please check or to see if someone has already asked the same question (see: [Yihui's Rule](https://yihui.name/en/2017/08/so-gh-email/)). 19 | 20 | * You might need to install these packages to create a reproducible example or share session info: 21 | 22 | ```r 23 | install.packages(c("reprex", "sessioninfo"), repos = "http://cran.r-project.org") 24 | ``` 25 | 26 | When you are ready to file the feature ✨ request, please delete everything above this line: 27 | < -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> 28 | 29 | ## Feature 30 | 31 | In situations when ... 32 | 33 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Getting help with poissonreg 2 | 3 | Thanks for using poissonreg! 4 | Before filing an issue, there are a few places to explore and pieces to put together to make the process as smooth as possible. 5 | 6 | ## Make a reprex 7 | 8 | Start by making a minimal **repr**oducible **ex**ample using the [reprex](https://reprex.tidyverse.org/) package. 9 | If you haven't heard of or used reprex before, you're in for a treat! 10 | Seriously, reprex will make all of your R-question-asking endeavors easier (which is a pretty insane ROI for the five to ten minutes it'll take you to learn what it's all about). 11 | For additional reprex pointers, check out the [Get help!](https://www.tidyverse.org/help/) section of the tidyverse site. 12 | 13 | ## Where to ask? 14 | 15 | Armed with your reprex, the next step is to figure out [where to ask](https://www.tidyverse.org/help/#where-to-ask). 16 | 17 | * If it's a question: start with [community.rstudio.com](https://community.rstudio.com/), and/or StackOverflow. There are more people there to answer questions. 18 | 19 | * If it's a bug: you're in the right place, [file an issue](https://github.com//issues/new). 20 | 21 | * If you're not sure: let the community help you figure it out! 22 | If your problem _is_ a bug or a feature request, you can easily return here and report it. 23 | 24 | Before opening a new issue, be sure to [search issues and pull requests](https://github.com//issues) to make sure the bug hasn't been reported and/or already fixed in the development version. 25 | By default, the search will be pre-populated with `is:issue is:open`. 26 | You can [edit the qualifiers](https://help.github.com/articles/searching-issues-and-pull-requests/) (e.g. `is:pr`, `is:closed`) as needed. 27 | For example, you'd simply remove `is:open` to search _all_ issues in the repo, open or closed. 28 | 29 | ## What happens next? 30 | 31 | To be as efficient as possible, development of tidyverse packages tends to be very bursty, so you shouldn't worry if you don't get an immediate response. 32 | Typically we don't look at a repo until a sufficient quantity of issues accumulates, then there’s a burst of intense activity as we focus our efforts. 33 | That makes development more efficient because it avoids expensive context switching between problems, at the cost of taking longer to get back to you. 34 | This process makes a good reprex particularly important because it might be multiple months between your initial report and when we start working on it. 35 | If we can’t reproduce the bug, we can’t fix it! 36 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/poisson_reg.md: -------------------------------------------------------------------------------- 1 | # arguments 2 | 3 | Code 4 | translate_args(basic) 5 | Output 6 | $formula 7 | missing_arg() 8 | 9 | $data 10 | missing_arg() 11 | 12 | $weights 13 | missing_arg() 14 | 15 | $family 16 | stats::poisson 17 | 18 | 19 | --- 20 | 21 | Code 22 | translate_args(set_engine(penalty, "glmnet")) 23 | Output 24 | $x 25 | missing_arg() 26 | 27 | $y 28 | missing_arg() 29 | 30 | $weights 31 | missing_arg() 32 | 33 | $family 34 | [1] "poisson" 35 | 36 | 37 | --- 38 | 39 | Code 40 | translate_args(set_engine(penalty, "glmnet", path_values = 4:2)) 41 | Output 42 | $x 43 | missing_arg() 44 | 45 | $y 46 | missing_arg() 47 | 48 | $weights 49 | missing_arg() 50 | 51 | $lambda 52 | 53 | expr: ^4:2 54 | env: empty 55 | 56 | $family 57 | [1] "poisson" 58 | 59 | 60 | --- 61 | 62 | Code 63 | translate_args(set_engine(mixture, "glmnet")) 64 | Output 65 | $x 66 | missing_arg() 67 | 68 | $y 69 | missing_arg() 70 | 71 | $weights 72 | missing_arg() 73 | 74 | $alpha 75 | 76 | expr: ^0.128 77 | env: empty 78 | 79 | $family 80 | [1] "poisson" 81 | 82 | 83 | --- 84 | 85 | Code 86 | translate_args(set_engine(mixture_tune, "glmnet")) 87 | Output 88 | $x 89 | missing_arg() 90 | 91 | $y 92 | missing_arg() 93 | 94 | $weights 95 | missing_arg() 96 | 97 | $alpha 98 | 99 | expr: ^tune() 100 | env: empty 101 | 102 | $family 103 | [1] "poisson" 104 | 105 | 106 | # check_args() works 107 | 108 | Code 109 | spec <- set_mode(set_engine(poisson_reg(mixture = -1), "glm"), "regression") 110 | fit(spec, gear ~ ., data = mtcars) 111 | Condition 112 | Error in `fit()`: 113 | ! `mixture` must be a number between 0 and 1 or `NULL`, not the number -1. 114 | 115 | --- 116 | 117 | Code 118 | spec <- set_mode(set_engine(poisson_reg(penalty = -1), "glm"), "regression") 119 | fit(spec, gear ~ ., data = mtcars) 120 | Condition 121 | Error in `fit()`: 122 | ! `penalty` must be a number larger than or equal to 0 or `NULL`, not the number -1. 123 | 124 | -------------------------------------------------------------------------------- /.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 == '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 == '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 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to poissonreg 2 | 3 | This outlines how to propose a change to poissonreg. 4 | For more detailed info about contributing to this, and other tidyverse packages, please see the 5 | [**development contributing guide**](https://rstd.io/tidy-contrib). 6 | 7 | ## Fixing typos 8 | 9 | You can fix typos, spelling mistakes, or grammatical errors in the documentation directly using the GitHub web interface, as long as the changes are made in the _source_ file. 10 | This generally means you'll need to edit [roxygen2 comments](https://roxygen2.r-lib.org/articles/roxygen2.html) in an `.R`, not a `.Rd` file. 11 | You can find the `.R` file that generates the `.Rd` by reading the comment in the first line. 12 | 13 | ## Bigger changes 14 | 15 | If you want to make a bigger change, it's a good idea to first file an issue and make sure someone from the team agrees that it’s needed. 16 | If you’ve found a bug, please file an issue that illustrates the bug with a minimal 17 | [reprex](https://www.tidyverse.org/help/#reprex) (this will also help you write a unit test, if needed). 18 | 19 | ### Pull request process 20 | 21 | * Fork the package and clone onto your computer. If you haven't done this before, we recommend using `usethis::create_from_github("", fork = TRUE)`. 22 | 23 | * Install all development dependences with `devtools::install_dev_deps()`, and then make sure the package passes R CMD check by running `devtools::check()`. 24 | If R CMD check doesn't pass cleanly, it's a good idea to ask for help before continuing. 25 | * Create a Git branch for your pull request (PR). We recommend using `usethis::pr_init("brief-description-of-change")`. 26 | 27 | * Make your changes, commit to git, and then create a PR by running `usethis::pr_push()`, and following the prompts in your browser. 28 | The title of your PR should briefly describe the change. 29 | The body of your PR should contain `Fixes #issue-number`. 30 | 31 | * For user-facing changes, add a bullet to the top of `NEWS.md` (i.e. just below the first header). Follow the style described in . 32 | 33 | ### Code style 34 | 35 | * New code should follow the tidyverse [style guide](https://style.tidyverse.org). 36 | You can use the [styler](https://CRAN.R-project.org/package=styler) package to apply these styles, but please don't restyle code that has nothing to do with your PR. 37 | 38 | * We use [roxygen2](https://cran.r-project.org/package=roxygen2), with [Markdown syntax](https://cran.r-project.org/web/packages/roxygen2/vignettes/rd-formatting.html), for documentation. 39 | 40 | * We use [testthat](https://cran.r-project.org/package=testthat) for unit tests. 41 | Contributions with test cases included are easier to accept. 42 | 43 | ## Code of Conduct 44 | 45 | Please note that the poissonreg project is released with a 46 | [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By contributing to this 47 | project you agree to abide by its terms. 48 | -------------------------------------------------------------------------------- /man/poissonreg-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/poissonreg-package.R 3 | \docType{package} 4 | \name{poissonreg-package} 5 | \alias{poissonreg} 6 | \alias{poissonreg-package} 7 | \title{parsnip methods for Poisson regression} 8 | \description{ 9 | \pkg{poissonreg} offers a function to fit model to count data using Poisson 10 | generalized linear models or via different methods for zero-inflated Poisson 11 | (ZIP) models. 12 | } 13 | \details{ 14 | The model function works with the tidymodels infrastructure so that the model 15 | can be resampled, tuned, tided, etc. 16 | } 17 | \section{Example}{ 18 | Let’s fit a model to the data from Agresti (2007) Table 7.6: 19 | 20 | \if{html}{\out{
}}\preformatted{library(poissonreg) 21 | library(tidymodels) 22 | tidymodels_prefer() 23 | 24 | log_lin_fit <- 25 | # Define the model 26 | poisson_reg() |> 27 | # Choose an engine for fitting. The default is 'glm' so 28 | # this next line is not strictly needed: 29 | set_engine("glm") |> 30 | # Fit the model to the data: 31 | fit(count ~ (.)^2, data = seniors) 32 | 33 | log_lin_fit 34 | }\if{html}{\out{
}} 35 | 36 | \if{html}{\out{
}}\preformatted{## parsnip model object 37 | ## 38 | ## 39 | ## Call: stats::glm(formula = count ~ (.)^2, family = stats::poisson, 40 | ## data = data) 41 | ## 42 | ## Coefficients: 43 | ## (Intercept) marijuanayes 44 | ## 5.6334 -5.3090 45 | ## cigaretteyes alcoholyes 46 | ## -1.8867 0.4877 47 | ## marijuanayes:cigaretteyes marijuanayes:alcoholyes 48 | ## 2.8479 2.9860 49 | ## cigaretteyes:alcoholyes 50 | ## 2.0545 51 | ## 52 | ## Degrees of Freedom: 7 Total (i.e. Null); 1 Residual 53 | ## Null Deviance: 2851 54 | ## Residual Deviance: 0.374 AIC: 63.42 55 | }\if{html}{\out{
}} 56 | 57 | The different engines for the model that are provided by this package 58 | are: 59 | 60 | \if{html}{\out{
}}\preformatted{show_engines("poisson_reg") 61 | }\if{html}{\out{
}} 62 | 63 | \if{html}{\out{
}}\preformatted{## # A tibble: 5 x 2 64 | ## engine mode 65 | ## 66 | ## 1 glm regression 67 | ## 2 hurdle regression 68 | ## 3 zeroinfl regression 69 | ## 4 glmnet regression 70 | ## 5 stan regression 71 | }\if{html}{\out{
}} 72 | } 73 | 74 | \seealso{ 75 | Useful links: 76 | \itemize{ 77 | \item \url{https://github.com/tidymodels/poissonreg} 78 | \item \url{https://poissonreg.tidymodels.org/} 79 | \item Report bugs at \url{https://github.com/tidymodels/poissonreg/issues} 80 | } 81 | 82 | } 83 | \author{ 84 | \strong{Maintainer}: Hannah Frick \email{hannah@posit.co} (\href{https://orcid.org/0000-0002-6049-5258}{ORCID}) 85 | 86 | Authors: 87 | \itemize{ 88 | \item Max Kuhn \email{max@posit.co} (\href{https://orcid.org/0000-0003-2402-136X}{ORCID}) 89 | } 90 | 91 | Other contributors: 92 | \itemize{ 93 | \item Posit Software, PBC (03wc8by49) [copyright holder, funder] 94 | } 95 | 96 | } 97 | \keyword{internal} 98 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | ``` 15 | 16 | # poissonreg Six fishes, each in a different color: red, green, orange, purple, yellow, blue. 17 | 18 | 19 | 20 | [![R-CMD-check](https://github.com/tidymodels/poissonreg/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tidymodels/poissonreg/actions/workflows/R-CMD-check.yaml) 21 | [![CRAN status](https://www.r-pkg.org/badges/version/poissonreg)](https://CRAN.R-project.org/package=poissonreg) 22 | [![Codecov test coverage](https://codecov.io/gh/tidymodels/poissonreg/graph/badge.svg)](https://app.codecov.io/gh/tidymodels/poissonreg) 23 | [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html) 24 | 25 | 26 | poissonreg enables the parsnip package to fit various types of Poisson regression models including ordinary generalized linear models, simple Bayesian models (via rstanarm), and two zero-inflated Poisson models (via pscl). 27 | 28 | ## Installation 29 | 30 | You can install the released version of poissonreg from [CRAN](https://CRAN.R-project.org) with: 31 | 32 | ``` r 33 | install.packages("poissonreg") 34 | ``` 35 | 36 | Install the development version from GitHub with: 37 | 38 | ``` r 39 | # install.packages("pak") 40 | pak::pak("tidymodels/poissonreg") 41 | ``` 42 | 43 | ## Available Engines 44 | 45 | The poissonreg package provides engines for the models in the following table. 46 | 47 | ```{r, echo=FALSE, message=FALSE} 48 | library(parsnip) 49 | 50 | parsnip_models <- get_from_env("models") 51 | names(parsnip_models) <- parsnip_models 52 | parsnip_models <- parsnip_models |> 53 | purrr::map_dfr(get_from_env, .id = "model") 54 | 55 | library(poissonreg) 56 | 57 | poissonreg_models <- get_from_env("models") 58 | names(poissonreg_models) <- poissonreg_models 59 | poissonreg_models <- poissonreg_models |> 60 | purrr::map_dfr(get_from_env, .id = "model") 61 | 62 | dplyr::anti_join( 63 | poissonreg_models, parsnip_models, 64 | by = c("model", "engine", "mode") 65 | ) |> 66 | knitr::kable() 67 | ``` 68 | 69 | ## Example 70 | 71 | A log-linear model for categorical data analysis: 72 | 73 | ```{r example} 74 | library(poissonreg) 75 | 76 | # 3D contingency table from Agresti (2007): 77 | poisson_reg() |> 78 | set_engine("glm") |> 79 | fit(count ~ (.)^2, data = seniors) 80 | ``` 81 | 82 | ## Contributing 83 | 84 | This project is released with a [Contributor Code of Conduct](https://www.contributor-covenant.org/version/2/1/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. 85 | 86 | - For questions and discussions about tidymodels packages, modeling, and machine learning, please [post on RStudio Community](https://community.rstudio.com/new-topic?category_id=15&tags=tidymodels,question). 87 | 88 | - If you think you have encountered a bug, please [submit an issue](https://github.com/tidymodels/poissonreg/issues). 89 | 90 | - Either way, learn how to create and share a [reprex](https://reprex.tidyverse.org/articles/articles/learn-reprex.html) (a minimal, reproducible example), to clearly communicate about your code. 91 | 92 | - Check out further details on [contributing guidelines for tidymodels packages](https://www.tidymodels.org/contribute/) and [how to get help](https://www.tidymodels.org/help/). 93 | 94 | -------------------------------------------------------------------------------- /tests/testthat/test-poisson_reg-glmnet.R: -------------------------------------------------------------------------------- 1 | test_that("prediction of single row", { 2 | skip_if_not_installed("glmnet") 3 | 4 | m <- poisson_reg(penalty = 0.1) |> 5 | set_engine("glmnet") |> 6 | fit(count ~ (.)^2, data = seniors[, 2:4]) 7 | 8 | pred_1 <- predict(m, new_data = seniors[1, ], penalty = 0.1) 9 | expect_equal(nrow(pred_1), 1) 10 | 11 | multi_pred_1 <- multi_predict(m, new_data = seniors[1, ]) 12 | expect_equal(nrow(multi_pred_1), 1) 13 | }) 14 | 15 | test_that("glmnet multi_predict(): type numeric", { 16 | skip_if_not_installed("glmnet") 17 | 18 | data(seniors, package = "poissonreg", envir = rlang::current_env()) 19 | seniors_x <- model.matrix(~., data = seniors[, -4])[, -1] 20 | seniors_y <- seniors$count 21 | 22 | penalty_values <- c(0.01, 0.1) 23 | 24 | exp_fit <- glmnet::glmnet( 25 | x = seniors_x, 26 | y = seniors_y, 27 | family = "poisson", 28 | alpha = 0.3, 29 | nlambda = 15 30 | ) 31 | exp_pred <- predict(exp_fit, seniors_x, s = penalty_values, type = "response") 32 | 33 | spec <- poisson_reg(penalty = 0.1, mixture = 0.3) |> 34 | set_engine("glmnet", nlambda = 15) 35 | f_fit <- fit(spec, count ~ ., data = seniors) 36 | xy_fit <- fit_xy(spec, x = seniors_x, y = seniors_y) 37 | 38 | expect_true(has_multi_predict(xy_fit)) 39 | expect_equal(multi_predict_args(xy_fit), "penalty") 40 | 41 | f_pred <- multi_predict( 42 | f_fit, 43 | seniors, 44 | type = "numeric", 45 | penalty = penalty_values 46 | ) 47 | xy_pred <- multi_predict( 48 | xy_fit, 49 | seniors_x, 50 | type = "numeric", 51 | penalty = penalty_values 52 | ) 53 | expect_equal(f_pred, xy_pred) 54 | 55 | f_pred_001 <- f_pred |> 56 | tidyr::unnest(cols = .pred) |> 57 | dplyr::filter(penalty == 0.01) |> 58 | dplyr::pull(.pred) 59 | f_pred_01 <- f_pred |> 60 | tidyr::unnest(cols = .pred) |> 61 | dplyr::filter(penalty == 0.1) |> 62 | dplyr::pull(.pred) 63 | expect_equal(f_pred_001, unname(exp_pred[, 1])) 64 | expect_equal(f_pred_01, unname(exp_pred[, 2])) 65 | 66 | # check format 67 | expect_s3_class(f_pred, "tbl_df") 68 | expect_equal(names(f_pred), ".pred") 69 | expect_equal(nrow(f_pred), nrow(seniors)) 70 | expect_true( 71 | all(purrr::map_lgl(f_pred$.pred, \(.x) all(dim(.x) == c(2, 2)))) 72 | ) 73 | expect_true( 74 | all(purrr::map_lgl( 75 | f_pred$.pred, 76 | \(.x) all(names(.x) == c("penalty", ".pred")) 77 | )) 78 | ) 79 | 80 | # single prediction 81 | f_pred_1 <- multi_predict( 82 | f_fit, 83 | seniors[1, ], 84 | type = "numeric", 85 | penalty = penalty_values 86 | ) 87 | xy_pred_1 <- multi_predict( 88 | xy_fit, 89 | seniors_x[1, , drop = FALSE], 90 | type = "numeric", 91 | penalty = penalty_values 92 | ) 93 | expect_equal(f_pred_1, xy_pred_1) 94 | expect_equal(nrow(f_pred_1), 1) 95 | expect_equal(nrow(f_pred_1$.pred[[1]]), 2) 96 | }) 97 | 98 | test_that("glmnet prediction type NULL", { 99 | skip_if_not_installed("glmnet") 100 | 101 | data(seniors, package = "poissonreg", envir = rlang::current_env()) 102 | 103 | spec <- poisson_reg(penalty = 0.1, mixture = 0.3) |> 104 | set_engine("glmnet", nlambda = 15) 105 | f_fit <- fit(spec, count ~ ., data = seniors) 106 | 107 | pred <- predict(f_fit, seniors[1:5, ]) 108 | pred_numeric <- predict(f_fit, seniors[1:5, ], type = "numeric") 109 | expect_identical(pred, pred_numeric) 110 | 111 | mpred <- multi_predict(f_fit, seniors[1:5, ]) 112 | mpred_numeric <- multi_predict(f_fit, seniors[1:5, ], type = "numeric") 113 | expect_identical(mpred, mpred_numeric) 114 | 115 | mpred_pred <- mpred |> 116 | tidyr::unnest(cols = .pred) |> 117 | dplyr::pull(.pred) 118 | expect_identical(pred$.pred, mpred_pred) 119 | }) 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # poissonreg Six fishes, each in a different color: red, green, orange, purple, yellow, blue. 5 | 6 | 7 | 8 | [![R-CMD-check](https://github.com/tidymodels/poissonreg/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tidymodels/poissonreg/actions/workflows/R-CMD-check.yaml) 9 | [![CRAN 10 | status](https://www.r-pkg.org/badges/version/poissonreg)](https://CRAN.R-project.org/package=poissonreg) 11 | [![Codecov test 12 | coverage](https://codecov.io/gh/tidymodels/poissonreg/graph/badge.svg)](https://app.codecov.io/gh/tidymodels/poissonreg) 13 | [![Lifecycle: 14 | experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html) 15 | 16 | 17 | poissonreg enables the parsnip package to fit various types of Poisson 18 | regression models including ordinary generalized linear models, simple 19 | Bayesian models (via rstanarm), and two zero-inflated Poisson models 20 | (via pscl). 21 | 22 | ## Installation 23 | 24 | You can install the released version of poissonreg from 25 | [CRAN](https://CRAN.R-project.org) with: 26 | 27 | ``` r 28 | install.packages("poissonreg") 29 | ``` 30 | 31 | Install the development version from GitHub with: 32 | 33 | ``` r 34 | # install.packages("pak") 35 | pak::pak("tidymodels/poissonreg") 36 | ``` 37 | 38 | ## Available Engines 39 | 40 | The poissonreg package provides engines for the models in the following 41 | table. 42 | 43 | | model | engine | mode | 44 | |:------------|:---------|:-----------| 45 | | poisson_reg | glm | regression | 46 | | poisson_reg | hurdle | regression | 47 | | poisson_reg | zeroinfl | regression | 48 | | poisson_reg | glmnet | regression | 49 | | poisson_reg | stan | regression | 50 | 51 | ## Example 52 | 53 | A log-linear model for categorical data analysis: 54 | 55 | ``` r 56 | library(poissonreg) 57 | 58 | # 3D contingency table from Agresti (2007): 59 | poisson_reg() |> 60 | set_engine("glm") |> 61 | fit(count ~ (.)^2, data = seniors) 62 | #> parsnip model object 63 | #> 64 | #> 65 | #> Call: stats::glm(formula = count ~ (.)^2, family = stats::poisson, 66 | #> data = data) 67 | #> 68 | #> Coefficients: 69 | #> (Intercept) marijuanayes 70 | #> 5.6334 -5.3090 71 | #> cigaretteyes alcoholyes 72 | #> -1.8867 0.4877 73 | #> marijuanayes:cigaretteyes marijuanayes:alcoholyes 74 | #> 2.8479 2.9860 75 | #> cigaretteyes:alcoholyes 76 | #> 2.0545 77 | #> 78 | #> Degrees of Freedom: 7 Total (i.e. Null); 1 Residual 79 | #> Null Deviance: 2851 80 | #> Residual Deviance: 0.374 AIC: 63.42 81 | ``` 82 | 83 | ## Contributing 84 | 85 | This project is released with a [Contributor Code of 86 | Conduct](https://www.contributor-covenant.org/version/2/1/CODE_OF_CONDUCT.html). 87 | By contributing to this project, you agree to abide by its terms. 88 | 89 | - For questions and discussions about tidymodels packages, modeling, and 90 | machine learning, please [post on RStudio 91 | Community](https://community.rstudio.com/new-topic?category_id=15&tags=tidymodels,question). 92 | 93 | - If you think you have encountered a bug, please [submit an 94 | issue](https://github.com/tidymodels/poissonreg/issues). 95 | 96 | - Either way, learn how to create and share a 97 | [reprex](https://reprex.tidyverse.org/articles/articles/learn-reprex.html) 98 | (a minimal, reproducible example), to clearly communicate about your 99 | code. 100 | 101 | - Check out further details on [contributing guidelines for tidymodels 102 | packages](https://www.tidymodels.org/contribute/) and [how to get 103 | help](https://www.tidymodels.org/help/). 104 | -------------------------------------------------------------------------------- /R/poisson_reg-glmnet.R: -------------------------------------------------------------------------------- 1 | # glmnet call stack for poissom regression using `predict` when object has 2 | # classes "_fishnet" and "model_fit": 3 | # 4 | # predict() 5 | # predict._fishnet(penalty = NULL) <-- checks and sets penalty 6 | # predict.model_fit() <-- checks for extra vars in ... 7 | # predict_numeric() 8 | # predict_numeric._fishnet() 9 | # predict_numeric.model_fit() 10 | # predict.fishnet() 11 | 12 | # glmnet call stack for poisson regression using `multi_predict` when object has 13 | # classes "_fishnet" and "model_fit": 14 | # 15 | # multi_predict() 16 | # multi_predict._fishnet(penalty = NULL) 17 | # predict._fishnet(multi = TRUE) <-- checks and sets penalty 18 | # predict.model_fit() <-- checks for extra vars in ... 19 | # predict_raw() 20 | # predict_raw._fishnet() 21 | # predict_raw.model_fit(opts = list(s = penalty)) 22 | # predict.fishnet() 23 | 24 | #' @export 25 | predict._fishnet <- 26 | function( 27 | object, 28 | new_data, 29 | type = NULL, 30 | opts = list(), 31 | penalty = NULL, 32 | multi = FALSE, 33 | ... 34 | ) { 35 | # See discussion in https://github.com/tidymodels/parsnip/issues/195 36 | if (is.null(penalty) & !is.null(object$spec$args$penalty)) { 37 | penalty <- object$spec$args$penalty 38 | } 39 | 40 | object$spec$args$penalty <- .check_glmnet_penalty_predict( 41 | penalty, 42 | object, 43 | multi 44 | ) 45 | 46 | object$spec <- parsnip::eval_args(object$spec) 47 | predict.model_fit( 48 | object, 49 | new_data = new_data, 50 | type = type, 51 | opts = opts, 52 | ... 53 | ) 54 | } 55 | 56 | #' @export 57 | predict_numeric._fishnet <- function(object, new_data, ...) { 58 | object$spec <- parsnip::eval_args(object$spec) 59 | parsnip::predict_numeric.model_fit(object, new_data = new_data, ...) 60 | } 61 | 62 | #' Model predictions across many sub-models 63 | #' 64 | #' For some models, predictions can be made on sub-models in the model object. 65 | #' @param object A `model_fit` object. 66 | #' @param new_data A rectangular data object, such as a data frame. 67 | #' @param opts A list of options.. 68 | #' @param ... Optional arguments to pass to `predict.model_fit(type = "raw")` 69 | #' such as `type`. 70 | #' @return A tibble with the same number of rows as the data being predicted. 71 | #' There is a list-column named `.pred` that contains tibbles with 72 | #' multiple rows per sub-model. 73 | #' @export 74 | #' @keywords internal 75 | predict_raw._fishnet <- function(object, new_data, opts = list(), ...) { 76 | object$spec <- parsnip::eval_args(object$spec) 77 | opts$s <- object$spec$args$penalty 78 | parsnip::predict_raw.model_fit(object, new_data = new_data, opts = opts, ...) 79 | } 80 | 81 | #' @importFrom dplyr full_join as_tibble arrange 82 | #' @importFrom tidyr gather 83 | #' @export 84 | #' @rdname predict_raw._fishnet 85 | #' @param penalty A numeric vector of penalty values. 86 | multi_predict._fishnet <- 87 | function(object, new_data, type = NULL, penalty = NULL, ...) { 88 | dots <- list(...) 89 | 90 | object$spec <- eval_args(object$spec) 91 | 92 | if (is.null(penalty)) { 93 | # See discussion in https://github.com/tidymodels/parsnip/issues/195 94 | if (!is.null(object$spec$args$penalty)) { 95 | penalty <- object$spec$args$penalty 96 | } else { 97 | penalty <- object$fit$lambda 98 | } 99 | } 100 | 101 | if (is.null(type)) { 102 | type <- "numeric" 103 | } 104 | if (type == "numeric") { 105 | # `glmnet:::predict.fishnet()` will receive `type = "response"` 106 | # via `parsnip:::predict_raw.model_fit` (#89) 107 | dots$type <- "response" 108 | } 109 | 110 | pred <- predict._fishnet( 111 | object, 112 | new_data = new_data, 113 | type = "raw", 114 | opts = dots, 115 | penalty = penalty, 116 | multi = TRUE 117 | ) 118 | param_key <- tibble(group = colnames(pred), penalty = penalty) 119 | pred <- as_tibble(pred) 120 | pred$.row <- seq_len(nrow(pred)) 121 | pred <- gather(pred, group, .pred, -.row) 122 | if (utils::packageVersion("dplyr") >= "1.0.99.9000") { 123 | pred <- full_join(param_key, pred, by = "group", multiple = "all") 124 | } else { 125 | pred <- full_join(param_key, pred, by = "group") 126 | } 127 | pred$group <- NULL 128 | pred <- arrange(pred, .row, penalty) 129 | .row <- pred$.row 130 | pred$.row <- NULL 131 | pred <- split(pred, .row) 132 | names(pred) <- NULL 133 | tibble(.pred = pred) 134 | } 135 | -------------------------------------------------------------------------------- /vignettes/articles/examples.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Fitting and Predicting with poissonreg" 3 | vignette: > 4 | %\VignetteEngine{knitr::rmarkdown} 5 | %\VignetteIndexEntry{Fitting and Predicting with poissonreg} 6 | output: 7 | knitr:::html_vignette 8 | --- 9 | 10 | ```{r} 11 | #| label: startup 12 | #| include: false 13 | library(utils) 14 | library(ggplot2) 15 | theme_set(theme_bw()) 16 | ``` 17 | 18 | These examples illustrate which models, engines, and prediction types are available in poissonreg. As a reminder, in parsnip, 19 | 20 | - the **model type** differentiates basic modeling approaches, such as random forests, proportional hazards models, etc., 21 | 22 | - the **mode** denotes in what kind of modeling context it will be used (here: regression), and 23 | 24 | - the computational **engine** indicates how the model is fit, such as with a specific R package implementation or even methods outside of R like Keras or Stan. 25 | 26 | The following examples use the same data set throughout. 27 | 28 | ## `poisson_reg()` models 29 | 30 |
31 | 32 | With the `"glm"` engine 33 | 34 | ```{r} 35 | #| echo: false 36 | knitr::spin_child("template-biochemists.R") 37 | ``` 38 | 39 | We can define the model: 40 | 41 | ```{r} 42 | pr_spec <- 43 | poisson_reg() |> 44 | set_engine("glm") |> 45 | set_mode("regression") 46 | pr_spec 47 | ``` 48 | 49 | Now we create the model fit object: 50 | 51 | ```{r} 52 | set.seed(1) 53 | pr_fit <- pr_spec |> fit(art ~ ., data = biochemists_train) 54 | pr_fit 55 | ``` 56 | 57 | The holdout data can be predicted: 58 | 59 | ```{r} 60 | predict(pr_fit, biochemists_test) 61 | ``` 62 | 63 |
64 | 65 |
66 | 67 | With the `"glmnet"` engine 68 | 69 | ```{r} 70 | #| echo: false 71 | knitr::spin_child("template-biochemists.R") 72 | ``` 73 | 74 | We can define the model with specific parameters: 75 | 76 | ```{r} 77 | pr_spec <- 78 | poisson_reg(penalty = 0.1) |> 79 | set_engine("glmnet") |> 80 | set_mode("regression") 81 | pr_spec 82 | ``` 83 | 84 | Now we create the model fit object: 85 | 86 | ```{r} 87 | set.seed(1) 88 | pr_fit <- pr_spec |> fit(art ~ ., data = biochemists_train) 89 | pr_fit 90 | ``` 91 | 92 | The holdout data can be predicted: 93 | 94 | ```{r} 95 | predict(pr_fit, biochemists_test) 96 | ``` 97 | 98 |
99 | 100 |
101 | 102 | With the `"hurdle"` engine 103 | 104 | ```{r} 105 | #| echo: false 106 | knitr::spin_child("template-biochemists.R") 107 | ``` 108 | 109 | We can define the model: 110 | 111 | ```{r} 112 | pr_spec <- 113 | poisson_reg() |> 114 | set_engine("hurdle") |> 115 | set_mode("regression") 116 | pr_spec 117 | ``` 118 | 119 | Now we create the model fit object: 120 | 121 | ```{r} 122 | set.seed(1) 123 | pr_fit <- pr_spec |> fit(art ~ . | ., data = biochemists_train) 124 | pr_fit 125 | ``` 126 | 127 | The holdout data can be predicted: 128 | 129 | ```{r} 130 | predict(pr_fit, biochemists_test) 131 | ``` 132 | 133 |
134 | 135 |
136 | 137 | With the `"stan"` engine 138 | 139 | ```{r} 140 | #| echo: false 141 | knitr::spin_child("template-biochemists.R") 142 | ``` 143 | 144 | We can define the model: 145 | 146 | ```{r} 147 | pr_spec <- 148 | poisson_reg() |> 149 | set_engine("stan") |> 150 | set_mode("regression") 151 | pr_spec 152 | ``` 153 | 154 | Now we create the model fit object: 155 | 156 | ```{r} 157 | set.seed(1) 158 | pr_fit <- pr_spec |> fit(art ~ ., data = biochemists_train) 159 | pr_fit 160 | ``` 161 | 162 | The holdout data can be predicted: 163 | 164 | ```{r} 165 | predict(pr_fit, biochemists_test) 166 | ``` 167 | 168 |
169 | 170 |
171 | 172 | With the `"zeroinfl"` engine 173 | 174 | ```{r} 175 | #| echo: false 176 | knitr::spin_child("template-biochemists.R") 177 | ``` 178 | 179 | We can define the model: 180 | 181 | ```{r} 182 | pr_spec <- 183 | poisson_reg() |> 184 | set_engine("zeroinfl") |> 185 | set_mode("regression") 186 | pr_spec 187 | ``` 188 | 189 | Now we create the model fit object: 190 | 191 | ```{r} 192 | set.seed(1) 193 | pr_fit <- pr_spec |> fit(art ~ . | ., data = biochemists_train) 194 | pr_fit 195 | ``` 196 | 197 | The holdout data can be predicted: 198 | 199 | ```{r} 200 | predict(pr_fit, biochemists_test) 201 | ``` 202 | 203 |
204 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at codeofconduct@posit.co. 63 | All complaints will be reviewed and investigated promptly and fairly. 64 | 65 | All community leaders are obligated to respect the privacy and security of the 66 | reporter of any incident. 67 | 68 | ## Enforcement Guidelines 69 | 70 | Community leaders will follow these Community Impact Guidelines in determining 71 | the consequences for any action they deem in violation of this Code of Conduct: 72 | 73 | ### 1. Correction 74 | 75 | **Community Impact**: Use of inappropriate language or other behavior deemed 76 | unprofessional or unwelcome in the community. 77 | 78 | **Consequence**: A private, written warning from community leaders, providing 79 | clarity around the nature of the violation and an explanation of why the 80 | behavior was inappropriate. A public apology may be requested. 81 | 82 | ### 2. Warning 83 | 84 | **Community Impact**: A violation through a single incident or series of 85 | actions. 86 | 87 | **Consequence**: A warning with consequences for continued behavior. No 88 | interaction with the people involved, including unsolicited interaction with 89 | those enforcing the Code of Conduct, for a specified period of time. This 90 | includes avoiding interactions in community spaces as well as external channels 91 | like social media. Violating these terms may lead to a temporary or permanent 92 | ban. 93 | 94 | ### 3. Temporary Ban 95 | 96 | **Community Impact**: A serious violation of community standards, including 97 | sustained inappropriate behavior. 98 | 99 | **Consequence**: A temporary ban from any sort of interaction or public 100 | communication with the community for a specified period of time. No public or 101 | private interaction with the people involved, including unsolicited interaction 102 | with those enforcing the Code of Conduct, is allowed during this period. 103 | Violating these terms may lead to a permanent ban. 104 | 105 | ### 4. Permanent Ban 106 | 107 | **Community Impact**: Demonstrating a pattern of violation of community 108 | standards, including sustained inappropriate behavior, harassment of an 109 | individual, or aggression toward or disparagement of classes of individuals. 110 | 111 | **Consequence**: A permanent ban from any sort of public interaction within the 112 | community. 113 | 114 | ## Attribution 115 | 116 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 117 | version 2.1, available at 118 | . 119 | 120 | Community Impact Guidelines were inspired by 121 | [Mozilla's code of conduct enforcement ladder][https://github.com/mozilla/inclusion]. 122 | 123 | For answers to common questions about this code of conduct, see the FAQ at 124 | . Translations are available at . 125 | 126 | [homepage]: https://www.contributor-covenant.org 127 | -------------------------------------------------------------------------------- /R/poisson_reg-data.R: -------------------------------------------------------------------------------- 1 | # These functions are tested indirectly when the models are used. Since this 2 | # function is executed on package startup, you can't execute them to test since 3 | # they are already in the parsnip model database. We'll exclude them from 4 | # coverage stats for this reason. 5 | 6 | # nocov start 7 | make_poisson_reg_glm <- function() { 8 | parsnip::set_model_engine("poisson_reg", mode = "regression", eng = "glm") 9 | parsnip::set_dependency( 10 | "poisson_reg", 11 | eng = "glm", 12 | pkg = "stats", 13 | mode = "regression" 14 | ) 15 | parsnip::set_dependency( 16 | "poisson_reg", 17 | eng = "glm", 18 | pkg = "poissonreg", 19 | mode = "regression" 20 | ) 21 | 22 | parsnip::set_fit( 23 | model = "poisson_reg", 24 | eng = "glm", 25 | mode = "regression", 26 | value = list( 27 | interface = "formula", 28 | protect = c("formula", "data", "weights"), 29 | func = c(pkg = "stats", fun = "glm"), 30 | defaults = list(family = expr(stats::poisson)) 31 | ) 32 | ) 33 | 34 | parsnip::set_encoding( 35 | model = "poisson_reg", 36 | eng = "glm", 37 | mode = "regression", 38 | options = list( 39 | predictor_indicators = "traditional", 40 | compute_intercept = TRUE, 41 | remove_intercept = TRUE, 42 | allow_sparse_x = FALSE 43 | ) 44 | ) 45 | 46 | parsnip::set_pred( 47 | model = "poisson_reg", 48 | eng = "glm", 49 | mode = "regression", 50 | type = "numeric", 51 | value = list( 52 | pre = NULL, 53 | post = NULL, 54 | func = c(fun = "predict"), 55 | args = list( 56 | object = expr(object$fit), 57 | newdata = expr(new_data), 58 | type = "response" 59 | ) 60 | ) 61 | ) 62 | 63 | parsnip::set_pred( 64 | model = "poisson_reg", 65 | eng = "glm", 66 | mode = "regression", 67 | type = "raw", 68 | value = list( 69 | pre = NULL, 70 | post = NULL, 71 | func = c(fun = "predict"), 72 | args = list(object = expr(object$fit), newdata = expr(new_data)) 73 | ) 74 | ) 75 | } 76 | 77 | make_poisson_reg_hurdle <- function() { 78 | parsnip::set_model_engine("poisson_reg", "regression", "hurdle") 79 | parsnip::set_dependency( 80 | "poisson_reg", 81 | eng = "hurdle", 82 | pkg = "pscl", 83 | mode = "regression" 84 | ) 85 | parsnip::set_dependency( 86 | "poisson_reg", 87 | eng = "hurdle", 88 | pkg = "poissonreg", 89 | mode = "regression" 90 | ) 91 | 92 | parsnip::set_fit( 93 | model = "poisson_reg", 94 | eng = "hurdle", 95 | mode = "regression", 96 | value = list( 97 | interface = "formula", 98 | protect = c("formula", "data", "weights"), 99 | func = c(pkg = "pscl", fun = "hurdle"), 100 | defaults = list() 101 | ) 102 | ) 103 | 104 | parsnip::set_encoding( 105 | model = "poisson_reg", 106 | eng = "hurdle", 107 | mode = "regression", 108 | options = list( 109 | predictor_indicators = "none", 110 | compute_intercept = FALSE, 111 | remove_intercept = FALSE, 112 | allow_sparse_x = FALSE 113 | ) 114 | ) 115 | 116 | parsnip::set_pred( 117 | model = "poisson_reg", 118 | eng = "hurdle", 119 | mode = "regression", 120 | type = "numeric", 121 | value = list( 122 | pre = NULL, 123 | post = NULL, 124 | func = c(fun = "predict"), 125 | args = list( 126 | object = expr(object$fit), 127 | newdata = expr(new_data) 128 | ) 129 | ) 130 | ) 131 | 132 | parsnip::set_pred( 133 | model = "poisson_reg", 134 | eng = "hurdle", 135 | mode = "regression", 136 | type = "raw", 137 | value = list( 138 | pre = NULL, 139 | post = NULL, 140 | func = c(fun = "predict"), 141 | args = list(object = expr(object$fit), newdata = expr(new_data)) 142 | ) 143 | ) 144 | } 145 | 146 | make_poisson_reg_zeroinfl <- function() { 147 | parsnip::set_model_engine("poisson_reg", "regression", "zeroinfl") 148 | parsnip::set_dependency( 149 | "poisson_reg", 150 | eng = "zeroinfl", 151 | pkg = "pscl", 152 | mode = "regression" 153 | ) 154 | parsnip::set_dependency( 155 | "poisson_reg", 156 | eng = "zeroinfl", 157 | pkg = "poissonreg", 158 | mode = "regression" 159 | ) 160 | 161 | parsnip::set_fit( 162 | model = "poisson_reg", 163 | eng = "zeroinfl", 164 | mode = "regression", 165 | value = list( 166 | interface = "formula", 167 | protect = c("formula", "data", "weights"), 168 | func = c(pkg = "pscl", fun = "zeroinfl"), 169 | defaults = list() 170 | ) 171 | ) 172 | 173 | parsnip::set_encoding( 174 | model = "poisson_reg", 175 | eng = "zeroinfl", 176 | mode = "regression", 177 | options = list( 178 | predictor_indicators = "none", 179 | compute_intercept = FALSE, 180 | remove_intercept = FALSE, 181 | allow_sparse_x = FALSE 182 | ) 183 | ) 184 | 185 | parsnip::set_pred( 186 | model = "poisson_reg", 187 | eng = "zeroinfl", 188 | mode = "regression", 189 | type = "numeric", 190 | value = list( 191 | pre = NULL, 192 | post = NULL, 193 | func = c(fun = "predict"), 194 | args = list( 195 | object = expr(object$fit), 196 | newdata = expr(new_data) 197 | ) 198 | ) 199 | ) 200 | 201 | parsnip::set_pred( 202 | model = "poisson_reg", 203 | eng = "zeroinfl", 204 | mode = "regression", 205 | type = "raw", 206 | value = list( 207 | pre = NULL, 208 | post = NULL, 209 | func = c(fun = "predict"), 210 | args = list(object = expr(object$fit), newdata = expr(new_data)) 211 | ) 212 | ) 213 | } 214 | 215 | make_poisson_reg_glmnet <- function() { 216 | parsnip::set_model_engine("poisson_reg", "regression", "glmnet") 217 | parsnip::set_dependency( 218 | "poisson_reg", 219 | eng = "glmnet", 220 | pkg = "glmnet", 221 | mode = "regression" 222 | ) 223 | parsnip::set_dependency( 224 | "poisson_reg", 225 | eng = "glmnet", 226 | pkg = "poissonreg", 227 | mode = "regression" 228 | ) 229 | 230 | parsnip::set_model_arg( 231 | model = "poisson_reg", 232 | eng = "glmnet", 233 | parsnip = "penalty", 234 | original = "lambda", 235 | func = list(pkg = "dials", fun = "penalty"), 236 | has_submodel = TRUE 237 | ) 238 | 239 | parsnip::set_model_arg( 240 | model = "poisson_reg", 241 | eng = "glmnet", 242 | parsnip = "mixture", 243 | original = "alpha", 244 | func = list(pkg = "dials", fun = "mixture"), 245 | has_submodel = FALSE 246 | ) 247 | 248 | parsnip::set_fit( 249 | model = "poisson_reg", 250 | eng = "glmnet", 251 | mode = "regression", 252 | value = list( 253 | interface = "matrix", 254 | protect = c("x", "y", "weights"), 255 | func = c(pkg = "glmnet", fun = "glmnet"), 256 | defaults = list(family = "poisson") 257 | ) 258 | ) 259 | 260 | parsnip::set_encoding( 261 | model = "poisson_reg", 262 | eng = "glmnet", 263 | mode = "regression", 264 | options = list( 265 | predictor_indicators = "traditional", 266 | compute_intercept = TRUE, 267 | remove_intercept = TRUE, 268 | allow_sparse_x = TRUE 269 | ) 270 | ) 271 | 272 | parsnip::set_pred( 273 | model = "poisson_reg", 274 | eng = "glmnet", 275 | mode = "regression", 276 | type = "numeric", 277 | value = list( 278 | pre = NULL, 279 | post = parsnip::.organize_glmnet_pred, 280 | func = c(fun = "predict"), 281 | args = list( 282 | object = expr(object$fit), 283 | newx = expr(as.matrix(new_data[, 284 | rownames(object$fit$beta), 285 | drop = FALSE 286 | ])), 287 | type = "response", 288 | s = expr(object$spec$args$penalty) 289 | ) 290 | ) 291 | ) 292 | 293 | parsnip::set_pred( 294 | model = "poisson_reg", 295 | eng = "glmnet", 296 | mode = "regression", 297 | type = "raw", 298 | value = list( 299 | pre = NULL, 300 | post = NULL, 301 | func = c(fun = "predict"), 302 | args = list( 303 | object = expr(object$fit), 304 | newx = expr(as.matrix(new_data[, 305 | rownames(object$fit$beta), 306 | drop = FALSE 307 | ])) 308 | ) 309 | ) 310 | ) 311 | } 312 | 313 | make_poisson_reg_stan <- function() { 314 | parsnip::set_model_engine("poisson_reg", "regression", "stan") 315 | parsnip::set_dependency( 316 | "poisson_reg", 317 | eng = "stan", 318 | pkg = "rstanarm", 319 | mode = "regression" 320 | ) 321 | parsnip::set_dependency( 322 | "poisson_reg", 323 | eng = "stan", 324 | pkg = "poissonreg", 325 | mode = "regression" 326 | ) 327 | 328 | parsnip::set_fit( 329 | model = "poisson_reg", 330 | eng = "stan", 331 | mode = "regression", 332 | value = list( 333 | interface = "formula", 334 | protect = c("formula", "data", "weights"), 335 | func = c(pkg = "rstanarm", fun = "stan_glm"), 336 | defaults = list(family = expr(stats::poisson)) 337 | ) 338 | ) 339 | 340 | parsnip::set_encoding( 341 | model = "poisson_reg", 342 | eng = "stan", 343 | mode = "regression", 344 | options = list( 345 | predictor_indicators = "none", 346 | compute_intercept = FALSE, 347 | remove_intercept = FALSE, 348 | allow_sparse_x = FALSE 349 | ) 350 | ) 351 | 352 | parsnip::set_pred( 353 | model = "poisson_reg", 354 | eng = "stan", 355 | mode = "regression", 356 | type = "numeric", 357 | value = list( 358 | pre = NULL, 359 | post = NULL, 360 | func = c(fun = "predict"), 361 | args = list(object = expr(object$fit), newdata = expr(new_data)) 362 | ) 363 | ) 364 | 365 | parsnip::set_pred( 366 | model = "poisson_reg", 367 | eng = "stan", 368 | mode = "regression", 369 | type = "conf_int", 370 | value = list( 371 | pre = NULL, 372 | post = function(results, object) { 373 | organize_stan_interval(results, object, interval_type = "conf") 374 | }, 375 | func = c(pkg = "rstanarm", fun = "posterior_epred"), 376 | args = list( 377 | object = expr(object$fit), 378 | newdata = expr(new_data), 379 | seed = expr(sample.int(10^5, 1)) 380 | ) 381 | ) 382 | ) 383 | 384 | parsnip::set_pred( 385 | model = "poisson_reg", 386 | eng = "stan", 387 | mode = "regression", 388 | type = "pred_int", 389 | value = list( 390 | pre = NULL, 391 | post = function(results, object) { 392 | organize_stan_interval(results, object, interval_type = "pred") 393 | }, 394 | func = c(pkg = "rstanarm", fun = "posterior_predict"), 395 | args = list( 396 | object = expr(object$fit), 397 | newdata = expr(new_data), 398 | seed = expr(sample.int(10^5, 1)) 399 | ) 400 | ) 401 | ) 402 | 403 | parsnip::set_pred( 404 | model = "poisson_reg", 405 | eng = "stan", 406 | mode = "regression", 407 | type = "raw", 408 | value = list( 409 | pre = NULL, 410 | post = NULL, 411 | func = c(fun = "predict"), 412 | args = list(object = expr(object$fit), newdata = expr(new_data)) 413 | ) 414 | ) 415 | } 416 | 417 | # nocov end 418 | --------------------------------------------------------------------------------