Search code examples
rexportoutputanova

R: Anova output of several models side-by-side


I am trying to get a nice publication-ready output of several anovas, in a similar fashion to what I usually do for regression tables. Code looks somewhat like that:

head(iris)
library(car)

# run model 1
lm1 <- lm(Sepal.Length ~ Species, data = iris)
summary(lm1)
a1 <- Anova(lm1)
# run model 2
lm2 <- lm(Petal.Width ~ Species, data = iris)
summary(lm2)        # long format (regression type output)
a2 <- Anova(lm2)    # short format (anova type output, which I need)

# what I usually do for regression outputs:
library(stargazer)
stargazer(lm1, lm2, type = "html", out ="iris.html")
# which yields a nice table with models side by side, including dependent variable names for each model; 
# this one I'd export as .html to Word and process there

# trying a similar joint table for anova type output:
stargazer(a1, a2, type = "html", out ="iris2.html")
# ... but that yields 2 separated tables and they can't be distinguished by dependent variables etc

# same problem here:
table <- rbind(a1, a2)
write.csv(as.data.frame(table), file = "iris2.csv")
# when I do this, I only get the same two tables underneath each other with their columnwise headers, 
# but without the distinguishing dependent variables 

As I will have to do that with many more models over and over again, I'd like there to be as little post-processing in Word as possible. I know there are very nice solutions out there using LaTeX, but due to coauthors these are completely out of the question, unfortunately. I played around with xtable, pixiedust and export packages, but wasn't able to get the results I want.

Hope somone can help, Thanks in advance!


Solution

  • I'd recommend looking into library(kableExtra) if you're interested in generating HTML and Latex tables regularly. Here is an excellent tutorial on HTML and Latex usage.

    Below is an example of how to create an html table. You'll get the followings results: ANOVA results table

    # Convert ANOVA results into dataframes allows for easier name manipulation
    a1_new <- data.frame(a1)
    a2_new <- data.frame(a2) 
    
    # Putting all into one dataframe/table
    anova_results <- data.frame(cbind(c("Species", "Residuals", "Species", "Residuals"), 
                                      rbind(a1_new, a2_new))) 
    colnames(anova_results) <- c("", "Sum Sq", "Df", "F value", "Pr(>F)")
    row.names(anova_results) <- NULL
    
    # create HTML table using kableExtra
    library(kableExtra)
    anova_results %>% kable("html", digits=2) %>% 
      kable_styling(bootstrap_options = "striped", full_width = F) %>% 
      pack_rows(., "Sepal Length", 1, 2) %>% # groups rows with label
      pack_rows(., "Petal Width", 3, 4) # groups rows with label
    

    If you want the values side by side, here is a sort of hacky way to get it done...

    anova_results2 <- data.frame(rbind(c("Sum Sq", "Df", "F value", "Pr(>F)", 
                                         "Sum Sq", "Df", "F value", "Pr(>F)"), 
                                       cbind(round(a1_new, 2), round(a2_new,2)))) 
    colnames(anova_results2) <- c("", "", "", "","", "", "", "")
    row.names(anova_results2)[1] <- ""
    
    anova_results2 %>% kable("html") %>% 
      kable_styling(bootstrap_options = "striped", full_width = F) %>%
      add_header_above(c("", "Sepal Length" = 4, "Petal Width" = 4))
    

    side by side

    NOTE: There are different modifications you'd need to make in order to get a functioning Latex table. I do think that, in the long run, using Latex in RMarkdown is probably the best way to go if you want to create publication quality tables.