Hi,
I currently use the package fixest
to estimate my regressions.
Then, I use the etable
function to produce a latex table with the results of multiple regressions.
I wrote a simple wrapper to make this pipeline a little bit smoother.
Also, as other colleagues of mine use esttab
command from stata
, I wanted my table to have the same format,
so we could easily interchange tables prodcued in r or stata.
The following gist is consisted of two parts.
- The R part: I added post process with the indicative name "mypostprocess", the postprocess has a few parts that one can shut down manually and independently:
mypostprocess
mypostprocess = function(x,onlyinner=TRUE,addfilename=TRUE ,comment_out_clutter=TRUE){
if(comment_out_clutter){
qui_se = grep("standard-errors in parentheses", x)
qui_significance = grep("Signif. Codes", x)
x[qui_se] = paste0("%",x[qui_se])
x[qui_significance]= gsub("\n","\n%",x[qui_significance])
class(x) = "etable_tex"
}
if(onlyinner){
qui_start = grep("begin\\{tabular", x)
qui_end = grep("end\\{tabular", x)
x = (x[(qui_start+1):(qui_end-1)])
class(x) = "etable_tex"
}
if(addfilename){
current_path = rstudioapi::getActiveDocumentContext()$path
current_file = gsub(".*/","",current_path)
x[length(x)+1] = paste0("% This table produced by the following file: \"",current_file,"\" on: ",Sys.Date()," \n ")
}
x
}
What's inside this postprocess?
A. comment_out_clutter
More often than not, I don't want to present the significane legend, nor how I cluster my Standart errors. I manually specify those details in the table's notes to save some space I comment out those lines instead of deleting them since I want to store the information. I simply don't want Latex to present it.
B. onlyinner
This argument deletes the \begin{tabular}
and \end{tabular}
I use it to replicate 'esttab' outputs.
C. addfilename
I really like this argument! It prints (as a comment) the file's name and the date of producing the table. I find that super useful when I want to update a table in my paper, without the need to find which file produces it. This argument requires 'rstudioapi' package.
An example of producng latex table using this postprocess
library(fixest)
df<-iris
lm1<-feols(Sepal.Length~Sepal.Width|Species,data=df)
lm2<-feols(Sepal.Length~Sepal.Width+Petal.Length|Species,data=df)
lm3<-feols(Petal.Length~Sepal.Width|Species,data=df)
etable(lm1,lm2,lm3,
vcov="hetero", #For clustered Ste, use vcov = ~Species)
digits = "r3", # rounding - coef/se
digits.stats = "r2", # rounding - fit stat (R^2 etc)
fitstat=c('r2','n'), # Which fit stat to keep?
style.tex = style.tex("base",line.top = "",line.bottom = "",
model.title="",stats.title="",
fixef.title = "",slopes.title = "",
fixef.suffix = " FE",fixef.prefix = "%",
var.title = "\\midrule", yesNo = "$\\checkmark$"),
headers = list("^:_:"=list("group1"=2,"group2"=1),
"^:_:"=list("a","b","c")),
extralines = list("^:_:"=list("group1"=2,"group2"=1),
"^:_:"=list("a","b","c")),
postprocess.tex = mypostprocess,
# One of the following lines should be commented out.
onlyinner=FALSE,view=TRUE, # The trial and error phase #
#replace = TRUE,file = "../tables/mynewtable.tex", # Save the table
tex = TRUE)
The view=True
renders the table in Rstudio Viewer, so I don't have to save a table, copy it to overleaf, compile it, just to find out that this is not the table I wanted in terms of specification or styling.
However, in order to use the view=TRUE
I need to shut off the onlyinner
part (using onlyinner=FALSE
).
When everything is ready, I comment out the following line onlyinner=FALSE,view=TRUE,
,
and uncommenting this line #replace = TRUE,file = "../tables/mynewtable.tex",
- The latex part the latex part is mainly based on the functions from this url - https://www.jwe.cc/2012/08/latex-stata-design/
Specifically, I add this lines of code to the preamble.
\makeatletter %this is needed to allow latex to revert to prior installations to fix noalign error
\let\estinput=\@@input %define a new input command so that we can still flatten the document
\newcommand{\estwide}[4]{
\vspace{.75ex}{
\begin{tabular*}
{#1}{@{\hskip\tabcolsep\extracolsep\fill}l*{#3}{#4}}
\toprule
\toprule
\estinput{#2}
\bottomrule
\bottomrule
\addlinespace[.75ex]
\end{tabular*}
}
}
% Table\Figures notes
\newcommand{\signifnote}{* p < 0.1, ** p < 0.05, *** p < 0.01.}
\newcommand{\clusternote}[1]{Standard errors are clustered at the #1 level and reported in parentheses. \signifnote}
\newenvironment{tablenotes}[1][1\linewidth]{\begin{minipage}[t]{ #1}\small{\itshape{Notes}: }}{\end{minipage}}
In the main text, I add the following:
\begin{table}
\centering
\caption{A beautiful table}\label{tab:wow}
\estwide{0.8\textwidth}{Tables/mynewtable}{3}{c}
\begin{tablenotes}[0.8\textwidth]
All regressions include Spices FE. Heteroskedasticity-robust standard-errors in parentheses. \signifnote}
\end{tablenotes}
\end{table}
When standard errors of all the regressions are clustered in the same way, adding \clusternote{state}
will add the following comment to the notes:
Standard errors are clustered at the state level and reported in parentheses. * p < 0.1, ** p < 0.05, *** p < 0.01.