mediate_MEMS: Function to conduct mediation analysis with micro effects on...

View source: R/mediate_MEMS.R

mediate_MEMSR Documentation

Function to conduct mediation analysis with micro effects on macro structure (MEMS).

Description

mediate_MEMS implements parametric and nonparametric routines to compare MEMS estimate between models. Largely a wrapper for compare_MEMS, the sole novel functionality of mediate_MEMS is provided when a user specifies the model_comparison argument to be TRUE. When model_comparison is set to TRUE, mediate_MEMS compares the direct, indirect, and total MEMS estimates to those obtained from partial_model2 and full_model2. This can be used as a sensitivity test to researchers' choice of model. It can also provide the basis for testing differences in direct, total, and indirect effect sizes within the same model by setting partial_model2 to equal partial_model and full_model2 to equal full_model and provide a second explanatory micro process to the micro_process2 argument. In these cases, the difference between "models" captures the differences effect size of the direct, indirect, and total MEMS estimates for two distinct explanatory micro processes. See Wertsching and Duxbury (2025) for details.

The difference in MEMS is the change in MEMS after one or more micro-processes are included into a model or, in the case of sensitivity tests, when the functional form is changed. Let MEMS_p represent the MEMS obtained from a model that omits one or more intervening variables and MEMS_f be the MMES obtained from a model that includes the intervening variable(s). The change in MEMS is given

\Delta MEMS=MEMS_p-MEMS_f

. MEMS_p and MEMS_f may also be have the same specification but use distinct functional forms or other modeling decisions in the case of sensitivity tests. Tuning parameters can be assigned to toggle the strength of \theta in model-implied estimates of MEMS. MEMS currently accepts glm, glmer, ergm, btergm, sienaFit, rem.dyad, and netlogit objects and implements both parametric and nonparametric estimation. Pooled estimation for multiple network models is also implemented for ergm and sienaFit objects.

Usage

mediate_MEMS(partial_model,
      full_model,
      micro_process,
      macro_function,
      model_comparison=FALSE,
      partial_model2=NULL,
      full_model2=NULL,
      micro_process2=NULL,
      macro_function2=NULL,
      object_type=NULL,
      interval=c(0,1),
      nsim=500,
      algorithm="parametric",
      silent=FALSE,
      full_output=FALSE,
      sensitivity_ev=TRUE,
      SAOM_data=NULL,
      SAOM_var=NULL,
      time_interval=NULL,
      covar_list=NULL,
      edgelist=NULL,
      net_logit_y=NULL,
      net_logit_x=NULL,
      group_id=NULL,
      node_numbers=NULL,
      mediator=NULL,
      link_id=NULL,
      controls=NULL,
      control_functions=NULL)

Arguments

partial_model

the micro-model excluding one or more intervening or confounding variables of interest. May also be a fully specified model with a distinct functional form in the case of sensitivity tests. Currently accepts glm, glmer, ergm, btergm, sienaFit, rem.dyad, and netlogit objects. Pooled estimation for multiple network models is also implemented for ergm and sienaFit objects. To implement pooled estimation, model should be provided as a list of ergm or sienaFit objects.

full_model

the micro-model including one or more intervening or confounding variables of interest. May also be a fully specified model with a distinct functional form in the case of sensitivity tests. Currently accepts glm, glmer, ergm, btergm, sienaFit, rem.dyad, and netlogit objects. Pooled estimation for multiple network models is also implemented for ergm and sienaFit objects. To implement pooled estimation, model should be provided as a list of ergm or sienaFit objects.

micro_process

a character string containing the name of the micro process of interest. The character string should exactly match coefficient names in model output.

macro_function

a function that calculates the macro statistic of interest. Currently accepts user defined functions as well as functions inherent in the igraph and statnet packages for R.

model_comparison

returns sensitivity tests evaluating robustness of partial, full, and indirect MEMS estimates to distinct model choices when set to TRUE. Default is FALSE

