Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert the output of cond_indirect_effects() to a data frame #109

Open
sfcheung opened this issue Jul 29, 2023 · 0 comments
Open

Convert the output of cond_indirect_effects() to a data frame #109

sfcheung opened this issue Jul 29, 2023 · 0 comments
Labels
enhancement New feature or request

Comments

@sfcheung
Copy link
Owner

Users may want to get the output of cond_indirect_effects() as a data frame such that it can be used by other functions.

# Adapted from https://sfcheung.github.io/manymome/articles/mome_lm.html

library(manymome)
dat <- data_med_mod_a
lm_m <- lm(m ~ x*w + c1 + c2, dat)
lm_y <- lm(y ~ m + x + c1 + c2, dat)
fit_lm <- lm2list(lm_m, lm_y)
boot_out_lm <- do_boot(fit_lm,
                       R = 5000,
                       seed = 54532,
                       ncores = 4)
#> 4 processes started to run bootstrapping.
out_xmy_on_w <- cond_indirect_effects(wlevels = "w",
                                      x = "x",
                                      y = "y",
                                      m = "m",
                                      fit = fit_lm,
                                      boot_ci = TRUE,
                                      boot_out = boot_out_lm)
out_xmy_on_w
#> 
#> == Conditional indirect effects ==
#> 
#>  Path: x -> m -> y
#>  Conditional on moderator(s): w
#>  Moderator(s) represented by: w
#> 
#>       [w]   (w)   ind  CI.lo CI.hi Sig   m~x   y~m
#> 1 M+1.0SD 3.164 3.060  1.914 3.979 Sig 3.192 0.959
#> 2 Mean    2.179 2.136  1.282 2.966 Sig 2.228 0.959
#> 3 M-1.0SD 1.194 1.212 -0.102 2.476     1.265 0.959
#> 
#>  - [CI.lo to CI.hi] are 95.0% percentile confidence intervals by
#>    nonparametric bootstrapping with 5000 samples.
#>  - The 'ind' column shows the indirect effects.
#>  - 'm~x','y~m' is/are the path coefficient(s) along the path conditional
#>    on the moderators.

For now, the output of cond_indirect_effects() has methods such as coef() and confint(), such that other packages that make use of these methods can be used. E.g.,

confint(out_xmy_on_w)
#>                2.5 %   97.5 %
#>w: M+1.0SD  1.9144062 3.978543
#>w: Mean     1.2816511 2.965547
#>w: M-1.0SD -0.1016396 2.475522
coef(out_xmy_on_w)   
#>w: M+1.0SD    w: Mean w: M-1.0SD 
#>  3.060021   2.136191   1.212360

However, there are cases in which users would like to have a data frame. If only the default results are needed (no standard errors, no p-values), then as.data.frame() will work. E.g.,

tmp <- as.data.frame(out_xmy_on_w)
tmp
#>       [w]      (w)      ind      CI.lo    CI.hi      m~x       y~m
#> 1 M+1.0SD 3.164128 3.060021  1.9144062 3.978543 3.191953 0.9586673
#> 2    Mean 2.179279 2.136191  1.2816511 2.965547 2.228292 0.9586673
#> 3 M-1.0SD 1.194429 1.212360 -0.1016396 2.475522 1.264631 0.9586673

The results can be used and manipulated as a usual data frame. E.g.,

tmp[, 1:5]
#>       [w]      (w)      ind      CI.lo    CI.hi
#> 1 M+1.0SD 3.164128 3.060021  1.9144062 3.978543
#> 2    Mean 2.179279 2.136191  1.2816511 2.965547
#> 3 M-1.0SD 1.194429 1.212360 -0.1016396 2.475522
tmp[c(1, 2), 1:5]
#>       [w]      (w)      ind    CI.lo    CI.hi
#> 1 M+1.0SD 3.164128 3.060021 1.914406 3.978543
#> 2    Mean 2.179279 2.136191 1.281651 2.965547

However, if SEs and/or p-values are needed, more need to be done. I do not yet have an idea on how to implement this appropriately. These columns could have been added in the table. However, I would avoid changing the structure (columns) of the output unless really necessary, to avoid breaking other functions that manipulate the output. Therefore, for now, SEs and p-values are stored internally but they are printed only if requested. This is done by the print methods.

