{"id":319,"date":"2019-10-30T22:04:32","date_gmt":"2019-10-31T02:04:32","guid":{"rendered":"http:\/\/blog.uvm.edu\/tbplante\/?p=319"},"modified":"2023-02-16T09:15:32","modified_gmt":"2023-02-16T14:15:32","slug":"working-with-stata-regression-results-matrix-matrices-macros-oh-my","status":"publish","type":"post","link":"https:\/\/blog.uvm.edu\/tbplante\/2019\/10\/30\/working-with-stata-regression-results-matrix-matrices-macros-oh-my\/","title":{"rendered":"Working with Stata regression results: Matrix\/matrices, macros, oh my!"},"content":{"rendered":"\n<p>If you make your own Stata programs and loops, you have discovered the wonders of automating output of analyses to tables. Extracting the results from regressions in Stata can be a bit cumbersome. Here&#8217;s one step-by-step approach that you might find helpful. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The set-up<\/h3>\n\n\n\n<p>Let&#8217;s use the classic 1978 auto dataset that comes with Stata. <strong>We want to regress MPG (Y) on weight (x) overall and by strata of domestic vs. foreign<\/strong> to complete the following table:<\/p>\n\n\n\n<table style=\"undefined;width: 455px\" border=\"1\">\n<colgroup>\n<col style=\"width: 137px\"\/>\n<col style=\"width: 146px\"\/>\n<col style=\"width: 100px\"\/>\n<\/colgroup>\n  <tbody><tr>\n    <th><\/th>\n    <th>Weight Beta (95% CI)<\/th>\n    <th>P-value<\/th>\n  <\/tr>\n  <tr>\n    <td>All<\/td>\n    <td><\/td>\n    <td><\/td>\n  <\/tr>\n  <tr>\n    <td>Domestic<\/td>\n    <td><\/td>\n    <td><\/td>\n  <\/tr>\n  <tr>\n    <td>Foreign<\/td>\n    <td><\/td>\n    <td><\/td>\n  <\/tr>\n<\/tbody><\/table>\n\n\n\n<p>In Stata you&#8217;ll run three regressions to fill out the three rows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sysuse auto, clear\nregress mpg weight\nregress mpg weight if foreign==0\nregress mpg weight if foreign==1<\/code><\/pre>\n\n\n\n<p>You can either copy the output manually, or automate it! Let&#8217;s learn how to automate this process.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Let&#8217;s get familiar with the &#8216;guts&#8217; and &#8216;brains&#8217; behind Stata&#8217;s regression functions.<\/h3>\n\n\n\n<p>When you run a regression, Stata saves relevant bits of these regressions in scalars and matrices saved in different r() and e() levels. You can view the r() &#8216;guts&#8217; with -return list- and e() &#8216;brains&#8217; with -ereturn list-. These have different uses. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><span style=\"text-decoration: underline\">return list<\/span><\/strong> &#8211; This will give the &#8216;guts&#8217; of the regression, namely the r() level bits, as you see it in the Stata output. <strong><em>Importantly, the r() level contains the r(table) matrix, which holds all of the raw numbers used to generate the output of your regression as you see it in Stata&#8217;s output.<\/em><\/strong> These are what you will use to fill out the above blank table.\n<ul class=\"wp-block-list\">\n<li>Type -matrix list r(table)- to see the structured output of this matrix.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong><span style=\"text-decoration: underline\">ereturn list<\/span><\/strong> &#8211; this will let you see the &#8216;brains&#8217; behind the regression, namely the e() level bits, which are useful in post-estimation commands. We actually don&#8217;t need this to fill out the above table. Just pointing out that they&#8217;re here. <\/li>\n<\/ul>\n\n\n\n<p>Let&#8217;s take a look at the regression output below and how they exist in the r() level r(table), I have bolded\/underlined the output of interest. Our goal is to:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Load the sysuse auto dataset.<\/li>\n\n\n\n<li>Run the regression. <\/li>\n\n\n\n<li>Take a look at the -return list- to see that the r(table) is hiding there (without actually viewing the contents of r(table)) <\/li>\n\n\n\n<li>Actually view the r(table) matrix in order to verify that all of the data points of interest are hiding there. <\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-preformatted\"><strong>. sysuse auto, clear<\/strong>\n. <strong>regress mpg weight<\/strong>\n\nSource |       SS           df       MS      Number of obs   =        74\n-------+----------------------------------   F(1, 72)        =    134.62\n Model |   1591.9902         1   1591.9902   Prob &gt; F        =    0.0000\nResidu |  851.469256        72  11.8259619   R-squared       =    0.6515\n-------+----------------------------------   Adj R-squared   =    0.6467\n Total |  2443.45946        73  33.4720474   Root MSE        =    3.4389\n\n-------------------------------------------------------------------\n   mpg |      Coef.   Std. Err.      t    P&gt;|t|     [95% Conf. Interval]\n-------+----------------------------------------------------------------     \nweight |  <strong><span style=\"text-decoration: underline\">-.0060087<\/span><\/strong>   .0005179   -11.60   <strong><span style=\"text-decoration: underline\">0.000<\/span><\/strong>    <strong><span style=\"text-decoration: underline\">-.0070411   -.0049763<\/span><\/strong>\n _cons |   39.44028   1.614003    24.44   0.000     36.22283    42.65774\n----------------------------------------------------------------------\n\n. <strong>return list<\/strong>\n\nscalars:\n              r(level) =  95\nmatrices:\n              <strong><span style=\"text-decoration: underline\">r(table) :  9 x 2<\/span><\/strong>\n\n. <strong>matrix list r(table)<\/strong>\n\nr(table)[9,2]\n            weight       _cons\n     b  <strong><span style=\"text-decoration: underline\">-.00600869<\/span><\/strong>   39.440284\n    se   .00051788   1.6140031\n     t   -11.60251   24.436312\npvalue   <strong><span style=\"text-decoration: underline\">3.798e-18<\/span><\/strong>   1.385e-36\n    ll  <strong><span style=\"text-decoration: underline\">-.00704106<\/span><\/strong>   36.222827\n    ul  <strong><span style=\"text-decoration: underline\">-.00497632<\/span><\/strong>    42.65774\n    df          72          72\n  crit   1.9934636   1.9934636\n eform           0           0<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">r(table) is a matrix, but an atypical matrix. Copy it to a custom &#8216;typical&#8217; matrix before doing anything else!<\/h3>\n\n\n\n<p>Matrices are basically small spreadsheets saved in the memory that can be accessed by referencing a [row,column] cell reference. These exist separate from the dataset, which is also basically a big spreadsheet. You&#8217;ll note above (after the -matrix list r(table)- command) that Stata tells you that the r(table) matrix has 9 rows and 2 columns, or [9,2]. <\/p>\n\n\n\n<p>For various reasons that you can read about <a href=\"https:\/\/www.stata.com\/statalist\/archive\/2013-11\/msg00824.html\">here<\/a>, r(table) is not a usual matrix and Stata will do funny things if you try to run matrix commands on it. <strong><em>Make sure to save the r(table) matrix as custom matrix before going any further<\/em><\/strong>. Since we actually need to save 3 separate r(table) matrices to fill out the blank table (one for each row), you should do this anyway to help facilitate completing the table. Use the -matrix- command to copy the contents of the r(table) to a custom matrix. Here we&#8217;ll: <\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Load the sysuse auto dataset<\/li>\n\n\n\n<li>Run three regressions, one for each row, and <\/li>\n\n\n\n<li>Save the r(table) matrix for each regression to a custom named matrix. We&#8217;ll specifically call them &#8220;row1&#8221;, &#8220;row2&#8221;, and &#8220;row3&#8221;. <\/li>\n\n\n\n<li>Then, we will confirm that each row is saved by plopping the command to view the matrices at the end. <\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-preformatted\">sysuse auto, clear \n* first row\nregress mpg weight\n* save as a custom matrix\nmatrix row1=r(table)\n* second row\nregress mpg weight if foreign==0\n* save as a custom matrix\nmatrix row2=r(table)\n* third row\nregress mpg weight if foreign==1\n* save as a custom matrix\nmatrix row3=r(table)\n* prove that all three saved\nmatrix list row1\nmatrix list row2\nmatrix list row3<\/pre>\n\n\n\n<p>The stata output for the last three lines should look like the output below. Note that the beta coefficient is at [1,1], the 95% confidence interval bounds are at [5,1] and [6,1], and the p-value is at [4,1]. I bolded\/underlined the first to highlight this.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">. <strong>matrix list row1<\/strong>\n\nrow1[9,2]\n            weight       _cons\n     b  <strong><span style=\"text-decoration: underline\">-.00600869<\/span><\/strong>   39.440284\n    se   .00051788   1.6140031\n     t   -11.60251   24.436312\npvalue   <strong><span style=\"text-decoration: underline\">3.798e-18<\/span><\/strong>   1.385e-36\n    ll  <strong><span style=\"text-decoration: underline\">-.00704106<\/span><\/strong>   36.222827\n    ul  <strong><span style=\"text-decoration: underline\">-.00497632<\/span><\/strong>    42.65774\n    df          72          72\n  crit   1.9934636   1.9934636\n eform           0           0\n\n. \n. <strong>matrix list row2<\/strong>\n\nrow2[9,2]\n            weight       _cons\n     b  -.00597508   39.646965\n    se   .00046538   1.5766224\n     t  -12.839251   25.146772\npvalue   1.890e-17   4.898e-30\n    ll  -.00690982   36.480225\n    ul  -.00504035   42.813704\n    df          50          50\n  crit   2.0085591   2.0085591\n eform           0           0\n\n. \n. <strong>matrix list row3<\/strong>\n\nrow3[9,2]\n            weight       _cons\n     b  -.01042596   48.918297\n    se   .00249417   5.8718507\n     t  -4.1801326   8.3309845\npvalue   .00046167   6.196e-08\n    ll   -.0156287   36.669831\n    ul  -.00522321   61.166763\n    df          20          20\n  crit   2.0859634   2.0859634\n eform           0           0<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Let&#8217;s extract the matrix components of interest as macros!<\/h3>\n\n\n\n<p>Macros are little &#8216;codewords&#8217; that represent another variable or string. You can pluck a cell of a matrix and store it as a macro. Later on, use can use that &#8216;codeword&#8217; associated with the macro to make Stata blurt out the stored cell result. We just need to point the macro at the right matrix cell in order to extract the cell&#8217;s results. It sounds confusing but it&#8217;s not. Remember the [row,column] numbers from above? We&#8217;ll use those numbers to extract the matrix cell results into macros. Next steps:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Load the sysuse auto dataset<\/li>\n\n\n\n<li>Run a regression for the first three rows of our table, saving the r(table) matrix for each regression as our custom matrix (row1-3)<\/li>\n\n\n\n<li>Use macros to extract the [1,1] as beta coefficient, [5,1] and [6,1] as the 95% confidence intervals, and [4,1] as the p-value for each row.<\/li>\n\n\n\n<li>View each macro with the -display- opening tick (`), to the left of the number 1 on your keyboard, the macro name, and a closing apostrophe (&#8216;).<\/li>\n\n\n\n<li>You can use number formatting like %3.2f (e.g., 0.56) or %4.3f (0.558) to limit the number of digits following the decimal.  This will also round. (Note: If you want to use super fancy formatting of a P-value, see <a rel=\"noreferrer noopener\" href=\"https:\/\/blog.uvm.edu\/tbplante\/2022\/10\/26\/formatting-p-values-for-stata-output\/\" target=\"_blank\">this post<\/a>.)<\/li>\n<\/ol>\n\n\n\n<p>Code to do this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sysuse auto, clear \n* first row\nregress mpg weight\n* save as a custom matrix\nmatrix row1=r(table)\n* second row\nregress mpg weight if foreign==0\n* save as a custom matrix\nmatrix row2=r(table)\n* third row\nregress mpg weight if foreign==1\n* save as a custom matrix\nmatrix row3=r(table)\n****\n*now save the beta, 95% ci, and P as macros\n*row 1\nlocal beta1=row1&#091;1,1]\nlocal low951=row1&#091;5,1]\nlocal high951=row1&#091;6,1]\nlocal pval1=row1&#091;4,1]\n*row 2\nlocal beta2=row2&#091;1,1]\nlocal low952=row2&#091;5,1]\nlocal high952=row2&#091;6,1]\nlocal pval2=row2&#091;4,1]\n*row 3\nlocal beta3=row3&#091;1,1]\nlocal low953=row3&#091;5,1]\nlocal high953=row3&#091;6,1]\nlocal pval3=row3&#091;4,1]\n*now view these\n*row 1\ndi \"row1 beta is \" %3.2f `beta1'\ndi \"row1 95% CI is \" %3.2f `low951' \" to \" %3.2f `high951'\ndi \"row1 P-val is \" %4.3f `pval1'\n*row 2\ndi \"row2 beta is \" %3.2f `beta2'\ndi \"row2 95% CI is \" %3.2f `low952' \" to \" %3.2f `high952'\ndi \"row2 P-val is \" %4.3f `pval2'\n*row 3\ndi \"row3 beta is \" %3.2f `beta3'\ndi \"row3 95% CI is \" %3.2f `low953' \" to \" %3.2f `high953'\ndi \"row3 P-val is \" %4.3f `pval3'\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Hide in -quietly- curly brackets and output a CSV file using -noisily- commands and a log!<\/h3>\n\n\n\n<p>Here&#8217;s my code to run the three regression, store the r(table) matrices, extract the data of interest, and output as a .csv file! <strong><em>Run this from a .do file<\/em><\/strong> as it includes the -quietly- command, which confuses Stata if it&#8217;s run from the command line. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sysuse auto, clear \n* first row\nregress mpg weight\n* save as a custom matrix\nmatrix row1=r(table)\n* second row\nregress mpg weight if foreign==0\n* save as a custom matrix\nmatrix row2=r(table)\n* third row\nregress mpg weight if foreign==1\n* save as a custom matrix\nmatrix row3=r(table)\n****\n*view the custom matrices to prove they worked\nmatrix list row1\nmatrix list row2\nmatrix list row3\n****\n*now save the beta, 95% ci, and P as macros\n*here's a loop that automates this a bit\nforeach x in 1 2 3 {\nlocal beta`x'=row`x'&#091;1,1]\nlocal low95`x'=row`x'&#091;5,1]\nlocal high95`x'=row`x'&#091;6,1]\nlocal pval`x'=row`x'&#091;4,1]\n}\n\npwd \/\/ this is where your CSV file is saved\n\nquietly {\ncapture log close table \/\/ always good to close any open logs\nlog using \"regressiontable.csv\", replace text name(table)\n*header\nnoisily di \",Weight beta (95% CI),P-value\"\n*row 1\nnoisily di \"All,\" %3.2f `beta1' \" (\"  %3.2f `low951' \" to \" %3.2f `high951' \"),\"  %4.3f `pval1'\n*row 2\nnoisily di \"Domestic,\" %3.2f `beta2' \" (\"  %3.2f `low952' \" to \" %3.2f `high952' \"),\"  %4.3f `pval2'\n*row 3\nnoisily di \"Foreign,\" %3.2f `beta3' \" (\"  %3.2f `low953' \" to \" %3.2f `high953' \"),\"  %4.3f `pval3'\nlog close table\n}<\/code><\/pre>\n\n\n\n<p>Boom! you&#8217;ll get a CSV file that looks like this, which should be simple to import in Excel!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>,Weight beta (95% CI),P-value\nAll,-0.01 (-0.01 to -0.00),0.000\nDomestic,-0.01 (-0.01 to -0.01),0.000\nForeign,-0.01 (-0.02 to -0.01),0.000\n<\/code><\/pre>\n\n\n\n<p>You&#8217;ll notice that these numbers are small, so you may want to use %4.3f instead of %3.2f to get 3 digits past the decimal place for the beta and 95% CIs. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Bonus: Generating a CSV file with pretty P-values<\/h3>\n\n\n\n<p>Here&#8217;s the same code, but using the <a rel=\"noreferrer noopener\" href=\"https:\/\/blog.uvm.edu\/tbplante\/2022\/10\/26\/formatting-p-values-for-stata-output\/\" target=\"_blank\">&#8220;pretty&#8221; p-value code<\/a> documented in this separate post. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sysuse auto, clear \n* first row\nregress mpg weight\n* save as a custom matrix\nmatrix row1=r(table)\n* second row\nregress mpg weight if foreign==0\n* save as a custom matrix\nmatrix row2=r(table)\n* third row\nregress mpg weight if foreign==1\n* save as a custom matrix\nmatrix row3=r(table)\n****\n*view the custom matrices to prove they worked\nmatrix list row1\nmatrix list row2\nmatrix list row3\n****\n*now save the beta, 95% ci, and P as macros\n*here's a loop that automates this a bit\nforeach x in 1 2 3 {\nlocal beta`x'=row`x'&#091;1,1]\nlocal low95`x'=row`x'&#091;5,1]\nlocal high95`x'=row`x'&#091;6,1]\nlocal pval`x'=row`x'&#091;4,1]\nlocal pval = r(table)&#091;4,1] \n\nif `pval`x''&gt;=0.056 {\n\tlocal pvalue`x' \"P=`: display %3.2f `pval`x'''\"\n}\nif `pval`x''&gt;=0.044 &amp; `pval'&lt;0.056 {\n\tlocal pvalue`x&#039; &quot;P=`: display %5.4f `pval`x&#039;&#039;&#039;&quot;\n}\nif `pval`x&#039;&#039; &lt;0.044 {\n\tlocal pvalue`x&#039; &quot;P=`: display %4.3f `pval`x&#039;&#039;&#039;&quot;\n}\nif `pval`x&#039;&#039; &lt;0.001 {\n\tlocal pvalue`x&#039; &quot;P&lt;0.001&quot;\n}\nif `pval`x&#039;&#039; &lt;0.0001 {\n\tlocal pvalue`x&#039; &quot;P&lt;0.0001&quot;\n}\ndi &quot;original P is &quot; `pval`x&#039;&#039; &quot;, formatted is &quot; &quot;`pvalue`x&#039;&#039;&quot;\n}\n\npwd \/\/ this is where your CSV file is saved\n\nquietly {\ncapture log close table \/\/ always good to close any open logs\nlog using &quot;regressiontable.csv&quot;, replace text name(table)\n*header\nnoisily di &quot;,Weight beta (95% CI),P-value&quot;\n*row 1\nnoisily di &quot;All,&quot; %3.2f `beta1&#039; &quot; (&quot;  %3.2f `low951&#039; &quot; to &quot; %3.2f `high951&#039; &quot;),&quot;  &quot;`pvalue1&#039;&quot;\n*row 2\nnoisily di &quot;Domestic,&quot; %3.2f `beta2&#039; &quot; (&quot;  %3.2f `low952&#039; &quot; to &quot; %3.2f `high952&#039; &quot;),&quot; &quot;`pvalue2&#039;&quot;\n*row 3\nnoisily di &quot;Foreign,&quot; %3.2f `beta3&#039; &quot; (&quot;  %3.2f `low953&#039; &quot; to &quot; %3.2f `high953&#039; &quot;),&quot;   &quot;`pvalue3&#039;&quot;\nlog close table\n}<\/code><\/pre>\n\n\n\n<p>Here&#8217;s the output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>,Weight beta (95% CI),P-value\nAll,-0.01 (-0.01 to -0.00),P&lt;0.0001\nDomestic,-0.01 (-0.01 to -0.01),P&lt;0.0001\nForeign,-0.01 (-0.02 to -0.01),P&lt;0.001<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>If you make your own Stata programs and loops, you have discovered the wonders of automating output of analyses to tables. Extracting the results from regressions in Stata can be a bit cumbersome. Here&#8217;s one step-by-step approach that you might find helpful. The set-up Let&#8217;s use the classic 1978 auto dataset that comes with Stata. &hellip; <a href=\"https:\/\/blog.uvm.edu\/tbplante\/2019\/10\/30\/working-with-stata-regression-results-matrix-matrices-macros-oh-my\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Working with Stata regression results: Matrix\/matrices, macros, oh my!<\/span><\/a><\/p>\n","protected":false},"author":4473,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[477491],"tags":[],"class_list":["post-319","post","type-post","status-publish","format-standard","hentry","category-stata-code"],"_links":{"self":[{"href":"https:\/\/blog.uvm.edu\/tbplante\/wp-json\/wp\/v2\/posts\/319","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.uvm.edu\/tbplante\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.uvm.edu\/tbplante\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.uvm.edu\/tbplante\/wp-json\/wp\/v2\/users\/4473"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.uvm.edu\/tbplante\/wp-json\/wp\/v2\/comments?post=319"}],"version-history":[{"count":38,"href":"https:\/\/blog.uvm.edu\/tbplante\/wp-json\/wp\/v2\/posts\/319\/revisions"}],"predecessor-version":[{"id":1397,"href":"https:\/\/blog.uvm.edu\/tbplante\/wp-json\/wp\/v2\/posts\/319\/revisions\/1397"}],"wp:attachment":[{"href":"https:\/\/blog.uvm.edu\/tbplante\/wp-json\/wp\/v2\/media?parent=319"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.uvm.edu\/tbplante\/wp-json\/wp\/v2\/categories?post=319"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.uvm.edu\/tbplante\/wp-json\/wp\/v2\/tags?post=319"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}