Version info: Code for this page was tested in Stata 12.1.
This code fragment page shows an example using Mata to write a function that calculates the SRMR by comparing the expected covariance from a saturated model to that of the model of interest. Thus it generalizes to models with non complete data.
mata /* mata function to calculate the SRMR given the expected covariance matrix under the saturated model and model of interest */ real scalar srmr(string scalar saturated, /// string scalar model) { sat = st_matrix(saturated) /*read in matrices */ mod = st_matrix(model) res = corr(sat) :- corr(mod) /*covar to cor and diff*/ n = cols(res) /*n manifest vars*/ res = lowertriangle(res) /*extract lower triangle including diag*/ std = sqrt((2 * sum(res :* res))/(n * (n + 1))) /*the SRMR*/ return(std) } /* function to calculate covariance of data matrix using an N rather than N - 1 matrix to match Stata's sem */ real matrix cov(string scalar varlist) { X = st_data(., varlist) n = rows(X) one = J(n, 1, 1) X = X - one * one' * X :* (1/n) Sigma = X'X :* (1/n) return(Sigma) } end /*load a built in Stata dataset*/ sysuse auto, clear /*Our first goal is to demonstrate that A: under a properly parameterized saturated model with complete data, $E(hat{Sigma} | theta) = Sigma$ B: ignoring the first moments, the above mata function, srmr, is equivalent to Stata's internal calculations */ /* saturated model */ quietly sem (<- price mpg weight), nomeans quietly estat framework, fitted mat satSigma = r(Sigma) /*store model expected covariance matrix*/ /*note that these two covariance matrices are identical */ mat list satSigma /*from the model*/ symmetric satSigma[3,3] observed: observed: observed: price mpg weight observed:price 8581964.8 observed:mpg -7888.225 33.019722 observed:weight 1217990 -3580.3798 595867.28 mata cov("price mpg weight") /*from the data*/ [symmetric] 1 2 3 +----------------------------------------------+ 1 | 8581964.812 | 2 | -7888.224982 33.01972243 | 3 | 1217990.004 -3580.379839 595867.2754 | +----------------------------------------------+ /*fit the model of interest and extract the expected covariance matrix. This is a dull model, but it serves its pedogogical purpose*/ quietly sem (price mpg <- weight), nomeans quietly estat framework, fitted mat mSigma = r(Sigma) /*because we have complete data, we can compare Stata's SRMR estimate with that of the srmr function*/ quietly estat gof, stats(res) display r(srmr) .01381637 mata srmr("satSigma", "mSigma") .0138163701 /*This method generalizes to non complete data however, the 'sample' covariance matrix, is not longer observed but estimated, and note we do not residuals separately for different missing data patterns*/ /*add some missingness (how much is irrelevant)*/ replace price = . in 1/10 /*fit a saturated model on all data using maximum likelihood again we use estat framework, fitted to get the expected covariance matrix under the model which becomes our reference for srmr*/ quietly sem (<- price mpg weight), method(mlmv) quietly estat framework, fitted mat satSigma = r(Sigma) /*fit model of interest on all data using maximum likelihood*/ quietly sem (price mpg <- weight), method(mlmv) quietly estat framework, fitted mat mSigma = r(Sigma) /*calculate SRMR, in this case the standardized root mean residual from a saturated model (not necessarily reality)*/ mata srmr("satSigma", "mSigma") .0154135804