Giter Club home page Giter Club logo

manymome's Introduction

About Me

I am Shu Fai. I like helping people, me included, to do analysis in psychological studies. These are the R packages and other tools I am working on:

Structural Equation Modelling (SEM)

manymome: Moderation (mo), mediation (me), and moderated mediation (mome) in "many" models. In colaboration with S.-H. Cheung (Cheung & Cheung, 2023). Our goals: Do things fast and do them right. This package is for computing indirect effects and conditional indirect effects fast and easily, with as little coding as possible. (A quick introduction)

semlbci: Likelihood-based confidence interval (lbci) in sem. LBCI is a useful but underused method to form CI in SEM. I hope more researchers can use this method (Cheung & Pesigan, 2023). (Get started)

semfindr: A finder (hence findr) for finding influential cases in an SEM analysis, in collaboration with Mark H. C. Lai. We should always see if there are any influential cases in SEM but this is not easy, even for me as I have projects with large samples with missing data. We hope this package, with efficiency and easiness-to-use in mind, can help more researchers to do this. (No, outliers are not necessarily influential cases, and influential cases are not necessarily outiers. Checking for outliers is not enough.) (How to use it)

semptools: Helpers for customizing an SEM figure generated by semPlot::semPaths(), in collaboration with Mark H. C. Lai. It helped me a lot to generate publication-ready and teaching-ready SEM figures quickly. (A quick start guide)

semhelpinghands: Helper functions I wrote to help myself to do some common tasks in SEM efficiently. See this page for an overview.

Multiple Regression

stdmod: Started out as a package for doing standardized moderation right (many did it wrong) in linear regression but now a tool for doing standardization right in linear regression, including moderated regression (Cheung, Cheung, Lau, Hui, & Vong, 2022). The usual method for confidence intervals is wrong and I hope this package (among others) can help people to form better CIs. it supports bootstrap confidence intervals. Illustrations can be found here for moderated regression and here for a regression model with categorical predictors.

manymome: Again? Yes, because it can also be used for regression models 😄! Moderation (mo), mediation (me), and moderated mediation (mome) in "many" regression models, fitted by several one-outcome regression models using lm(). In colaboration with S.-H. Cheung (Cheung & Cheung, 2023). Our goal: Do things fast, and do them right. This package is for computing indirect effects and conditional indirect effects fast and easy, with as little coding as possible. Illustrations can be found in this page for mediation and this page for moderated mediation.

SPSS

DIY Bootstrapping in SPSS: For forming nonparametric bootstrap confidence intervals for literally anything we can see in the SPSS output (Cheung, Pesigan, & Vong, 2023). Flexibility comes at a cost ... some coding is inevitable. But I meant it: Anything we can see, including standardized regression coefficients ("betas") and adjusted R-squares, reliability coefficients, and many other statistics. Video demonstration can be found here.

Hope you find the tools useful. (I certainly do find the tools useful because I usually develop tools that I myself also want to use in my research. 😊)

I would love to see bug reports and suggestions. Feel free to raise them in the corresponding GitHub issues pages. Thanks. 🙏🙂

manymome's People

Contributors

sfcheung avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

Forkers

irissun

manymome's Issues

Issues with conditional indirect effects when using a categorical moderator

Hi,

I have an issue with the manymome functions cond_indirect_effects() and mod_levels() when using a categorical moderator with two categories.

I get these warning and error messages :

Warning in seq_len(ncol(w_gp)): first element used of 'length.out' argument
Error in seq_len(ncol(w_gp)) : argument must be coercible to non-negative integer

I'm following the steps from Cheung & Cheung (2023) manymome:__ An R package for computing the indirect effects, conditional effects, and conditional indirect effects, standardized or unstandardized, and their bootstrap confidence intervals, in many (though not all) models.

I don't understand what's the issue. Is it a bug or is it an issue with my code/data ?

Mind that I don't have this issue when I'm using a continuous moderator with the same data.

Thanks in advance

