---
title: "lfe2fixest"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{lfe2fixest}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
```
Start by loading this package. Note the example scripts that follow assume you
have both **lfe** and **fixest**, as well as **modelsummary** installed on your system.
```{r libs}
library(lfe2fixest) ## This package
## Aside: Make sure you have the following packages installed on your system if
## you want to run the example scripts below:
## library(lfe); library(fixest); library(modelsummary)
```
Let's create an **lfe**-based R script, that's deliberately messy to pose an
additional challenge (inconsistent formatting, etc.)
```{r lfe_script}
lfe_string = "
library(lfe)
library(modelsummary)
## Toy dataset
aq = airquality
names(aq) = c('y', 'x1', 'x2', 'x3', 'mnth', 'dy')
## Simple OLS
mod1 = felm(y ~ x1 + x2, aq)
## Add FE & cluster var
mod2 = felm(y ~ x1 + x2 |
dy |
0 |
mnth, aq)
## Add 2nd cluster var & some estimation options
mod3 = felm(y ~ x1 + x2 |
dy |
0 |
dy + mnth,
cmethod = 'reghdfe',
exactDOF = TRUE, ## Irrelevant for feols (should be ignored)
aq)
## IV reg with weights
mod4 = felm(y ~ 1 |
dy |
(x1 ~ x3) |
mnth,
weights = aq$x2,
data = aq
)
## Multiple IV
mod5 = felm(y ~ 1 |
0 |
(x1|x2 ~ x3 + dy + mnth) |
dy,
data = aq
)
## Regression table
mods = list(mod1, mod2, mod3, mod4, mod5)
msummary(mods, gof_omit = 'Pseudo|Within|Log|IC', output = 'markdown')
"
writeLines(lfe_string, 'lfe_script.R')
```
We can now convert this script to the **fixest** equivalent using the package's
main function, `lfe2fixest()`, or its alias, `felm2feols()`.
While the function(s) accept several arguments, the only required argument is an
input file. Similarly, if no output file argument is provided, then the
function(s) will just print the conversion results to screen.
```{r fixest_script1}
# felm2feols('lfe_script.R') ## same thing
lfe2fixest('lfe_script.R')
```
Looks good. Note that the `feols` (`felm`) model syntax has been cleaned up,
with comments removed and everything collapsed onto a single line.^[The loss of inline comments is a little unfortunate, but necessary given the way that the function parses input.]
Let's write it to disk by supplying an output file this time.
```{r fixest_script2}
# felm2feols(infile = 'lfe_script.R', outfile = 'fixest_script.R') ## same thing
lfe2fixest(infile = 'lfe_script.R', outfile = 'fixest_script.R')
```
Note that the `lfe2fixest()` is a pure conversion function. It never actually
runs anything from either the input or output files. That being said, here's a
quick comparison of the resulting regressions — i.e. what we get if we
actually *do* run the scripts. As an aside, my scripts make use of the excellent
[**modelsummary**](https://vincentarelbundock.github.io/modelsummary/index.html)
package to generate the simple regression tables that you see below, although
we're really not showing off its functionality here.
First, the original **lfe** version:
```{r comparison, message = FALSE}
source('lfe_script.R', print.eval = TRUE)
```
Second, the **fixest** conversion:
```{r comparison2, message = FALSE}
source('fixest_script.R', print.eval = TRUE)
```
Some minor formatting differences aside, looks like it worked and we get the
exact same results from both scripts. Great!
Let's clean up before closing.
```{r cleanup}
file.remove(c('lfe_script.R', 'fixest_script.R'))
```