Estimations table (export the results of multiples estimations to a DF or to Latex)
Source:R/alias_etable.R
, R/etable.R
etable.Rd
Aggregates the results of multiple estimations and displays them in the form of either a Latex
table or a data.frame
. Note that you will need the booktabs
package for the Latex table to
render properly. See setFixest_etable
to set the default values, and style.tex
to customize Latex output.
Usage
esttable(
...,
vcov = NULL,
stage = 2,
agg = NULL,
se = NULL,
ssc = NULL,
cluster = NULL,
.vcov = NULL,
.vcov_args = NULL,
digits = 4,
digits.stats = 5,
fitstat = NULL,
coefstat = "se",
ci = 0.95,
se.row = NULL,
se.below = NULL,
keep = NULL,
drop = NULL,
order = NULL,
dict = TRUE,
file = NULL,
replace = FALSE,
convergence = NULL,
signif.code = NULL,
headers = list("auto"),
fixef_sizes = FALSE,
fixef_sizes.simplify = TRUE,
keepFactors = TRUE,
family = NULL,
powerBelow = -5,
interaction.combine = NULL,
interaction.order = NULL,
i.equal = NULL,
depvar = TRUE,
style.df = NULL,
group = NULL,
extralines = NULL,
fixef.group = NULL,
drop.section = NULL,
poly_dict = c("", " square", " cube"),
postprocess.df = NULL,
fit_format = "__var__",
coef.just = NULL,
highlight = NULL,
coef.style = NULL,
export = NULL,
page.width = "fit",
div.class = "etable"
)
esttex(
...,
vcov = NULL,
stage = 2,
agg = NULL,
se = NULL,
ssc = NULL,
cluster = NULL,
.vcov = NULL,
.vcov_args = NULL,
digits = 4,
digits.stats = 5,
fitstat = NULL,
title = NULL,
coefstat = "se",
ci = 0.95,
se.row = NULL,
se.below = NULL,
keep = NULL,
drop = NULL,
order = NULL,
dict = TRUE,
file = NULL,
replace = FALSE,
convergence = NULL,
signif.code = NULL,
label = NULL,
float = NULL,
headers = list("auto"),
fixef_sizes = FALSE,
fixef_sizes.simplify = TRUE,
keepFactors = TRUE,
family = NULL,
powerBelow = -5,
interaction.combine = NULL,
interaction.order = NULL,
i.equal = NULL,
depvar = TRUE,
style.tex = NULL,
notes = NULL,
group = NULL,
extralines = NULL,
fixef.group = NULL,
placement = "htbp",
drop.section = NULL,
poly_dict = c("", " square", " cube"),
postprocess.tex = NULL,
tpt = FALSE,
arraystretch = NULL,
adjustbox = NULL,
fontsize = NULL,
fit_format = "__var__",
tabular = "normal",
highlight = NULL,
coef.style = NULL,
meta = NULL,
meta.time = NULL,
meta.author = NULL,
meta.sys = NULL,
meta.call = NULL,
meta.comment = NULL,
view = FALSE,
export = NULL,
markdown = NULL,
page.width = "fit",
div.class = "etable"
)
etable(
...,
vcov = NULL,
stage = 2,
agg = NULL,
se = NULL,
ssc = NULL,
cluster = NULL,
.vcov = NULL,
.vcov_args = NULL,
digits = 4,
digits.stats = 5,
tex,
fitstat = NULL,
title = NULL,
coefstat = "se",
ci = 0.95,
se.row = NULL,
se.below = NULL,
keep = NULL,
drop = NULL,
order = NULL,
dict = TRUE,
file = NULL,
replace = FALSE,
convergence = NULL,
signif.code = NULL,
label = NULL,
float = NULL,
headers = list("auto"),
fixef_sizes = FALSE,
fixef_sizes.simplify = TRUE,
keepFactors = TRUE,
family = NULL,
powerBelow = -5,
interaction.combine = NULL,
interaction.order = NULL,
i.equal = NULL,
depvar = TRUE,
style.tex = NULL,
style.df = NULL,
notes = NULL,
group = NULL,
extralines = NULL,
fixef.group = NULL,
placement = "htbp",
drop.section = NULL,
poly_dict = c("", " square", " cube"),
postprocess.tex = NULL,
postprocess.df = NULL,
tpt = FALSE,
arraystretch = NULL,
adjustbox = NULL,
fontsize = NULL,
fit_format = "__var__",
coef.just = NULL,
tabular = "normal",
highlight = NULL,
coef.style = NULL,
meta = NULL,
meta.time = NULL,
meta.author = NULL,
meta.sys = NULL,
meta.call = NULL,
meta.comment = NULL,
view = FALSE,
export = NULL,
markdown = NULL,
page.width = "fit",
div.class = "etable"
)
setFixest_etable(
digits = 4,
digits.stats = 5,
fitstat,
coefstat = c("se", "tstat", "confint"),
ci = 0.95,
se.below = TRUE,
keep,
drop,
order,
dict,
float,
fixef_sizes = FALSE,
fixef_sizes.simplify = TRUE,
family,
powerBelow = -5,
interaction.order = NULL,
depvar,
style.tex = NULL,
style.df = NULL,
notes = NULL,
group = NULL,
extralines = NULL,
fixef.group = NULL,
placement = "htbp",
drop.section = NULL,
view = FALSE,
markdown = NULL,
view.cache = FALSE,
page.width = "fit",
postprocess.tex = NULL,
postprocess.df = NULL,
fit_format = "__var__",
meta.time = NULL,
meta.author = NULL,
meta.sys = NULL,
meta.call = NULL,
meta.comment = NULL,
reset = FALSE,
save = FALSE
)
getFixest_etable()
# S3 method for etable_tex
print(x, ...)
# S3 method for etable_df
print(x, ...)
log_etable(type = "pdflatex")
Arguments
- ...
Used to capture different
fixest
estimation objects (obtained withfemlm
,feols
orfeglm
). Note that any other type of element is discarded. Note that you can give a list offixest
objects.- vcov
Versatile argument to specify the VCOV. In general, it is either a character scalar equal to a VCOV type, either a formula of the form:
vcov_type ~ variables
. The VCOV types implemented are: "iid", "hetero" (or "HC1"), "cluster", "twoway", "NW" (or "newey_west"), "DK" (or "driscoll_kraay"), and "conley". It also accepts object fromvcov_cluster
,vcov_NW
,NW
,vcov_DK
,DK
,vcov_conley
andconley
. It also accepts covariance matrices computed externally. Finally it accepts functions to compute the covariances. See thevcov
documentation in the vignette.- stage
Can be equal to
2
(default),1
,1:2
or2:1
. Only used if the object is an IV estimation: defines the stage to whichsummary
should be applied. Ifstage = 1
and there are multiple endogenous regressors or ifstage
is of length 2, then an object of classfixest_multi
is returned.- agg
A character scalar describing the variable names to be aggregated, it is pattern-based. For
sunab
estimations, the following keywords work: "att", "period", "cohort" andFALSE
(to have full disaggregation). All variables that match the pattern will be aggregated. It must be of the form"(root)"
, the parentheses must be there and the resulting variable name will be"root"
. You can add another root with parentheses:"(root1)regex(root2)"
, in which case the resulting name is"root1::root2"
. To name the resulting variable differently you can pass a named vector:c("name" = "pattern")
orc("name" = "pattern(root2)")
. It's a bit intricate sorry, please see the examples.- se
Character scalar. Which kind of standard error should be computed: “standard”, “hetero”, “cluster”, “twoway”, “threeway” or “fourway”? By default if there are clusters in the estimation:
se = "cluster"
, otherwisese = "iid"
. Note that this argument is deprecated, you should usevcov
instead.- ssc
An object of class
ssc.type
obtained with the functionssc
. Represents how the degree of freedom correction should be done.You must use the functionssc
for this argument. The arguments and defaults of the functionssc
are:adj = TRUE
,fixef.K="nested"
,cluster.adj = TRUE
,cluster.df = "min"
,t.df = "min"
,fixef.force_exact=FALSE)
. See the help of the functionssc
for details.- cluster
Tells how to cluster the standard-errors (if clustering is requested). Can be either a list of vectors, a character vector of variable names, a formula or an integer vector. Assume we want to perform 2-way clustering over
var1
andvar2
contained in the data.framebase
used for the estimation. All the followingcluster
arguments are valid and do the same thing:cluster = base[, c("var1", "var2")]
,cluster = c("var1", "var2")
,cluster = ~var1+var2
. If the two variables were used as fixed-effects in the estimation, you can leave it blank withvcov = "twoway"
(assumingvar1
[resp.var2
] was the 1st [resp. 2nd] fixed-effect). You can interact two variables using^
with the following syntax:cluster = ~var1^var2
orcluster = "var1^var2"
.- .vcov
A function to be used to compute the standard-errors of each fixest object. You can pass extra arguments to this function using the argument
.vcov_args
. See the example.- .vcov_args
A list containing arguments to be passed to the function
.vcov
.- digits
Integer or character scalar. Default is 4 and represents the number of significant digits to be displayed for the coefficients and standard-errors. To apply rounding instead of significance use, e.g.,
digits = "r3"
which will round at the first 3 decimals. If character, it must be of the form"rd"
or"sd"
withd
a digit (r
is for round ands
is for significance). For the number of digits for the fit statistics, usedigits.stats
. Note that when significance is used it does not exactly display the number of significant digits: see details for its exact meaning.- digits.stats
Integer or character scalar. Default is 5 and represents the number of significant digits to be displayed for the fit statistics. To apply rounding instead of significance use, e.g.,
digits = "r3"
which will round at the first 3 decimals. If character, it must be of the form"rd"
or"sd"
withd
a digit (r
is for round ands
is for significance). Note that when significance is used it does not exactly display the number of significant digits: see details for its exact meaning.- fitstat
A character vector or a one sided formula (both with only lowercase letters). A vector listing which fit statistics to display. The valid types are 'n', 'll', 'aic', 'bic' and r2 types like 'r2', 'pr2', 'war2', etc (see all valid types in
r2
). Also accepts valid types from the functionfitstat
. The default value depends on the models to display. Example of use:fitstat=c('n', 'cor2', 'ar2', 'war2')
, orfitstat=~n+cor2+ar2+war2
using a formula. You can use the dot to refer to default values:~ . + ll
would add the log-likelihood to the default fit statistics.- coefstat
One of
"se"
(default),"tstat"
or"confint"
. The statistic to report for each coefficient: the standard-error, the t-statistics or the confidence interval. You can adjust the confidence interval with the argumentci
.- ci
Level of the confidence interval, defaults to
0.95
. Only used ifcoefstat = confint
.- se.row
Logical scalar, default is
NULL
. Whether should be displayed the row with the type of standard-error for each model. Whentex = FALSE
, the default isTRUE
. Whentex = FALSE
, the row is showed only when there is a table-footer and the types of standard-errors differ across models.- se.below
Logical or
NULL
(default). Should the standard-errors be displayed below the coefficients? IfNULL
, then this isTRUE
for Latex andFALSE
otherwise.- keep
Character vector. This element is used to display only a subset of variables. This should be a vector of regular expressions (see
base::regex
help for more info). Each variable satisfying any of the regular expressions will be kept. This argument is applied post aliasing (see argumentdict
). Example: you have the variablex1
tox55
and want to display onlyx1
tox9
, then you could usekeep = "x[[:digit:]]$"
. If the first character is an exclamation mark, the effect is reversed (e.g. keep = "!Intercept" means: every variable that does not contain “Intercept” is kept). See details.- drop
Character vector. This element is used if some variables are not to be displayed. This should be a vector of regular expressions (see
base::regex
help for more info). Each variable satisfying any of the regular expressions will be discarded. This argument is applied post aliasing (see argumentdict
). Example: you have the variablex1
tox55
and want to display onlyx1
tox9
, then you could usedrop = "x[[:digit:]]{2}
". If the first character is an exclamation mark, the effect is reversed (e.g. drop = "!Intercept" means: every variable that does not contain “Intercept” is dropped). See details.- order
Character vector. This element is used if the user wants the variables to be ordered in a certain way. This should be a vector of regular expressions (see
base::regex
help for more info). The variables satisfying the first regular expression will be placed first, then the order follows the sequence of regular expressions. This argument is applied post aliasing (see argumentdict
). Example: you have the following variables:month1
tomonth6
, thenx1
tox5
, thenyear1
toyear6
. If you want to display first the x's, then the years, then the months you could use:order = c("x", "year")
. If the first character is an exclamation mark, the effect is reversed (e.g. order = "!Intercept" means: every variable that does not contain “Intercept” goes first). See details.- dict
A named character vector or a logical scalar. It changes the original variable names to the ones contained in the
dict
ionary. E.g. to change the variables nameda
andb3
to (resp.) “$log(a)$” and to “$bonus^3$”, usedict=c(a="$log(a)$",b3="$bonus^3$")
. By default, it is equal togetFixest_dict()
, a default dictionary which can be set withsetFixest_dict
. You can usedict = FALSE
to disable it. By defaultdict
modifies the entries in the global dictionary, to disable this behavior, use "reset" as the first element (ex:dict=c("reset", mpg="Miles per gallon")
).- file
A character scalar. If provided, the Latex (or data frame) table will be saved in a file whose path is
file
. If you provide this argument, then a Latex table will be exported, to export a regulardata.frame
, use argumenttex = FALSE
.- replace
Logical, default is
FALSE
. Only used if optionfile
is used. Should the exported table be written in a new file that replaces any existing file?- convergence
Logical, default is missing. Should the convergence state of the algorithm be displayed? By default, convergence information is displayed if at least one model did not converge.
- signif.code
Named numeric vector, used to provide the significance codes with respect to the p-value of the coefficients. Default is
c("***"=0.01, "**"=0.05, "*"=0.10)
for a Latex table andc("***"=0.001, "**"=0.01, "*"=0.05, "."=0.10)
for a data.frame (to conform with R's default). To suppress the significance codes, usesignif.code=NA
orsignif.code=NULL
. Can also be equal to"letters"
, then the default becomesc("a"=0.01, "b"=0.05, "c"=0.10)
.- headers
Character vector or list. Adds one or more header lines in the table. A header line can be represented by a character vector or a named list of numbers where the names are the cell values and the numbers are the span. Example:
headers=list("M"=2, "F"=3)
will create a row with 2 times "M" and three time "F" (this is identical toheaders=rep(c("M", "F"), c(2, 3))
). You can stack header lines within a list, in that case the list names will be displayed in the leftmost cell. Example:headers=list(Gender=list("M"=2, "F"=3), Country="US"
will create two header lines. Whentex = TRUE
, you can add a rule to separate groups by using":_:"
somewhere in the row name (ex:headers=list(":_:Gender"=list("M"=2, "F"=3))
. You can monitor the placement by inserting a special character in the row name: "^" means at the top, "-" means in the middle (default) and "_" means at the bottom. Example:headers=list("_Country"="US")
will add the country row as the very last header row (after the model row). Finally, you can use the special value "auto" to include automatic headers when the data contains split sample estimations. By default it is equal tolist("auto")
. You can use.()
instead oflist()
.- fixef_sizes
(Tex only.) Logical, default is
FALSE
. IfTRUE
and fixed-effects were used in the models, then the number of "units" per fixed-effect dimension is also displayed.- fixef_sizes.simplify
Logical, default is
TRUE
. Only used iffixef_sizes = TRUE
. IfTRUE
, the fixed-effects sizes will be displayed in parentheses instead of in a separate line if there is no ambiguity (i.e. if the size is constant across models).- keepFactors
Logical, default is
TRUE
. IfFALSE
, then factor variables are displayed as fixed-effects and no coefficient is shown.- family
Logical, default is missing. Whether to display the families of the models. By default this line is displayed when at least two models are from different families.
- powerBelow
(Tex only.) Integer, default is -5. A coefficient whose value is below
10**(powerBelow+1)
is written with a power in Latex. For example0.0000456
would be written4.56$\\times 10^{-5}$
by default. SettingpowerBelow = -6
would lead to0.00004
in Latex.- interaction.combine
Character scalar, defaults to
" $\\times$ "
for Tex and to" = "
otherwise. When the estimation contains interactions, then the variables names (after aliasing) are combined with this argument. For example: ifdict = c(x1="Wind", x2="Rain")
and you have the following interactionx1:x2
, then it will be renamed (by default)Wind $\\times$ Rain
-- usinginteraction.combine = "*"
would lead toWind*Rain
.- interaction.order
Character vector of regular expressions. Only affects variables that are interacted like x1 and x2 in
feols(y ~ x1*x2, data)
. You can change the order in which the interacted variables are displayed: e.g.interaction.order = "x2"
would lead to "x1 x x2" instead of "x1 x x2". Please look at the argument 'order' and the dedicated section in the help page for more information.- i.equal
Character scalar, defaults to
" $=$ "
whentex = TRUE
and" = "
otherwise. Only affects factor variables created with the functioni
, tells how the variable should be linked to its value. For example if you have theSpecies
factor from theiris
data set, by default the display of the variable isSpecies = Setosa
, etc. Ifi.equal = ": "
the display becomesSpecies: Setosa
.- depvar
Logical, default is
TRUE
. Whether a first line containing the dependent variables should be shown.- style.df
An object created by the function
style.df
It represents the style of the data frame returned (iftex = FALSE
), see the documentation ofstyle.df
.- group
A list. The list elements should be vectors of regular expressions. For each elements of this list: A new line in the table is created, all variables that are matched by the regular expressions are discarded (same effect as the argument
drop
) andTRUE
orFALSE
will appear in the model cell, depending on whether some of the previous variables were found in the model. Example:group=list("Controls: personal traits"=c("gender", "height", "weight"))
will create an new line with"Controls: personal traits"
in the leftmost cell, all three variables gender, height and weight are discarded,TRUE
appearing in each model containing at least one of the three variables (the style ofTRUE
/FALSE
is governed by the argumentyesNo
). You can control the placement of the new row by using 1 or 2 special characters at the start of the row name. The meaning of these special characters are: 1)"^"
: coef.,"-"
: fixed-effect,"_"
: stats, section; 2)"^"
: 1st,"_"
: last, row. For example:group=list("_^Controls"=stuff)
will place the line at the top of the 'stats' section, and usinggroup=list("^_Controls"=stuff)
will make the row appear at the bottom of the coefficients section. For details, see the dedicated section.- extralines
A vector, a list or a one sided formula. The list elements should be either a vector representing the value of each cell, a list of the form
list("item1" = #item1, "item2" = #item2, etc)
, or a function. This argument can be many things, please have a look at the dedicated help section; a simplified description follows. For each elements of this list: A new line in the table is created, the list name being the row name and the vector being the content of the cells. Example:extralines=list("Sub-sample"=c("<20 yo", "all", ">50 yo"))
will create an new line with"Sub-sample"
in the leftmost cell, the vector filling the content of the cells for the three models. You can control the placement of the new row by using 1 or 2 special characters at the start of the row name. The meaning of these special characters are:"^"
: coef.,"-"
: fixed-effect,"_"
: stats, section;"^"
: 1st,"_"
: last, row. For example:extralines=list("__Controls"=stuff)
will place the line at the bottom of the stats section, and usingextralines=list("^^Controls"=stuff)
will make the row appear at the top of the 'coefficients' section. For details, see the dedicated section. You can use.()
instead oflist()
.
- fixef.group
Logical scalar or list (default is
NULL
). If equal toTRUE
, then all fixed-effects always appearing jointly in models will be grouped in one row. If a list, its elements must be character vectors of regular expressions and the list names will be the row names. For ex.fixef.group=list("Dates fixed-effects"="Month|Day")
will remove the"Month"
and"Day"
fixed effects from the display and replace them with a single row named "Dates fixed-effects". You can monitor the placement of the new row with two special characters telling where to place the row within a section: first in which section it should appear:"^"
(coef.),"-"
(fixed-effects), or"_"
(stat.) section; then whether the row should be"^"
(first), or"_"
(last). These two special characters must appear first in the row names. Please see the dedicated section- drop.section
Character vector which can be of length 0 (i.e. equal to
NULL
). Can contain the values "coef", "fixef", "slopes" or "stats". It would drop, respectively, the coefficients section, fixed-effects section, the variables with varying slopes section or the fit statistics section.- poly_dict
Character vector, default is
c("", " square", " cube")
. When raw polynomials (x^2
, etc) are used, the variables are automatically renamed andpoly_dict
rules the display of the power. For powers greater than the number of elements of the vector, the value displayed is$^{pow}$
in Latex and^ pow
in the R console.- postprocess.df
A function that will postprocess.tex the resulting data.frame. Only when
tex = FALSE
. By default it is equal toNULL
, meaning that there is no postprocessing. Whentex = TRUE
, see the argumentpostprocess.tex
.- fit_format
Character scalar, default is
"__var__"
. Only used in the presence of IVs. By default the endogenous regressors are namedfit_varname
in the second stage. The format of the endogenous regressor to appear in the table is governed byfit_format
. For instance, by default, the prefix"fit_"
is removed, leading to onlyvarname
to appear. Iffit_format = "$\\\\hat{__var__$"}
, then"$\\hat{varname$"}
will appear in the table.- coef.just
(DF only.) Either
"."
,"("
,"l"
,"c"
or"r"
, default isNULL
. How the coefficients should be justified. IfNULL
then they are right aligned ifse.below = FALSE
and aligned to the dot ifse.below = TRUE
. The keywords stand respectively for dot-, parenthesis-, left-, center- and right-aligned.- highlight
List containing coefficients to highlight. Highlighting is of the form
.("options1" = "coefs1", "options2" = "coefs2", etc)
. The coefficients to be highlighted can be written in three forms: 1) row, eg"x1"
will highlight the full row of the variablex1
; 2) cells, use'@'
after the coefficient name to give the column, it accepts ranges, eg"x1@2, 4-6, 8"
will highlight only the columns 2, 4, 5, 6, and 8 of the variablex1
; 3) range, by giving the top-left and bottom-right values separated with a semi-colon, eg"x1@2 ; x3@5"
will highlight from the column 2 ofx1
to the 5th column ofx3
. Coefficient names are partially matched, use a'%'
first to refer to the original name (before dictionary) and use'@'
first to use a regular expression. You can add a vector of row/cell/range. The options are a comma-separated list of items. By default the highlighting is done with a frame (a thick box) around the coefficient, use'rowcol'
to highlight with a row color instead. Here are the other options:'se'
to highlight the standard-errors too;'square'
to have a square box (instead of rounded);'thick1'
to'thick6'
to monitor the width of the box;'sep0'
to'sep9'
to monitor the inner spacing. Finally the remaining option is the color: simply add an R color (it must be a valid R color!). You can use"color!alpha"
with "alpha" a number between 0 to 100 to change the alpha channel of the color.- coef.style
Named list containing styles to be applied to the coefficients. It must be of the form
.("style1" = "coefs1", "style2" = "coefs2", etc)
. The style must contain the string":coef:"
(or":coef_se:"
to style both the coefficient and its standard-error). The string:coef:
will be replaced verbatim by the coefficient value. For example use"\\textbf{:coef:}"
to put the coefficient in bold. Note that markdown markup is enabled so"**:coef:**"
would also put it in bold. The coefficients to be styled can be written in three forms: 1) row, eg"x1"
will style the full row of the variablex1
; 2) cells, use'@'
after the coefficient name to give the column, it accepts ranges, eg"x1@2, 4-6, 8"
will style only the columns 2, 4, 5, 6, and 8 of the variablex1
; 3) range, by giving the top-left and bottom-right values separated with a semi-colon, eg"x1@2 ; x3@5"
will style from the column 2 ofx1
to the 5th column ofx3
. Coefficient names are partially matched, use a'%'
first to refer to the original name (before dictionary) and use'@'
first to use a regular expression. You can add a vector of row/cell/range.- export
Character scalar giving the path to a PNG file to be created, default is
NULL
. If provided, the Latex table will be converted to PNG and copied to theexport
location. Note that for this option to work you need a working distribution ofpdflatex
,imagemagick
andghostscript
, or the R packagestinytex
andpdftools
.- page.width
Character scalar equal to
'fit'
(default),'a4'
or'us'
; or a single Latex measure (like'17cm'
) or a double one (like"21, 2cm"
). Only used when the Latex table is to be viewed (view = TRUE
), exported (export != NULL
) or displayed in Rmarkdown (markdown != NULL
). It represents the text width of the page in which the Latex table will be inserted. By default,'fit'
, the page fits exactly the table (i.e. text width = table width). If'a4'
or'us'
, two times 2cm is removed from the page width to account for margins. Providing a page width and a margin width, like in"17in, 1in"
, enables a correct display of the argumentadjustbox
. Note that the margin width represent the width of a single side margin (and hence will be doubled).- div.class
Character scalar, default is
"etable"
. Only used in Rmarkdown documents whenmarkdown = TRUE
. The table in an image format is embedded in a<div>
container, and that container is of classdiv.class
.- title
(Tex only.) Character scalar. The title of the Latex table.
- label
(Tex only.) Character scalar. The label of the Latex table.
- float
(Tex only.) Logical. By default, if the argument
title
orlabel
is provided, it is set toTRUE
. Otherwise, it is set toFALSE
.- style.tex
An object created by the function
style.tex
. It represents the style of the Latex table, see the documentation ofstyle.tex
.- notes
(Tex only.) Character vector. If provided, a
"notes"
section will be added at the end right after the end of the table, containing the text of this argument. If it is a vector, it will be collapsed with new lines. Iftpt = TRUE
, the behavior is different: each element of the vector is an item. If the first element of the vector starts with"@"
, then it will be included verbatim, and in case oftpt = TRUE
, right before the first item. If that element is provided, it will replace the value defined instyle.tex(notes.intro)
orstyle.tex(notes.tpt.intro)
.- placement
(Tex only.) Character string giving the position of the float in Latex. Default is "htbp". It must consist of only the characters 'h', 't', 'b', 'p', 'H' and '!'. Reminder: h: here; t: top; b: bottom; p: float page; H: definitely here; !: prevents Latex to look for other positions. Note that it can be equal to the empty string (and you'll get the default placement).
- postprocess.tex
A function that will postprocess the character vector defining the latex table. Only when
tex = TRUE
. By default it is equal toNULL
, meaning that there is no postprocessing. Whentex = FALSE
, see the argumentpostprocess.df
. See details.- tpt
(Tex only.) Logical scalar, default is FALSE. Whether to use the
threeparttable
environment. If so, thenotes
will be integrated into thetablenotes
environment.- arraystretch
(Tex only.) A numeric scalar, default is
NULL
. If provided, the command\\renewcommand*{\\arraystretch{x}}
is inserted, replacingx
by the value ofarraystretch
. The changes are specific to the current table and do not affect the rest of the document.- adjustbox
(Tex only.) A logical, numeric or character scalar, default is
NULL
. If notNULL
, the table is inserted within theadjustbox
environment. By default the options arewidth = 1\\textwidth, center
(ifTRUE
). A numeric value changes the value before\\textwidth
. You can also add a character of the form"x tw"
or"x th"
withx
a number and where tw (th) stands for text-width (text-height). Finally any other character value is passed verbatim as anadjustbox
option.- fontsize
(Tex only.) A character scalar, default is
NULL
. Can be equal totiny
,scriptsize
,footnotesize
,small
,normalsize
,large
, orLarge
. The change affect the table only (and not the rest of the document).- tabular
(Tex only.) Character scalar equal to "normal" (default),
"*"
or"X"
. Represents the type of tabular environment to use: eithertabular
,tabular*
ortabularx
.- meta
(Tex only.) A one-sided formula that shall contain the following elements: date or time, sys, author, comment and call. Default is
NULL
. This argument is a shortcut to controlling the meta information that can be displayed in comments before the table. Typically if the element is in the formula, it means that the argument will be equal toTRUE
. Example:meta = ~time+call
is equivalent tometa.time = TRUE
andmeta.call = TRUE
. The "author" and "comment" elements are a bit special. Usingmeta = ~author("Mark")
is equivalent tometa.author = "Mark"
whilemeta=~author
is equiv. tometa.author = TRUE
. The "comment" must be used with a character string inside:meta = ~comment("this is a comment")
. The order in the formula controls the order of appearance of the meta elements. It also has precedence over themeta.XX
arguments.- meta.time
(Tex only.) Either a logical scalar (default is
FALSE
) or "time" or "date". Whether to include the time (ifTRUE
or "time") or the date (if "date") of creation of the table in a comment right before the table.- meta.author
(Tex only.) A logical scalar (default is
FALSE
) or a character vector. IfTRUE
then the identity of the author (deduced from the system user inSys.info()
) is inserted in a comment right before the table. If a character vector, then it should contain author names that will be inserted as comments before the table, prefixed with"Created by:"
. For free-form comments see the argumentmeta.comment
.- meta.sys
(Tex only.) A logical scalar, default is
FALSE
. Whether to include system information (fromSys.info()
) in a comment right before the table.- meta.call
(Tex only.) Logical scalar, default is
FALSE
. IfTRUE
then the call to the function is inserted right before the table in a comment.- meta.comment
(Tex only.) A character vector containing free-form comments to be inserted right before the table.
- view
Logical, default is
FALSE
. IfTRUE
, then the table generated in Latex byetable
and then is displayed in the viewer pane. Note that for this option to work you need i) pdflatex or the R packagetinytex
, ii) imagemagick and ghostscript, or the R packagepdftools
. All three software must be installed and on the path.- markdown
Character scalar giving the location of a directory, or a logical scalar. Default is
NULL
. This argument only works in Rmarkdown documents, when knitting the document. If provided: two behaviors depending on context. A) if the output document is Latex, the table is exported in Latex. B) if the output document is not Latex, the table will be exported to PNG at the desired location and inserted in the document via a markdown link. If equal toTRUE
, the default location of the PNGs is a temporary folder forR > 4.0.0
, or to"images/etable/"
for earlier versions.- tex
Logical: whether the results should be a data.frame or a Latex table. By default, this argument is
TRUE
if the argumentfile
(used for exportation) is not missing; it is equal toFALSE
otherwise.- view.cache
Logical, default is
FALSE
. Only used whenview = TRUE
. Whether the PNGs of the tables should be cached.- reset
(
setFixest_etable
only.) Logical, default isFALSE
. IfTRUE
, this will reset all the default values that were already set by the user in previous calls.- save
Either a logical or equal to
"reset"
. Default isFALSE
. IfTRUE
then the value is set permanently at the project level, this means that if you restart R, you will still obtain the previously saved defaults. This is done by writing in the".Renviron"
file, located in the project's working directory, hence we must have write permission there for this to work, and only works with Rstudio. If equal to "reset", the default at the project level is erased. Since there is writing in a file involved, permission is asked to the user.- x
An object returned by
etable
.- type
Character scalar equal to 'pdflatex' (default), 'magick', 'dir' or 'tex'. Which log file to report; if 'tex', the full source code of the tex file is returned, if 'dir': the directory of the log files is returned.
Value
If tex = TRUE
, the lines composing the Latex table are returned invisibly while the table
is directly prompted on the console.
If tex = FALSE
, the data.frame is directly returned. If the argument file
is not missing,
the data.frame
is printed and returned invisibly.
Details
The function esttex
is equivalent to the function etable
with argument tex = TRUE
.
The function esttable
is equivalent to the function etable
with argument tex = FALSE
.
To display the table, you will need the Latex package booktabs
which contains
the \\toprule
, \\midrule
and \\bottomrule
commands.
You can permanently change the way your table looks in Latex by using setFixest_etable
.
The following vignette gives an example as well as illustrates how to use the style
and
postprocessing functions: Exporting estimation tables.
When the argument postprocess.tex
is not missing, two additional tags will be included in the
character vector returned by etable
: "%start:tab\\n"
and "%end:tab\\n"
. These can be used
to identify the start and end of the tabular and are useful to insert code within the table
environment.
Functions
esttable()
: Exports the results of multiplefixest
estimations in a Latex table.esttex()
: Exports the results of multiplefixest
estimations in a Latex table.
How does digits
handle the number of decimals displayed?
The default display of decimals is the outcome of an algorithm. Let's take the example
of digits = 3
which "kind of" requires 3 significant digits to be displayed.
For numbers greater than 1 (in absolute terms), their integral part is always displayed and
the number of decimals shown is equal to digits
minus the number of digits in the integral
part. This means that 12.345
will be displayed as 12.3
. If the number of decimals should
be 0, then a single decimal is displayed to suggest that the number is not whole. This means
that 1234.56
will be displayed as 1234.5
. Note that if the number is whole, no decimals
are shown.
For numbers lower than 1 (in absolute terms), the number of decimals displayed is equal
to digits
except if there are only 0s in which case the first significant digit is shown.
This means that 0.01234
will be displayed as 0.012
(first rule), and that 0.000123 will
be displayed as 0.0001
(second rule).
Arguments keep, drop and order
The arguments keep
, drop
and order
use regular expressions. If you are not aware
of regular expressions, I urge you to learn it, since it is an extremely powerful way
to manipulate character strings (and it exists across most programming languages).
For example drop = "Wind" would drop any variable whose name contains "Wind". Note that
variables such as "Temp:Wind" or "StrongWind" do contain "Wind", so would be dropped.
To drop only the variable named "Wind", you need to use drop = "^Wind$"
(with "^" meaning
beginning, resp. "$" meaning end, of the string => this is the language of regular expressions).
Although you can combine several regular expressions in a single character string using pipes,
drop
also accepts a vector of regular expressions.
You can use the special character "!" (exclamation mark) to reverse the effect of the regular
expression (this feature is specific to this function). For example drop = "!Wind"
would drop
any variable that does not contain "Wind".
You can use the special character "%" (percentage) to make reference to the original variable
name instead of the aliased name. For example, you have a variable named "Month6"
, and use a
dictionary dict = c(Month6="June")
. Thus the variable will be displayed as "June"
. If you
want to delete that variable, you can use either drop="June"
, or drop="%Month6"
(which makes
reference to its original name).
The argument order
takes in a vector of regular expressions, the order will follow the
elements of this vector. The vector gives a list of priorities, on the left the elements with
highest priority. For example, order = c("Wind", "!Inter", "!Temp") would give highest
priorities to the variables containing "Wind" (which would then appear first), second highest
priority is the variables not containing "Inter", last, with lowest priority, the variables not
containing "Temp". If you had the following variables: (Intercept), Temp:Wind, Wind, Temp you
would end up with the following order: Wind, Temp:Wind, Temp, (Intercept).
The argument extralines
The argument extralines
adds well... extra lines to the table. It accepts either a list, or a
one-sided formula.
For each line, you can define the values taken by each cell using 4 different ways: a) a vector, b) a list, c) a function, and d) a formula.
If a vector, it should represent the values taken by each cell. Note that if the length of the vector is smaller than the number of models, its values are recycled across models, but the length of the vector is required to be a divisor of the number of models.
If a list, it should be of the form list("item1" = #item1, "item2" = #item2, etc)
. For example
list("A"=2, "B"=3)
leads to c("A", "A", "B", "B", "B")
. Note that if the number of items is
1, you don't need to add = 1
. For example list("A"=2, "B")
is valid and leads to
c("A", "A", "B"
. As for the vector the values are recycled if necessary.
If a function, it will be applied to each model and should return a scalar (NA
values
returned are accepted).
If a formula, it must be one-sided and the elements in the formula must represent either
extralines
macros, either fit statistics (i.e. valid types of the function fitstat
). One
new line will be added for each element of the formula. To register extralines
macros, you
must first register them in extralines_register
.
Finally, you can combine as many lines as wished by nesting them in a list. The names of the
nesting list are the row titles (values in the leftmost cell). For example
extralines = list(~r2, Controls = TRUE, Group = list("A"=2, "B"))
will add three lines,
the titles of which are "R2", "Controls" and "Group".
Controlling the placement of extra lines
The arguments group
, extralines
and fixef.group
allow to add customized lines in the
table. They can be defined via a list where the list name will be the row name. By default, the
placement of the extra line is right after the coefficients (except for fixef.group
, covered
in the last paragraph). For instance, group = list("Controls" = "x[[:digit:]]")
will create a
line right after the coefficients telling which models contain the control variables.
But the placement can be customized. The previous example (of the controls) will be used for
illustration (the mechanism for extralines
and fixef.group
is identical).
The row names accept 2 special characters at the very start. The first character tells in which
section the line should appear: it can be equal to "^"
, "-"
, or "_"
, meaning respectively
the coefficients, the fixed-effects and the statistics section (which typically appear at the
top, mid and bottom of the table). The second one governs the placement of the new line within
the section: it can be equal to "^"
, meaning first line, or "_"
, meaning last line.
Let's have some examples. Using the previous example, writing "_^Controls"
would place the new
line at the top of the statistics section. Writing "-_Controls"
places it as the last row of
the fixed-effects section; "^^Controls"
at the top row of the coefficients section; etc...
The second character is optional, the default placement being in the bottom. This means that
"_Controls"
would place it at the bottom of the statistics section.
The placement in fixef.group
is defined similarly, only the default placement is different.
Its default placement is at the top of the fixed-effects section.
Escaping special Latex characters
By default on all instances (with the notable exception of the elements of style.tex
)
special Latex characters are escaped. This means that title="Exports in million $."
will be
exported as "Exports in million \\$."
: the dollar sign will be escaped. This is true for the
following characters: &, $
, %, _, ^ and #.
Note, importantly, that equations are NOT escaped. This means that
title="Functional form $a_i \\times x^b$, variation in %."
will be displayed as:
"Functional form $a_i \\times x^b$, variation in \\%."
: only the
last percentage will be escaped.
If for some reason you don't want the escaping to take place, the arguments headers
and
extralines
are the only ones allowing that. To disable escaping, add the special token
":tex:" in the row names.
Example: in headers=list(":tex:Row title"="weird & & %\\n tex stuff\\\\")
,
the elements will be displayed verbatim. Of course, since it can easily ruin your table,
it is only recommended to super users.
Markdown markup
Within anything that is Latex-escaped (see previous section), you can use a markdown-style
markup to put the text in italic and/or bold. Use *text*
, **text**
or ***text***
to
put some text in, respectively, italic (with \\textit
), bold (with \\textbf
) and italic-bold.
The markup can be escaped by using an backslash first. For example "***This: \\***, are three stars***"
will leave the three stars in the middle untouched.
See also
For styling the table: setFixest_etable
, style.tex
, style.df
.
See also the main estimation functions femlm
, feols
or feglm
.
Use summary.fixest
to see the results with the appropriate standard-errors, fixef.fixest
to extract the
fixed-effects coefficients.
Examples
est1 = feols(Ozone ~ i(Month) / Wind + Temp, data = airquality)
#> NOTE: 37 observations removed because of NA values (LHS: 37).
est2 = feols(Ozone ~ i(Month, Wind) + Temp | Month, data = airquality)
#> NOTE: 37 observations removed because of NA values (LHS: 37).
# Displaying the two results in a single table
etable(est1, est2)
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Constant -100.2*** (26.35)
#> Month = 6 -54.99* (26.34)
#> Month = 7 35.89. (18.37)
#> Month = 8 44.52* (18.05)
#> Month = 9 -11.78 (18.22)
#> Temp 2.042*** (0.3078) 2.042*** (0.2242)
#> Wind x Month = 5 -1.086 (1.127) -1.086** (0.1408)
#> Wind x Month = 6 2.046 (1.784) 2.046*** (0.0398)
#> Wind x Month = 7 -5.616*** (1.316) -5.616*** (0.1554)
#> Wind x Month = 8 -6.515*** (1.220) -6.515*** (0.2203)
#> Wind x Month = 9 -1.349 (1.147) -1.349* (0.3175)
#> Fixed-Effects: ----------------- ------------------
#> Month No Yes
#> ________________ _________________ __________________
#> S.E. type IID by: Month
#> Observations 116 116
#> R2 0.68106 0.68106
#> Within R2 -- 0.58296
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# keep/drop: keeping only interactions
etable(est1, est2, keep = " x ")
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Wind x Month = 5 -1.086 (1.127) -1.086** (0.1408)
#> Wind x Month = 6 2.046 (1.784) 2.046*** (0.0398)
#> Wind x Month = 7 -5.616*** (1.316) -5.616*** (0.1554)
#> Wind x Month = 8 -6.515*** (1.220) -6.515*** (0.2203)
#> Wind x Month = 9 -1.349 (1.147) -1.349* (0.3175)
#> Fixed-Effects: ----------------- ------------------
#> Month No Yes
#> ________________ _________________ __________________
#> S.E. type IID by: Month
#> Observations 116 116
#> R2 0.68106 0.68106
#> Within R2 -- 0.58296
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# or using drop (see regexp help):
etable(est1, est2, drop = "^(Month|Temp|\\()")
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Constant -100.2*** (26.35)
#> Wind x Month = 5 -1.086 (1.127) -1.086** (0.1408)
#> Wind x Month = 6 2.046 (1.784) 2.046*** (0.0398)
#> Wind x Month = 7 -5.616*** (1.316) -5.616*** (0.1554)
#> Wind x Month = 8 -6.515*** (1.220) -6.515*** (0.2203)
#> Wind x Month = 9 -1.349 (1.147) -1.349* (0.3175)
#> Fixed-Effects: ----------------- ------------------
#> Month No Yes
#> ________________ _________________ __________________
#> S.E. type IID by: Month
#> Observations 116 116
#> R2 0.68106 0.68106
#> Within R2 -- 0.58296
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# keep/drop: dropping interactions
etable(est1, est2, drop = " x ")
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Constant -100.2*** (26.35)
#> Month = 6 -54.99* (26.34)
#> Month = 7 35.89. (18.37)
#> Month = 8 44.52* (18.05)
#> Month = 9 -11.78 (18.22)
#> Temp 2.042*** (0.3078) 2.042*** (0.2242)
#> Fixed-Effects: ----------------- -----------------
#> Month No Yes
#> _______________ _________________ _________________
#> S.E. type IID by: Month
#> Observations 116 116
#> R2 0.68106 0.68106
#> Within R2 -- 0.58296
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# or using keep ("!" reverses the effect):
etable(est1, est2, keep = "! x ")
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Constant -100.2*** (26.35)
#> Month = 6 -54.99* (26.34)
#> Month = 7 35.89. (18.37)
#> Month = 8 44.52* (18.05)
#> Month = 9 -11.78 (18.22)
#> Temp 2.042*** (0.3078) 2.042*** (0.2242)
#> Fixed-Effects: ----------------- -----------------
#> Month No Yes
#> _______________ _________________ _________________
#> S.E. type IID by: Month
#> Observations 116 116
#> R2 0.68106 0.68106
#> Within R2 -- 0.58296
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# order: Wind variable first, intercept last (note the "!" to reverse the effect)
etable(est1, est2, order = c("Wind", "!Inter"))
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Wind x Month = 5 -1.086 (1.127) -1.086** (0.1408)
#> Wind x Month = 6 2.046 (1.784) 2.046*** (0.0398)
#> Wind x Month = 7 -5.616*** (1.316) -5.616*** (0.1554)
#> Wind x Month = 8 -6.515*** (1.220) -6.515*** (0.2203)
#> Wind x Month = 9 -1.349 (1.147) -1.349* (0.3175)
#> Constant -100.2*** (26.35)
#> Month = 6 -54.99* (26.34)
#> Month = 7 35.89. (18.37)
#> Month = 8 44.52* (18.05)
#> Month = 9 -11.78 (18.22)
#> Temp 2.042*** (0.3078) 2.042*** (0.2242)
#> Fixed-Effects: ----------------- ------------------
#> Month No Yes
#> ________________ _________________ __________________
#> S.E. type IID by: Month
#> Observations 116 116
#> R2 0.68106 0.68106
#> Within R2 -- 0.58296
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Month, then interactions, then the rest
etable(est1, est2, order = c("^Month", " x "))
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Month = 6 -54.99* (26.34)
#> Month = 7 35.89. (18.37)
#> Month = 8 44.52* (18.05)
#> Month = 9 -11.78 (18.22)
#> Wind x Month = 5 -1.086 (1.127) -1.086** (0.1408)
#> Wind x Month = 6 2.046 (1.784) 2.046*** (0.0398)
#> Wind x Month = 7 -5.616*** (1.316) -5.616*** (0.1554)
#> Wind x Month = 8 -6.515*** (1.220) -6.515*** (0.2203)
#> Wind x Month = 9 -1.349 (1.147) -1.349* (0.3175)
#> Constant -100.2*** (26.35)
#> Temp 2.042*** (0.3078) 2.042*** (0.2242)
#> Fixed-Effects: ----------------- ------------------
#> Month No Yes
#> ________________ _________________ __________________
#> S.E. type IID by: Month
#> Observations 116 116
#> R2 0.68106 0.68106
#> Within R2 -- 0.58296
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#
# dict
#
# You can rename variables with dict = c(var1 = alias1, var2 = alias2, etc)
# You can also rename values taken by factors.
# Here's a full example:
dict = c(Temp = "Temperature", "Month::5"="May", "6"="Jun")
etable(est1, est2, dict = dict)
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Constant -100.2*** (26.35)
#> Month = Jun -54.99* (26.34)
#> Month = 7 35.89. (18.37)
#> Month = 8 44.52* (18.05)
#> Month = 9 -11.78 (18.22)
#> Temperature 2.042*** (0.3078) 2.042*** (0.2242)
#> Wind x May -1.086 (1.127) -1.086** (0.1408)
#> Wind x Month = Jun 2.046 (1.784) 2.046*** (0.0398)
#> Wind x Month = 7 -5.616*** (1.316) -5.616*** (0.1554)
#> Wind x Month = 8 -6.515*** (1.220) -6.515*** (0.2203)
#> Wind x Month = 9 -1.349 (1.147) -1.349* (0.3175)
#> Fixed-Effects: ----------------- ------------------
#> Month No Yes
#> __________________ _________________ __________________
#> S.E. type IID by: Month
#> Observations 116 116
#> R2 0.68106 0.68106
#> Within R2 -- 0.58296
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Note the difference of treatment between Jun and May
# Assume the following dictionary:
dict = c("Month::5"="May", "Month::6"="Jun", "Month::7"="Jul",
"Month::8"="Aug", "Month::9"="Sep")
# We would like to keep only the Months, but now the names are all changed...
# How to do?
# We can use the special character '%' to make reference to the original names.
etable(est1, est2, dict = dict, keep = "%Month")
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Jun -54.99* (26.34)
#> Jul 35.89. (18.37)
#> Aug 44.52* (18.05)
#> Sep -11.78 (18.22)
#> Wind x May -1.086 (1.127) -1.086** (0.1408)
#> Wind x Jun 2.046 (1.784) 2.046*** (0.0398)
#> Wind x Jul -5.616*** (1.316) -5.616*** (0.1554)
#> Wind x Aug -6.515*** (1.220) -6.515*** (0.2203)
#> Wind x Sep -1.349 (1.147) -1.349* (0.3175)
#> Fixed-Effects: ----------------- ------------------
#> Month No Yes
#> _______________ _________________ __________________
#> S.E. type IID by: Month
#> Observations 116 116
#> R2 0.68106 0.68106
#> Within R2 -- 0.58296
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#
# signif.code
#
etable(est1, est2, signif.code = c(" A"=0.01, " B"=0.05, " C"=0.1, " D"=0.15, " F"=1))
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Constant -100.2 A (26.35)
#> Month = 6 -54.99 B (26.34)
#> Month = 7 35.89 C (18.37)
#> Month = 8 44.52 B (18.05)
#> Month = 9 -11.78 F (18.22)
#> Temp 2.042 A (0.3078) 2.042 A (0.2242)
#> Wind x Month = 5 -1.086 F (1.127) -1.086 A (0.1408)
#> Wind x Month = 6 2.046 F (1.784) 2.046 A (0.0398)
#> Wind x Month = 7 -5.616 A (1.316) -5.616 A (0.1554)
#> Wind x Month = 8 -6.515 A (1.220) -6.515 A (0.2203)
#> Wind x Month = 9 -1.349 F (1.147) -1.349 B (0.3175)
#> Fixed-Effects: ---------------- -----------------
#> Month No Yes
#> ________________ ________________ _________________
#> S.E. type IID by: Month
#> Observations 116 116
#> R2 0.68106 0.68106
#> Within R2 -- 0.58296
#> ---
#> Signif. codes: 0 ' A' 0.01 ' B' 0.05 ' C' 0.1 ' D' 0.15 ' F' 1 ' ' 1
#
# Using the argument style to customize Latex exports
#
# If you don't like the default layout of the table, no worries!
# You can modify many parameters with the argument style
# To drop the headers before each section, use:
# Note that a space adds an extra line
style_noHeaders = style.tex(var.title = "", fixef.title = "", stats.title = " ")
etable(est1, est2, dict = dict, tex = TRUE, style.tex = style_noHeaders)
#> \begingroup
#> \centering
#> \begin{tabular}{lcc}
#> \tabularnewline \midrule \midrule
#> Dependent Variable: & \multicolumn{2}{c}{Ozone}\\
#> Model: & (1) & (2)\\
#> Constant & -100.2$^{***}$ & \\
#> & (26.35) & \\
#> Jun & -54.99$^{**}$ & \\
#> & (26.34) & \\
#> Jul & 35.89$^{*}$ & \\
#> & (18.37) & \\
#> Aug & 44.52$^{**}$ & \\
#> & (18.05) & \\
#> Sep & -11.78 & \\
#> & (18.22) & \\
#> Temp & 2.042$^{***}$ & 2.042$^{***}$\\
#> & (0.3078) & (0.2242)\\
#> Wind $\times$ May & -1.086 & -1.086$^{***}$\\
#> & (1.127) & (0.1408)\\
#> Wind $\times$ Jun & 2.046 & 2.046$^{***}$\\
#> & (1.784) & (0.0398)\\
#> Wind $\times$ Jul & -5.616$^{***}$ & -5.616$^{***}$\\
#> & (1.316) & (0.1554)\\
#> Wind $\times$ Aug & -6.515$^{***}$ & -6.515$^{***}$\\
#> & (1.220) & (0.2203)\\
#> Wind $\times$ Sep & -1.349 & -1.349$^{**}$\\
#> & (1.147) & (0.3175)\\
#> Month & & Yes\\
#> \\
#> Observations & 116 & 116\\
#> R$^2$ & 0.68106 & 0.68106\\
#> Within R$^2$ & & 0.58296\\
#> \midrule \midrule
#> \multicolumn{3}{l}{\emph{Signif. Codes: ***: 0.01, **: 0.05, *: 0.1}}\\
#> \end{tabular}
#> \par\endgroup
# To change the lines of the table + dropping the table footer
style_lines = style.tex(line.top = "\\toprule", line.bottom = "\\bottomrule",
tablefoot = FALSE)
etable(est1, est2, dict = dict, tex = TRUE, style.tex = style_lines)
#> \begingroup
#> \centering
#> \begin{tabular}{lcc}
#> \toprule
#> Dependent Variable: & \multicolumn{2}{c}{Ozone}\\
#> Model: & (1) & (2)\\
#> \midrule
#> \emph{Variables}\\
#> Constant & -100.2$^{***}$ & \\
#> & (26.35) & \\
#> Jun & -54.99$^{**}$ & \\
#> & (26.34) & \\
#> Jul & 35.89$^{*}$ & \\
#> & (18.37) & \\
#> Aug & 44.52$^{**}$ & \\
#> & (18.05) & \\
#> Sep & -11.78 & \\
#> & (18.22) & \\
#> Temp & 2.042$^{***}$ & 2.042$^{***}$\\
#> & (0.3078) & (0.2242)\\
#> Wind $\times$ May & -1.086 & -1.086$^{***}$\\
#> & (1.127) & (0.1408)\\
#> Wind $\times$ Jun & 2.046 & 2.046$^{***}$\\
#> & (1.784) & (0.0398)\\
#> Wind $\times$ Jul & -5.616$^{***}$ & -5.616$^{***}$\\
#> & (1.316) & (0.1554)\\
#> Wind $\times$ Aug & -6.515$^{***}$ & -6.515$^{***}$\\
#> & (1.220) & (0.2203)\\
#> Wind $\times$ Sep & -1.349 & -1.349$^{**}$\\
#> & (1.147) & (0.3175)\\
#> \midrule
#> \emph{Fixed-effects}\\
#> Month & & Yes\\
#> \midrule
#> \emph{Fit statistics}\\
#> Standard-Errors & IID & Month \\
#> Observations & 116 & 116\\
#> R$^2$ & 0.68106 & 0.68106\\
#> Within R$^2$ & & 0.58296\\
#> \bottomrule
#> \end{tabular}
#> \par\endgroup
# Or you have the predefined type "aer"
etable(est1, est2, dict = dict, tex = TRUE, style.tex = style.tex("aer"))
#> \begingroup
#> \centering
#> \begin{tabular}{lcc}
#> \toprule
#> & \multicolumn{2}{c}{Ozone}\\
#> & (1) & (2)\\
#> \midrule
#> Constant & -100.2$^{***}$ & \\
#> & (26.35) & \\
#> Jun & -54.99$^{**}$ & \\
#> & (26.34) & \\
#> Jul & 35.89$^{*}$ & \\
#> & (18.37) & \\
#> Aug & 44.52$^{**}$ & \\
#> & (18.05) & \\
#> Sep & -11.78 & \\
#> & (18.22) & \\
#> Temp & 2.042$^{***}$ & 2.042$^{***}$\\
#> & (0.3078) & (0.2242)\\
#> Wind $\times$ May & -1.086 & -1.086$^{***}$\\
#> & (1.127) & (0.1408)\\
#> Wind $\times$ Jun & 2.046 & 2.046$^{***}$\\
#> & (1.784) & (0.0398)\\
#> Wind $\times$ Jul & -5.616$^{***}$ & -5.616$^{***}$\\
#> & (1.316) & (0.1554)\\
#> Wind $\times$ Aug & -6.515$^{***}$ & -6.515$^{***}$\\
#> & (1.220) & (0.2203)\\
#> Wind $\times$ Sep & -1.349 & -1.349$^{**}$\\
#> & (1.147) & (0.3175)\\
#> \\
#> Standard-Errors & IID & Month \\
#> Observations & 116 & 116\\
#> R$^2$ & 0.68106 & 0.68106\\
#> Within R$^2$ & & 0.58296\\
#> \\
#> Month fixed effects & & $\checkmark$\\
#> \bottomrule
#> \end{tabular}
#> \par\endgroup
#
# Group and extralines
#
# Sometimes it's useful to group control variables into a single line
# You can achieve that with the group argument
setFixest_fml(..ctrl = ~ poly(Wind, 2) + poly(Temp, 2))
est_c0 = feols(Ozone ~ Solar.R, data = airquality)
#> NOTE: 42 observations removed because of NA values (LHS: 37, RHS: 7).
est_c1 = feols(Ozone ~ Solar.R + ..ctrl, data = airquality)
#> NOTE: 42 observations removed because of NA values (LHS: 37, RHS: 7).
est_c2 = feols(Ozone ~ Solar.R + Solar.R^2 + ..ctrl, data = airquality)
#> NOTE: 42 observations removed because of NA values (LHS: 37, RHS: 7).
etable(est_c0, est_c1, est_c2, group = list(Controls = "poly"))
#> est_c0 est_c1 est_c2
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant 18.60** (6.748) 29.83*** (4.101) 25.79*** (6.506)
#> Solar.R 0.1272*** (0.0328) 0.0659** (0.0201) 0.1347 (0.0881)
#> Solar.R square -0.0002 (0.0003)
#> Controls No Yes Yes
#> _______________ __________________ _________________ ________________
#> S.E. type IID IID IID
#> Observations 111 111 111
#> R2 0.12134 0.71231 0.71408
#> Adj. R2 0.11328 0.69861 0.69758
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# 'group' here does the same as drop = "poly", but adds an extra line
# with TRUE/FALSE where the variables were found
# 'extralines' adds an extra line, where you can add the value for each model
est_all = feols(Ozone ~ Solar.R + Temp + Wind, data = airquality)
#> NOTE: 42 observations removed because of NA values (LHS: 37, RHS: 7).
est_sub1 = feols(Ozone ~ Solar.R + Temp + Wind, data = airquality,
subset = ~ Month %in% 5:6)
#> NOTE: 28 observations removed because of NA values (LHS: 26, RHS: 4).
est_sub2 = feols(Ozone ~ Solar.R + Temp + Wind, data = airquality,
subset = ~ Month %in% 7:8)
#> NOTE: 13 observations removed because of NA values (LHS: 10, RHS: 3).
est_sub3 = feols(Ozone ~ Solar.R + Temp + Wind, data = airquality,
subset = ~ Month == 9)
#> NOTE: 1 observation removed because of NA values (LHS: 1).
etable(est_all, est_sub1, est_sub2, est_sub3,
extralines = list("Sub-sample" = c("All", "May-June", "Jul.-Aug.", "Sept.")))
#> est_all est_sub1 est_sub2
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant -64.34** (23.05) -48.52 (30.42) -80.06 (57.59)
#> Solar.R 0.0598* (0.0232) 0.0249 (0.0319) 0.0993* (0.0414)
#> Temp 1.652*** (0.2535) 1.184** (0.4123) 2.037** (0.6508)
#> Wind -3.334*** (0.6544) -1.107 (0.9236) -5.830*** (1.124)
#> Sub-sample All May-June Jul.-Aug.
#> _______________ __________________ ________________ _________________
#> S.E. type IID IID IID
#> Observations 111 33 49
#> R2 0.60589 0.35006 0.66607
#> Adj. R2 0.59484 0.28282 0.64381
#>
#> est_sub3
#> Dependent Var.: Ozone
#>
#> Constant -112.9** (34.81)
#> Solar.R 0.0225 (0.0322)
#> Temp 2.005*** (0.3716)
#> Wind -1.353 (0.9065)
#> Sub-sample Sept.
#> _______________ _________________
#> S.E. type IID
#> Observations 29
#> R2 0.71724
#> Adj. R2 0.68330
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# You can monitor the placement of the new lines with two special characters
# at the beginning of the row name.
# 1) "^", "-" or "_" which mean the coefficients, the fixed-effects or the
# statistics section.
# 2) "^" or "_" which mean first or last line of the section
#
# Ex: starting with "_^" will place the line at the top of the stat. section
# starting with "-_" will place the line at the bottom of the FEs section
# etc.
#
# You can use a single character which will represent the section,
# the line would then appear at the bottom of the section.
# Examples
etable(est_c0, est_c1, est_c2, group = list("_Controls" = "poly"))
#> est_c0 est_c1 est_c2
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant 18.60** (6.748) 29.83*** (4.101) 25.79*** (6.506)
#> Solar.R 0.1272*** (0.0328) 0.0659** (0.0201) 0.1347 (0.0881)
#> Solar.R square -0.0002 (0.0003)
#> _______________ __________________ _________________ ________________
#> S.E. type IID IID IID
#> Observations 111 111 111
#> R2 0.12134 0.71231 0.71408
#> Adj. R2 0.11328 0.69861 0.69758
#> Controls No Yes Yes
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
etable(est_all, est_sub1, est_sub2, est_sub3,
extralines = list("^^Sub-sample" = c("All", "May-June", "Jul.-Aug.", "Sept.")))
#> est_all est_sub1 est_sub2
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Sub-sample All May-June Jul.-Aug.
#> Constant -64.34** (23.05) -48.52 (30.42) -80.06 (57.59)
#> Solar.R 0.0598* (0.0232) 0.0249 (0.0319) 0.0993* (0.0414)
#> Temp 1.652*** (0.2535) 1.184** (0.4123) 2.037** (0.6508)
#> Wind -3.334*** (0.6544) -1.107 (0.9236) -5.830*** (1.124)
#> _______________ __________________ ________________ _________________
#> S.E. type IID IID IID
#> Observations 111 33 49
#> R2 0.60589 0.35006 0.66607
#> Adj. R2 0.59484 0.28282 0.64381
#>
#> est_sub3
#> Dependent Var.: Ozone
#>
#> Sub-sample Sept.
#> Constant -112.9** (34.81)
#> Solar.R 0.0225 (0.0322)
#> Temp 2.005*** (0.3716)
#> Wind -1.353 (0.9065)
#> _______________ _________________
#> S.E. type IID
#> Observations 29
#> R2 0.71724
#> Adj. R2 0.68330
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#
# headers
#
# You can add header lines with 'headers'
# These lines will appear at the top of the table
# first, 3 estimations
est_header = feols(c(Ozone, Solar.R, Wind) ~ poly(Temp, 2), airquality)
# header => vector: adds a line w/t title
etable(est_header, headers = c("A", "A", "B"))
#> est_header.1 est_header.2 est_header.3
#> A A B
#> Dependent Var.: Ozone Solar.R Wind
#>
#> Constant 42.14*** (2.086) 185.2*** (7.218) 9.958*** (0.2548)
#> poly(Temp)1 272.4*** (25.94) 317.2*** (91.89) -19.89*** (3.152)
#> poly(Temp)2 102.8*** (27.46) -33.07 (92.49) -0.6379 (3.152)
#> _______________ ________________ ________________ _________________
#> S.E. type IID IID IID
#> Observations 116 146 153
#> R2 0.54422 0.07691 0.20997
#> Adj. R2 0.53615 0.06400 0.19943
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# header => list: identical way to do the previous header
# The form is: list(item1 = #item1, item2 = #item2, etc)
etable(est_header, headers = list("A" = 2, "B" = 1))
#> est_header.1 est_header.2 est_header.3
#> A A B
#> Dependent Var.: Ozone Solar.R Wind
#>
#> Constant 42.14*** (2.086) 185.2*** (7.218) 9.958*** (0.2548)
#> poly(Temp)1 272.4*** (25.94) 317.2*** (91.89) -19.89*** (3.152)
#> poly(Temp)2 102.8*** (27.46) -33.07 (92.49) -0.6379 (3.152)
#> _______________ ________________ ________________ _________________
#> S.E. type IID IID IID
#> Observations 116 146 153
#> R2 0.54422 0.07691 0.20997
#> Adj. R2 0.53615 0.06400 0.19943
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Adding a title +
# when an element is to be repeated only once, you can avoid the "= 1":
etable(est_header, headers = list(Group = list("A" = 2, "B")))
#> est_header.1 est_header.2 est_header.3
#> Group A A B
#> Dependent Var.: Ozone Solar.R Wind
#>
#> Constant 42.14*** (2.086) 185.2*** (7.218) 9.958*** (0.2548)
#> poly(Temp)1 272.4*** (25.94) 317.2*** (91.89) -19.89*** (3.152)
#> poly(Temp)2 102.8*** (27.46) -33.07 (92.49) -0.6379 (3.152)
#> _______________ ________________ ________________ _________________
#> S.E. type IID IID IID
#> Observations 116 146 153
#> R2 0.54422 0.07691 0.20997
#> Adj. R2 0.53615 0.06400 0.19943
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# To change the placement, add as first character:
# - "^" => top
# - "-" => mid (default)
# - "_" => bottom
# Note that "mid" and "top" are only distinguished when tex = TRUE
# Placing the new header line at the bottom
etable(est_header, headers = list("_Group" = c("A", "A", "B"),
"^Currency" = list("US $" = 2, "CA $" = 1)))
#> est_header.1 est_header.2 est_header.3
#> Currency US $ US $ CA $
#> Dependent Var.: Ozone Solar.R Wind
#> Group A A B
#>
#> Constant 42.14*** (2.086) 185.2*** (7.218) 9.958*** (0.2548)
#> poly(Temp)1 272.4*** (25.94) 317.2*** (91.89) -19.89*** (3.152)
#> poly(Temp)2 102.8*** (27.46) -33.07 (92.49) -0.6379 (3.152)
#> _______________ ________________ ________________ _________________
#> S.E. type IID IID IID
#> Observations 116 146 153
#> R2 0.54422 0.07691 0.20997
#> Adj. R2 0.53615 0.06400 0.19943
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# In Latex, you can add "grouped underlines" (cmidrule from the booktabs package)
# by adding ":_:" in the title:
etable(est_header, tex = TRUE,
headers = list("^:_:Group" = c("A", "A", "B")))
#> \begingroup
#> \centering
#> \begin{tabular}{lccc}
#> \tabularnewline \midrule \midrule
#> Group & \multicolumn{2}{c}{A} & B \\ \cmidrule(lr){2-3} \cmidrule(lr){4-4}
#> Dependent Variables: & Ozone & Solar.R & Wind\\
#> Model: & (1) & (2) & (3)\\
#> \midrule
#> \emph{Variables}\\
#> Constant & 42.14$^{***}$ & 185.2$^{***}$ & 9.958$^{***}$\\
#> & (2.086) & (7.218) & (0.2548)\\
#> poly(Temp)1 & 272.4$^{***}$ & 317.2$^{***}$ & -19.89$^{***}$\\
#> & (25.94) & (91.89) & (3.152)\\
#> poly(Temp)2 & 102.8$^{***}$ & -33.07 & -0.6379\\
#> & (27.46) & (92.49) & (3.152)\\
#> \midrule
#> \emph{Fit statistics}\\
#> Observations & 116 & 146 & 153\\
#> R$^2$ & 0.54422 & 0.07691 & 0.20997\\
#> Adjusted R$^2$ & 0.53615 & 0.06400 & 0.19943\\
#> \midrule \midrule
#> \multicolumn{4}{l}{\emph{IID standard-errors in parentheses}}\\
#> \multicolumn{4}{l}{\emph{Signif. Codes: ***: 0.01, **: 0.05, *: 0.1}}\\
#> \end{tabular}
#> \par\endgroup
#
# extralines and headers: .() for list()
#
# In the two arguments extralines and headers, .() can be used for list()
# For example:
etable(est_header, headers = .("^Currency" = .("US $" = 2, "CA $" = 1)))
#> est_header.1 est_header.2 est_header.3
#> Currency US $ US $ CA $
#> Dependent Var.: Ozone Solar.R Wind
#>
#> Constant 42.14*** (2.086) 185.2*** (7.218) 9.958*** (0.2548)
#> poly(Temp)1 272.4*** (25.94) 317.2*** (91.89) -19.89*** (3.152)
#> poly(Temp)2 102.8*** (27.46) -33.07 (92.49) -0.6379 (3.152)
#> _______________ ________________ ________________ _________________
#> S.E. type IID IID IID
#> Observations 116 146 153
#> R2 0.54422 0.07691 0.20997
#> Adj. R2 0.53615 0.06400 0.19943
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#
# fixef.group
#
# You can group the fixed-effects line with fixef.group
est_0fe = feols(Ozone ~ Solar.R + Temp + Wind, airquality)
#> NOTE: 42 observations removed because of NA values (LHS: 37, RHS: 7).
est_1fe = feols(Ozone ~ Solar.R + Temp + Wind | Month, airquality)
#> NOTE: 42 observations removed because of NA values (LHS: 37, RHS: 7).
est_2fe = feols(Ozone ~ Solar.R + Temp + Wind | Month + Day, airquality)
#> NOTE: 42 observations removed because of NA values (LHS: 37, RHS: 7).
# A) automatic way => simply use fixef.group = TRUE
etable(est_0fe, est_2fe, fixef.group = TRUE)
#> est_0fe est_2fe
#> Dependent Var.: Ozone Ozone
#>
#> Constant -64.34** (23.05)
#> Solar.R 0.0598* (0.0232) 0.0509 (0.0428)
#> Temp 1.652*** (0.2535) 2.052** (0.2390)
#> Wind -3.334*** (0.6544) -3.289* (1.051)
#> Fixed-Effects: ------------------ ----------------
#> Month and Day No Yes
#> _______________ __________________ ________________
#> S.E. type IID by: Month
#> Observations 111 111
#> R2 0.60589 0.81604
#> Within R2 -- 0.61471
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Note that when grouping would lead to inconsistencies across models,
# it is avoided
etable(est_0fe, est_1fe, est_2fe, fixef.group = TRUE)
#> est_0fe est_1fe est_2fe
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant -64.34** (23.05)
#> Solar.R 0.0598* (0.0232) 0.0522 (0.0408) 0.0509 (0.0428)
#> Temp 1.652*** (0.2535) 1.875*** (0.1816) 2.052** (0.2390)
#> Wind -3.334*** (0.6544) -3.109. (1.306) -3.289* (1.051)
#> Fixed-Effects: ------------------ ----------------- ----------------
#> Month No Yes Yes
#> Day No No Yes
#> _______________ __________________ _________________ ________________
#> S.E. type IID by: Month by: Month
#> Observations 111 111 111
#> R2 0.60589 0.63686 0.81604
#> Within R2 -- 0.53154 0.61471
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# B) customized way => use a list
etable(est_0fe, est_2fe, fixef.group = list("Dates" = "Month|Day"))
#> est_0fe est_2fe
#> Dependent Var.: Ozone Ozone
#>
#> Constant -64.34** (23.05)
#> Solar.R 0.0598* (0.0232) 0.0509 (0.0428)
#> Temp 1.652*** (0.2535) 2.052** (0.2390)
#> Wind -3.334*** (0.6544) -3.289* (1.051)
#> Fixed-Effects: ------------------ ----------------
#> Dates No Yes
#> _______________ __________________ ________________
#> S.E. type IID by: Month
#> Observations 111 111
#> R2 0.60589 0.81604
#> Within R2 -- 0.61471
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Note that when a user grouping would lead to inconsistencies,
# the term partial replaces yes/no and the fixed-effects are not removed.
etable(est_0fe, est_1fe, est_2fe, fixef.group = list("Dates" = "Month|Day"))
#> Warning: In etable(est_0fe, est_1fe, est_2fe, fixef.group = l...:
#> In 'fixef.group', the group leads to an inconsistent row (defined by
#> "Month|Day").
#> To create inconsistent rows: use drop.section = 'fixef' combined with the
#> arghument 'extralines'.
#> est_0fe est_1fe est_2fe
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant -64.34** (23.05)
#> Solar.R 0.0598* (0.0232) 0.0522 (0.0408) 0.0509 (0.0428)
#> Temp 1.652*** (0.2535) 1.875*** (0.1816) 2.052** (0.2390)
#> Wind -3.334*** (0.6544) -3.109. (1.306) -3.289* (1.051)
#> Fixed-Effects: ------------------ ----------------- ----------------
#> Dates No partial Yes
#> Month No Yes Yes
#> Day No No Yes
#> _______________ __________________ _________________ ________________
#> S.E. type IID by: Month by: Month
#> Observations 111 111 111
#> R2 0.60589 0.63686 0.81604
#> Within R2 -- 0.53154 0.61471
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Using customized placement => as with 'group' and 'extralines',
# the user can control the placement of the new line.
# See the previous 'group' examples and the dedicated section in the help.
# On top of the coefficients:
etable(est_0fe, est_2fe, fixef.group = list("^^Dates" = "Month|Day"))
#> est_0fe est_2fe
#> Dependent Var.: Ozone Ozone
#>
#> Dates No Yes
#> Constant -64.34** (23.05)
#> Solar.R 0.0598* (0.0232) 0.0509 (0.0428)
#> Temp 1.652*** (0.2535) 2.052** (0.2390)
#> Wind -3.334*** (0.6544) -3.289* (1.051)
#> _______________ __________________ ________________
#> S.E. type IID by: Month
#> Observations 111 111
#> R2 0.60589 0.81604
#> Within R2 -- 0.61471
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Last line of the statistics
etable(est_0fe, est_2fe, fixef.group = list("_Dates" = "Month|Day"))
#> est_0fe est_2fe
#> Dependent Var.: Ozone Ozone
#>
#> Constant -64.34** (23.05)
#> Solar.R 0.0598* (0.0232) 0.0509 (0.0428)
#> Temp 1.652*** (0.2535) 2.052** (0.2390)
#> Wind -3.334*** (0.6544) -3.289* (1.051)
#> _______________ __________________ ________________
#> S.E. type IID by: Month
#> Observations 111 111
#> R2 0.60589 0.81604
#> Within R2 -- 0.61471
#> Dates No Yes
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#
# Using custom functions to compute the standard errors
#
# You can use external functions to compute the VCOVs
# by feeding functions in the 'vcov' argument.
# Let's use some covariances from the sandwich package
etable(est_c0, est_c1, est_c2, vcov = sandwich::vcovHC)
#> est_c0 est_c1 est_c2
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant 18.60*** (3.949) 29.83*** (3.064) 25.79*** (4.436)
#> Solar.R 0.1272*** (0.0266) 0.0659*** (0.0150) 0.1347* (0.0651)
#> poly(Wind)1 -155.5*** (39.20) -153.6*** (39.12)
#> poly(Wind)2 98.77** (36.32) 98.88** (36.42)
#> poly(Temp)1 166.7*** (25.38) 159.3*** (25.99)
#> poly(Temp)2 67.20* (27.38) 68.77* (27.36)
#> Solar.R square -0.0002 (0.0002)
#> _______________ __________________ __________________ _________________
#> S.E. type vcovHC vcovHC vcovHC
#> Observations 111 111 111
#> R2 0.12134 0.71231 0.71408
#> Adj. R2 0.11328 0.69861 0.69758
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# To add extra arguments to vcovHC, you need to write your wrapper:
etable(est_c0, est_c1, est_c2, vcov = function(x) sandwich::vcovHC(x, type = "HC0"))
#> est_c0 est_c1 est_c2
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant 18.60*** (3.850) 29.83*** (2.890) 25.79*** (4.091)
#> Solar.R 0.1272*** (0.0260) 0.0659*** (0.0140) 0.1347* (0.0603)
#> poly(Wind)1 -155.5*** (35.29) -153.6*** (35.11)
#> poly(Wind)2 98.77** (32.31) 98.88** (32.35)
#> poly(Temp)1 166.7*** (23.41) 159.3*** (23.76)
#> poly(Temp)2 67.20** (24.84) 68.77** (24.68)
#> Solar.R square -0.0002 (0.0002)
#> _______________ __________________ __________________ _________________
#> S.E. type vcovHC(type="HC0") vcovHC(type="HC0") vcovHC(type="HC..
#> Observations 111 111 111
#> R2 0.12134 0.71231 0.71408
#> Adj. R2 0.11328 0.69861 0.69758
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#
# Customize which fit statistic to display
#
# You can change the fit statistics with the argument fitstat
# and you can rename them with the dictionary
etable(est1, est2, fitstat = ~ r2 + n + G)
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Constant -100.2*** (26.35)
#> Month = 6 -54.99* (26.34)
#> Month = 7 35.89. (18.37)
#> Month = 8 44.52* (18.05)
#> Month = 9 -11.78 (18.22)
#> Temp 2.042*** (0.3078) 2.042*** (0.2242)
#> Wind x Month = 5 -1.086 (1.127) -1.086** (0.1408)
#> Wind x Month = 6 2.046 (1.784) 2.046*** (0.0398)
#> Wind x Month = 7 -5.616*** (1.316) -5.616*** (0.1554)
#> Wind x Month = 8 -6.515*** (1.220) -6.515*** (0.2203)
#> Wind x Month = 9 -1.349 (1.147) -1.349* (0.3175)
#> Fixed-Effects: ----------------- ------------------
#> Month No Yes
#> ________________ _________________ __________________
#> S.E. type IID by: Month
#> R2 0.68106 0.68106
#> Observations 116 116
#> G 105 5
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# If you use a formula, '.' means the default:
etable(est1, est2, fitstat = ~ ll + .)
#> est1 est2
#> Dependent Var.: Ozone Ozone
#>
#> Constant -100.2*** (26.35)
#> Month = 6 -54.99* (26.34)
#> Month = 7 35.89. (18.37)
#> Month = 8 44.52* (18.05)
#> Month = 9 -11.78 (18.22)
#> Temp 2.042*** (0.3078) 2.042*** (0.2242)
#> Wind x Month = 5 -1.086 (1.127) -1.086** (0.1408)
#> Wind x Month = 6 2.046 (1.784) 2.046*** (0.0398)
#> Wind x Month = 7 -5.616*** (1.316) -5.616*** (0.1554)
#> Wind x Month = 8 -6.515*** (1.220) -6.515*** (0.2203)
#> Wind x Month = 9 -1.349 (1.147) -1.349* (0.3175)
#> Fixed-Effects: ----------------- ------------------
#> Month No Yes
#> ________________ _________________ __________________
#> S.E. type IID by: Month
#> Log-Likelihood -503.37 -503.37
#> Observations 116 116
#> R2 0.68106 0.68106
#> Within R2 -- 0.58296
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#
# Computing a different SE for each model
#
est = feols(Ozone ~ Solar.R + Wind + Temp, data = airquality)
#> NOTE: 42 observations removed because of NA values (LHS: 37, RHS: 7).
#
# Method 1: use summary
s1 = summary(est, "iid")
s2 = summary(est, cluster = ~ Month)
s3 = summary(est, cluster = ~ Day)
s4 = summary(est, cluster = ~ Day + Month)
etable(list(s1, s2, s3, s4))
#> model 1 model 2 model 3
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant -64.34** (23.05) -64.34* (21.30) -64.34** (20.15)
#> Solar.R 0.0598* (0.0232) 0.0598 (0.0335) 0.0598*** (0.0162)
#> Wind -3.334*** (0.6544) -3.334* (1.181) -3.334*** (0.8343)
#> Temp 1.652*** (0.2535) 1.652*** (0.1583) 1.652*** (0.1927)
#> _______________ __________________ _________________ __________________
#> S.E. type IID by: Month by: Day
#> Observations 111 111 111
#> R2 0.60589 0.60589 0.60589
#> Adj. R2 0.59484 0.59484 0.59484
#>
#> model 4
#> Dependent Var.: Ozone
#>
#> Constant -64.34* (19.66)
#> Solar.R 0.0598 (0.0314)
#> Wind -3.334* (1.135)
#> Temp 1.652*** (0.1386)
#> _______________ _________________
#> S.E. type by: Day & Month
#> Observations 111
#> R2 0.60589
#> Adj. R2 0.59484
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#
# Method 2: using a list in the argument 'vcov'
est_bis = feols(Ozone ~ Solar.R + Wind + Temp | Month, data = airquality)
#> NOTE: 42 observations removed because of NA values (LHS: 37, RHS: 7).
etable(est, est_bis, vcov = list("hetero", ~ Month))
#> est est_bis
#> Dependent Var.: Ozone Ozone
#>
#> Constant -64.34** (21.23)
#> Solar.R 0.0598** (0.0191) 0.0522 (0.0408)
#> Wind -3.334*** (0.8749) -3.109. (1.306)
#> Temp 1.652*** (0.2025) 1.875*** (0.1816)
#> Fixed-Effects: ------------------ -----------------
#> Month No Yes
#> _______________ __________________ _________________
#> S.E. type Heteroskedas.-rob. by: Month
#> Observations 111 111
#> R2 0.60589 0.63686
#> Within R2 -- 0.53154
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# When you have only one model, this model is replicated
# along the elements of the vcov list.
etable(est, vcov = list("hetero", ~ Month))
#> est est.1
#> Dependent Var.: Ozone Ozone
#>
#> Constant -64.34** (21.23) -64.34* (21.30)
#> Solar.R 0.0598** (0.0191) 0.0598 (0.0335)
#> Wind -3.334*** (0.8749) -3.334* (1.181)
#> Temp 1.652*** (0.2025) 1.652*** (0.1583)
#> _______________ __________________ _________________
#> S.E. type Heteroskedas.-rob. by: Month
#> Observations 111 111
#> R2 0.60589 0.60589
#> Adj. R2 0.59484 0.59484
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#
# Method 3: Using "each" or "times" in vcov
# If the first element of the list in 'vcov' is "each" or "times",
# then all models will be replicated and all the VCOVs will be
# applied to each model. The order in which they are replicated
# are governed by the each/times keywords.
# each
etable(est, est_bis, vcov = list("each", "iid", ~ Month, ~ Day))
#> est est.1 est.2
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant -64.34** (23.05) -64.34* (21.30) -64.34** (20.15)
#> Solar.R 0.0598* (0.0232) 0.0598 (0.0335) 0.0598*** (0.0162)
#> Wind -3.334*** (0.6544) -3.334* (1.181) -3.334*** (0.8343)
#> Temp 1.652*** (0.2535) 1.652*** (0.1583) 1.652*** (0.1927)
#> Fixed-Effects: ------------------ ----------------- ------------------
#> Month No No No
#> _______________ __________________ _________________ __________________
#> S.E. type IID by: Month by: Day
#> Observations 111 111 111
#> R2 0.60589 0.60589 0.60589
#> Within R2 -- -- --
#>
#> est_bis est_bis.1 est_bis.2
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant
#> Solar.R 0.0522* (0.0237) 0.0522 (0.0408) 0.0522* (0.0202)
#> Wind -3.109*** (0.6601) -3.109. (1.306) -3.109*** (0.7986)
#> Temp 1.875*** (0.3407) 1.875*** (0.1816) 1.875*** (0.3671)
#> Fixed-Effects: ------------------ ----------------- ------------------
#> Month Yes Yes Yes
#> _______________ __________________ _________________ __________________
#> S.E. type IID by: Month by: Day
#> Observations 111 111 111
#> R2 0.63686 0.63686 0.63686
#> Within R2 0.53154 0.53154 0.53154
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# times
etable(est, est_bis, vcov = list("times", "iid", ~ Month, ~ Day))
#> est est_bis est.1
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant -64.34** (23.05) -64.34* (21.30)
#> Solar.R 0.0598* (0.0232) 0.0522* (0.0237) 0.0598 (0.0335)
#> Wind -3.334*** (0.6544) -3.109*** (0.6601) -3.334* (1.181)
#> Temp 1.652*** (0.2535) 1.875*** (0.3407) 1.652*** (0.1583)
#> Fixed-Effects: ------------------ ------------------ -----------------
#> Month No Yes No
#> _______________ __________________ __________________ _________________
#> S.E. type IID IID by: Month
#> Observations 111 111 111
#> R2 0.60589 0.63686 0.60589
#> Within R2 -- 0.53154 --
#>
#> est_bis.1 est.2 est_bis.2
#> Dependent Var.: Ozone Ozone Ozone
#>
#> Constant -64.34** (20.15)
#> Solar.R 0.0522 (0.0408) 0.0598*** (0.0162) 0.0522* (0.0202)
#> Wind -3.109. (1.306) -3.334*** (0.8343) -3.109*** (0.7986)
#> Temp 1.875*** (0.1816) 1.652*** (0.1927) 1.875*** (0.3671)
#> Fixed-Effects: ----------------- ------------------ ------------------
#> Month Yes No Yes
#> _______________ _________________ __________________ __________________
#> S.E. type by: Month by: Day by: Day
#> Observations 111 111 111
#> R2 0.63686 0.60589 0.63686
#> Within R2 0.53154 -- 0.53154
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#
# Notes and markup
#
# Notes can be also be set in a dictionary
# You can use markdown markup to put text into italic/bold
dict = c("note 1" = "*Notes:* This data is not really random.",
"source 1" = "**Source:** the internet?")
est = feols(Ozone ~ csw(Solar.R, Wind, Temp), data = airquality)
#> NOTE: 42 observations removed because of NA values (LHS: 37, RHS: 7).
#> |-> this msg only concerns the variables common to all estimations
etable(est, dict = dict, tex = TRUE, notes = c("note 1", "source 1"))
#> \begingroup
#> \centering
#> \begin{tabular}{lccc}
#> \tabularnewline \midrule \midrule
#> Dependent Variable: & \multicolumn{3}{c}{Ozone}\\
#> Model: & (1) & (2) & (3)\\
#> \midrule
#> \emph{Variables}\\
#> Constant & 18.60$^{***}$ & 77.25$^{***}$ & -64.34$^{***}$\\
#> & (6.748) & (9.068) & (23.05)\\
#> Solar.R & 0.1272$^{***}$ & 0.1004$^{***}$ & 0.0598$^{**}$\\
#> & (0.0328) & (0.0263) & (0.0232)\\
#> Wind & & -5.402$^{***}$ & -3.334$^{***}$\\
#> & & (0.6732) & (0.6544)\\
#> Temp & & & 1.652$^{***}$\\
#> & & & (0.2535)\\
#> \midrule
#> \emph{Fit statistics}\\
#> Observations & 111 & 111 & 111\\
#> R$^2$ & 0.12134 & 0.44949 & 0.60589\\
#> Adjusted R$^2$ & 0.11328 & 0.43930 & 0.59484\\
#> \midrule \midrule
#> \multicolumn{4}{l}{\emph{IID standard-errors in parentheses}}\\
#> \multicolumn{4}{l}{\emph{Signif. Codes: ***: 0.01, **: 0.05, *: 0.1}}\\
#> \end{tabular}
#>
#> \par \raggedright
#> \textit{Notes:} This data is not really random.\\
#> \textbf{Source:} the internet?
#> \par\endgroup