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

后端 未结 2 1682
-上瘾入骨i
-上瘾入骨i 2021-01-06 18:41

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\

相关标签:
2条回答
  • 2021-01-06 18:49

    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"
    header-includes:
        - \usepackage{dcolumn}
    output: 
      pdf_document:
        includes:
          in_header: header.tex
    ---
    
    ```{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
    }
    
    make_addtorow <- function(row.name, terms) {
      # 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 <- list()
    addtorow$pos <- list(0, 6, 6, 6, 6, 6)
    addtorow$command <- c(
      make_addtorow("", c("Base model", "Add Horsepower and AM")),
      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),
      make_addtorow("Num. obs.", sum_stats$df.null + 1)
      )
    
    xtbl <- xtable(combo, add.to.row = addtorow, include.colnames = FALSE,  
                   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)
          add.to.row = addtorow, 
          include.colnames = FALSE,
          comment = FALSE)
    ```
    

    0 讨论(0)
  • 2021-01-06 19:02

    Here is an attempt using broom. You'll still need to clean up the labels though.

    library(broom)
    library(dplyr)
    library(pander)
    library(tidyr)
    
    m1 = glm(mpg ~ wt + factor(cyl), data=mtcars)
    m2 = glm(mpg ~ wt + factor(cyl) + hp + factor(am), data=mtcars)
    base <- tidy(m1) %>% select(term, estimate) %>% mutate(type = "base_model")
    with_am_hp <- tidy(m2) %>% select(term, estimate) %>% mutate(type = "Add_Horsepower_and_AM")
    models <- bind_rows(base, with_am_hp)
    formatted_models <- models  %>% spread(type, estimate)
    
    m1_glance <- glance(m1) %>% mutate(type = "base_model")
    m2_glance <- glance(m2) %>% mutate(type = "Add_Horsepower_and_AM")
    glance_table <- data.frame("Add_Horsepower_and_AM" = unlist(glance(m2)), "base_model" = unlist(glance(m1))) %>% mutate(term = row.names(.))
    
    full_results <- bind_rows(formatted_models, glance_table)
    pandoc.table(full_results, justify = "left")
    
    0 讨论(0)
提交回复
热议问题