Skip to content

estimate_contrasts() doesn't follow contrast (i.e., categorical) coding scheme #580

@rbcavanaugh

Description

@rbcavanaugh

It looks like estimate contrasts doesn't change the direction of the contrast when the categorical contrast coding scheme is only changed using something like contrasts(data$cat) <- c(1, 0); it requires the levels of the factor to be change explicitly. I'm not sure this is intended behavior.

library(tidyverse)
library(medicaldata)
library(easystats)
#> # Attaching packages: easystats 0.7.5 (red = needs update)
#> ✔ bayestestR  0.17.0   ✔ correlation 0.8.8 
#> ✖ datawizard  1.2.0    ✔ effectsize  1.0.1 
#> ✔ insight     1.4.2    ✔ modelbased  0.13.0
#> ✖ performance 0.15.1   ✔ parameters  0.28.2
#> ✔ report      0.6.1    ✔ see         0.12.0
#> 
#> Restart the R-Session and update packages with `easystats::easystats_update()`.
strep_data <- strep_tb

# default coding
contrasts(strep_data$arm)
#>              Control
#> Streptomycin       0
#> Control            1
m0 <- glm(improved ~ arm + baseline_condition, data = strep_data, family = "binomial") # model
model_parameters(m0) # results
#> Parameter                   | Log-Odds |      SE |           95% CI |     z |      p
#> ------------------------------------------------------------------------------------
#> (Intercept)                 |    20.40 | 1416.66 | [ -69.19,      ] |  0.01 | 0.989 
#> arm [Control]               |    -2.74 |    0.67 | [  -4.26, -1.56] | -4.09 | < .001
#> baseline condition [2_Fair] |   -18.14 | 1416.66 | [-375.70, 55.51] | -0.01 | 0.990 
#> baseline condition [3_Poor] |   -20.45 | 1416.66 | [       , 68.83] | -0.01 | 0.988
#> 
#> Uncertainty intervals (profile-likelihood) and p-values (two-tailed)
#>   computed using a Wald z-distribution approximation.
#> 
#> The model has a log- or logit-link. Consider using `exponentiate =
#>   TRUE` to interpret coefficients as ratios.
#>   
#> Some coefficients are very large, which may indicate issues with
#>   complete separation.
estimate_contrasts(m0, contrast = "arm") 
#> Marginal Contrasts Analysis
#> 
#> Level1  | Level2       | Difference |   SE |         95% CI |     z |      p
#> ----------------------------------------------------------------------------
#> Control | Streptomycin |      -0.32 | 0.05 | [-0.42, -0.21] | -5.83 | < .001
#> 
#> Variable predicted: improved
#> Predictors contrasted: arm
#> Predictors averaged: baseline_condition
#> p-values are uncorrected.
#> Contrasts are on the response-scale.

# set control as reference using contrasts
contrasts(strep_data$arm) <- c(1, 0)
contrasts(strep_data$arm)
#>              [,1]
#> Streptomycin    1
#> Control         0
m1 <- glm(improved ~ arm + baseline_condition, data = strep_data, family = "binomial") # model
model_parameters(m1) # results
#> Parameter                   | Log-Odds |      SE |          95% CI |     z |      p
#> -----------------------------------------------------------------------------------
#> (Intercept)                 |    17.65 | 1416.66 | [-58.87,      ] |  0.01 | 0.990 
#> arm [1]                     |     2.74 |    0.67 | [  1.56,  4.26] |  4.09 | < .001
#> baseline condition [2_Fair] |   -18.14 | 1416.66 | [      , 65.04] | -0.01 | 0.990 
#> baseline condition [3_Poor] |   -20.45 | 1416.66 | [      , 68.83] | -0.01 | 0.988
#> 
#> Uncertainty intervals (profile-likelihood) and p-values (two-tailed)
#>   computed using a Wald z-distribution approximation.
estimate_contrasts(m1, contrast = "arm") 
#> Marginal Contrasts Analysis
#> 
#> Level1  | Level2       | Difference |   SE |         95% CI |     z |      p
#> ----------------------------------------------------------------------------
#> Control | Streptomycin |      -0.32 | 0.05 | [-0.42, -0.21] | -5.83 | < .001
#> 
#> Variable predicted: improved
#> Predictors contrasted: arm
#> Predictors averaged: baseline_condition
#> p-values are uncorrected.
#> Contrasts are on the response-scale.

# set contral as reference using factor levels
strep_data$arm <- factor(strep_data$arm, levels = c("Control", "Streptomycin"))
contrasts(strep_data$arm)
#>              Streptomycin
#> Control                 0
#> Streptomycin            1
m2 <- glm(improved ~ arm + baseline_condition, data = strep_data, family = "binomial") # model
model_parameters(m2) # results
#> Parameter                   | Log-Odds |      SE |          95% CI |     z |      p
#> -----------------------------------------------------------------------------------
#> (Intercept)                 |    17.65 | 1416.66 | [-58.87,      ] |  0.01 | 0.990 
#> arm [Streptomycin]          |     2.74 |    0.67 | [  1.56,  4.26] |  4.09 | < .001
#> baseline condition [2_Fair] |   -18.14 | 1416.66 | [      , 65.04] | -0.01 | 0.990 
#> baseline condition [3_Poor] |   -20.45 | 1416.66 | [      , 68.83] | -0.01 | 0.988
#> 
#> Uncertainty intervals (profile-likelihood) and p-values (two-tailed)
#>   computed using a Wald z-distribution approximation.
estimate_contrasts(m2, contrast = "arm") 
#> Marginal Contrasts Analysis
#> 
#> Level1       | Level2  | Difference |   SE |       95% CI |    z |      p
#> -------------------------------------------------------------------------
#> Streptomycin | Control |       0.32 | 0.05 | [0.21, 0.42] | 5.83 | < .001
#> 
#> Variable predicted: improved
#> Predictors contrasted: arm
#> Predictors averaged: baseline_condition
#> p-values are uncorrected.
#> Contrasts are on the response-scale.

Created on 2025-10-23 with reprex v2.1.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions