eipi10 - 1 year ago 127
LaTeX Question

# How to decimal-align regression coefficients in Latex table output in rmarkdown document

In an

rmarkdown
document, I'm creating a Latex table of regression coefficients with standard errors to compare several regression models in a single table. I'd like to vertically align the coefficients for each model so that the decimal points of the coefficients line up vertically down a column.

I'm using
texreg
to create the table. The coefficients aren't decimal-aligned by default (instead, each string is centered within its column) and I'm looking for a way to get the coefficents decimal-aligned. I'm not wedded to
texreg
, so if you have a solution using
xtable
,
pander
,
stargazer
or any other method, I'd be interested in that as well. Ideally, I'd like a solution that can be implemented programmatically within the
rmarkdown
document, rather than tweaking the
latex
markup after rendering the document into a
.tex
file.

As a bonus, I'd also like to be able to put line breaks in table headings. For example, in
texreg
you can use the
custom.model.names
argument to set the column names for each regression model. In the example below, I'd like to have
"Add Horsepower and AM"
split into two lines so that the column doesn't need to be so wide. I tried
"Add Horsepower \newline and AM"
but that just adds "ewline" to the final column header and the "\n" is ignored.

Here's a reproducible example:

---
title: "Regression Table"
author: "eipi10"
date: "August 15, 2016"
- \usepackage{dcolumn}
output: pdf_document
---

{r, echo=FALSE, message=FALSE, results="asis"}
library(texreg)

m1 = glm(mpg ~ wt + factor(cyl), data=mtcars)
m2 = glm(mpg ~ wt + factor(cyl) + hp + factor(am), data=mtcars)

texreg(list(m1,m2),
single.row=TRUE,
custom.model.names=c("Base Model", "Add Horsepower and AM"),
custom.coef.names=c("Intercept", "Weight","Cyl: 6", "Cyl: 8", "Horsepower","AM: 1"))



And here's what the output table looks like:

This took quite a bit of wrangling, but I think it gets you close to what you want. I used xtable. The main idea is to create two columns for each model, one aligned right (coefficients) and the other aligned left (standard errors). So for a table with two models, we have five columns. Headers and the summary statistics are displayed in cells that span two columns.

First, we have header.tex, drawing on p. 27 of the xtable vignette:

\usepackage{array}
\usepackage{tabularx}
\newcolumntype{L}[1]{>{\raggedright\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{C}[1]{>{\centering\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{R}[1]{>{\raggedleft\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{P}[1]{>{\raggedright\tabularxbackslash}p{#1}}


The .Rmd file. I learnt about add.to.row from this answer.

---
title: "Regression Table"
author: "eipi10"
date: "August 15, 2016"
- \usepackage{dcolumn}
output:
pdf_document:
includes:
---

{r, echo=FALSE, message=FALSE, results="asis"}
library(xtable)
library(broom)

m1 = glm(mpg ~ wt + factor(cyl), data=mtcars)
m2 = glm(mpg ~ wt + factor(cyl) + hp + factor(am), data=mtcars)

p_val <- c(0, 0.001, 0.01, 0.05, 1)
stars <- sapply(3:0, function(x) paste0(rep("*", x), collapse=""))

make_tbl <- function(model) {
coefs <- summary(model)$coefficients coef_col <- round(coefs[,1], 2) se_col <- round(coefs[,2], 2) star_col <- stars[findInterval(coefs[,4], p_val)] tbl <- data.frame(coef=coef_col) tbl$se <- sprintf("(%0.2f)%s", se_col, star_col)
tbl
}

# xtable allows the addition of custom rows. This function
# makes a row with a one column (which is used for the row
# names for the model statistics),
# followed by two columns that each span two columns.
paste0(row.name,
paste0('& \\multicolumn{2}{C{3cm}}{',
terms,
'}',
collapse=''),
'\\\\')
}

tbl1 <- make_tbl(m1)
tbl2 <- make_tbl(m2)
combo <- merge(tbl1, tbl2, by = "row.names", all = TRUE)[,-1]
rownames(combo) <- c("Intercept", "AM: 1", "Cyl: 6", "Cyl: 8", "Horsepower", "Weight")
sum_stats <- round(rbind(glance(m1), glance(m2)), 2)

addtorow$pos <- list(0, 6, 6, 6, 6, 6) addtorow$command <- c(
make_addtorow("\\hline AIC", sum_stats$AIC), # Draw a line after coefficients make_addtorow("BIC", sum_stats$BIC),
make_addtorow("Log Likelihood", sum_stats$logLik), make_addtorow("Deviance", sum_stats$deviance),
)

comment = FALSE)
# Specify column alignment for tabularx environment
# We're using the custom column types we created in header.tex
# \hskip specifies the width between columns
align(xtbl) <- c("L{2.5cm}", "R{1.5cm}@{\\hskip 0.1cm}", "L{1.5cm}",
"R{1.5cm}@{\\hskip 0.1cm}","L{1.5cm}")

print(xtbl,
tabular.environment = "tabularx", # tabularx takes two arguments
width = ".60\\textwidth",         # width, and alignment (specified above)