/* meta analysis module by Evangelos Kontopantelis creted in STATA v9.2 last update: 19 Aug 2009 */ /*metaeff calculates the effect and SE for each study (if possible)*/ program define metaeff /*stata version define*/ version 9.2 /*command syntax*/ syntax namelist(min=2 max=2) [if] [in], [ni(string) nc(string) i(string) c(string) orval(string) ci95lo(string) /* */ ci95up(string) md(string) meani(string) meanc(string) sdi(string) sdc(string) ci95loi(string) ci95upi(string) /* */ ci95loc(string) ci95upc(string) p(string) t(string)/* */ or owrite infovar] /*rename some variables to less ordinary names to avoid messing up later*/ local nia = "`ni'" local nca = "`nc'" local ia = "`i'" local ca = "`c'" /*temp variables used in all methods*/ tempvar eff seeff uCI95smd lCI95smd denom denomi denomc pia pca sediff rd sd orv q mdv sdia sdca tvaly pvaly z ifvar method /*INITIAL STUFF*/ /*get variable names for effect sizes and SE of effects*/ local var1 = word("`namelist'",1) local var2 = word("`namelist'",2) local var3 = "_method" /*make sure a user doesn't give the same variable names*/ if "`var1'"=="`var2'" { di in red "Output variables need to have different names!" error 110 } /*find out if the variables specified are there and store info in 'exists' variables*/ forvalues i=1(1)3 { capture confirm numeric variable `var`i'', exact local exists`i'=!_rc } /*if one of them is there (or both) end program if overwrite has not been specified. otherwise just warn*/ if `exists1'==1 | `exists2'==1 | (`exists3'==1 & "`infovar'"!="") { if "`owrite'" =="" { if `exists1'==1 | `exists2'==1 { di in red "At least one of the specified variables already exist. Either use different names or the overwrite option" } if (`exists3'==1 & "`infovar'"!="") { di in red "Problem with the infovar option: a variable named '_method' already exists. Either rename it or use the overwrite option" } error 110 } else { di in yellow "At least one of the specified variables already exist. Values in existing variables will be overwritten as selected" } } /*generate the 3 needed variables*/ qui gen `seeff' = . qui gen `eff' = . qui gen str3 `method' = "" scalar execm = 0 /*CALLING APPROPRIATE METHOD*/ /*method 7 - Mean Difference method requiring NI, NC and P-value (or t-value) for two sample t-test*/ if "`nia'"!="" & "`nca'"!="" & ("`p'"!="" | "`t'"!="") { /*verify variables are there and numeric*/ foreach x in `nia' `nca' `md' `meani' `meanc' `p' `t' { confirm numeric variable `x', exact } /*dealing with p and t*/ if "`t'"!="" { /*if t provided use value to create tempvar `pvaly'*/ qui gen `pvaly'= 2*ttail(`nia'+`nca'-2, `t') /*if p provided as well copy cases where t is missing*/ if "`p'"!="" { qui replace `pvaly' = `p' if `pvaly'==. } } else { /*if t not provided, use p value*/ qui gen `pvaly' = `p' } /*calculate z value*/ qui gen `z' = abs(invnormal(`pvaly'/2)) /*effect and SE*/ qui replace `seeff' = sqrt(1/`nia' + 1/`nca') if `nia'!=. & `nca'!=. & `z'!=. qui replace `eff' = `z'*`seeff' if `nia'!=. & `nca'!=. & `z'!=. qui replace `method' = "7" if `nia'!=. & `nca'!=. & `z'!=. qui drop `z' `pvaly' scalar execm = 1 } /*method 6 - Mean Difference method requiring NI, NC, MD (or two means) and P-value (or-tvalue) for two sample t-test*/ if "`nia'"!="" & "`nca'"!="" & ("`md'"!="" | ("`meani'"!="" & "`meanc'"!="")) & ("`p'"!="" | "`t'"!="") { /*verify variables are there and numeric*/ foreach x in `nia' `nca' `md' `meani' `meanc' `p' `t'{ confirm numeric variable `x', exact } /*dealing with MD*/ if "`md'"!="" { /*if MD provided copy to temp variable `mdv'*/ qui gen `mdv'= `md' /*if means provided as well copy cases where MD is missing*/ if "`meani'"!="" & "`meanc'"!="" { qui replace `mdv' = `meani' - `meanc' if `mdv'==. } } else { /*if MD not provided, generate from means*/ qui gen `mdv' = `meani' - `meanc' } /*dealing with p and t*/ if "`t'"!="" { /*if t provided copy to temp variable `tvaly'*/ qui gen `tvaly'= `t' /*if p provided as well copy cases where t is missing*/ if "`p'"!="" { qui replace `tvaly' = invttail(`nia'+`nca'-2, `p'/2) if `tvaly'==. } } else { /*if tval not provided, generate from pvalue*/ qui gen `tvaly' = invttail(`nia'+`nca'-2, `p'/2) } /*calculate SE of the difference from p value*/ qui gen `sediff' = `mdv'/`tvaly' /*effect, its SE and SD*/ qui replace `seeff' = sqrt(1/`nia' + 1/`nca') if `nia'!=. & `nca'!=. & `sediff'!=. qui gen `sd' = `sediff'/`seeff' qui replace `eff' = `mdv'/`sd' if `nia'!=. & `nca'!=. & `sediff'!=. qui replace `method' = "6" if `nia'!=. & `nca'!=. & `sediff'!=. qui drop `sediff' `sd' `tvaly' `mdv' scalar execm = 1 } /*method 3 - Mean Difference method requiring NI, NC, MD (or two means) and CI95%(MD)*/ if "`nia'"!="" & "`nca'"!="" & "`ci95lo'"!="" & "`ci95up'"!="" & ("`md'"!="" | ("`meani'"!="" & "`meanc'"!="")) { /*verify variables are there and numeric*/ foreach x in `nia' `nca' `ci95lo' `ci95up' `md' `meani' `meanc' { confirm numeric variable `x', exact } /*if MD provided copy to temp variable `mdv'*/ if "`md'"!="" { qui gen `mdv'= `md' /*if means provided as well copy cases where MD is missing*/ if "`meani'"!="" & "`meanc'"!="" { qui replace `mdv' = `meani' - `meanc' if `mdv'==. } } /*if MD not provided, generate from means*/ else { qui gen `mdv' = `meani' - `meanc' } /*different denominator based on sizes - normal approximation or not*/ qui gen `denom' = 3.92 if `nia'<60 | `nca'<60 { qui replace `denom' = 2*invttail(`nia'+`nca'-2, 0.025) } /*calculate SE of the difference from confidence interval*/ qui gen `sediff' = (`ci95up'-`ci95lo')/`denom' /*effect, its SE and SD*/ qui replace `seeff' = sqrt(1/`nia' + 1/`nca') if `nia'!=. & `nca'!=. & `sediff'!=. & `mdv'!=. qui gen `sd' = `sediff'/`seeff' qui replace `eff' = `mdv'/`sd' if `nia'!=. & `nca'!=. & `sediff'!=. & `mdv'!=. qui replace `method' = "3" if `nia'!=. & `nca'!=. & `sediff'!=. & `mdv'!=. qui drop `sediff' `sd' `denom' `mdv' scalar execm = 1 } /*method 5 - Mean Difference method requiring NI, NC, MD (or two means), CI(I) & CI(C)*/ if "`nia'"!="" & "`nca'"!="" & "`ci95loi'"!="" & "`ci95loc'"!="" & "`ci95upi'"!="" & "`ci95upc'"!="" /* */ & ("`md'"!="" | ("`meani'"!="" & "`meanc'"!="")) { /*verify variables are there and numeric*/ foreach x in `nia' `nca' `ci95loi' `ci95loc' `ci95upi' `ci95upc' `md' `meani' `meanc' { confirm numeric variable `x', exact } /*if MD provided copy to temp variable `mdv'*/ if "`md'"!="" { qui gen `mdv'= `md' /*if means provided as well copy cases where MD is missing*/ if "`meani'"!="" & "`meanc'"!="" { qui replace `mdv' = `meani' - `meanc' if `mdv'==. } } /*if MD not provided, generate from means*/ else { qui gen `mdv' = `meani' - `meanc' } /*different denominator based on sizes - normal approximation or not*/ qui gen `denomi' = 3.92 if `nia'<60 qui replace `denomi' = 2*invttail(`nia'-1, 0.025) qui gen `denomc' = 3.92 if `nca'<60 qui replace `denomc' = 2*invttail(`nca'-1, 0.025) /*calculate SDs from confidence intervals*/ qui gen `sdia' = sqrt(`nia')*(`ci95upi'-`ci95loi')/`denomi' qui gen `sdca' = sqrt(`nca')*(`ci95upc'-`ci95loc')/`denomc' /*overall SD calculation*/ qui gen `sd' = sqrt((`sdia'^2*`nia' + `sdca'^2*`nca')/(`nia'+`nca')) /*effect and its SE*/ qui replace `eff' = `mdv'/`sd' if `nia'!=. & `nca'!=. & `mdv'!=. & `sd'!=. qui replace `seeff' = sqrt(1/`nia' + 1/`nca') if `nia'!=. & `nca'!=. & `mdv'!=. & `sd'!=. qui replace `method' = "5" if `nia'!=. & `nca'!=. & `mdv'!=. & `sd'!=. qui drop `sd' `sdia' `sdca' `denomi' `denomc' `mdv' scalar execm = 1 } /*method 4 - Mean Difference method requiring NI, NC, MD (or two means), SD(I) & SD(C)*/ if "`nia'"!="" & "`nca'"!="" & "`sdi'"!="" & "`sdc'"!="" & ("`md'"!="" | ("`meani'"!="" & "`meanc'"!="")) { /*verify variables are there and numeric*/ foreach x in `nia' `nca' `sdi' `sdc' `md' `meani' `meanc' { confirm numeric variable `x', exact } /*if MD provided copy to temp variable `mdv'*/ if "`md'"!="" { qui gen `mdv'= `md' /*if means provided as well copy cases where MD is missing*/ if "`meani'"!="" & "`meanc'"!="" { qui replace `mdv' = `meani' - `meanc' if `mdv'==. } } /*if MD not provided, generate from means*/ else { qui gen `mdv' = `meani' - `meanc' } /*overall SD calculation*/ qui gen `sd' = sqrt((`sdi'^2*(`nia'-1) + `sdc'^2*(`nca'-1))/(`nia'+`nca'-2)) /*effect and its SE*/ qui replace `eff' = `mdv'/`sd' if `nia'!=. & `nca'!=. & `mdv'!=. & `sd'!=. qui replace `seeff' = sqrt(1/`nia' + 1/`nca') if `nia'!=. & `nca'!=. & `mdv'!=. & `sd'!=. qui replace `method' = "4" if `nia'!=. & `nca'!=. & `mdv'!=. & `sd'!=. qui drop `sd' `mdv' scalar execm = 1 } /*method 1b - Odds Ratio method requiring NI, NC, I and C and used only if has been specifically selected over RD method 1a*/ if "`nia'"!="" & "`nca'"!="" & "`ia'"!="" & "`ca'"!="" & "`or'"!="" { /*verify variables are there and numeric*/ foreach x in `nia' `nca' `ia' `ca' { confirm numeric variable `x', exact } /*odds ratio calculations*/ qui gen `orv' = (`ia'/(`nia'-`ia')) / (`ca'/(`nca'-`ca')) qui gen `q' = ln(`orv') qui gen `sediff' = sqrt(1/`ia' + 1/(`nia'-`ia') + 1/`ca' + 1/(`nca'-`ca')) /*effect and its SE*/ qui replace `eff' = (sqrt(3)/_pi) * `q' if `q'!=. & `sediff'!=. qui replace `seeff' = (sqrt(3)/_pi) * `sediff' if `q'!=. & `sediff'!=. qui replace `method' = "1b" if `q'!=. & `sediff'!=. qui drop `orv' `q' `sediff' scalar execm = 1 } /*method 1a - Risk Difference method requiring NI, NC, I and C and used as default unless OR 1b has been specifically selected*/ if "`nia'"!="" & "`nca'"!="" & "`ia'"!="" & "`ca'"!="" & "`or'"=="" { /*verify variables are there and numeric*/ foreach x in `nia' `nca' `ia' `ca' { confirm numeric variable `x', exact } /*percentages*/ qui gen `pia' = `ia' / `nia' qui gen `pca' = `ca' / `nca' /*SE of the difference*/ qui gen `sediff' = sqrt(`pia'*(1-`pia')/`nia'+`pca'*(1-`pca')/`nca') /*risk difference*/ qui gen `rd' = `ia'/`nia'-`ca'/`nca' /*effect and its SE - using SD as well*/ qui replace `seeff' = sqrt(1/`nia'+1/`nca') if `nia'!=. & `nca'!=. & `rd'!=. & `sediff'!=. qui gen `sd' = `sediff'/`seeff' qui replace `eff' = `rd'/`sd' if `nia'!=. & `nca'!=. & `rd'!=. & `sediff'!=. qui replace `method' = "1a" if `nia'!=. & `nca'!=. & `rd'!=. & `sediff'!=. qui drop `pia' `pca' `rd' `sediff' `sd' scalar execm = 1 } /*method 2 - Odds Ratio method requiring NI, NC, OR and CI95%(OR)*/ if "`nia'"!="" & "`nca'"!="" & "`orval'"!="" & "`ci95lo'"!="" & "`ci95up'"!="" { /*verify variables are there and numeric*/ foreach x in `nia' `nca' `orval' `ci95lo' `ci95up' { confirm numeric variable `x', exact } /*lower and upper CI for Standardised Mean Difference*/ qui gen `uCI95smd' = (sqrt(3)/_pi)*ln(`ci95up') qui gen `lCI95smd' = (sqrt(3)/_pi)*ln(`ci95lo') /*different denominator based on sizes - normal approximation or not*/ qui gen `denom' = 3.92 if `nia'<60 | `nca'<60 { qui replace `denom' = 2*invttail(`nia'+`nca'-2, 0.025) } qui replace `eff' = (sqrt(3)/_pi)*ln(`orval') if `orval'!=. & `uCI95smd'!=. & `lCI95smd'!=. & `denom'!=. qui replace `seeff' = (`uCI95smd' - `lCI95smd')/`denom' if `orval'!=. & `uCI95smd'!=. & `lCI95smd'!=. & `denom'!=. qui replace `method' = "2" if `orval'!=. & `uCI95smd'!=. & `lCI95smd'!=. & `denom'!=. qui drop `uCI95smd' `lCI95smd' `denom' scalar execm = 1 } /*if no method is selected*/ if execm==0 { di in red "No method selected: not enough input variables. Please refer to the help file for more details" error 110 } /*if program proceeds this far all went OK and we can create the final variables from the temp ones*/ qui gen `ifvar'=0 /*ifvar needed in case user gives "if eff==." or "if seeff==." a way to update eff & seeff simultaneously*/ qui replace `ifvar'=1 `if' /*final effect*/ qui capture gen `var1'=. qui replace `var1' = `eff' `in' if `ifvar'==1 label var `var1' "effect sizes" /*final SE of the effect*/ qui capture gen `var2'=. qui replace `var2' = `seeff' `in' if `ifvar'==1 label var `var2' "SE of the effect sizes" /*final information on method variable*/ if "`infovar'"!="" { qui capture gen str3 _method="" qui replace _method = `method' `in' if `ifvar'==1 label var _method "selected effect size estimation method" } /*see if dichotomous methods had be used and warn about transformation*/ //qui count if _method=="1b" | _method=="2" di in yellow "Warning: Transformation to SMD (via Odds Ratios, methods 1b and/or 2) took place in certain cases." di in yellow _col(10) "If you want to meta-analyse dichotomous outcomes only, please use metan to estimate the effects" end