Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# tidypredict (development version)

- Fixed `cforest()` models failing with "'language' object cannot be coerced to type 'symbol'" under partykit 1.3-0. That release added a shim to partykit's methods that identifies the caller with `as.name()`, which errors when the generic is reached as `partykit::gettree()`. (#434)

- The error raised when no method knows how to handle a model at all now carries the condition class `tidypredict_unsupported_model`. Many other errors also say "are not supported", but they report an unsupported *configuration* of a model that is otherwise handled, so the wording alone could not distinguish the two. Packages that wrap `tidypredict_fit()`, such as orbital, need that distinction to decide whether to fall back or to report the model as unsupported. (#432)

- New articles for `kernlab::ksvm()`, `mboost::blackboost()` and `xrf::xrf()`, and the model list menu now links to the `LiblineaR` and `quantreg` sections directly. (#317)
Expand Down
24 changes: 22 additions & 2 deletions R/model-cforest.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@
# weighted terminal-node mean, so it can be expressed as the mean of the
# individual party-tree expressions.

# partykit 1.3-0 added a shim to its methods that warns when a method is called
# directly instead of through the generic. It identifies the caller with
# `as.name(as.list(sys.call(-1))[[1L]])`, which errors on a call whose first
# element is not a symbol. The generic's own frame is the method's caller, so
# writing `partykit::gettree(...)` makes that first element the `::` call and
# every `gettree()` on a cforest model fails with "'language' object cannot be
# coerced to type 'symbol'".
#
# Binding the generic to a local name calls it through a symbol instead. The
# name has to be `gettree`, because the shim then compares that symbol against
# the generic's own name and stays quiet only if they match.
#
# Only `gettree` is affected. The other partykit functions used here
# (`nodeids`, `nodeapply`, `as.party`, `id_node`, `is.terminal`, `kids_node`)
# were checked and are fine with the `::` prefix.
cforest_gettree <- function(model, tree_no) {
gettree <- partykit::gettree
gettree(model, tree_no)
}

cforest_check_regression <- function(model) {
response_col <- model$fitted[["(response)"]]
if (!is.numeric(response_col)) {
Expand All @@ -24,7 +44,7 @@ parse_model.cforest <- function(model) {
n_trees <- length(model$nodes)
pm$tree_info_list <- map(
seq_len(n_trees),
function(tree_no) partykit_tree_info_full(partykit::gettree(model, tree_no))
function(tree_no) partykit_tree_info_full(cforest_gettree(model, tree_no))
)
as_parsed_model(pm)
}
Expand All @@ -39,7 +59,7 @@ tidypredict_fit.cforest <- function(model, ...) {
tree_exprs <- map(
seq_len(n_trees),
function(tree_no) {
tree_info <- partykit_tree_info_full(partykit::gettree(model, tree_no))
tree_info <- partykit_tree_info_full(cforest_gettree(model, tree_no))
generate_nested_case_when_tree(tree_info, missing = "na")
}
)
Expand Down
17 changes: 17 additions & 0 deletions tests/testthat/test-model-cforest.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ test_that("cforest regression predictions match", {
expect_false(tidypredict_test(model, df = mtcars)$alert)
})

test_that("gettree() is reached without tripping partykit's method shim", {
skip_if_not_installed("partykit")

set.seed(1)
model <- partykit::cforest(mpg ~ wt + cyl, data = mtcars, ntree = 2)

# partykit 1.3-0's shim errors if the generic is called as
# `partykit::gettree()`, and warns if it is reached under any name other than
# `gettree`. Assert both: no condition of either kind.
expect_no_error(cforest_gettree(model, 1))
expect_no_warning(cforest_gettree(model, 1))
expect_s3_class(cforest_gettree(model, 1), "party")

expect_no_warning(tidypredict_fit(model))
expect_no_warning(parse_model(model))
})

test_that("terminal nodes use in-bag weighted means, not unweighted means", {
skip_if_not_installed("partykit")

Expand Down
Loading