*! version 1.0.0 25jun2024 // Daniel Klein & Ariel Linden program r2_nakagawa , rclass version 16.1 syntax // nothing allowed if ("`e(cmd)'" != "mixed") { display as err "r2_nakagawa is only valid after {bf:mixed}" exit 321 } re_equation_no_fv_or_ts_varlist quietly estat recovariance // error for single-level models intended /* Do not call any commands that return r() after the call to -estat recovariance- ! */ tempvar esample xb cons quietly { generate double `esample' = e(sample) predict `xb' if `esample' , xb generate byte `cons' = 1 } tempname Var_e // variance of the residual scalar `Var_e' = exp(_b[/lnsig_e])^2 mata : r2_nakagawa( /// "`xb'", /// "`esample'", /// "`cons'", /// st_numscalar("`Var_e'") /// ) return add display display as txt "Nakagawa's R-squared for Mixed Models" display display as txt %31s "Conditional R-squared: " as res %5.4f return(r2_c) display as txt %31s "Marginal R-squared: " as res %5.4f return(r2_m) end program re_equation_no_fv_or_ts_varlist local e_revars = subinstr(subinstr(" `e(revars)' "," "," ",.)," _cons ","",.) // sic! local e_revars `e_revars' // strip leading and trailing whitespaces if ("`e_revars'" == "") /// random intercepts only exit local e_revars = ustrtrim(ustrregexra("`e_revars'","R\.\S+","")) if ("`e_revars'" == "") /// random intercepts or R.varname only exit fvexpand `e_revars' if ( !inlist("true","`r(fvops)'","`r(tsops)'") ) /// no fv or ts operators exit display as err "{bf:r2_nakagawa} does not support" /// " factor variable and time-series operators in {it:re_equation}" exit 321 end version 16.1 mata : mata set matastrict on mata set mataoptimize on void r2_nakagawa( string scalar xb, string scalar esample, string scalar cons, real scalar Var_e ) { real scalar Var_fe real scalar Var_re real scalar r2_c real scalar r2_m // variance of the fixed effects Var_fe = variance(st_data(.,xb,esample)) // variance of the random effects Var_re = Var_re(cons,esample) // conditional R^2 r2_c = (Var_fe + Var_re) / (Var_fe + Var_re + Var_e) // marginal R^2 r2_m = (Var_fe ) / (Var_fe + Var_re + Var_e) st_rclear() st_numscalar("r(Var_e)",Var_e) st_numscalar("r(Var_re)",Var_re) st_numscalar("r(Var_fe)",Var_fe) st_numscalar("r(r2_m)",r2_m) st_numscalar("r(r2_c)",r2_c) } real scalar Var_re( string scalar cons, string scalar esample ) { real scalar Var_re string rowvector e_revars real colvector revars_idx real scalar k real scalar i real matrix Sigma string rowvector colnames string rowvector e_revars_i real matrix Z pragma unset Z Var_re = 0 e_revars = tokens(st_global("e(revars)")) revars_idx = (0 \ 0) k = st_numscalar("r(relevels)") for (i=2;i<=k;i++) { Sigma = st_matrix(sprintf("r(Cov%f)",i)) colnames = st_matrixcolstripe(sprintf("r(Cov%f)",i))[,2]' colnames = ustrregexrf(colnames,"^_cons$",cons) revars_idx = ((revars_idx[2]+1) \ (revars_idx[2]+cols(Sigma))) e_revars_i = ustrregexrf(e_revars[|revars_idx|],"^_cons$",cons) if ( any(ustrregexm(e_revars_i,"^R\.")) ) R_varname(e_revars_i,colnames,cons) else if (e_revars_i != colnames) unexpected_error() // NotReached if ( allof(e_revars_i,cons) ) { /* Shortcut for random intercepts or R. notation */ Var_re = Var_re + sum(Sigma) continue } // Johnson (2014, eqn 10 & eqn 11) st_view(Z,.,e_revars_i,esample) Var_re = Var_re + ( trace(Z*Sigma*Z') / rows(Z) ) } return(Var_re) } void R_varname( string rowvector e_revars_i, string rowvector colnames, string scalar cons ) { if (ustrregexrf(e_revars_i,"^R\.","R_") != colnames) unexpected_error() // NotReached e_revars_i = ustrregexrf(e_revars_i,"^R\..*$",cons) } void unexpected_error() { errprintf("unexpected error in {bf:r2_nakagawa}\n") errprintf("variable names in e(revars) do not match") errprintf(" column names of random-effects covariance matrix\n") exit(322) } end exit