Is there a reasonable way with texreg or similar in R (making html tables) to round coefficients to different digits than goodness-of-fit measures?
Asked Answered
R

2

6

I am using texreg to show regressions side-by-side, including SUR systems with systemfit, but I have some formatting constraints/preferences. I would like to be able to round the coefficients one way, while rounding the goodness-of-fit measures to more digits. For now at least I will also be displaying confidence intervals instead of standard errors, so those are not necessarily a factor here. I also need to output this in HTML and not LaTeX format.

My issue is similar to emagar's How to show only coefficients rounded to whole numbers in LaTeX tables?, but the answer there was largely based around LaTeX tables, while I currently need to be using HTML tables, so the answer to that question, for this and other reasons, is not sufficiently applicable to my issue.
The actual function I am using to do this is actually knitreg (since this is in R Markdown), but have generally been treating it as htmlreg.

    texreg::knitreg(
    l=list(ln(...), systemfit_object), 
    <various formatting>, 
    digits=?
    )

I suspect that there are several potential work-arounds, and I have already done some complex in this project for other purposes. Obviously, though, I would prefer something simpler, if possible, but really my main preference would be to able to use primarily R-based code for this.

Rooftree answered 20/4, 2022 at 23:32 Comment(5)
For those who are wondering, the "complexity" that I am alluding to at the end there is really just that I rolled the actual function into a purr::as_mapper(~knitreg(...) thing so that I can use the file= value to export to multiple formats and also can vary the digits when I call it.Rooftree
To format the coefficient and goodness-of-fit blocks separately, there is currently no provision within the texreg package. But maybe the matrixreg function could help you work towards a solution outside of texreg. It returns a character matrix of the table. Maybe that's something you can work on in the ways you want. But then you won't have the other formatting options of the package at your disposal, such as turning the table into HTML or rounding coefficients etc.Solicit
Thanks, I will look into matrixreg, but converting to html is pretty central to what I want to do with this, so I doubt This will be enough on its own to solve this.Rooftree
can you make a reproducible example with data and code?Aphrodisia
@Aphrodisia I am basing this off of relatively large and complex datasets and regressions, and I am still relatively new to posting questions on here, but I will try to see if I can put together some reproducible code. It seems that the functionality I want does not exist within the specific function I have been using, and it seems completely redoing to workflow, or at least switching functions, will be necessary to get this to work the way I want. Given that, I am not sure that reproducible code will be all that helpful.Rooftree
L
1

If you're happy using my huxtable package, this is very simple:

library(huxtable)
r1 <- lm(Sepal.Width ~ Sepal.Length, iris)
r2 <- lm(Sepal.Width ~ Sepal.Length + Petal.Width, iris)
h <- huxreg(r1, r2)
h
              ────────────────────────────────────────────────────
                                      (1)              (2)        
                               ───────────────────────────────────
                (Intercept)           3.419 ***        1.926 ***  
                                     (0.254)          (0.321)     
                Sepal.Length         -0.062            0.289 ***  
                                     (0.043)          (0.066)     
                Petal.Width                           -0.466 ***  
                                                      (0.072)     
                               ───────────────────────────────────
                N                   150              150          
                R2                    0.014            0.234      
                logLik              -86.732          -67.781      
                AIC                 179.464          143.563      
              ────────────────────────────────────────────────────
                *** p < 0.001; ** p < 0.01; * p < 0.05.           

Column names: names, model1, model2

# rows 9-11, columns 2-3 are the model statistics
# display them to one decimal place:
number_format(h)[9:11, 2:3] <- 1 
h
              ────────────────────────────────────────────────────
                                      (1)              (2)        
                               ───────────────────────────────────
                (Intercept)           3.419 ***        1.926 ***  
                                     (0.254)          (0.321)     
                Sepal.Length         -0.062            0.289 ***  
                                     (0.043)          (0.066)     
                Petal.Width                           -0.466 ***  
                                                      (0.072)     
                               ───────────────────────────────────
                N                   150              150          
                R2                    0.0              0.2        
                logLik              -86.7            -67.8        
                AIC                 179.5            143.6        
              ────────────────────────────────────────────────────
                *** p < 0.001; ** p < 0.01; * p < 0.05.           

Column names: names, model1, model2

Huxtable tables will automatically print to the right format in knitr documents, so you can just evaluate the object.

An alternative is to use pipe style:

huxreg(r1, r2) |>
  set_number_format(9:11, -1, 1)
              ────────────────────────────────────────────────────
                                      (1)              (2)        
                               ───────────────────────────────────
                (Intercept)           3.419 ***        1.926 ***  
                                     (0.254)          (0.321)     
                Sepal.Length         -0.062            0.289 ***  
                                     (0.043)          (0.066)     
                Petal.Width                           -0.466 ***  
                                                      (0.072)     
                               ───────────────────────────────────
                N                   150              150          
                R2                    0.0              0.2        
                logLik              -86.7            -67.8        
                AIC                 179.5            143.6        
              ────────────────────────────────────────────────────
                *** p < 0.001; ** p < 0.01; * p < 0.05.           

Column names: names, model1, model2

Incidentally, if you like the texreg output style, then you can use huxtablereg in that package, then set number_format as above.

Laverty answered 20/5, 2022 at 8:23 Comment(8)
Though this answer does technically work for reformatting these things to how I would want it, it actually does not solve my specific problem. I am using systemfit, and it seems that huxtable is unable to handle it correctly: it treats the various regressions I want to show as if they were a single model, which they technically sort of are, but the point of creating a table is to look at each one separately. Even when I try to use texreg::huxtablereg using formatting that works for all other versions of texreg, it comes out wrong.Rooftree
Re systemfit, that sounds like it could be a huxtable bug. Regarding texreg, that sounds like a separate issue, maybe worth checking ?huxtablereg and/or using huxtable formatting on the texreg object.Laverty
Also, if the output shows everything as a single model, why not just split the table into two?Laverty
I have a whole bunch (like 5-to-10) regressions within a systemfit object, and I may need to add an additional one on to that. I want to show them side by side because they use mainly the same variables. The main problem I have been running into is that it seems that huxtable just does not seem to recognize systemfit-generated objects, even when I disaggregate them into a list of individual equations, they are still typed as systemfit-regressions and the function seemingly refuses to work with them.Rooftree
So if I do e.g. the first example from ?systemfit and then call hr <- huxreg(fitols, statistics = c()), I get a long table with one column. If I then do e.g. cbind(hr[2:7,], hr[8:13,]) I get the columns side by side.Laverty
I have been busy and haven't had much time to get back to this issue. The method of your last comment does produce them roughly in the form I want, so that is what I am going for. If you just want confirmation of what the end result should look like, then that is correct, but it is not methodologically all that helpful when I am using a larger group of SUR regressions. texreg is usually able to distinguish the different regressions to format them, but for some reason, it does not appear to work only for huxtablereg. Cutting it 10 times is less practical than 2, but possible.Rooftree
Sounds like a texreg bug.Laverty
agreed. I think I might report it if it doesn't already have there attention.Rooftree
P
2

One approach would be to map2 two lists (one of models, one of desired digits), reduce the output by cbinding the second column of matrixreg (= the coefficients), and afterwards kableing them to the desired output format:

library(systemfit)
library(purrr)
library(kableExtra)

## generate some example models,
## e.g. fit3sls and fit2sls (used below):
example(systemfit)


## map2 and reduce:
map2(list(fit3sls, fit2sls), ## list of models
     list(2, 3), ## list of desired output digits per model
     function(MODEL, DIGITS) matrixreg(MODEL, digits = DIGITS)
     ) %>%
  ## cbind 2nd columns (coefficients) of upstream matrixreg results:
  reduce(~ cbind(.x, .y[,2])) %>%
  as.data.frame %>% ## convert to dataframe for kable
  kable(format = 'html') ## or 'latex' etc.

Below code shows (for other occasions, but since I were at it ...) how to modify the output digits per result class (inspired by this SO thread). So, if you were to choose digits per result class (e.g. print systemfit() results with 4, and lm() results with 6 digits) you could:

... inspect the "factory default" like this: systemfit:::print.systemfit (note the threefold colon) which reveals that the number of digits is part of the function's arguments (formals)

## > systemfit:::print.systemfit
## function (x, digits = max(3, getOption("digits") - 1), ...) 
## {
## etc.

... then hoist the "factory version" into your global environment:

print.systemfit <- systemfit:::print.systemfit

... and set the digits formal for the session like this:

formals(print.systemfit)$digits <-  10

... see if it works:

## > example(systemfit)
## ...
Coefficients:
demand_(Intercept)       demand_price      demand_income supply_(Intercept) 
     99.8954229115      -0.3162988049       0.3346355982      58.2754312020 
      supply_price   supply_farmPrice       supply_trend 
      0.1603665957       0.2481332947       0.2483023473 
## ...
## it works! :-)
Palgrave answered 18/5, 2022 at 21:10 Comment(0)
L
1

If you're happy using my huxtable package, this is very simple:

library(huxtable)
r1 <- lm(Sepal.Width ~ Sepal.Length, iris)
r2 <- lm(Sepal.Width ~ Sepal.Length + Petal.Width, iris)
h <- huxreg(r1, r2)
h
              ────────────────────────────────────────────────────
                                      (1)              (2)        
                               ───────────────────────────────────
                (Intercept)           3.419 ***        1.926 ***  
                                     (0.254)          (0.321)     
                Sepal.Length         -0.062            0.289 ***  
                                     (0.043)          (0.066)     
                Petal.Width                           -0.466 ***  
                                                      (0.072)     
                               ───────────────────────────────────
                N                   150              150          
                R2                    0.014            0.234      
                logLik              -86.732          -67.781      
                AIC                 179.464          143.563      
              ────────────────────────────────────────────────────
                *** p < 0.001; ** p < 0.01; * p < 0.05.           

Column names: names, model1, model2

# rows 9-11, columns 2-3 are the model statistics
# display them to one decimal place:
number_format(h)[9:11, 2:3] <- 1 
h
              ────────────────────────────────────────────────────
                                      (1)              (2)        
                               ───────────────────────────────────
                (Intercept)           3.419 ***        1.926 ***  
                                     (0.254)          (0.321)     
                Sepal.Length         -0.062            0.289 ***  
                                     (0.043)          (0.066)     
                Petal.Width                           -0.466 ***  
                                                      (0.072)     
                               ───────────────────────────────────
                N                   150              150          
                R2                    0.0              0.2        
                logLik              -86.7            -67.8        
                AIC                 179.5            143.6        
              ────────────────────────────────────────────────────
                *** p < 0.001; ** p < 0.01; * p < 0.05.           

Column names: names, model1, model2

Huxtable tables will automatically print to the right format in knitr documents, so you can just evaluate the object.

An alternative is to use pipe style:

huxreg(r1, r2) |>
  set_number_format(9:11, -1, 1)
              ────────────────────────────────────────────────────
                                      (1)              (2)        
                               ───────────────────────────────────
                (Intercept)           3.419 ***        1.926 ***  
                                     (0.254)          (0.321)     
                Sepal.Length         -0.062            0.289 ***  
                                     (0.043)          (0.066)     
                Petal.Width                           -0.466 ***  
                                                      (0.072)     
                               ───────────────────────────────────
                N                   150              150          
                R2                    0.0              0.2        
                logLik              -86.7            -67.8        
                AIC                 179.5            143.6        
              ────────────────────────────────────────────────────
                *** p < 0.001; ** p < 0.01; * p < 0.05.           

Column names: names, model1, model2

Incidentally, if you like the texreg output style, then you can use huxtablereg in that package, then set number_format as above.

Laverty answered 20/5, 2022 at 8:23 Comment(8)
Though this answer does technically work for reformatting these things to how I would want it, it actually does not solve my specific problem. I am using systemfit, and it seems that huxtable is unable to handle it correctly: it treats the various regressions I want to show as if they were a single model, which they technically sort of are, but the point of creating a table is to look at each one separately. Even when I try to use texreg::huxtablereg using formatting that works for all other versions of texreg, it comes out wrong.Rooftree
Re systemfit, that sounds like it could be a huxtable bug. Regarding texreg, that sounds like a separate issue, maybe worth checking ?huxtablereg and/or using huxtable formatting on the texreg object.Laverty
Also, if the output shows everything as a single model, why not just split the table into two?Laverty
I have a whole bunch (like 5-to-10) regressions within a systemfit object, and I may need to add an additional one on to that. I want to show them side by side because they use mainly the same variables. The main problem I have been running into is that it seems that huxtable just does not seem to recognize systemfit-generated objects, even when I disaggregate them into a list of individual equations, they are still typed as systemfit-regressions and the function seemingly refuses to work with them.Rooftree
So if I do e.g. the first example from ?systemfit and then call hr <- huxreg(fitols, statistics = c()), I get a long table with one column. If I then do e.g. cbind(hr[2:7,], hr[8:13,]) I get the columns side by side.Laverty
I have been busy and haven't had much time to get back to this issue. The method of your last comment does produce them roughly in the form I want, so that is what I am going for. If you just want confirmation of what the end result should look like, then that is correct, but it is not methodologically all that helpful when I am using a larger group of SUR regressions. texreg is usually able to distinguish the different regressions to format them, but for some reason, it does not appear to work only for huxtablereg. Cutting it 10 times is less practical than 2, but possible.Rooftree
Sounds like a texreg bug.Laverty
agreed. I think I might report it if it doesn't already have there attention.Rooftree

© 2022 - 2024 — McMap. All rights reserved.