Skip to content

Commit ccef621

Browse files
Merge pull request #46 from grantmcdermott/fixest_0.13.0
`fixest` 0.13.0
2 parents 6482970 + 7e42f34 commit ccef621

File tree

2 files changed

+55
-57
lines changed

2 files changed

+55
-57
lines changed

src/content/docs/extras.mdx

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -595,15 +595,14 @@ collap(dat, var1 + var2 ~ group1 + group2, FUN = list(fmin, fmax))
595595
_More standard error adjustments_
596596

597597
**fixest** package comes with plenty of shortcuts for accessing standard error
598-
adjustments like HC1 heteroskedasticity-robust standard errors, Newey-West,
599-
Driscoll-Kraay, clustered standard errors, etc. But of course there are still
600-
more than that. A host of additional options are covered by the
601-
[**sandwich**](https://sandwich.r-forge.r-project.org/) package, which comes
602-
with a long list of functions like `vcovBS()` for bootstrapped standard errors,
603-
or `vcovHC()` for HC1-5. **sandwich** supports nearly every model class in R, so
604-
it shouldn't surprise that these can slot right into `fixest` estimates, too.
605-
You shouldn't be using those `, robust` errors for smaller samples anyway... but
606-
you [knew that](http://datacolada.org/99), right?
598+
adjustments like HC1-3 heteroskedasticity-robust, clustered, Newey-West,
599+
Driscoll-Kraay, etc. But of course there are still more than that. A host of
600+
additional options are covered by the
601+
[**sandwich**](https://sandwich.r-forge.r-project.org/) package, including
602+
HC4-5 and jackknife standard errors. Despite
603+
[some exceptions](https://github.com/lrberge/fixest/blob/0e37f1f7e5741787bdc27ef25b31927dd4e55a02/ONGOING_ISSUES.md#compatibility-with-the-sandwich-package)
604+
**sandwich** has good integration with **fixest** and so you should be able to
605+
plug and play the two packages together.
607606

608607
### Linear Model Adjustments
609608

@@ -637,13 +636,13 @@ _Summary tables, regression tables, and more_
637636
The **fixest** package already has the `etable()` function for generating
638637
regression tables. However, it is only really intended to work with models from
639638
the same package. So we also recommend checking out the fantastic
640-
[**modelsummary**](https://vincentarelbundock.github.io/modelsummary) package.
639+
[**modelsummary**](https://modelsummary.com/) package.
641640
It works with all sorts of model objects, including those not from **fixest**,
642641
is incredibly customizable, and outputs to a bunch of different formats (PDF,
643642
HTML, DOCX, etc.) Similarly, **modelsummary** has a wealth of options for
644643
producing publication-ready summary tables. Oh, and it produces coefficient
645644
plots too. Check out the [package
646-
website](https://vincentarelbundock.github.io/modelsummary/) for more.
645+
website](https://modelsummary.com/) for more.
647646

648647

649648
### Summary tables
@@ -726,7 +725,7 @@ msummary(list(est1, est1, est3),
726725
_Marginal effects, contrasts, joint hypothesis tests, etc._
727726

728727
The Stata `margins` command is great. To replicate it in R, we highly recommend
729-
the [**marginaleffects**](https://vincentarelbundock.github.io/marginaleffects/)
728+
the [**marginaleffects**](https://marginaleffects.com/)
730729
package. Individual marginal effects or average marginal effects for nonlinear
731730
models, or models with interactions or transformations, etc. The documentation
732731
is outstanding and the underlying functions are also very fast.
@@ -799,7 +798,7 @@ equivalent with `fixest::wald()`. But what about combinations of coefficients _a
799798
la_ Stata's `lincom` and `nlcom` commands? While several R packages do this,
800799
we'll again recommend the **marginaleffects** package. It's lightweight and fast,
801800
and supports
802-
[hypothesis testing](https://vincentarelbundock.github.io/marginaleffects/articles/hypothesis.html)
801+
[hypothesis testing](https://marginaleffects.com/man/r/hypotheses.html)
803802
of both linear and non-linear combinations.
804803

805804
<div class='code--container grid grid-row grid-cols-1 gap-y-2 lg:gap-y-0 lg:grid-cols-2 lg:gap-x-2 [&>*]:!mt-0'>

src/content/docs/fixest.mdx

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ install.packages("fixest")
2121
# install.packages("fixest", repos = "https://fastverse.r-universe.dev")
2222
```
2323

24+
**Important:** In the code below, we assume that you are running **fixest**
25+
v0.13.0 or above (which is available on CRAN as of early September 2025).
26+
2427
Once **fixest** is installed, don't forget to load it whenever you want to
2528
use it. Unlike Stata, you have to re-load a package every time you start a new R
2629
session.
@@ -133,16 +136,10 @@ feols(wage ~ educ + i(treat, ref = 1), dat)
133136
<div>
134137

135138
```stata
136-
reghdfe wage educ, absorb(countyfips) cluster(countyfips)
137-
138-
139-
140-
141-
139+
reghdfe wage educ, absorb(countyfips)
140+
reghdfe wage educ, absorb(countyfips) cluster(countyfips)
142141
143-
reghdfe wage educ, absorb(countyfips)
144-
145-
* Add more fixed effects...
142+
* Add more fixed effects (and clusted SEs)...
146143
reghdfe wage educ, absorb(countyfips year) ///
147144
vce(cluster countyfips year)
148145
reghdfe wage educ, absorb(countyfips#year) ///
@@ -152,20 +149,14 @@ reghdfe wage educ, absorb(countyfips#year) ///
152149
<div>
153150

154151
```r
152+
feols(wage ~ educ | countyfips, dat)
155153
feols(wage ~ educ | countyfips, dat, vcov = ~countyfips)
156-
# feols(wage ~ educ | countyfips, dat) # same (see below)
157-
158-
# Note: fixest automatically clusters SEs by the first
159-
# fixed effect (if there are any). We'll get to SEs
160-
# later, but if you just want iid errors for a fixed
161-
# effect model:
162-
feols(wage ~ educ | countyfips, dat, vcov = 'iid')
163154

164-
# Add more fixed effects...
165-
feols(wage ~ educ | countyfips + year,
166-
dat, vcov = ~countyfips + year)
167-
feols(wage ~ educ | countyfips^year,
168-
dat) # defaults to vcov = ~countyfips^year
155+
# Add more fixed effects (and clusted SEs)...
156+
feols(wage ~ educ | countyfips + year, dat,
157+
vcov = ~countyfips + year)
158+
feols(wage ~ educ | countyfips^year, dat,
159+
vcov = ~countyfips^year)
169160
```
170161
</div>
171162
</div>
@@ -234,7 +225,7 @@ logit marr age black hisp
234225
235226
* https://github.com/sergiocorreia/ppmlhdfe
236227
ppmlhdfe educ age black hisp, absorb(statefips year) ///
237-
vce(cluster statefips)
228+
vce(robust)
238229
```
239230
</div>
240231
<div>
@@ -248,7 +239,8 @@ feglm(marr ~ age + black + hisp | statefips + year,
248239
dat, family = 'probit')
249240

250241
# fepois() is there for Poisson regression
251-
fepois(educ ~ age + black + hisp | statefips + year, dat)
242+
fepois(educ ~ age + black + hisp | statefips + year,
243+
dat, vcov = 'hc1')
252244
```
253245
</div>
254246
</div>
@@ -480,17 +472,18 @@ reghdfe wage educ, absorb(statefips#year)
480472
481473
* Varying slopes (e.g. time trend for each state)
482474
reghdfe wage educ, absorb(statefips#c.year) ///
483-
vce(cluster statefips#c.year)
475+
vce(cluster statefips#c.year)
484476
```
485477
</div>
486478
<div>
487479

488480
```r
489481
# Combine fixed effects
490-
feols(wage ~ educ | statefips^year, dat)
482+
feols(wage ~ educ | statefips^year, dat)
491483

492484
# Varying slopes (e.g. time trend for each state)
493-
feols(wage ~ educ | statefips[year], dat)
485+
feols(wage ~ educ | statefips[year], dat,
486+
vcov = ~statefips:year)
494487
```
495488
</div>
496489
</div>
@@ -500,10 +493,10 @@ feols(wage ~ educ | statefips[year], dat)
500493

501494
While you can specify standard errors inside the original **fixest** model call
502495
(just like Stata), a unique feature of R is that you can adjust errors for an
503-
existing model _on-the-fly_. This has [several
504-
benefits](https://grantmcdermott.com/better-way-adjust-SEs), including being
505-
much more efficient since you don't have to re-estimate your whole model. We'll
506-
try to highlight examples of both approaches below.
496+
existing model _on-the-fly_. This has
497+
[several benefits](https://grantmcdermott.com/posts/better-way-adjust-ses/),
498+
including being much more efficient since you don't have to re-estimate your
499+
whole model. We'll try to highlight examples of both approaches below.
507500

508501

509502
### HC
@@ -512,23 +505,28 @@ try to highlight examples of both approaches below.
512505
<div>
513506

514507
```stata
515-
reg wage educ, vce(robust)
508+
reg wage educ, vce(robust)
509+
reg wage educ, vce(hc2)
516510
reg wage educ, vce(hc3)
517511
```
518512
</div>
519513
<div>
520514

521515
```r
522516
feols(wage ~ educ, dat, vcov = 'hc1')
523-
feols(wage ~ educ, dat, vcov = sandwich::vcovHC)
517+
feols(wage ~ educ, dat, vcov = 'hc2')
518+
feols(wage ~ educ, dat, vcov = 'hc3')
524519

525520
# Note: You can also adjust the SEs of an existing model
526521
m = feols(wage ~ educ, dat) # iid
527522
summary(m, vcov = 'hc1') # switch to HC1
528523
```
529524
</div>
530525
</div>
531-
526+
527+
Aside: You shouldn't be using `, robust` for smaller samples... but you
528+
[knew that](http://datacolada.org/99), right?
529+
532530
### HAC
533531

534532
<div class='code--container grid grid-row grid-cols-1 gap-y-2 lg:gap-y-0 lg:grid-cols-2 lg:gap-x-2 [&>*]:!mt-0'>
@@ -570,17 +568,17 @@ reghdfe wage educ, absorb(countyfips#year) ///
570568
<div>
571569

572570
```r
573-
feols(wage ~ educ | countyfips, dat) # Auto clusters by FE
574-
# feols(wage ~ educ | countyfips, dat, vcov = ~countyfips) # ofc can be explicit too
571+
feols(wage ~ educ | countyfips, dat,
572+
vcov = ~countyfips)
575573

576574
# Twoway clustering etc.
577-
feols(wage ~ educ | countyfips + year,
578-
dat, vcov = ~countyfips + year)
579-
# feols(wage ~ educ | countyfips + year,
580-
# dat, vcov = 'twoway') ## same as above
575+
feols(wage ~ educ | countyfips + year, dat,
576+
vcov = ~countyfips + year)
577+
# feols(wage ~ educ | countyfips + year, dat,
578+
# vcov = 'twoway') ## same as above
581579

582-
feols(wage ~ educ | countyfips^year,
583-
dat, vcov = ~countyfips^year)
580+
feols(wage ~ educ | countyfips^year, dat,
581+
vcov = ~countyfips^year)
584582
```
585583
</div>
586584
</div>
@@ -614,8 +612,9 @@ functions, e.g. `etable()`. But here is a quick example using `summary()`:
614612

615613
```r
616614
m = feols(wage ~ educ | countyfips + year, dat)
617-
m # Clustered by countyfips (default)
618-
summary(m, vcov = 'iid') # Switch to iid errors
615+
m # IID (default)
616+
summary(m, vcov = 'hc3') # Switch to HC3 errors
617+
summary(m, vcov = ~countyfips) # Cluster by countyfips
619618
summary(m, vcov = 'twoway') # Cluster by countyfips and year
620619
summary(m, vcov = ~countyfips^year) # Cluster by countyfips*year interaction
621620
```
@@ -673,7 +672,7 @@ time.)
673672
etable(est1, est2, vcov = 'hc1')
674673

675674
# Report multiple SEs for the same model
676-
etable(est1, vcov = list('iid', 'hc1', ~id, ~countyfips))
675+
etable(est1, vcov = list('iid', 'hc2', ~id, ~countyfips))
677676

678677
# Multi-model example: Two dep. vars, stepwise coefs,
679678
# varying slopes, split sample, etc. (18 models in total!)

0 commit comments

Comments
 (0)