partial_model2

a second model identitical to the specification of partial_model that uses a distinct functional form. Differences in MEMS estimates from partial_model are compared to MEMS estimates from partial_model2. Required if model_comparison=TRUE and ignored otherwise.

full_model2

a second model identitical to the specification of full_model that uses a distinct functional form. Differences in MEMS estimates from full_model are compared to MEMS estimates from full_model2. Required if model_comparison=TRUE and ignored otherwise.

micro_process2

the character string identifying the micro_process to compare in sensitivity analysis. Required if model_comparison=TRUE and ignored otherwise.

macro_function2

an optional function that calculates the macro statistic of interest. When provided, macro_function2 will be used in place of macro_function when calculating the MEMS provided by the partial_model2 and full_model2 arguments. This is intended for use in comparisons between distinct models (e.g., SAOM and ERGM) when a user provided function must be written differently for each model's output. Defaults to NULL.

object_type

A character string that tells netmediate the type of object to apply the macro_function to. Currently accepts igraph and network objects. If left NULL, network objects are assumed. Can be over-ridden to use other object types with a user-function by defining a function that accepts either a network or igraph object and returns a numeric value or vector of numeric values (see examples).

interval

The value of tuning parameters to assign to \theta. Should be provided as a vector of numeric values with 2 entries.

nsim

The number of simulations or bootstrap samples to use during estimation.

algorithm

The estimation algorithm to be used. Currently accepts "parametric" and "nonparametric". If "parametric", estimation is obtained with Monte Carlo sampling. If "nonparametric", estimation uses bootstrap resampling.

silent

logical parameter. Whether to provide updates on the progress of the simulation or not.

full_output

logical parameter. If set to TRUE, mediate_MEMS will return all sampled statistics and complete results for MEMS_p and MEMS_f.

sensitivity_ev

optional parameter. If set to TRUE, will return E-values for direct, total, and indirect MEMS estimates.

SAOM_data

required when the model is a sienaFit object; ignored otherwise. If a sienaFit object is provided, SAOM_data should be the siena object that contains the data for SAOM estimation. If using pooled estimation on multiple sienaFit objects (i.e., providing a list of sienaFit objects), then SAOM_data should be provided as an ordered list with each entry containing the siena object corresponding to list of sienaFit objects.

SAOM_var

optional parameter when the model is a sienaFit object. SAOM_var is a list of of the varCovar and varDyadCovar objects used to assign time varying node and dyad covariates when calling sienaDataCreate. If provided, netmediate assigns the varying node covariates and dyad covariates to each simulated network. This parameter is required when macro_function computes a statistic that varies as a function of time varying node or dyad covariates (i.e., network segregation, assorativity). Time invariant characteristics (coCovar and coDyadCovar) are handled internally by MEMS and should not be provided. When providing a list of sienaFit objects for pooled estimation, SAOM_var should be provided as a list of lists, where each entry in the list contains a list of varCovar and varDyadCovar objects associated with corresponding sienaFit object.

time_interval

an optional parameter to be used with rem.dyad objects. May be provided as a numeric vector or the character string "aggregate". If a numeric vector is provided unique network snapshots at each interval. For example, time_interval=c(0,2,3) would induce two networks, one for the 0 - 2 time period and one for the 2 - 3 time period. If specified as "aggregate", the MEMS is calculated by creating an aggregated cross-sectional representation of the entire event sequence. If left NULL, defaults to |"aggregate".

covar_list

an optional list of sender/receiver covariates used in rem.dyad estimation. Only required for rem.dyad objects when covariates are included. The list format should correspond to the format required by rem.dyad

edgelist

an optional three column edgelist providing the sender, receiver, and time of event occurrence when using rem.rem.dyad. Only required when time_interval is set to NULL or "aggregate". Ignored for other types of models.

net_logit_y

the dependent variable for netlogit objects. Should be provided as a vector. Only required when model is a netlogit object.

net_logit_x