Until the team has a decision, if SEs and/or p-values are needed, the following function can be used as a tentative solution:

cond_indirect_effects_to_data_frame <- function(x,
                                                pvalue = FALSE,
                                                se = FALSE) {
    out <- as.data.frame(x)
    full_output <- attr(x, "full_output")
    if (se) {
        se <- sapply(full_output, function(x) {
            if (!is.null(x$boot_se)) return(x$boot_se)
            if (!is.null(x$mc_se)) return(x$mc_se)
            return(NA)
          })
        out$SE <- se
      }
    if (pvalue) {
        pv <- sapply(full_output, function(x) {
            if (!is.null(x$boot_p)) return(x$boot_p)
            if (!is.null(x$mc_p)) return(x$mc_p)
            return(NA)
          })
        out$pvalue <- pv
      }
    return(out)
  }

This is how it works:

tmp <- cond_indirect_effects_to_data_frame(out_xmy_on_w, pvalue = TRUE)
tmp
#>       [w]      (w)      ind      CI.lo    CI.hi      m~x       y~m pvalue
#> 1 M+1.0SD 3.164128 3.060021  1.9144062 3.978543 3.191953 0.9586673 0.0004
#> 2    Mean 2.179279 2.136191  1.2816511 2.965547 2.228292 0.9586673 0.0000
#> 3 M-1.0SD 1.194429 1.212360 -0.1016396 2.475522 1.264631 0.9586673 0.0736

tmp <- cond_indirect_effects_to_data_frame(out_xmy_on_w, se = TRUE)
tmp
#>       [w]      (w)      ind      CI.lo    CI.hi      m~x       y~m        SE
#> 1 M+1.0SD 3.164128 3.060021  1.9144062 3.978543 3.191953 0.9586673 0.5230653
#> 2    Mean 2.179279 2.136191  1.2816511 2.965547 2.228292 0.9586673 0.4283923
#> 3 M-1.0SD 1.194429 1.212360 -0.1016396 2.475522 1.264631 0.9586673 0.6569414

tmp <- cond_indirect_effects_to_data_frame(out_xmy_on_w, pvalue = TRUE, se = TRUE)
tmp
#>       [w]      (w)      ind      CI.lo    CI.hi      m~x       y~m        SE
#> 1 M+1.0SD 3.164128 3.060021  1.9144062 3.978543 3.191953 0.9586673 0.5230653
#> 2    Mean 2.179279 2.136191  1.2816511 2.965547 2.228292 0.9586673 0.4283923
#> 3 M-1.0SD 1.194429 1.212360 -0.1016396 2.475522 1.264631 0.9586673 0.6569414
#>   pvalue
#> 1 0.0004
#> 2 0.0000
#> 3 0.0736

This is not good solution, I admit. Nevertheless, this works for now.

Users who want the results as data frames can just use as.data.frame() or the function cond_indirect_effects_to_data_frame(). Because the output is just a usual data frame, they can be manipulated as data frames (e..g, columns reordered or some rows deleted). E.g.,

tmp <- cond_indirect_effects_to_data_frame(out_xmy_on_w, pvalue = TRUE, se =$
tmp
#>     [w]      (w)      ind      CI.lo    CI.hi      m~x       y~m        SE
#> M+1.0SD 3.164128 3.060021  1.9144062 3.978543 3.191953 0.9586673 0.5230653
#>    Mean 2.179279 2.136191  1.2816511 2.965547 2.228292 0.9586673 0.4283923
#> M-1.0SD 1.194429 1.212360 -0.1016396 2.475522 1.264631 0.9586673 0.6569414
#> pvalue
#> 0.0004
#> 0.0000
#> 0.0736
tmp[, c("[w]", "ind", "SE", "pvalue")]
#>     [w]      ind        SE pvalue
#> M+1.0SD 3.060021 0.5230653 0.0004
#>    Mean 2.136191 0.4283923 0.0000
#> M-1.0SD 1.212360 0.6569414 0.0736

I opened this issue to remind me to work on it.

Comments and suggests are welcomed.

@sfcheung sfcheung added the enhancement New feature or request label Jul 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant