fixest 0.11.0

Bug fixes

Multiple estimations

base = setNames(iris, c("y", "x1", "x2", "x3", "species"))
mult_est = feols(y ~ csw(x.[,1:3]), base)
models(mult_est)
#>   id          rhs
#> 1  1           x1
#> 2  2      x1 + x2
#> 3  3 x1 + x2 + x3
coef(mult_est)
#>   id          rhs (Intercept)         x1       x2         x3
#> 1  1           x1    6.526223 -0.2233611       NA         NA
#> 2  2      x1 + x2    2.249140  0.5955247 0.471920         NA
#> 3  3 x1 + x2 + x3    1.855997  0.6508372 0.709132 -0.5564827

# Now in long format
coef(mult_est, long = TRUE)
#>    id          rhs coefficient   estimate
#> 1   1           x1 (Intercept)  6.5262226
#> 2   1           x1          x1 -0.2233611
#> 5   2      x1 + x2 (Intercept)  2.2491402
#> 6   2      x1 + x2          x1  0.5955247
#> 7   2      x1 + x2          x2  0.4719200
#> 9   3 x1 + x2 + x3 (Intercept)  1.8559975
#> 10  3 x1 + x2 + x3          x1  0.6508372
#> 11  3 x1 + x2 + x3          x2  0.7091320
#> 12  3 x1 + x2 + x3          x3 -0.5564827
coeftable(mult_est)
#>   id          rhs coefficient   Estimate Std. Error   t value     Pr(>|t|)
#> 1  1           x1 (Intercept)  6.5262226 0.47889634 13.627631 6.469702e-28
#> 2  1           x1          x1 -0.2233611 0.15508093 -1.440287 1.518983e-01
#> 3  2      x1 + x2 (Intercept)  2.2491402 0.24796963  9.070224 7.038510e-16
#> 4  2      x1 + x2          x1  0.5955247 0.06932816  8.589940 1.163254e-14
#> 5  2      x1 + x2          x2  0.4719200 0.01711768 27.569160 5.847914e-60
#> 6  3 x1 + x2 + x3 (Intercept)  1.8559975 0.25077711  7.400984 9.853855e-12
#> 7  3 x1 + x2 + x3          x1  0.6508372 0.06664739  9.765380 1.199846e-17
#> 8  3 x1 + x2 + x3          x2  0.7091320 0.05671929 12.502483 7.656980e-25
#> 9  3 x1 + x2 + x3          x3 -0.5564827 0.12754795 -4.362929 2.412876e-05

xpd

x = ""
xpd(y ~ .[x] + .[NULL])
#> y ~ 1 + 1
xpd(am ~ ..("!^am"), data = mtcars)
#> am ~ mpg + cyl + disp + hp + drat + wt + qsec + vs + gear + carb
base = setNames(iris, c("y", "x1", "x2", "x3", "species"))
xpd(y ~ x.., data = base)
#> y ~ x1 + x2 + x3
feols(y ~ x.., base)
#> OLS estimation, Dep. Var.: y
#> Observations: 150 
#> Standard-errors: IID 
#>              Estimate Std. Error  t value   Pr(>|t|)    
#> (Intercept)  1.855997   0.250777  7.40098 9.8539e-12 ***
#> x1           0.650837   0.066647  9.76538  < 2.2e-16 ***
#> x2           0.709132   0.056719 12.50248  < 2.2e-16 ***
#> x3          -0.556483   0.127548 -4.36293 2.4129e-05 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> RMSE: 0.310327   Adj. R2: 0.855706
lm(xpd(y ~ x..), base)
#> Call:
#> lm(formula = xpd(y ~ x..), data = base)
#> 
#> Coefficients:
#> (Intercept)           x1           x2           x3  
#>      1.8560       0.6508       0.7091      -0.5565 
x_all = ~sepal + petal
xpd(color ~ .[x_all])
#> color ~ sepal + petal

etable

base = setNames(iris, c("y", "x1", "x2", "x3", "species"))
est = feols(y ~ csw(x.[,1:3]), base)

# setting the macro
setFixest_fml(..fit_ols = ~ n + ar2 + my)

# summoning it
etable(est, fitstat = ~..fit_ols)
#>                             est.1              est.2               est.3
#> Dependent Var.:                 y                  y                   y
#>                                                                         
#> Constant        6.526*** (0.4789)  2.249*** (0.2480)   1.856*** (0.2508)
#> x1               -0.2234 (0.1551) 0.5955*** (0.0693)  0.6508*** (0.0667)
#> x2                                0.4719*** (0.0171)  0.7091*** (0.0567)
#> x3                                                   -0.5565*** (0.1275)
#> _______________ _________________ __________________ ___________________
#> S.E. type                     IID                IID                 IID
#> Observations                  150                150                 150
#> Adj. R2                   0.00716            0.83800             0.85571
#> Dep. Var. mean             5.8433             5.8433              5.8433

