Estimate a linear regression models with fixed effects using fixest formula syntax.
Parameters
Name
Type
Description
Default
fml
str
A three-sided formula string using fixest formula syntax. Syntax: “Y ~ X1 + X2 | FE1 + FE2 | X1 ~ Z1”. “|” separates dependent variable, fixed effects, and instruments. Special syntax includes stepwise regressions, cumulative stepwise regression, multiple dependent variables, interaction of variables (i(X1,X2)), and interacted fixed effects (fe1^fe2).
required
data
DataFrameType
A pandas or polars dataframe containing the variables in the formula.
required
vcov
Union[VcovTypeOptions, dict[str, str]]
Type of variance-covariance matrix for inference. Options include “iid”, “hetero”, “HC1”, “HC2”, “HC3”, or a dictionary for CRV1/CRV3 inference.
None
weights
Union[None, str], optional.
Default is None. Weights for WLS estimation. If None, all observations are weighted equally. If a string, the name of the column in data that contains the weights.
None
ssc
str
A ssc object specifying the small sample correction for inference.
None
fixef_rm
FixedRmOptions
Specifies whether to drop singleton fixed effects. Options: “none” (default), “singleton”.
'none'
collin_tol
float
Tolerance for collinearity check, by default 1e-10.
1e-10
fixef_tol
Tolerance for the fixed effects demeaning algorithm. Defaults to 1e-08.
1e-08
drop_intercept
bool
Whether to drop the intercept from the model, by default False.
False
i_ref1
Deprecated with pyfixest version 0.18.0. Please use i-syntax instead, i.e. feols(‘Y~ i(f1, ref=1)’, data = data) instead of the former feols(‘Y~ i(f1)’, data = data, i_ref=1).
None
copy_data
bool
Whether to copy the data before estimation, by default True. If set to False, the data is not copied, which can save memory but may lead to unintended changes in the input data outside of fepois. For example, the input data set is re-index within the function. As far as I know, the only other relevant case is when using interacted fixed effects, in which case you’ll find a column with interacted fixed effects in the data set.
True
store_data
bool
Whether to store the data in the model object, by default True. If set to False, the data is not stored in the model object, which can improve performance and save memory. However, it will no longer be possible to access the data via the data attribute of the model object. This has impact on post-estimation capabilities that rely on the data, e.g. predict() or vcov().
True
lean
bool
False by default. If True, then all large objects are removed from the returned result: this will save memory but will block the possibility to use many methods. It is recommended to use the argument vcov to obtain the appropriate standard-errors at estimation time, since obtaining different SEs won’t be possible afterwards.
False
weights_type
WeightsTypeOptions
Options include aweights or fweights. aweights implement analytic or precision weights, while fweights implement frequency weights. For details see this blog post: https://notstatschat.rbind.io/2020/08/04/weights-in-statistics/.
'aweights'
solver
SolverOptions, optional.
The solver to use for the regression. Can be either “np.linalg.solve” or “np.linalg.lstsq”. Defaults to “np.linalg.solve”.
'np.linalg.solve'
use_compression
bool
Whether to use sufficient statistics to losslessly fit the regression model on compressed data. False by default. If True, the model is estimated on compressed data, which can lead to a significant speed-up for large data sets. See the paper by Wong et al (2021) for more details https://arxiv.org/abs/2102.11297. Note that if use_compression = True, inference is lossless. If standard errors are clustered, a wild cluster bootstrap is employed. Parameters for the wild bootstrap can be specified via the reps and seed arguments. Additionally, note that for one-way fixed effects, the estimation method uses a Mundlak transform to “control” for the fixed effects. For two-way fixed effects, a two-way Mundlak transform is employed. For two-way fixed effects, the Mundlak transform is only identical to a two-way fixed effects model if the data set is a panel. We do not provide any checks for the panel status of the data set.
False
reps
int
Number of bootstrap repetitions. Only relevant for boostrap inference applied to compute cluster robust errors when use_compression = True.
100
seed
Optional[int]
Seed for the random number generator. Only relevant for boostrap inference applied to compute cluster robust errors when use_compression = True.
None
split
Optional[str]
A character string, i.e. ‘split = var’. If provided, the sample is split according to the variable and one estimation is performed for each value of that variable. If you also want to include the estimation for the full sample, use the argument fsplit instead.
None
fsplit
Optional[str]
This argument is the same as split but also includes the full sample as the first estimation.
None
Returns
Name
Type
Description
object
An instance of the [Feols(/reference/Feols.qmd) class or FixestMulti class for multiple models specified via fml.
Examples
As in fixest, the [Feols(/reference/Feols.qmd) function can be used to estimate a simple linear regression model with fixed effects. The following example regresses Y on X1 and X2 with fixed effects for f1 and f2: fixed effects are specified after the | symbol.
import pyfixest as pfdata = pf.get_data()fit = pf.feols("Y ~ X1 + X2 | f1 + f2", data)fit.summary()
Calling feols() returns an instance of the [Feols(/reference/Feols.qmd) class. The summary() method can be used to print the results.
An alternative way to retrieve model results is via the tidy() method, which returns a pandas dataframe with the estimated coefficients, standard errors, t-statistics, and p-values.
fit.tidy()
Estimate
Std. Error
t value
Pr(>|t|)
2.5%
97.5%
Coefficient
X1
-0.924046
0.060934
-15.164621
2.664535e-15
-1.048671
-0.799421
X2
-0.174107
0.014608
-11.918277
1.069367e-12
-0.203985
-0.144230
You can also access all elements in the tidy data frame by dedicated methods, e.g. fit.coef() for the coefficients, fit.se() for the standard errors, fit.tstat() for the t-statistics, and fit.pval() for the p-values, and fit.confint() for the confidence intervals.
The employed type of inference can be specified via the vcov argument. If vcov is not provided, PyFixest employs the fixest default of iid inference, unless there are fixed effects in the model, in which case feols() clusters the standard error by the first fixed effect (CRV1 inference).
Supported inference types are “iid”, “hetero”, “HC1”, “HC2”, “HC3”, and “CRV1”/“CRV3”. Clustered standard errors are specified via a dictionary, e.g. {"CRV1": "f1"} for CRV1 inference with clustering by f1 or {"CRV3": "f1"} for CRV3 inference with clustering by f1. For two-way clustering, you can provide a formula string, e.g. {"CRV1": "f1 + f2"} for CRV1 inference with clustering by f1.
The ssc argument specifies the small sample correction for inference. In general, feols() uses all of fixest::feols() defaults, but sets the fixef.K argument to "none" whereas the fixest::feols() default is "nested". See here for more details: link to github.
feols() supports a range of multiple estimation syntax, i.e. you can estimate multiple models in one call. The following example estimates two models, one with fixed effects for f1 and one with fixed effects for f2 using the sw() syntax.
The returned object is an instance of the FixestMulti class. You can access the results of the first model via fit.fetch_model(0) and the results of the second model via fit.fetch_model(1). You can compare the model results via the etable() function:
pf.etable(fit)
Y
(1)
(2)
coef
X1
-0.950***
(0.067)
-0.979***
(0.077)
X2
-0.174***
(0.018)
-0.175***
(0.022)
fe
f1
x
-
f2
-
x
stats
Observations
997
998
S.E. type
by: f1
by: f2
R2
0.489
0.354
Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error)
Other supported multiple estimation syntax include sw0(), csw() and csw0(). While sw() adds variables in a “stepwise” fashion, csw() does so cumulatively.
Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error)
The feols() function also supports multiple dependent variables. The following example estimates two models, one with Y1 as the dependent variable and one with Y2 as the dependent variable.
fit = pf.feols("Y + Y2 ~ X1 | f1 + f2", data)pf.etable(fit)
Y
Y2
(1)
(2)
coef
X1
-0.919***
(0.065)
-1.228***
(0.195)
fe
f1
x
x
f2
x
x
stats
Observations
997
998
S.E. type
by: f1
by: f1
R2
0.609
0.168
Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error)
It is possible to combine different multiple estimation operators:
Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error)
In general, using muliple estimation syntax can improve the estimation time as covariates that are demeaned in one model and are used in another model do not need to be demeaned again: feols() implements a caching mechanism that stores the demeaned covariates.
Additionally, you can fit models on different samples via the split and fsplit arguments. The split argument splits the sample according to the variable specified in the argument, while the fsplit argument also includes the full sample in the estimation.
fit = pf.feols("Y ~ X1 + X2 | f1 + f2", data, split ="f1")pf.etable(fit)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
/home/runner/work/pyfixest/pyfixest/pyfixest/utils/utils.py:160: RuntimeWarning: divide by zero encountered in scalar divide
cluster_adj_value = G / (G - 1)
Y
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
(9)
(10)
(11)
(12)
(13)
(14)
(15)
(16)
(17)
(18)
(19)
(20)
(21)
(22)
(23)
(24)
(25)
(26)
(27)
(28)
(29)
(30)
coef
X1
-1.357
(INF)
-1.137
(INF)
-0.455
(INF)
-1.138
(INF)
0.201
(INF)
-0.306
(INF)
-0.597
(INF)
-0.824
(INF)
-1.482
(INF)
-1.117
(INF)
-1.142
(INF)
-1.334
(INF)
-3.531
(INF)
-1.102
(INF)
-0.826
(INF)
-0.773
(INF)
-1.501
(INF)
-1.226
(INF)
-0.641
(INF)
-0.378
(INF)
-0.652
(INF)
-1.508
(INF)
-0.941
(INF)
-0.206
(INF)
-0.195
(INF)
-0.702
(INF)
-1.141
(INF)
-1.349
(INF)
-0.537
(INF)
-1.141
(INF)
X2
-0.250
(INF)
0.198
(INF)
-0.145
(INF)
-0.330
(INF)
-0.177
(INF)
-0.187
(INF)
-0.118
(INF)
-0.292
(INF)
-0.029
(INF)
-0.264
(INF)
-0.148
(INF)
-0.313
(INF)
-0.152
(INF)
-0.296
(INF)
0.130
(INF)
-0.059
(INF)
-0.223
(INF)
-0.113
(INF)
-0.261
(INF)
0.089
(INF)
-0.148
(INF)
-0.267
(INF)
-0.125
(INF)
-0.282
(INF)
-0.153
(INF)
0.004
(INF)
0.083
(INF)
-0.226
(INF)
-0.158
(INF)
-0.160
(INF)
fe
f1
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
f2
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
stats
Observations
30
29
44
30
31
36
36
30
36
35
32
30
23
28
34
34
48
40
36
34
35
37
27
35
29
27
43
36
24
28
S.E. type
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
by: f1
R2
0.850
0.691
0.578
0.745
0.939
0.644
0.792
0.776
0.919
0.797
0.727
0.822
0.924
0.865
0.711
0.808
0.651
0.819
0.746
0.731
0.880
0.868
0.796
0.648
0.915
0.820
0.837
0.789
0.688
0.883
Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error)
Besides OLS, feols() also supports IV estimation via three part formulas:
fit = pf.feols("Y ~ X2 | f1 + f2 | X1 ~ Z1", data)fit.tidy()
Estimate
Std. Error
t value
Pr(>|t|)
2.5%
97.5%
Coefficient
X1
-1.050097
0.085493
-12.282912
5.133671e-13
-1.224949
-0.875245
X2
-0.174351
0.014779
-11.797039
1.369793e-12
-0.204578
-0.144124
Here, X1 is the endogenous variable and Z1 is the instrument. f1 and f2 are the fixed effects, as before. To estimate IV models without fixed effects, simply omit the fixed effects part of the formula:
fit = pf.feols("Y ~ X2 | X1 ~ Z1", data)fit.tidy()
Estimate
Std. Error
t value
Pr(>|t|)
2.5%
97.5%
Coefficient
Intercept
0.861939
0.151187
5.701137
1.567858e-08
0.565257
1.158622
X1
-0.967238
0.130078
-7.435847
2.238210e-13
-1.222497
-0.711980
X2
-0.176416
0.021769
-8.104001
1.554312e-15
-0.219134
-0.133697
Last, feols() supports interaction of variables via the i() syntax. Documentation on this is tba.
After fitting a model via feols(), you can use the predict() method to get the predicted values:
fit = pf.feols("Y ~ X1 + X2 | f1 + f2", data)fit.predict()[0:5]
Last, you can plot the results of a model via the coefplot() method:
fit = pf.feols("Y ~ X1 + X2 | f1 + f2", data)fit.coefplot()
We can conduct a regression decomposition via the decompose() method, which implements a regression decomposition following the method developed in Gelbach (2016):
import reimport pyfixest as pffrom pyfixest.utils.dgps import gelbach_datadata_gelbach = gelbach_data(nobs =1000)fit = pf.feols("y ~ x1 + x21 + x22 + x23", data=data_gelbach)# simple decompositionres = fit.decompose(param ="x1")pf.make_table(res)# group covariates via "combine_covariates" argumentres = fit.decompose(param ="x1", combine_covariates={"g1": ["x21", "x22"], "g2": ["x23"]})pf.make_table(res)# group covariates via regexres = fit.decompose(param="x1", combine_covariates={"g1": re.compile("x2[1-2]"), "g2": re.compile("x23")})
0%| | 0/1000 [00:00<?, ?it/s]/home/runner/work/pyfixest/pyfixest/.pixi/envs/docs/lib/python3.12/site-packages/joblib/externals/loky/backend/fork_exec.py:38: RuntimeWarning: Using fork() can cause Polars to deadlock in the child process.
In addition, using fork() with Python in general is a recipe for mysterious
deadlocks and crashes.
The most likely reason you are seeing this error is because you are using the
multiprocessing module on Linux, which uses fork() by default. This will be
fixed in Python 3.14. Until then, you want to use the "spawn" context instead.
See https://docs.pola.rs/user-guide/misc/multiprocessing/ for details.
If you really know what your doing, you can silence this warning with the warning module
or by setting POLARS_ALLOW_FORKING_THREAD=1.
pid = os.fork()
1%| | 8/1000 [00:02<05:06, 3.24it/s] 2%|▏ | 16/1000 [00:02<02:13, 7.39it/s] 14%|█▍ | 140/1000 [00:02<00:09, 95.06it/s] 40%|███▉ | 396/1000 [00:02<00:01, 321.57it/s] 78%|███████▊ | 780/1000 [00:02<00:00, 681.57it/s]100%|██████████| 1000/1000 [00:02<00:00, 337.25it/s]
0%| | 0/1000 [00:00<?, ?it/s] 18%|█▊ | 184/1000 [00:00<00:00, 1556.39it/s] 38%|███▊ | 376/1000 [00:00<00:00, 1614.18it/s] 54%|█████▍ | 538/1000 [00:00<00:00, 1540.67it/s] 76%|███████▌ | 760/1000 [00:00<00:00, 1711.34it/s]100%|██████████| 1000/1000 [00:00<00:00, 2169.16it/s]
0%| | 0/1000 [00:00<?, ?it/s] 18%|█▊ | 184/1000 [00:00<00:00, 1521.16it/s] 38%|███▊ | 376/1000 [00:00<00:00, 1618.58it/s] 54%|█████▍ | 539/1000 [00:00<00:00, 1530.09it/s] 76%|███████▌ | 760/1000 [00:00<00:00, 1701.89it/s]100%|██████████| 1000/1000 [00:00<00:00, 2154.59it/s]
Objects of type Feols support a range of other methods to conduct inference. For example, you can run a wild (cluster) bootstrap via the wildboottest() method:
fit = pf.feols("Y ~ X1 + X2", data)fit.wildboottest(param ="X1", reps=1000)
param X1
t value -12.444998
Pr(>|t|) 0.0
bootstrap_type 11
inference HC
impose_null True
ssc 1.00201
dtype: object
would run a wild bootstrap test for the coefficient of X1 with 1000 bootstrap repetitions.
For a wild cluster bootstrap, you can specify the cluster variable via the cluster argument:
/home/runner/work/pyfixest/pyfixest/pyfixest/estimation/feols_.py:1408: UserWarning: The initial model was not clustered. CRV1 inference is computed and stored in the model object.
warnings.warn(