I am using Phylogenetic Least Squares models, fitted with the phylolm package, to understand the effect of continuous and categorical variables. I used the MuMIn package to gel model-averaged coefficients, and my response was log-transformed.

How do I visualize slopes for multiple factor levels, with confidence bands, using model-averaged coefficients? My aim is a plot that combines the raw data, and the slopes for each factor level (in other words, to visualize two effects in a single plot).

I would normally rely on predict(se.fit = TRUE) or the ggpredict package, but unfortunately, these methods are not compatible with model-averaged phylolm objects.

Therefore, I am thinking on relying on model-averaged coefficients, standard errors / confidence intervals. In particular, my model has 3 levels, and a common slope (the reprex below has significant differences among factor levels, but it serves to illustrate my doubts).

From previous SO questions (here, here), I've got an idea about how to plot slopes when there is a transformation: inverse.function(intercept + slope * variable).

However, I am stumped when it comes to visualizing the uncertainty around the slopes for multiple factor levels. For instance, if using the method of +/- 1.96 * Standard error, how should I take into account the uncertainty around the factor level and the slope? In the reprex below I only used the standard error of the intercept and each factor level. A similar doubt would apply if relying on confidence intervals.

Note that in the reprex below, phylolm is loaded before MuMIn, this is needed for compatibility of logLik method (https://github.com/lamho86/phylolm/issues/65).

library(caper)
#> Warning: package 'caper' was built under R version 4.1.3
#> Loading required package: ape
#> Warning: package 'ape' was built under R version 4.1.3
#> Loading required package: MASS
#> Loading required package: mvtnorm
#> Warning: package 'mvtnorm' was built under R version 4.1.1
library(phylolm)
#> Warning: package 'phylolm' was built under R version 4.1.3
library(MuMIn)
#> Warning: package 'MuMIn' was built under R version 4.1.3
#> Registered S3 methods overwritten by 'MuMIn':
#>   method         from   
#>   nobs.pgls      caper  
#>   nobs.phylolm   phylolm
#>   logLik.phylolm phylolm
library(tidyverse)
#> Warning: package 'tidyverse' was built under R version 4.1.3
#> Warning: package 'ggplot2' was built under R version 4.1.3
#> Warning: package 'tibble' was built under R version 4.1.3
#> Warning: package 'tidyr' was built under R version 4.1.3
#> Warning: package 'readr' was built under R version 4.1.3
#> Warning: package 'purrr' was built under R version 4.1.3
#> Warning: package 'dplyr' was built under R version 4.1.3
#> Warning: package 'stringr' was built under R version 4.1.3
#> Warning: package 'forcats' was built under R version 4.1.3

## Create data
data(shorebird)
shorebird.data$M.Mass.std <- (shorebird.data$M.Mass - mean(shorebird.data$M.Mass))/sd(shorebird.data$M.Mass)
str(shorebird.data)
#> 'data.frame':    71 obs. of  7 variables:
#>  $ Species   : chr  "Actophilornis_africanus" "Aphriza_virgata" "Arenaria_interpres" "Arenaria_melanocephala" ...
#>  $ M.Mass    : num  143 186 108 114 151 ...
#>  $ F.Mass    : num  261 216 113 124 164 ...
#>  $ Egg.Mass  : num  8.6 22.4 17.9 17.3 23.5 11.2 10.7 9.6 19.3 13.3 ...
#>  $ Cl.size   : num  4 4 3.5 4 3.99 3.9 3.9 4 3.7 3.9 ...
#>  $ Mat.syst  : Factor w/ 3 levels "MO","PA","PG": 2 1 1 1 1 2 1 1 1 1 ...
#>  $ M.Mass.std: num  -0.1658 0.0666 -0.3557 -0.3255 -0.1238 ...
str(shorebird.tree)
#> List of 4
#>  $ edge       : num [1:132, 1:2] 72 73 74 75 76 77 78 79 79 80 ...
#>  $ edge.length: num [1:132] 18.1 13.4 13.4 2.6 2.3 ...
#>  $ tip.label  : chr [1:71] "Catoptrophorus_semipalmatus" "Tringa_ochropus" "Tringa_stagnatilis" "Tringa_flavipes" ...
#>  $ Nnode      : num 62
#>  - attr(*, "class")= chr "phylo"
#>  - attr(*, "origin")= chr "/Users/dorme/Scripts/CAIC/caic/pkg/data/shorebird.nex"

## Fit model
mod <- phylolm::phylolm(log(Egg.Mass) ~ M.Mass.std + Mat.syst, data = shorebird.data, phy = shorebird.tree, model = "lambda")


## Model average
options(na.action = "na.fail")
mod.d <- MuMIn::dredge(mod, rank = "AICc")
#> Fixed term is "(Intercept)"
mod.avg <- MuMIn::model.avg(mod.d, revised.var = TRUE, fit = TRUE)

# Coefficients and model-averaged confidence intervalss
summary(mod.avg)$coefmat.full
#>               Estimate Std. Error   z value   Pr(>|z|)
#> (Intercept)  2.9477111 0.24188761 12.186284 0.00000000
#> M.Mass.std   0.4704710 0.05739476  8.197107 0.00000000
#> Mat.systPA  -0.2154969 0.09765281  2.206766 0.02733044
#> Mat.systPG   0.2837279 0.17353949  1.634947 0.10206008

# Keep coefficients
intercept <- summary(mod.avg)$coefmat.full[1, 1]
slope <- summary(mod.avg)$coefmat.full[2, 1]
level.pa <- summary(mod.avg)$coefmat.full[3, 1]
level.pg <- summary(mod.avg)$coefmat.full[4, 1]

# Keep standard errors
intercept.std <- summary(mod.avg)$coefmat.full[1, 2]
slope.std <- summary(mod.avg)$coefmat.full[2, 2]
level.pa.std <- summary(mod.avg)$coefmat.full[3, 2]
level.pg.std <- summary(mod.avg)$coefmat.full[4, 2]


# Slopes at the response scale, from model-averaged coefficients
seq.x <- seq(min(shorebird.data$M.Mass.std), max(shorebird.data$M.Mass.std), by = 0.05)
slope.mo <- exp(intercept + slope * seq.x)
slope.pa <- exp(intercept + level.pa + slope * seq.x)
slope.pg <- exp(intercept + level.pg + slope * seq.x)

# Uncertainty around slope, from model-averaged standard errors
uncert.mo.low <- exp(intercept + slope * seq.x - 1.96 * intercept.std)
uncert.mo.up <- exp(intercept + slope * seq.x + 1.96 * intercept.std)
uncert.pa.low <- exp(intercept + level.pa + slope * seq.x - 1.96 * level.pa.std)
uncert.pa.up <- exp(intercept + level.pa + slope * seq.x + 1.96 * level.pa.std)
uncert.pg.low <- exp(intercept + level.pg + slope * seq.x - 1.96 * level.pg.std)
uncert.pg.up <- exp(intercept + level.pg + slope * seq.x + 1.96 * level.pg.std)


ggplot() + 
  geom_jitter(data = shorebird.data, aes(x = M.Mass.std, y = Egg.Mass, col = Mat.syst)) +
  geom_line(aes(x = seq.x, y = slope.mo), col = "red") +
  geom_ribbon(aes(x = seq.x, y = slope.mo, ymin = uncert.mo.low, ymax = uncert.mo.up), fill = "red", alpha = 0.5) +
  geom_line(aes(x = seq.x, y = slope.pa), col = "green") +
  geom_ribbon(aes(x = seq.x, y = slope.pa, ymin = uncert.pa.low, ymax = uncert.pa.up), fill = "green", alpha = 0.5) +
  geom_line(aes(x = seq.x, y = slope.pg), col = "blue") +
  geom_ribbon(aes(x = seq.x, y = slope.pg, ymin = uncert.pg.low, ymax = uncert.pg.up), fill = "blue", alpha = 0.5) +
  theme_bw()

confint(mod.avg, full = TRUE)
#>                   2.5 %      97.5 %
#> (Intercept)  2.47362007  3.42180208
#> M.Mass.std   0.35797932  0.58296266
#> Mat.systPA  -0.40689283 -0.02410087
#> Mat.systPG  -0.05640321  0.62385908
  

sessionInfo()
#> R version 4.1.0 (2021-05-18)
#> Platform: x86_64-w64-mingw32/x64 (64-bit)
#> Running under: Windows 10 x64 (build 19045)
#> 
#> Matrix products: default
#> 
#> locale:
#> [1] LC_COLLATE=Spanish_Spain.1252  LC_CTYPE=Spanish_Spain.1252   
#> [3] LC_MONETARY=Spanish_Spain.1252 LC_NUMERIC=C                  
#> [5] LC_TIME=Spanish_Spain.1252    
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#>  [1] forcats_0.5.1   stringr_1.5.0   dplyr_1.1.1     purrr_1.0.1    
#>  [5] readr_2.1.2     tidyr_1.3.0     tibble_3.2.1    ggplot2_3.4.2  
#>  [9] tidyverse_1.3.1 MuMIn_1.46.0    phylolm_2.6.2   caper_1.0.1    
#> [13] mvtnorm_1.1-3   MASS_7.3-54     ape_5.6-2      
#> 
#> loaded via a namespace (and not attached):
#>  [1] Rcpp_1.0.8.3       lubridate_1.8.0    lattice_0.20-44    listenv_0.8.0     
#>  [5] assertthat_0.2.1   digest_0.6.29      utf8_1.2.2         parallelly_1.31.1 
#>  [9] cellranger_1.1.0   R6_2.5.1           backports_1.4.1    reprex_2.0.1      
#> [13] stats4_4.1.0       evaluate_0.15      httr_1.4.2         highr_0.9         
#> [17] pillar_1.9.0       rlang_1.1.0        readxl_1.4.0       rstudioapi_0.13   
#> [21] Matrix_1.3-3       rmarkdown_2.13     labeling_0.4.2     munsell_0.5.0     
#> [25] broom_0.8.0        modelr_0.1.8       compiler_4.1.0     xfun_0.30         
#> [29] pkgconfig_2.0.3    globals_0.15.0     htmltools_0.5.2    tidyselect_1.2.0  
#> [33] codetools_0.2-18   fansi_1.0.3        future_1.25.0      crayon_1.5.1      
#> [37] tzdb_0.3.0         dbplyr_2.1.1       withr_2.5.0        grid_4.1.0        
#> [41] jsonlite_1.8.0     nlme_3.1-152       gtable_0.3.0       lifecycle_1.0.3   
#> [45] DBI_1.1.2          magrittr_2.0.3     scales_1.2.0       future.apply_1.9.0
#> [49] cli_3.6.0          stringi_1.7.6      farver_2.1.0       fs_1.5.2          
#> [53] xml2_1.3.3         ellipsis_0.3.2     generics_0.1.2     vctrs_0.6.1       
#> [57] tools_4.1.0        glue_1.6.2         hms_1.1.1          parallel_4.1.0    
#> [61] fastmap_1.1.0      yaml_2.3.5         colorspace_2.0-3   rvest_1.0.2       
#> [65] knitr_1.38         haven_2.5.0

Created on 2023-11-06 by the reprex package (v2.0.1)

0

There are 0 answers