Usage and examples
Every form of metest, from the help file, with output
metest [exp] [, options]
metest list, pwcompare [options]exp refers to marginal effects by the # shown in the mecompare table, or by their coefficient names, combined with +, -, *, /, parentheses, or =. A bare number is always an ME number; a literal number is written with a leading # (#2 is the number two, 2 is the second marginal effect). Non-whole numbers are always literals. list lists the marginal effects to compare pairwise, by ME # (1 2 3), as a range (1/3), or by name.
The examples below are the ones in the help file, run in order.
Setup: fit and store two models, then calculate the marginal effects
sysuse nlsw88, clear(NLSW, 1988 extract)
drop if missing(union, married, age, race, wage)(368 observations deleted)
logit union i.married age i.race, vce(robust)Iteration 0: Log pseudolikelihood = -1046.6242
Iteration 1: Log pseudolikelihood = -1038.8701
Iteration 2: Log pseudolikelihood = -1038.8354
Iteration 3: Log pseudolikelihood = -1038.8354
Logistic regression Number of obs = 1,878
Wald chi2(4) = 15.82
Prob > chi2 = 0.0033
Log pseudolikelihood = -1038.8354 Pseudo R2 = 0.0074
------------------------------------------------------------------------------
| Robust
union | Coefficient std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
married |
Married | -0.176 0.114 -1.549 0.121 -0.399 0.047
age | 0.011 0.018 0.637 0.524 -0.024 0.046
|
race |
Black | 0.372 0.120 3.093 0.002 0.136 0.608
Other | 0.553 0.439 1.260 0.208 -0.307 1.412
|
_cons | -1.570 0.711 -2.207 0.027 -2.964 -0.176
------------------------------------------------------------------------------
est store m1
logit union i.married age i.race wage, vce(robust)Iteration 0: Log pseudolikelihood = -1046.6242
Iteration 1: Log pseudolikelihood = -1016.7478
Iteration 2: Log pseudolikelihood = -1016.3517
Iteration 3: Log pseudolikelihood = -1016.3517
Logistic regression Number of obs = 1,878
Wald chi2(5) = 59.14
Prob > chi2 = 0.0000
Log pseudolikelihood = -1016.3517 Pseudo R2 = 0.0289
------------------------------------------------------------------------------
| Robust
union | Coefficient std. err. z P>|z| [95% conf. interval]
-------------+----------------------------------------------------------------
married |
Married | -0.119 0.116 -1.029 0.303 -0.345 0.108
age | 0.013 0.018 0.705 0.481 -0.023 0.048
|
race |
Black | 0.492 0.122 4.025 0.000 0.252 0.732
Other | 0.483 0.482 1.002 0.316 -0.462 1.427
|
wage | 0.084 0.012 6.819 0.000 0.060 0.108
_cons | -2.356 0.739 -3.189 0.001 -3.803 -0.908
------------------------------------------------------------------------------
est store m2
mecompare age i.married, models(m1 m2)Predicting: Pr(union)
Marginal effects and cross-model differences (N_m1=1878) (N_m2=1878)
| ME # Estimate Robust SE P>|z|
---------------------------------+---------------------------------------
age + 1 (centered) |
m1 | 1 0.002 0.003 0.524
m2 | 2 0.002 0.003 0.480
Difference | 3 -0.000 0.001 0.689
---------------------------------+---------------------------------------
married |
Married - Single |
m1 | 4 -0.033 0.021 0.126
m2 | 5 -0.021 0.021 0.308
Difference | 6 -0.011 0.004 0.003
A single marginal effect, by number and by name
metest 1 | estimate se pvalue
---------------------------------+--------------------------------
age |
m1 | 0.002 0.003 0.524
metest age:m1 | estimate se pvalue
---------------------------------+--------------------------------
age |
m1 | 0.002 0.003 0.524
The cross-model difference, three equivalent ways
Note that mecompare already reports it as ME 3.
metest 1 - 2 | estimate se pvalue
---------------------------------+--------------------------------
age |
m1 - m2 | -0.000 0.001 0.689
metest 3 | estimate se pvalue
---------------------------------+--------------------------------
age |
Difference | -0.000 0.001 0.689
metest _b[age:m1] - _b[age:m2] | estimate se pvalue
---------------------------------+--------------------------------
age |
m1 - m2 | -0.000 0.001 0.689
A ratio and an average
Note the # on the divisor of the average, which makes it the number two rather than ME 2.
metest 1 / 2 | estimate se pvalue
---------------------------------+--------------------------------
age |
m1 / m2 | 0.910 0.254 0.000
metest (1 + 2) / #2 | estimate se pvalue
---------------------------------+--------------------------------
age |
(m1 + m2) / 2 | 0.002 0.003 0.501
Scaling by a literal value
10 times the effect for a change in age:
metest 1 * #10 | estimate se pvalue
---------------------------------+--------------------------------
age |
m1 * 10 | 0.021 0.033 0.524
Equality tests, including a joint test and two constraints at once
metest 1 = 2Tests of equality
| chi2 df pvalue
---------------------------------+--------------------------------
age |
m1 = m2 | 0.161 1.000 0.689
metest 1 = 2 = 3Tests of equality
| chi2 df pvalue
---------------------------------+--------------------------------
age |
m1 = m2 = Difference | 0.645 2.000 0.725
metest (1 = 2) (4 = 5)Tests of equality
| chi2 df pvalue
---------------------------------+--------------------------------
(age~1 = age~2)(mar~1 = mar~2) | 9.216 2.000 0.010
Building up a table
Estimates and equality tests are shown in separate tables.
metest, clear
metest 1 - 2 | estimate se pvalue
---------------------------------+--------------------------------
age |
m1 - m2 | -0.000 0.001 0.689
metest 4 - 5, add | estimate se pvalue
---------------------------------+--------------------------------
age |
m1 - m2 | -0.000 0.001 0.689
---------------------------------+--------------------------------
married |
m1 - m2 | -0.011 0.004 0.003
metest 1 = 2, add | estimate se pvalue
---------------------------------+--------------------------------
age |
m1 - m2 | -0.000 0.001 0.689
---------------------------------+--------------------------------
married |
m1 - m2 | -0.011 0.004 0.003
Tests of equality
| chi2 df pvalue
---------------------------------+--------------------------------
age |
m1 = m2 | 0.161 1.000 0.689
Redisplayed at any point, with a title, by typing metest on its own:
metest, title("Age and marriage")Age and marriage
| estimate se pvalue
---------------------------------+--------------------------------
age |
m1 - m2 | -0.000 0.001 0.689
---------------------------------+--------------------------------
married |
m1 - m2 | -0.011 0.004 0.003
Age and marriage
| chi2 df pvalue
---------------------------------+--------------------------------
age |
m1 = m2 | 0.161 1.000 0.689
All six statistics, and a label of your own
metest 1 - 2, stat(all) | estimate se zvalue pvalue ll ul
-------------+-----------------------------------------------------------------
age |
m1 - m2 | -0.000 0.001 -0.401 0.689 -0.001 0.001
metest 1 - 2, rownames("Age effect, m1 vs m2") | estimate se pvalue
---------------------------------+--------------------------------
Age effect, m1 vs m2 | -0.000 0.001 0.689
Pairwise comparisons of marginal effects
Whether the effect of marriage differs across three ages:
mecompare i.married, models(m1) covariates(age=(35 40 45))Predicting: Pr(union)
Marginal effects (N_m1=1878)
| ME # Estimate Robust SE P>|z|
---------------------------------+---------------------------------------
married |
Married - Single |
age=35 | 1 -0.032 0.021 0.127
age=40 | 2 -0.033 0.022 0.126
age=45 | 3 -0.034 0.022 0.126
metest 1 2 3, pwcompare | estimate se pvalue
---------------------------------+--------------------------------
ME 2 vs ME 1 | -0.001 0.002 0.552
ME 3 vs ME 1 | -0.002 0.003 0.550
ME 3 vs ME 2 | -0.001 0.002 0.547
metest 1/3, pwcompare rownames("age 35" "age 40" "age 45") mcompare(bonferroni) | estimate se pvalue
---------------------------------+--------------------------------
age 40 vs age 35 | -0.001 0.002 1.000
age 45 vs age 35 | -0.002 0.003 1.000
age 45 vs age 40 | -0.001 0.002 1.000
NOTE: p-values (and CIs) are Bonferroni-adjusted for the 3 comparisons.
Options
| Option | Purpose |
|---|---|
statistics(list) |
Statistics to display: estimate, se, zvalue, pvalue, ll, ul, or all. The default is estimate se pvalue. Ignored for equality tests, which report the test statistic, its degrees of freedom, and the p-value. stats() is a synonym. |
allstats |
Same as statistics(all). |
pwcompare |
Compares the listed marginal effects pairwise: each later effect in the list minus each earlier one, in the order margins, pwcompare uses. List the effects by ME #, as a range, or by name: metest 1 2 3, pwcompare or metest 1/3, pwcompare. The rows are labeled ME 2 vs ME 1 and so on, or from rownames(). |
mcompare(method) |
Adjusts the p-values (and confidence intervals, when shown) of the pwcompare rows for multiple comparisons; method is bonferroni or sidak. |
add |
Adds the result as another row of the saved table rather than starting a new one. save is a synonym. |
clear |
Clears the saved table before running; metest, clear on its own clears it without running anything. |
rownames(string) |
Labels the row. A : in the label puts what comes before it on a row of its own, with the rest indented underneath, which is how several rows are grouped under one heading. A label longer than 32 characters (after any heading) is shortened to 32. With pwcompare, give one label per listed effect, as in rownames("age 35" "age 40" "age 45"); e.g., one row will read age 40 vs age 35. Labels of up to 14 characters are shown in full, and longer ones are shortened so the row fits 32 characters. label() is a synonym. |
decimals(#) |
Decimal places; the default is 3. |
width(#) |
Width of each statistic column; the default is 9. |
labwidth(#) |
Width of the label column; the maximum is 32. twidth() is a synonym. |
title(string) |
Title above the table. |
notable |
Suppresses the table. |
details |
Shows the underlying nlcom or test output. |
level(#) |
Confidence level for ll and ul. |
Results accumulate in the matrix _metest (estimates) and _metest_test (equality tests). metest is r-class: after an expression it returns r(estimate), r(se), r(zvalue), r(pvalue), r(ll), and r(ul); after an equality test, r(chi2) (or r(F)), r(df), and r(pvalue). After pwcompare, r(table) holds the rows of the comparisons.
Use after other commands
metest also works after other estimation commands: a number refers to the nth coefficient in e(b), in the order of matrix list e(b), and coefficient names work as usual.
sysuse nlsw88, clear(NLSW, 1988 extract)
regress wage age ttl_exp grade Source | SS df MS Number of obs = 2,244
-------------+---------------------------------- F(3, 2240) = 132.71
Model | 11221.4453 3 3740.48178 Prob > F = 0.0000
Residual | 63132.8852 2,240 28.1843237 R-squared = 0.1509
-------------+---------------------------------- Adj R-squared = 0.1498
Total | 74354.3305 2,243 33.1495009 Root MSE = 5.3089
------------------------------------------------------------------------------
wage | Coefficient Std. err. t P>|t| [95% conf. interval]
-------------+----------------------------------------------------------------
age | -0.101 0.037 -2.735 0.006 -0.174 -0.029
ttl_exp | 0.271 0.025 10.819 0.000 0.222 0.320
grade | 0.641 0.045 14.106 0.000 0.552 0.730
_cons | -0.061 1.570 -0.039 0.969 -3.140 3.019
------------------------------------------------------------------------------
metest 1 - 2 | estimate se pvalue
---------------------------------+--------------------------------
age - ttl_exp | -0.372 0.047 0.000
metest 1 / 2 | estimate se pvalue
---------------------------------+--------------------------------
age / ttl_exp | -0.374 0.136 0.006
metest 1 = 2 = 3Tests of equality
| F df pvalue
---------------------------------+--------------------------------
age = ttl_exp = grade | 88.241 2.000 0.000
metest abs(1) - abs(2) | estimate se pvalue
---------------------------------+--------------------------------
abs(age) - abs(ttl_exp) | -0.170 0.042 0.000
metest min(1,2) | estimate se pvalue
---------------------------------+--------------------------------
min(age,ttl_exp) | -0.101 0.037 0.006
metest _b[age] * #10 | estimate se pvalue
---------------------------------+--------------------------------
age * 10 | -1.011 0.370 0.006
After margins, post, a number refers to a row of the margins table. E.g., the difference in two predicted probabilities, averaging over observed values, in the Health and Retirement Study 2020; this replicates mecompare collegeB:
use "https://tdmize.github.io/data/data/cda_hrs", clear(cda_hrs.dta | Health & Retirement Study 2020)
drop if missing(cogB, marstatB, collegeB, woman, age)(761 observations deleted)
logit cogB i.collegeB i.marstatB i.woman c.ageIteration 0: Log likelihood = -2466.5782
Iteration 1: Log likelihood = -2311.9677
Iteration 2: Log likelihood = -2282.8575
Iteration 3: Log likelihood = -2282.3938
Iteration 4: Log likelihood = -2282.3924
Iteration 5: Log likelihood = -2282.3924
Logistic regression Number of obs = 14,962
LR chi2(4) = 368.37
Prob > chi2 = 0.0000
Log likelihood = -2282.3924 Pseudo R2 = 0.0747
---------------------------------------------------------------------------------------
cogB | Coefficient Std. err. z P>|z| [95% conf. interval]
----------------------+----------------------------------------------------------------
collegeB |
bachelor's or higher | -1.458 0.157 -9.269 0.000 -1.766 -1.150
|
marstatB |
currently married | -0.586 0.092 -6.401 0.000 -0.766 -0.407
|
woman |
woman | -0.221 0.091 -2.428 0.015 -0.400 -0.043
age | 0.048 0.004 12.085 0.000 0.040 0.056
_cons | -5.926 0.310 -19.128 0.000 -6.533 -5.318
---------------------------------------------------------------------------------------
margins collegeB, postPredictive margins Number of obs = 14,962
Model VCE: OIM
Expression: Pr(cogB), predict()
---------------------------------------------------------------------------------------
| Delta-method
| Margin std. err. z P>|z| [95% conf. interval]
----------------------+----------------------------------------------------------------
collegeB |
no bachelor's | 0.048 0.002 23.986 0.000 0.044 0.052
bachelor's or higher | 0.012 0.002 6.758 0.000 0.008 0.015
---------------------------------------------------------------------------------------
metest 2 - 1 | estimate se pvalue
---------------------------------+--------------------------------
1_collegeB - 0bn_collegeB | -0.036 0.003 0.000
For risk ratios, use the rratios option of mecompare, which tests each ratio against 1. metest would test a risk ratio against a null of 0, which is not appropriate for risk ratios.
Omitted (o.) coefficients are skipped when numbering, so check the numbers with matrix list e(b). After some commands test reports F rather than chi-squared; run metest, clear before accumulating results from a model of the other kind.