the matrix of independent variables for netlogit type objects. Only required when model is a netlogit object.

group_id

optional vector of group identifiers to use when estimating a glm or glmer on grouped data (i.e., multiple time periods, multiple networks). When specified, MEMS will induce unique networks for each grouping factor. If left unspecified, all groups/time periods are pooled. If using glmer, the grouping factor does not have to be provided as part of the model or used as a random effect.

node_numbers

a numeric vector containing the number of nodes in each group_id when using glm or glmer. If estimating MEMS aggregated over all networks (i.e., group_id=NULL), this shoud be the total number of nodes in all networks. Required when using glm or glmer, ignored otherwise.

mediator

a character string detailing the mediator of interest. Intended for internal use with the AMME function; not intended for end users.

link_id

a vector or list of vectors corresponding to unique identifiers. Intended for internal use with the AMME function; not intended for end users.

controls

a vector of character strings listing the controls to be calculated when using AMME. Intended for internal use with the AMME function; not intended for end users.

control_functions

a list of functions to calculate the macro control variables provided in controls. Intended for internal use with the AMME function; not intended for end users.

Details

Compares MEMS estimates between two models. If one or more confounding or intervening variables are excluded or included between models, the change in MEMS can be interpreted as the portion of the MEMS explained by one or more confounding or intervening variable. If two models are provided with the same specification but a distinct functional form, the change in MEMS is a sensitivty test of how much the MEMS estimate changes because of a model decision. This can be useful, for example, when comparing TERGM and SAOM estimates as each models make distinct assumptions about sources of network change and the temporal ordering of tie changes.

If a single pair of models are compared, mediate_MEMS results will be identical to compare_MEMS results. However, if model_comparison is set to TRUE and a second pair of models are provided using a different set of control variables or a distinct functional form, mediate_MEMS will also return sensitivity tests evaluating whether the partial, full, and indirect MEMS estimates are significantly different between the two sets of models. This functionality can also be used to formally test differences in partial, full, and indirect effect sizes by setting partial_model2 to be the same as partial model and full_model2 to be the same as full_model and setting micro_process2 to be a different variable than micro_process.

mediate_MEMS functionality inherits directly from the compare_MEMS and MEMS commands. See the compare_MEMS and MEMS pages for more details.

Value

If full_output=FALSE and model_comparison=FALSE, then a table is returned with the change MEMS, its standard error, confidence interval, and p-value, and the same results for the partial and complete MEMS.

If full_output=TRUE and model_comparison=FALSE, then a list is returned with the following three elements.

diff_MEMS_results

is the table of summary output containing the MEMS, its standard error, confidence interval, and p-value, and a list of the simulated values of the change in MEMS.

p_MEMS_results

contains the summary statistics for the partial MEMS along with all simulated statistics.

f_MEMS_results

contains the summary statistics for the full MEMS along with all simulated statistics.

If full_output=FALSE and model_comparison=TRUE, then a list is returned with the following elements.

model_set1

is the table of summary output testing the partial, full, and indirect MEMS using partial_model and full_model.

model_set2

is the table of summary output testing the partial, full, and indirect MEMS using partial_model2 and full_model2

model_comparison

is the table of output testing the difference in estimates between model_set1 and model_set2

If full_output=TRUE and model_comparison=TRUE, then a list is returned with the following three elements.

summary_results

is the list of summary output provided as described above when full_output=TRUE.

sample_results

is a list containing the simulation draws used to calculate point estimates, variance estimates, and sensitivity tests for the partial MEMS, full MEMS, and indirect MEMS.

Author(s)

Duxbury, Scott W. Associate Professor, University of North Carolina–Chapel Hill, Department of Sociology.

References

Duxbury, Scott W. 2024. "Micro Effects on Macro Structure in Social Networks." Sociological Methodology.

Wertsching, Jenna, and Scott W. Duxbury. Working paper. "Micro Effects on Macro Structure: Identification, Comparison between Nested Models, and Sensitivity Tests for Functional Form."