coeftable

est = feols(mpg ~ cyl + drat + wt, mtcars)
ct = coeftable(est, list = TRUE)
ct$constant$coef
#> Estimate 
#> 39.76766 
ct$wt$se
#> Std. Error 
#>  0.8293065

All estimations

base = setNames(iris, c("y", "x1", "x2", "x3", "species"))
est = feols(y ~ x.[1:3], base, fsplit = ~species %keep% c("set", "vers"))
etable(est)
#>                              model 1            model 2            model 3
#> Sample (species)         Full sample             setosa         versicolor
#> Dependent Var.:                    y                  y                  y
#>                                                                           
#> (Intercept)        1.856*** (0.2508)  2.352*** (0.3929)  1.896*** (0.5071)
#> x1                0.6508*** (0.0667) 0.6548*** (0.0925)   0.3869. (0.2045)
#> x2                0.7091*** (0.0567)    0.2376 (0.2080) 0.9083*** (0.1654)
#> x3               -0.5565*** (0.1275)    0.2521 (0.3469)   -0.6792 (0.4354)
#> ________________ ___________________ __________________ __________________
#> S.E. type                        IID                IID                IID
#> Observations                     150                 50                 50
#> R2                           0.85861            0.57514            0.60503
#> Adj. R2                      0.85571            0.54743            0.57927

Dictionary

x = "
# Main vars
mpg: Miles per gallon
hp: Horsepower

# Categorical variables
cyl: Number of cylinders; vs: Engine"

as.dict(x)
#>                   mpg                    hp                   cyl                    vs 
#>    "Miles per gallon"          "Horsepower" "Number of cylinders"              "Engine" 

# setFixest_dict works directly with x
setFixest_dict(x)

New functions

Other

fixest 0.10.4

Hot fix

Other bug fixes

Other

fixest 0.10.3

fixest 0.10.2

Bug fixes

etable

New arguments

New features

dsb

# At first sight, it's impossible to understand what's going on.
# But I assure you, it's pretty logical! 
# Type dsb("--help") to get some help.

dollar = 6
reason = "glory"
dsb("Why do you develop packages? For .[`dollar`*c!$]?",
    "For money? No... for .[U,''s, c?reason]!", sep = "\n")
#> Why do you develop packages? For $$$$$$?
#> For money? No... for G L O R Y!
xpd(~ sw(.[, "disp:.[/mpg, cyl]"]))
#> ~sw(disp:mpg, disp:cyl)

New argument in all estimations

New functions

# First we get the environment (the estimation is not performed!)
env = feols(mpg ~ disp + drat, mtcars, only.env = TRUE)

# Then we estimate: we get the reult from feols(mpg ~ disp + drat, mtcars)

est_env(env)
#> OLS estimation, Dep. Var.: mpg
#> Observations: 32 
#> Standard-errors: IID 
#>              Estimate Std. Error  t value   Pr(>|t|)    
#> (Intercept) 21.844880   6.747971  3.23725 3.0167e-03 ** 
#> disp        -0.035694   0.006653 -5.36535 9.1914e-06 ***
#> drat         1.802027   1.542091  1.16856 2.5210e-01    
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> RMSE: 3.07661   Adj. R2: 0.712458

# Why doing that? You can modify the env w/t incurring overheads

assign("weights.value", mtcars$wt, env)
# New estimation with weights
est_env(env)
#> OLS estimation, Dep. Var.: mpg
#> Observations: 32 
#> Standard-errors: IID 
#>              Estimate Std. Error  t value   Pr(>|t|)    
#> (Intercept) 21.967576   6.320006  3.47588 1.6241e-03 ** 
#> disp        -0.032922   0.005884 -5.59478 4.8664e-06 ***
#> drat         1.505517   1.470671  1.02369 3.1444e-01    
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> RMSE: 5.08781   Adj. R2: 0.709392
# We want to place 5 in the first place
ref(1:5, 5)
#> [1] 1 2 3 4 5
#> Levels: 5 1 2 3 4

# You can also bin at the same time
ref(1:5, .("4:5" = 4:5))
#> [1] 1   2   3   4:5 4:5
#> Levels: 4:5 1 2 3

Other

fixest 0.10.1

Bug fixes

Dot square bracket operator

lhs_vars = c("var1", "var2")
xpd(c(.[,lhs_vars]) ~ csw(x.[,1:3]))
#> c(var1, var2) ~ csw(x1, x2, x3)
name = c("Juliet", "Romeo")

# default behavior => vector
dsb("hello .[name], what's up?")
#> [1] "hello Juliet, what's up?" "hello Romeo, what's up?" 

