easystats/parameters

`print(include_reference = TRUE)` doesn't work with pipes

snhansen opened this issue · 1 comments

The following example shows that the include_reference = TRUE option of print() doesn't work with pipes.

library(parameters)
lm(Sepal.Length ~ Petal.Length + Species, data = iris) |> parameters() |> print(include_reference = TRUE)

# Parameter            | Coefficient |   SE |         95% CI | t(146) |      p
# ----------------------------------------------------------------------------
# (Intercept)          |        3.68 | 0.11 | [ 3.47,  3.89] |  34.72 | < .001
# Petal Length         |        0.90 | 0.06 | [ 0.78,  1.03] |  13.96 | < .001
# Species [versicolor] |       -1.60 | 0.19 | [-1.98, -1.22] |  -8.28 | < .001
# Species [virginica]  |       -2.12 | 0.27 | [-2.66, -1.58] |  -7.74 | < .001

model_name <- lm(Sepal.Length ~ Petal.Length + Species, data = iris)
model_name |> parameters() |> print(include_reference = TRUE)

# Parameter            | Coefficient |   SE |         95% CI | t(146) |      p
# ----------------------------------------------------------------------------
# (Intercept)          |        3.68 | 0.11 | [ 3.47,  3.89] |  34.72 | < .001
# Petal Length         |        0.90 | 0.06 | [ 0.78,  1.03] |  13.96 | < .001
# Species [setosa]     |        0.00 |      |                |        |       
# Species [versicolor] |       -1.60 | 0.19 | [-1.98, -1.22] |  -8.28 | < .001
# Species [virginica]  |       -2.12 | 0.27 | [-2.66, -1.58] |  -7.74 | < .001

I believe the issue stems from the first lines of the .add_reference_level() function. Here we have

.add_reference_level <- function(params) {
  # check if we have a model object, else return parameter table
  model <- .get_object(params)
  if (is.null(model)) {
    params
  }
...
}

and if we look at .get_object() we can see that NULL is returned if the model object doesn't have an object_name attribute which it won't have if it's part of a pipe.

.get_object <- function(x, attribute_name = "object_name") {
  obj_name <- attr(x, attribute_name, exact = TRUE)
  model <- NULL
  if (!is.null(obj_name)) {
    model <- .safe(get(obj_name, envir = parent.frame()))
    # prevent self reference
    if (is.null(model) || inherits(model, "parameters_model")) {
      model <- .safe(get(obj_name, envir = globalenv()))
    }
  }
  model
}

Thanks, should be fixed in #924:

library(parameters)
lm(Sepal.Length ~ Petal.Length + Species, data = iris) |>
  parameters() |>
  print(include_reference = TRUE)
#> Parameter            | Coefficient |   SE |         95% CI | t(146) |      p
#> ----------------------------------------------------------------------------
#> (Intercept)          |        3.68 | 0.11 | [ 3.47,  3.89] |  34.72 | < .001
#> Petal Length         |        0.90 | 0.06 | [ 0.78,  1.03] |  13.96 | < .001
#> Species [setosa]     |        0.00 |      |                |        |       
#> Species [versicolor] |       -1.60 | 0.19 | [-1.98, -1.22] |  -8.28 | < .001
#> Species [virginica]  |       -2.12 | 0.27 | [-2.66, -1.58] |  -7.74 | < .001
#> 
#> Uncertainty intervals (equal-tailed) and p-values (two-tailed) computed
#>   using a Wald t-distribution approximation.

Created on 2023-12-01 with reprex v2.0.2

I guess pipe-workflow will also fail in other situations, maybe we can in general improve stability when we rely on the call if no object name is available.