Duxbury, Scott W., and Xin Zhao. Working paper. "Sensitivity Tests for Micro-Macro Network Analysis."

See Also

AMME MEMS ergm.mma mediate compare_MEMS

Examples





##############
# Not run
###############
library(statnet)
library(igraph)
data("faux.mesa.high")

#how much of the effect of racial homophily on transitivity
#is explained by triadic closure effects?

model<-ergm(faux.mesa.high~edges+nodecov("Grade")+nodefactor("Race")+
              nodefactor("Sex")+nodematch("Race")+nodematch("Sex")+absdiff("Grade"))

model2<-ergm(faux.mesa.high~edges+nodecov("Grade")+nodefactor("Race")+
               nodefactor("Sex")+nodematch("Race")+nodematch("Sex")+absdiff("Grade")+
               gwesp(.5,fixed=TRUE))

#compare results from compare_MEMS and mediate_MEMS

compare_MEMS(partial_model=model,
             full_model=model2,
             micro_process="nodematch.Race",
             macro_function=transitivity,
             object_type = "igraph",
             silent=FALSE,
             algorithm="parametric")


mediate_MEMS(partial_model=model,
             full_model=model2,
             micro_process="nodematch.Race",
             macro_function=transitivity,
             object_type = "igraph",
             silent=FALSE,
             algorithm="parametric")




###test sensitivity to MPLE versus MCMC MLE estimation

modela<-ergmMPLE(faux.mesa.high~edges+nodecov("Grade")+nodefactor("Race")+
              nodefactor("Sex")+nodematch("Race")+nodematch("Sex")+absdiff("Grade"),
              output="fit")

model2a<-ergmMPLE(faux.mesa.high~edges+nodecov("Grade")+nodefactor("Race")+
               nodefactor("Sex")+nodematch("Race")+nodematch("Sex")+absdiff("Grade")+
               gwesp(.5,fixed=TRUE),
               output="fit")




mediate_MEMS(partial_model=model,
             full_model=model2,
             micro_process="nodematch.Race",
             model_comparison  = TRUE,
             partial_model2=modela,
             full_model2=model2a,
             micro_process2="nodematch.Race",
             macro_function=transitivity,
             object_type = "igraph",
             silent=FALSE,
             algorithm="parametric")


##compare direct, total, and indirect effect sizes

mediate_MEMS(partial_model=model,
             full_model=model2,
             micro_process="nodematch.Race",
             model_comparison  = TRUE,
             partial_model2=model,
             full_model2=model2,
             micro_process2="absdiff.Grade",
             macro_function=transitivity,
             object_type = "igraph",
             silent=FALSE,
             algorithm="parametric")





#####################################################
# More complicated sensitivty test using macro function 2
#####################################################

#are the direct, total, and indirect MEMS of
  #network selection on similar smoking behavior on
  #students' shared smoking robust to distinct
  #model choices?

###Compare between SAOM and TERGM treating behavioral
 #(smoking) autocorrelation as outcome, smoking homophily
 #as treatment, and triadic closure as mediator




########################################
#       Co-evolution SAOM
#######################################

library(RSiena)
network_array<-list(s501,s502,s503)
smoking<-as.data.frame(s50s)

for(i in 1:ncol(smoking)){

  smoking[,i][smoking[,i]>1]<-2
}

alcohol<-as.data.frame(s50a) ##we'll use alcohol consumption as a covariate as well


##create "sienaDependent" object,
TLSnet<-sienaDependent(array(c(network_array[[1]],
                               network_array[[2]],
                               network_array[[3]]),
                             dim=c(50,50,3)))
TLSbeh<-sienaDependent(as.matrix(smoking),type="behavior")

#set covariates
Alcohol<-varCovar(as.matrix(alcohol))


###create dataset, but specify network AND behavior
SAOM.Data<-sienaDataCreate(Network=TLSnet,
                           Behavior=TLSbeh,
                           Alcohol)