# string literal in first position
dsb("hello .[' and ', name], what's up?")
#> [1] "hello Juliet and Romeo, what's up?"

# string literal in last position
dsb("hello .[name, ' and '], what's up?")
#> [1] "hello Juliet and hello Romeo, what's up?"

bin

data(iris)
plen = iris$Petal.Length

# 3 parts of (roughly) equal size
table(bin(plen, "cut::3"))
#> 
#> [1.0; 1.9] [3.0; 4.9] [5.0; 6.9] 
#>         50         54         46 

# Three custom bins
table(bin(plen, "cut::2]5]"))
#> 
#> [1.0; 1.9] [3.0; 5.0] [5.1; 6.9] 
#>         50         58         42 

# .. same, excluding 5 in the 2nd bin
table(bin(plen, "cut::2]5["))
#> 
#> [1.0; 1.9] [3.0; 4.9] [5.0; 6.9] 
#>         50         54         46 

# Using quartiles
table(bin(plen, "cut::q1]q2]q3]"))
#> 
#> [1.0; 1.6] [1.7; 4.3] [4.4; 5.1] [5.2; 6.9] 
#>         44         31         41         34 

# Using percentiles
table(bin(plen, "cut::p20]p50]p70]p90]"))
#> 
#> [1.0; 1.5] [1.6; 4.3] [4.4; 5.0] [5.1; 5.8] [5.9; 6.9] 
#>         37         38         33         29         13 

# Mixing all
table(bin(plen, "cut::2[q2]p90]"))
#> 
#> [1.0; 1.9] [3.0; 4.3] [4.4; 5.8] [5.9; 6.9] 
#>         50         25         62         13

# Adding custom names
table(bin(plen, c("cut::2[q2]p90]", "<2", "]2; Q2]", NA, ">90%")))
#>         <2    ]2; Q2] [4.4; 5.8]       >90% 
#>         50         25         62         13 
base = setNames(iris, c("y", "x1", "x2", "x3", "species"))
table(base$species)
#>     setosa versicolor  virginica 
#>         50         50         50

table(bin(base$species, .("@3" = "seto", "@1 VIRGIN" = "virg")))
#>     VIRGIN versicolor     setosa 
#>         50         50         50 

etable

base = setNames(iris, c("y", "x1", "x2", "x3", "species"))

New function

New functions, unrelated but possibly useful

Although a bit unrelated to the purpose of this package, these functions are so extensively used in the author’s research that he decided to leverage his author privileges to include them in fixest to make them easier to share with co-authors.

Other new features

base = setNames(iris, c("y", "x1", "x2", "x3", "species"))
y = c("y", "x1")
feols(.[y] ~ x2, base)
#> Standard-errors: IID 
#> Dep. var.: y
#>             Estimate Std. Error t value  Pr(>|t|)    
#> (Intercept) 4.306603   0.078389 54.9389 < 2.2e-16 ***
#> x2          0.408922   0.018891 21.6460 < 2.2e-16 ***
#> ---
#> Dep. var.: x1
#>              Estimate Std. Error  t value   Pr(>|t|)    
#> (Intercept)  3.454874   0.076095 45.40188  < 2.2e-16 ***
#> x2          -0.105785   0.018339 -5.76845 4.5133e-08 ***


etable(feols(..("x") ~ y + i(species), base))
#>                                  model 1            model 2            model 3
#> Dependent Var.:                       x1                 x2                 x3
#>                                                                               
#> (Intercept)            1.677*** (0.2354) -1.702*** (0.2301) -0.4794** (0.1557)
#> y                     0.3499*** (0.0463) 0.6321*** (0.0453) 0.1449*** (0.0306)
#> species = versicolor -0.9834*** (0.0721)  2.210*** (0.0705) 0.9452*** (0.0477)
#> species = virginica   -1.008*** (0.0933)  3.090*** (0.0912)  1.551*** (0.0617)
#> ____________________ ___________________ __________________ __________________
#> S.E. type                            IID                IID                IID
#> Observations                         150                150                150
#> R2                               0.56925            0.97489            0.93833
#> Adj. R2                          0.56040            0.97438            0.93706

Other

fixest 0.10.0

Bugs fixes

Major changes

base = setNames(iris, c("y", "x1", "x2", "x3", "species"))
i = 2:3
z = "i(species)"
feols(y ~ x.[i] + .[z], base)
#> OLS estimation, Dep. Var.: y
#> Observations: 150 
#> Standard-errors: IID 
#>                      Estimate Std. Error   t value   Pr(>|t|)    
#> (Intercept)          3.682982   0.107403 34.291343  < 2.2e-16 ***
#> x2                   0.905946   0.074311 12.191282  < 2.2e-16 ***
#> x3                  -0.005995   0.156260 -0.038368 9.6945e-01    
#> species::versicolor -1.598362   0.205706 -7.770113 1.3154e-12 ***
#> species::virginica  -2.112647   0.304024 -6.948940 1.1550e-10 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#> RMSE: 0.333482   Adj. R2: 0.832221

