From 23366d4fedefe8c0e46237eba88e8864ce241f98 Mon Sep 17 00:00:00 2001 From: Andrea Discacciati Date: Mon, 26 Nov 2018 09:38:11 +0100 Subject: [PATCH] minor changes, v2.2.3 --- README.md | 4 +- med4way.ado | 16 ++- med4way.pkg | 4 +- med4way.sthlp | 14 +-- med4way_engine.ado | 265 ++++++++------------------------------------- 5 files changed, 72 insertions(+), 231 deletions(-) diff --git a/README.md b/README.md index 54a40e1..27ea9d1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # med4way ### A Stata command for the 4-way decomposition using parametric regression models -- Current version: `2.2.2` -- Release date: `14jun2018` +- Current version: `2.2.3` +- Release date: `25nov2018` --- diff --git a/med4way.ado b/med4way.ado index 8ddb670..a476002 100644 --- a/med4way.ado +++ b/med4way.ado @@ -1,8 +1,9 @@ *! Hello, I'm med4way.ado -*! v2.2.2 - 14jun2018 +*! v2.2.3 - 25nov2018 /* Previous versions: +v2.2.2 - 14jun2018 v2.2.1 - 19sep2017 v2.2.0 - 31jul2017 v2.1.1 - 28jul2017 @@ -246,6 +247,13 @@ program define med4way, eclass } } + //casecontrol works only with yreg logistic + if ("`casecontrol'"=="true") & !("`yreg'"=="logistic") { + display as error "Error: option casecontrol can only be specified together with a " /* + */ "logistic regression model for the outcome (yreg)." + error 198 + } + //validate rare outcome if ("`yreg'"=="logistic") { if "`casecontrol'"=="true" { @@ -615,9 +623,13 @@ program define validate_c, rclass // c_local eretc "`c'" // c used in med4way's ereturn c_local wrnngtxt `wrnngtxt' + mata: st_local("c_missing", strofreal(hasmissing(strtoreal(tokens(st_local("c")))))) // check that there are no missing values in c. It happens for example if c() contains strings. + if (`c_missing' == 1) { + di as error "Error: please, check the option c(). It must contain only numbers and/or dots (.)" + error 198 + } tempname cmatrix // c needs to be a matrix to pass it on to mata -> dump c into cmatrix mata: st_matrix("`cmatrix'", strtoreal(tokens(st_local("c")))) - return mat cmatrix = `cmatrix' end validate_c diff --git a/med4way.pkg b/med4way.pkg index cb46930..ce40e14 100644 --- a/med4way.pkg +++ b/med4way.pkg @@ -6,8 +6,8 @@ d A.Discacciati, A.Bellavia, L.Valeri d d After installation, see help med4way d -d Current version: 2.2.2 -d Distribution-Date: 14jun2018 +d Current version: 2.2.3 +d Distribution-Date: 25nov2018 d f med4way.ado f med4way_engine.ado diff --git a/med4way.sthlp b/med4way.sthlp index 410ad93..8ce8a8f 100644 --- a/med4way.sthlp +++ b/med4way.sthlp @@ -1,5 +1,5 @@ {smcl} -{* *! version 2.2.2 14jun2018}{...} +{* *! version 2.2.3 25nov2018}{...} {cmd:help med4way} {hline} @@ -91,22 +91,22 @@ Note: the 4-way decomposition holds without any assumptions about confounding. H {p 7 6 2}{opt logb:inomial}: logbinomial regression (GLM with binomial distribution and log link function){p_end} {p 7 6 2}{opt poi:sson}: Poisson regression{p_end} {p 7 6 2}{opt negb:inomial}: negative binomial regression{p_end} -{p 7 6 2}{opt aft, {ul on}e{ul off}xponential}: Accelerated Failure Time (exponential survival distribution) ({helpb stset} required){p_end} -{p 7 6 2}{opt aft, {ul on}w{ul off}eibull}: Accelerated Failure Time (Weibull survival distribution) ({helpb stset} required){p_end} -{p 7 6 2}{opt cox}: Cox proportional hazards model ({helpb stset} required){p_end} +{p 7 6 2}{opt aft, {ul on}e{ul off}xponential}: Accelerated Failure Time regression (exponential distribution) ({helpb stset} required){p_end} +{p 7 6 2}{opt aft, {ul on}w{ul off}eibull}: Accelerated Failure Time regression (Weibull distribution) ({helpb stset} required){p_end} +{p 7 6 2}{opt cox}: Cox proportional hazards regression ({helpb stset} required){p_end} {phang} {opt mreg(string)} specifies the form of the regression model for the mediator. The available forms are: {p 7 6 2}{opt lin:ear}: linear regression{p_end} -{p 7 6 2}{opt logi:stic}: logistic regression regression{p_end} +{p 7 6 2}{opt logi:stic}: logistic regression{p_end} {phang} {opt c(string)} fixes the values of the covariates {it:cvars} at which to compute the 4-way decomposition. If {it:cvars} are specified but this option is omitted, {it:cvars} will be automatically fixed at their respective mean values. If this option is specified, the number of values of {opt c(numlist)} must correspond to the number of {it:cvars}. A dot (.) can be used to fix the value of a specific covariate to its mean. Example: the covariates specified are {it:cvar1 cvar2 cvar3} and the user wants to fix the value for {it:cvar2} to 6, while letting the values for {it:cvar1} and {it:cvar3} to be equal to their respective means. This can be achieved with the option {opt c(. 6 .)}. {phang} -{opt casec:ontrol} specifies that the data comes from a case-control study (that is, sampling was done on the outcome). +{opt casec:ontrol} specifies that the data comes from a case-control study (that is, sampling was done on the outcome). This option can be specified only together with a logistic regression model for the outcome. {phang} {opt full:output} specifies that, in addition to the 4 components of the total effect (controlled direct effect, reference interaction, mediated interaction, pure indirect effect), the following quantities are to be estimated: the proportions of the total effect due to each of the 4 components, the overall proportion mediated, the overall proportion due to interaction, and the overall proportion that would be eliminated if the mediator {it:mvar} were fixed to the value {opt m(#)}. @@ -245,7 +245,7 @@ For example, to calculate the overall proportion mediated (op_m){p_end} {title:References} -{phang}Discacciati, A., Bellavia, A., Lee, J.J., Mazumdar, M., Valeri, L., 2018. Med4way: a Stata command to investigate mediating and interactive mechanisms using the four-way effect decomposition. International Journal of Epidemiology. +{phang}Discacciati, A., Bellavia, A., Lee, J.J., Mazumdar, M., Valeri, L., 2018. Med4way: a Stata command to investigate mediating and interactive mechanisms using the four-way effect decomposition. International Journal of Epidemiology. doi: 10.1093/ije/dyy236 {phang}VanderWeele, T.J., 2014. A unification of mediation and interaction: a 4-way decomposition. Epidemiology (Cambridge, Mass.), 25(5), p.749. diff --git a/med4way_engine.ado b/med4way_engine.ado index ada93db..482f5e7 100644 --- a/med4way_engine.ado +++ b/med4way_engine.ado @@ -21,236 +21,65 @@ program define med4way_engine, eclass local titlem `"_n(2) as text "-> Model for the mediator""' tempname Vy betay Vm betam - - // Each block is a combination of a different yreg/mreg. There are 7 yreg - // and 2 mreg = 14 blocks in total - // Block 1: yreg=linear, mreg=linear - if (("`yreg'"=="linear") & ("`mreg'"=="linear")) { - display `titley' + // Models for the outcome (7) + display `titley' + if ("`yreg'"=="linear") { // 1 linear regress `yvar' `avar' `mvar' `inter' `cvar' if `touse', level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - - display `titlem' - regress `mvar' `avar' `cvar' if `touse', level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 1 + } + else if ("`yreg'"=="logistic") { // 2 logit + logit `yvar' `avar' `mvar' `inter' `cvar' if `touse', level(`level') + } + else if ("`yreg'"=="cox") { // 3 cox + stcox `avar' `mvar' `inter' `cvar' if `touse', level(`level') + } + else if ("`yreg'"=="aft") { // 4 aft + streg `avar' `mvar' `inter' `cvar' if `touse', time dist(`dist') level(`level') + } + else if ("`yreg'"=="logbinomial") { // 5 logbinomial + glm `yvar' `avar' `mvar' `inter' `cvar' if `touse', family(binomial) /* + */ link(log) irls level(`level') vce(oim) + } + else if ("`yreg'"=="poisson") { // 6 poisson + poisson `yvar' `avar' `mvar' `inter' `cvar' if `touse', `robust' level(`level') + } + else if ("`yreg'"=="negbinomial") { // 7 negbinomial + nbreg `yvar' `avar' `mvar' `inter' `cvar' if `touse', level(`level') + } - // Block 2: yreg=linear, mreg=logistic - else if (("`yreg'"=="linear") & ("`mreg'"=="logistic")) { - display `titley' - regress `yvar' `avar' `mvar' `inter' `cvar' if `touse', level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - - display `titlem' - logit `mvar' `avar' `cvar' if `touse', level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) + // Store e(b) and e(V) for the model for the outcome + matrix `Vy' = e(V) + matrix `betay' = e(b) + if ((("`yreg'"=="aft") & ("`dist'"=="weibull")) | ("`yreg'"=="negbinomial")) { // drop ancillary parameters (move to m4w_deriv?) + matrix `Vy' = `Vy'[1..colsof(`Vy')-1, 1..colsof(`Vy')-1] + matrix `betay' = `betay'[1, 1..colsof(`betay')-1] } - // End of Block 2 - - // Block 3: yreg=logistic, mreg=linear - else if (("`yreg'"=="logistic") & ("`mreg'"=="linear")) { - display `titley' - logit `yvar' `avar' `mvar' `inter' `cvar' if `touse', level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - display `titlem' - if "`casecontrol'"=="true" { + // Models for the mediator (2) + display `titlem' + if ("`mreg'"=="linear") { // 1 linear + if ("`casecontrol'"=="true") { regressml `mvar' `avar' `cvar' if `yvar' == 0 & `touse', /* */ onlybeta(`bootstrap') level(`level') } - else if "`casecontrol'"=="false" { + else if ("`casecontrol'"=="false") { regressml `mvar' `avar' `cvar' if `touse', /* */ onlybeta(`bootstrap') level(`level') } - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 3 - - // Block 4: yreg=logistic, mreg=linear - else if (("`yreg'"=="logistic") & ("`mreg'"=="logistic")) { - display `titley' - logit `yvar' `avar' `mvar' `inter' `cvar' if `touse', level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - - display `titlem' - if "`casecontrol'"=="true" { + } + else if ("`mreg'"=="logistic") { // 2 logit + if ("`casecontrol'"=="true") { logit `mvar' `avar' `cvar' if `yvar' == 0 & `touse', level(`level') } - else if "`casecontrol'"=="false" { + else if ("`casecontrol'"=="false") { logit `mvar' `avar' `cvar' if `touse', level(`level') } - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 4 - - // Block 5: yreg=cox, mreg=linear - else if (("`yreg'"=="cox") & ("`mreg'"=="linear")) { - display `titley' - stcox `avar' `mvar' `inter' `cvar' if `touse', level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - - display `titlem' - regressml `mvar' `avar' `cvar' if `touse', /* - */ onlybeta(`bootstrap') level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 5 - - // Block 6: yreg=cox, mreg=logistic - else if (("`yreg'"=="cox") & ("`mreg'"=="logistic")) { - display `titley' - stcox `avar' `mvar' `inter' `cvar' if `touse', nohr level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - - display `titlem' - logit `mvar' `avar' `cvar' if `touse', level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 6 + } - // Block 7: yreg=aft, mreg=linear - else if (("`yreg'"=="aft") & ("`mreg'"=="linear")) { - display `titley' - streg `avar' `mvar' `inter' `cvar' if `touse', time dist(`dist') level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - if "`dist'"=="weibull" { // drop ancillary parameters - matrix `Vy' = `Vy'[1..colsof(`Vy')-1, 1..colsof(`Vy')-1] - matrix `betay' = `betay'[1, 1..colsof(`betay')-1] - } + // Store e(b) and e(V) for the model for the mediator + matrix `Vm' = e(V) + matrix `betam' = e(b) - display `titlem' - regressml `mvar' `avar' `cvar' if `touse', /* - */ onlybeta(`bootstrap') level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 7 - - // Block 8: yreg=aft, mreg=logistic - else if (("`yreg'"=="aft") & ("`mreg'"=="logistic")) { - display `titley' - streg `avar' `mvar' `inter' `cvar' if `touse', time dist(`dist') level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - if "`dist'"=="weibull" { // drop ancillary parameters - matrix `Vy' = `Vy'[1..colsof(`Vy')-1, 1..colsof(`Vy')-1] - matrix `betay' = `betay'[1, 1..colsof(`betay')-1] - } - - display `titlem' - logit `mvar' `avar' `cvar' if `touse', level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 8 - - // Block 9: yreg=logbinomial, mreg=linear - else if (("`yreg'"=="logbinomial") & ("`mreg'"=="linear")) { - display `titley' - glm `yvar' `avar' `mvar' `inter' `cvar' if `touse', family(binomial) /* - */ link(log) ml level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - - display `titlem' - regressml `mvar' `avar' `cvar' if `touse', /* - */ onlybeta(`bootstrap') level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 9 - - // Block 10: yreg=logbinomial, mreg=logistic - else if (("`yreg'"=="logbinomial") & ("`mreg'"=="logistic")) { - display `titley' - glm `yvar' `avar' `mvar' `inter' `cvar' if `touse', family(binomial) /* - */ link(log) ml level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - - display `titlem' - logit `mvar' `avar' `cvar' if `touse', level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 10 - - // Block 11: yreg=poisson, mreg=linear - else if (("`yreg'"=="poisson") & ("`mreg'"=="linear")) { - display `titley' - poisson `yvar' `avar' `mvar' `inter' `cvar' if `touse', `robust' level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - - display `titlem' - regressml `mvar' `avar' `cvar' if `touse', /* - */ onlybeta(`bootstrap') level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 11 - - // Block 12: yreg=poisson, mreg=logistic - else if (("`yreg'"=="poisson") & ("`mreg'"=="logistic")) { - display `titley' - poisson `yvar' `avar' `mvar' `inter' `cvar' if `touse', `robust' level(`level') - matrix `Vy' = e(V) - matrix `betay' = e(b) - - display `titlem' - logit `mvar' `avar' `cvar' if `touse', level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 12 - - // Block 13: yreg=negbinomial, mreg=linear - else if (("`yreg'"=="negbinomial") & ("`mreg'"=="linear")) { - display `titley' - nbreg `yvar' `avar' `mvar' `inter' `cvar' if `touse', level(`level') - matrix `Vy' = e(V) - matrix `Vy' = `Vy'[1..colsof(`Vy')-1, 1..colsof(`Vy')-1] // drop ancillary parameters - matrix `betay' = e(b) - matrix `betay' = `betay'[1, 1..colsof(`betay')-1] // drop ancillary parameters - - display `titlem' - regressml `mvar' `avar' `cvar' if `touse', /* - */ onlybeta(`bootstrap') level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 13 - - // Block 14: yreg=negbinomial, mreg=logistic - else if (("`yreg'"=="negbinomial") & ("`mreg'"=="logistic")) { - display `titley' - nbreg `yvar' `avar' `mvar' `inter' `cvar' if `touse', level(`level') - matrix `Vy' = e(V) - matrix `Vy' = `Vy'[1..colsof(`Vy')-1, 1..colsof(`Vy')-1] // drop ancillary parameters - matrix `betay' = e(b) - matrix `betay' = `betay'[1, 1..colsof(`betay')-1] // drop ancillary parameters - - display `titlem' - logit `mvar' `avar' `cvar' if `touse', level(`level') - matrix `Vm' = e(V) - matrix `betam' = e(b) - } - // End of Block 14 ******************************************************************************** @@ -304,7 +133,7 @@ program define regressml, eclass marksample touse - if "`onlybeta'" == "" local onlybeta "false" + if ("`onlybeta'" == "") local onlybeta "false" gettoken dep indep: varlist @@ -314,7 +143,7 @@ program define regressml, eclass matrix colnames `sigma2reg' = "sigma2:_cons" local nm = e(N) - if "`onlybeta'"=="false" { + if ("`onlybeta'"=="false") { tempname breg matrix `breg' = e(b) matrix coleq `breg' = "mu" @@ -326,11 +155,11 @@ program define regressml, eclass } tempname bML VML - if "`onlybeta'" =="false" { + if ("`onlybeta'" =="false") { matrix `bML' = e(b) matrix `VML' = e(V) } - else if "`onlybeta'"== "true" { + else if ("`onlybeta'"== "true") { matrix `bML' = e(b), `sigma2reg' matrix `VML' = J(colsof(e(b))+1, colsof(e(b))+1, 0) @@ -392,7 +221,7 @@ void function m4w_deriv(real vector betay, real vector betam, /* /********************** * m4w_formulas (mata) **********************/ -void m4w_formulas(real vector b, real vector c, /* +void function m4w_formulas(real vector b, real vector c, /* */ real scalar nc, string scalar yreg, string scalar mreg, /* */ real vector aam, string scalar output, v) {