###Create the effects object
SAOM.terms<-getEffects(SAOM.Data)



###We'll start by specifying the NETWORK function

SAOM.terms<-includeEffects(SAOM.terms,egoX,altX,absDiffX,interaction1="Alcohol")
SAOM.terms<-includeEffects(SAOM.terms,egoX,altX,sameX,interaction1="Behavior")



###Now let's specify the BEHAVIOR function
SAOM.terms<-includeEffects(SAOM.terms,effFrom,name="Behavior",
                           interaction1="Alcohol")
SAOM.terms<-includeEffects(SAOM.terms,totSim,name="Behavior",
                           interaction1="Network")
SAOM.terms<-includeEffects(SAOM.terms,isolate,
                           name="Behavior",interaction1="Network")



#estimate the model WITHOUT transitive ties

create.model<-sienaAlgorithmCreate(projname="Co-evolution_output",
                                   seed=21093,
                                   nsub=4,
                                   n3=1000)
TLSmodel_notrans<-siena07(create.model,
                  data=SAOM.Data,
                  effects=SAOM.terms,
                  verbose=TRUE,
                  returnDeps=TRUE)


#include transTies
SAOM.terms<-includeEffects(SAOM.terms,transTies,inPop)
TLSmodel<-siena07(create.model,
                  data=SAOM.Data,
                  effects=SAOM.terms,
                  verbose=TRUE,
                  returnDeps=TRUE)





#now fit the TERGM
library(statnet)


net_list<-list(as.network(s501),as.network(s502),as.network(s503))
net_list[[1]]<-network::set.vertex.attribute(net_list[[1]],"smoking",s50s[,1])
net_list[[2]]<-network::set.vertex.attribute(net_list[[2]],"smoking",s50s[,2])
net_list[[3]]<-network::set.vertex.attribute(net_list[[3]],"smoking",s50s[,3])
net_list[[1]]<-network::set.vertex.attribute(net_list[[1]],"alcohol",s50a[,1])
net_list[[2]]<-network::set.vertex.attribute(net_list[[2]],"alcohol",s50a[,2])
net_list[[3]]<-network::set.vertex.attribute(net_list[[3]],"alcohol",s50a[,3])


TERGM_1_nogwesp<-tergm(net_list~Form(
  ~edges+
    mutual+
    gwidegree(.5,fixed=TRUE)+
    nodeicov("smoking")+
    nodeocov("smoking")+
    nodematch("smoking")+
    nodeicov("alcohol")+
    nodeocov("alcohol")+
    absdiff("alcohol")),
  estimate="CMLE"

)


TERGM_1<-tergm(net_list~Form(
  ~edges+
    mutual+
    gwesp(.5,fixed=TRUE)+
    gwidegree(.5,fixed=TRUE)+
    nodeicov("smoking")+
    nodeocov("smoking")+
    nodematch("smoking")+
    nodeicov("alcohol")+
    nodeocov("alcohol")+
    absdiff("alcohol")),
  estimate="CMLE"

)

  #create network autocorrelation function for TERGM
Moran_tergm<-function(x){

  y<-network::get.vertex.attribute(x,"smoking")
  return(nacf(x,y,type="moran",lag=1)[2])

}


#test difference in TERGM and SAOM direct, total, and indirect
  #MEMS estimates

mediate_MEMS(partial_model=TLSmodel_notrans,
             full_model=TLSmodel,
             micro_process="same Behavior",
             macro_function =Moran_dv,
             model_comparison = TRUE,
             partial_model2=TERGM_1_nogwesp,
             full_model2=TERGM_1,
             micro_process2="Form~nodematch.smoking",
             macro_function2=Moran_tergm,
             object_type = "network",
             SAOM_data = SAOM.Data,
             silent=FALSE,
             nsim=100)







netmediate documentation built on June 8, 2025, 1:35 p.m.