Breaking changes

New features

base = setNames(iris = c("y", "x1", "x2", "x3", "species"))

# Setting up the data
setFixest_estimation(data = base)

# Now vcov can be used without using vcov = stuff:
feols(y ~ x1 + x2, ~species)

# => same as feols(y ~ x1 + x2, vcov = ~species)
mtcars |> feols(cyl ~ mpg)
# => same as feols(cyl ~ mpg, mtcars)

etable

Other

fixest 0.9.0

Bugs

Breaking changes: new i() function

Breaking changes: new default family for feglm

Breaking changes: coefplot is now split in two

etable

Sun and Abraham staggered DiD method

fixest_multi methods

Common methods have been extended to fixest_multi objects.

fitstat: New fit statistics

New functions

New features

Minor breaking changes

Other changes

fixest 0.8.4

Bugs

New features

Other changes

fixest 0.8.3 (2021-03-01)

Bugs

New features

fixest 0.8.2 (2021-02-11)

Bugs

Other

fixest 0.8.1 (2021-01-13)

Bugs

Sun and Abraham method for staggered DiD

New features

Other

fixest 0.8.0 (2020-12-14)

Bugs

IV

base = iris
names(base) = c("y", "x1", "x_endo", "x_inst", "species")
base$endo_bis = 0.5 * base$y + 0.3 * base$x_inst + rnorm(150)
base$inst_bis = 0.2 * base$x_endo + 0.3 * base$endo_bis + rnorm(150)

# The endo/instrument is defined in a formula past a pipe
res_iv1 = feols(y ~ x1 | x_endo ~ x_inst, base)

# Same with the species fixed-effect
res_iv2 = feols(y ~ x1 | species | x_endo ~ x_inst, base)

# To add multiple endogenous regressors: embed them in c()
res_iv3 = feols(y ~ x1 | c(x_endo, x_endo_bis) ~ x_inst + x_inst_bis, base)

fit statistics

Multiple estimations

aq = airquality[airquality$Month %in% 5:6, ]
est_split = feols(c(Ozone, Solar.R) ~ sw(poly(Wind, 2), poly(Temp, 2)),
                 aq, split = ~ Month)
                 
# By default: sample is the root
etable(est_split)

# Let's reorder, by considering lhs the root
etable(est_split[lhs = TRUE])

# Selecting only one LHS and RHS
etable(est_split[lhs = "Ozone", rhs = 1])

# Taking the first root (here sample = 5)
etable(est_split[I = 1])

# The first and last estimations
etable(est_split[i = c(1, .N)])

Formula macros

data(longley)
# All variables containing "GNP" or "ployed" in their names are fetched
feols(Armed.Forces ~ Population + ..("GNP|ployed"), longley)

New features in etable

Other new features

Improvements of the internal algorithm

fixest 0.7.1 (2020-10-27)

Hotfixes

Improvements

New features

fixest 0.7.0 (2020-10-24)

Bugs

Internal improvements

Standard-errors, important changes

New function: fitstat

New features in interact()

New features in etable

User visible changes

Deprecation

fixest 0.6.0 (2020-07-13)

Bugs

New vignettes

Major changes: etable

Major changes: dof

User visible changes

New methods

fixest 0.5.1 (2020-06-18)

Hotfix

Bugs

User visible change

Major update of etable

Other

fixest 0.5.0 (2020-06-10)

Bug fixes

New functionality: formula macros

New functions

Major user-visible changes

User-visible changes

New Methods

Vignette and Readme

Issue found: convergence problems with multiples variables with varying slopes

Error-handling

Other

fixest 0.4.1 (2020-04-13)

Bug fixes

Help

Other

fixest 0.4.0 (2020-03-27)

User visible changes: Latex export

User visible changes: coefplot

New methods

Other

fixest 0.3.1 (2020-02-09)

Major bug fix

Other bug fixes

New features

fixest 0.3.0 (2020-02-01)

New feature: Lagging

New feature: Interactions

New feature: coefplot

New functions

User visible changes

Bug correction

fixest 0.2.1 (2019-11-22)

Major bug correction

Major user visible changes

fixest 0.2.0 (2019-11-19)

New function

-[did_means] New function did_means to conveniently compare means of groups of observations (both treat/control and pre/post). Contains tools to easily export in Latex.

Major user visible changes

Minor user visible changes

Bug correction

Error handling

fixest 0.1.2 (2019-10-04)

Major bug correction

fixest 0.1.1 (2019-09-20)

Major bug correction

Minor bug correction

Error handling

fixest 0.1.0 (2019-09-03)

First version