library(lavaan)
#> This is lavaan 0.6-17
#> lavaan is FREE software! Please report any bugs.
library(manymome)
##Sample data
df <- data.frame(
     Intense = c(1.20302400035313,0.377413381825115,
                 -1.18646351469919,1.20057716684428,1.20138456799171,
                 -2.7774605624413,-1.94239715523117,0.402302832389528,-0.421912163704315,
                 0.331669138980736),
     CatPers = c("0.792961214431443","0.792961214431443",
                 "-1.25872969475283","-1.25872969475283","-1.25872969475283",
                 "0.792961214431443","0.792961214431443","-1.25872969475283",
                 "0.792961214431443","0.792961214431443"),
         Pos = c(-0.233043705579646,-0.376337459099043,
                 -0.530671521945183,1.34621539413837,-0.957223025488462,
                 0.90322432738519,-0.640637299527499,-0.158533233160109,
                 0.27334450686968,0.0162900160068483),
         Wfc = c(1.00645422416079,0.418767308104094,
                 0.543193979890933,0.150878583032073,0.671868144845523,
                 -0.203760346081739,0.522581840151886,0.123494795372463,0.20299495139938,
                 0.211670048655376)
)

##Dummy variable based on a categorical variable with two categories
corsci <- factor2var(df$CatPers, 
                     x_contrasts = "contr.treatment")
df[, "corsci"] <- corsci

##Interaction term
df$Intense_corsci <- df$Intense*df$corsci

##Structural model
mtest <- "
Pos ~ Intense + Intense_corsci + corsci
Wfc ~ Pos"

test.fit <- sem(mtest, df, std.lv = TRUE, fixed.x = FALSE, missing = "fiml")

##Condtional indirect effect
outest <- cond_indirect_effects(wlevels = "corsci",
                        x = "Intense",
                        y = "Wfc",
                        m = "Pos",
                        fit = test.fit)
#> Warning in seq_len(ncol(w_gp)): seul le premier élément de l'argument
#> 'length.out' est utilisé
#> Error in seq_len(ncol(w_gp)): l'argument doit être convertible automatiquement en un entier non négatif

Created on 2024-02-14 with reprex v2.1.0

Mod_level

Hello,
I have binary and continuous moderators, but the function to fix moderator levels and merge them does not work. R keeps giving me error messages. It is like it cannot find the variables that are correctly used by lm.
Also, sd_from_means works but values does not.

Problems with using do_mc () & cond_indirect_effects () in getting the Monte Carlo Estimates for indirect effects

First of all, thanks a lot for creating this wonderful function to simplify the process to generate the Monte Carlo confidence intervals for indirect effects.

In my study, I've used multiple imputations to handle missing data first using the mice package. I then used runMi to conduct a multiple mediation analysis to analyze 5 parallel mediators using the sem function of semTools. After that, I would like to generate the Monte Carlo confidence intervals. However, I'm having the error message below.

Error in names(x) <- wnames : 
  'names' attribute [1] must be the same length as the vector [0]

Below are the codes I used. In my model, I don't have levels, so I put NULL in the codes. Would this be the problem? If not, would you please advise what's wrong with my code?

## specify the model ====
model1 <- '# total effect
          total := c + (a*b1) + (c*b2) + (d*b3) + (e*b4) + (f*b5)
       
          # mediator
          IRQ_original_total ~ a*ECR_anxiety_average
          IRQ_partner_total ~ c*ECR_anxiety_average
          CEER_total ~ d*ECR_anxiety_average
          IRIS_total ~ e*ECR_anxiety_average
          DERS_total ~ f*ECR_anxiety_average
          CTS2_psy_perp_total~ b1*IRQ_original_total
          CTS2_psy_perp_total~ b2*IRQ_partner_total
          CTS2_psy_perp_total~ b3*CEER_total
          CTS2_psy_perp_total~ b4*IRIS_total
          CTS2_psy_perp_total~ b5*DERS_total
          
          # direct effect
          CTS2_psy_perp_total ~ c*ECR_anxiety_average
          
          # indirect effect (a*b)
          ab := a*b1
          cb := c*b2
          db := d*b3
          eb := e*b4
          fb := f*b5
          '
## run the analysis ====
output <- runMI(model1, data=alldata5.mi.1, fun="sem")
summary(output, standardized=TRUE, fit = TRUE, ci=TRUE)

## robust Monte Carlo confidence intervals of indirect effects ====
install.packages("manymome")
library(manymome)

mc_out <- do_mc(fit = output,
                       R = 10000,
                       seed = 1234)

out <- cond_indirect_effects(wlevels = NULL,
                             x = "ECR_anxiety_average",
                             y = "CTS2_psy_perp_total",
                             m = "IRQ_original_total", "IRQ_partner_total", "CEER_total", "IRIS_total", "DERS_total",
                             fit = output,
                             mc_ci = TRUE,
                             mc_out = mc_out)

Plot indirect effect against moderator

For now, the plot-method of cond_indirect_effects objects only supports plotting conditional effects when there is no mediator (i.e., moderation only). This is because we are still thinking about how to plot conditional effects in moderated mediation.

One commonly used plot is plotting the conditional indirect effect against the value of the moderator. For now, this can be done manually using mod_levels(), coef(), and confint(), along with cond_indirect_effects(). Set the values of the moderator (2 SDs below mean to 2 SDs above mean, with an interval of .2, in the following example) using mod_levels(), and then extract the values need to plot the three lines. This is an example:

# This function add columns for standard errors (SEs)
# and p-values if requested and available.

# 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.
wlevels <- mod_levels(w = "w",
                      fit = fit_lm,
                      sd_from_mean = seq(-2, 2, .2))
head(wlevels)
#>                w
#> M+2.0SD 4.148978
#> M+1.8SD 3.952008
#> M+1.6SD 3.755038
#> M+1.4SD 3.558068
#> M+1.2SD 3.361098
#> M+1.0SD 3.164128
tail(wlevels)
#>                 w
#> M-1.0SD 1.1944286
#> M-1.2SD 0.9974587
#> M-1.4SD 0.8004887
#> M-1.6SD 0.6035187
#> M-1.8SD 0.4065487
#> M-2.0SD 0.2095787
# The following call will take some time to run:
out_xmy_on_w <- cond_indirect_effects(wlevels = wlevels,
                                      x = "x",
                                      y = "y",
                                      m = "m",
                                      fit = fit_lm,
                                      boot_ci = TRUE,
                                      boot_out = boot_out_lm)
head(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+2.0SD 4.149 3.984 2.144 5.498 Sig 4.156 0.959
#> 2 M+1.8SD 3.952 3.799 2.100 5.162 Sig 3.963 0.959
#> 3 M+1.6SD 3.755 3.614 2.052 4.848 Sig 3.770 0.959
#> 4 M+1.4SD 3.558 3.430 2.015 4.550 Sig 3.577 0.959
#> 5 M+1.2SD 3.361 3.245 1.978 4.256 Sig 3.385 0.959
#> 6 M+1.0SD 3.164 3.060 1.914 3.979 Sig 3.192 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.
tail(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 1.194 1.212 -0.102 2.476     1.265 0.959
#> 2 M-1.2SD 0.997 1.028 -0.420 2.429     1.072 0.959
#> 3 M-1.4SD 0.800 0.843 -0.743 2.369     0.879 0.959
#> 4 M-1.6SD 0.604 0.658 -1.088 2.327     0.686 0.959
#> 5 M-1.8SD 0.407 0.473 -1.409 2.279     0.494 0.959
#> 6 M-2.0SD 0.210 0.289 -1.733 2.255     0.301 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.
wvalue <- wlevels[, "w"]
ind <- coef(out_xmy_on_w)
ci_lower <- confint(out_xmy_on_w)[, 1]
ci_upper <- confint(out_xmy_on_w)[, 2]
tmp <- data.frame(wvalue, ind, ci_lower, ci_upper)
head(tmp)
#>     wvalue      ind ci_lower ci_upper
#> 1 4.148978 3.983851 2.144130 5.498216
#> 2 3.952008 3.799085 2.099943 5.161536
#> 3 3.755038 3.614319 2.051911 4.848483
#> 4 3.558068 3.429553 2.014613 4.550057
#> 5 3.361098 3.244787 1.977689 4.256482
#> 6 3.164128 3.060021 1.914406 3.978543

library(ggplot2)
p <- ggplot(data = tmp,
            aes(x = wvalue,
                y = ind)) +
      geom_line(color = "blue") +
      geom_line(aes(x = wvalue,
                    y = ci_lower),
                linetype = "longdash") +
      geom_line(aes(x = wvalue,
                    y = ci_upper),
                linetype = "longdash") +
      xlab("Moderator w") +
      ylab("Indirect Effect: x -> m -> y")
p

Created on 2023-07-29 with reprex v2.0.2

The plot method may be updated to do this automatically. For now, the technique above can be used.

Compute the difference between any two effects and form its percentile bootstrap confidence interval

Some users would like to compute and test the difference between any two effects.

For now, this cannot be done because the outputs of indirect_effect() are supposed to have one x-variable and one y-variable each. The + and - operator, when used on the outputs, will also be a similar object with one x-variable and one y-variable. If we allow the operators to work on two paths with different x and/or y variable(s), we need to make drastic changes to the indirect-class object.

Nevertheless, there are cases in which this is what users need.

Before we have decided on a long term solution, the following ad hoc function, any_diff_boot, can be used this way. It compute the difference between two effects, that of object1 - that of object2, and form the bootstrap CIs, if they have been requested when computing the two effects. Note: Users need to ensure that they are computed on the same set of bootstrap samples, which should be the case if the same object is used in the boot_out argument.

any_diff_boot <- function(object1,
                          object2,
                          level = .95) {
    boot_est1 <- object1$boot_indirect
    boot_est2 <- object2$boot_indirect
    if (is.null(boot_est1) || is.null(boot_est2)) {
        stop("Bootstrap estimates not available one or both objects.")
      }
    nboot <- length(boot_est1)
    if (nboot != length(boot_est2)) {
        stop("The numbers of bootstrap samples are not identical.")
      }
    boot_diff <- boot_est1 - boot_est2
    diff <- object1$indirect - object2$indirect
    tmp <- list(t = matrix(boot_diff, nrow = nboot, ncol = 1),
                t0 = diff,
                R = nboot)
    boot_ci0 <- boot::boot.ci(tmp, conf = level, type = "perc")
    boot_ci1 <- boot_ci0$percent[4:5]
    names(boot_ci1) <- paste0(formatC(c(100 * (1 - level) / 2,
                                  100 * (1 - (1 - level) / 2)), 2,
                                  format = "f"), "%")
    boot_se <- stats::sd(boot_diff, na.rm = TRUE)
    out <- c(Difference = diff, boot_ci1)
    out
  }

The following illustrates how it is used:

# Source:
# https://sfcheung.github.io/manymome/articles/manymome.html#mediation-only
library(manymome)
library(lavaan)
#> This is lavaan 0.6-16
#> lavaan is FREE software! Please report any bugs.
library(semhelpinghands)

dat <- data_serial

mod_med <- "
m1 ~ x + c1 + c2
m2 ~ m1 + x + c1 + c2
y ~ m2 + m1 + bx*x + bc1*c1 + c2
diff := bx - bc1
"
fit_med <- sem(model = mod_med,
               data = dat,
               fixed.x = FALSE)
fit_med_boot <- sem(model = mod_med,
                    data = dat,
                    fixed.x = FALSE,
                    se = "boot",
                    bootstrap = 1000,
                    iseed = 12345)
boot_out <- do_boot(fit_med,
                    R = 1000,
                    seed = 12345)
#> 5 processes started to run bootstrapping.
#> The expected CPU time is about 0 second(s).
tmp <- indirect_effect(x = "x",
                       y = "y",
                       fit = fit_med,
                       standardized_x = TRUE,
                       standardized_y = TRUE)
std_x_y <- indirect_effect(x = "x",
                           y = "y",
                           fit = fit_med,
                           standardized_x = TRUE,
                           standardized_y = TRUE,
                           boot_ci = TRUE,
                           boot_out = boot_out)
std_c1_y <- indirect_effect(x = "c1",
                            y = "y",
                            fit = fit_med,
                            standardized_x = TRUE,
                            standardized_y = TRUE,
                            boot_ci = TRUE,
                            boot_out = boot_out)
std_x_y
#> 
#> ==  Effect ==
#>                                       
#>  Path:               x -> y           
#>  Effect              0.234            
#>  95.0% Bootstrap CI: [-0.017 to 0.468]
#> 
#> Computation Formula:
#>   (b.y~x)*sd_x/sd_y
#> Computation:
#>   (0.49285)*(0.95010)/(1.99960)
#> 
#> Percentile confidence interval formed by nonparametric bootstrapping
#> with 1000 bootstrap samples.
std_c1_y
#> 
#> ==  Effect ==
#>                                       
#>  Path:               c1 -> y          
#>  Effect              0.049            
#>  95.0% Bootstrap CI: [-0.157 to 0.245]
#> 
#> Computation Formula:
#>   (b.y~c1)*sd_c1/sd_y
#> Computation:
#>   (0.09884)*(0.99841)/(1.99960)
#> 
#> Percentile confidence interval formed by nonparametric bootstrapping
#> with 1000 bootstrap samples.

# Show that the estimates are the same
print(standardizedSolution(fit_med)[10:11, 1:5], nd = 7)
#>    lhs op rhs label   est.std
#> 10   y  ~   x    bx 0.2341759
#> 11   y  ~  c1   bc1 0.0493495
coef(std_x_y)
#>       y~x 
#> 0.2341759
coef(std_c1_y)
#>       y~c1 
#> 0.04934946

# Show that the differences computed are the same
print(standardizedSolution(fit_med)[22, 1:5], nd = 8)
#>     lhs op    rhs label   est.std
#> 22 diff := bx-bc1  diff 0.1848264
coef(std_x_y) - coef(std_c1_y)
#>       y~x 
#> 0.1848264
any_diff_boot(std_x_y, std_c1_y)
#> Difference      2.50%     97.50% 
#>  0.1848264 -0.1042021  0.4646119

# Show that the bootstrap CIs are the same
std_boot_ci <- standardizedSolution_boot_ci(fit_med_boot)
print(std_boot_ci[22, c(1:5, 11, 12)], nd = 8)
#>     lhs op    rhs label   est.std boot.ci.lower boot.ci.upper
#> 22 diff := bx-bc1  diff 0.1848264    -0.1042021     0.4646119
any_diff_boot(std_x_y, std_c1_y)
#> Difference      2.50%     97.50% 
#>  0.1848264 -0.1042021  0.4646119

Created on 2023-11-18 with reprex v2.0.2

Certainly, if the goal is to test the difference between two standardized indirect effects, lavaan can already do this: label the two paths, define the difference, and form the bootstrap CI for the standardized solution (this needs to be done using functions such as semhelpinghands::standardizedSolution_boot_ci() because the CIs in lavaan::standardizedSolution() are not bootstrap CIs even if bootstrapping is requested).

Nevertheless, if do_boot() is used, then indirect_effect() and do_boot() can be used, without the need to do bootstrapping when fitting the model by lavaan::sem().

Find a standard way to accommodate other CI methods in the future

Note

The current approach works for bootstrapping confidence intervals and Monte Carlo confidence intervals. However, it may not be convenient to extend support for other types of confidence intervals in the future. Some lines are also repeated across functions, leading to duplicate code.

This is not urgent for now but should be considered when time allows.

To-Dos For Updating to a Major Version

To-Dos

  • Check the documentation of new functions.
  • Check the documentation of old functions.
  • Check the documentation of functions: Are all classes documented?
  • Proofread the examples.
  • Proofread the vignettes.
  • Update NEWS.
  • Update DESCRIPTION.
  • Test by testthat.
  • Check by pkgdown::build_site()
  • Check by devtools::check().

Convert the output of `cond_indirect_effects()` to a data frame

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.