statspai.fixest¶
fixest ¶
High-dimensional fixed effects estimation via pyfixest.
This module provides thin wrappers around pyfixest's estimation functions,
converting results into StatsPAI's EconometricResults for seamless
integration with outreg2 and the rest of the ecosystem.
Requires: pip install pyfixest
Examples:
>>> from statspai.fixest import feols, fepois
>>>
>>> # Two-way fixed effects with clustered SEs
>>> result = feols("wage ~ experience | firm + year",
... data=df, vcov={"CRV1": "firm"})
>>> print(result.summary())
>>>
>>> # Poisson regression
>>> result = fepois("patents ~ rd_spending | firm", data=df)
>>>
>>> # Works with outreg2
>>> from statspai import outreg2
>>> outreg2(result, filename="table.xlsx")
feols ¶
feols(fml: str, data: DataFrame, vcov: Optional[Union[str, Dict[str, str]]] = None, *, weights: Optional[str] = None, ssc: Optional[Any] = None, fixef_rm: str = 'none', collin_tol: float = 1e-06, lean: bool = False, cluster: Optional[str] = None, wild_reps: int = 999, wild_weight_type: str = 'rademacher', seed: Optional[int] = None, conley_lat: Optional[str] = None, conley_lon: Optional[str] = None, conley_cutoff: Optional[float] = None, **kwargs: Any) -> Union[EconometricResults, List[EconometricResults]]
Estimate OLS / IV with high-dimensional fixed effects via pyfixest.
Uses the Frisch-Waugh-Lovell theorem for fast absorption of high-dimensional fixed effects.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fml
|
str
|
A pyfixest-style formula. Examples:
|
required |
data
|
DataFrame
|
Input dataset. |
required |
vcov
|
str or dict
|
Variance-covariance estimator (
|
None
|
weights
|
str
|
Column name for regression weights. |
None
|
ssc
|
optional
|
Small-sample correction via |
None
|
fixef_rm
|
str
|
How to handle singleton fixed effects:
|
"none"
|
collin_tol
|
float
|
Collinearity tolerance. |
1e-6
|
lean
|
bool
|
If True, drop large intermediate arrays to save memory. |
False
|
cluster
|
str
|
Cluster id column for the extended |
None
|
wild_reps
|
int
|
Bootstrap replications for |
999
|
wild_weight_type
|
str
|
Wild weight distribution ( |
"rademacher"
|
seed
|
int
|
RNG seed for |
None
|
conley_lat
|
str
|
Coordinate columns (decimal degrees) for |
None
|
conley_lon
|
str
|
Coordinate columns (decimal degrees) for |
None
|
conley_cutoff
|
float
|
Conley distance cutoff in km for |
None
|
**kwargs
|
Any
|
Additional arguments passed to |
{}
|
Returns:
| Type | Description |
|---|---|
EconometricResults or list of EconometricResults
|
Single result for simple formulas, list for multiple estimations
(e.g. |
Examples:
Two-way fixed effects with clustered SEs:
>>> import statspai as sp
>>> import numpy as np
>>> import pandas as pd
>>> rng = np.random.default_rng(0)
>>> n = 400
>>> firm = rng.integers(0, 8, n)
>>> year = rng.integers(0, 5, n)
>>> x1 = rng.normal(size=n)
>>> y = 1.0 + 0.5 * x1 + 0.1 * firm + 0.2 * year + rng.normal(0, 0.5, n)
>>> df = pd.DataFrame({"y": y, "x1": x1, "firm": firm, "year": year})
>>> res = sp.feols("y ~ x1 | firm + year", data=df, vcov={"CRV1": "firm"})
>>> "x1" in res.params.index
True
Multiple estimation (csw0 returns a list, one fit per FE set):
>>> results = sp.feols("y ~ x1 | csw0(firm, year)", data=df)
>>> summaries = [r.summary() for r in results]
Use with outreg2 to build a regression table:
fepois ¶
fepois(fml: str, data: DataFrame, vcov: Optional[Union[str, Dict[str, str]]] = None, *, weights: Optional[str] = None, ssc: Optional[Any] = None, fixef_rm: str = 'none', collin_tol: float = 1e-06, iwls_tol: float = 1e-08, iwls_maxiter: int = 25, cluster: Optional[str] = None, wild_reps: int = 9999, wild_weight_type: str = 'rademacher', seed: Optional[int] = None, conley_lat: Optional[str] = None, conley_lon: Optional[str] = None, conley_cutoff: Optional[float] = None, **kwargs: Any) -> Union[EconometricResults, List[EconometricResults]]
Estimate Poisson regression with high-dimensional fixed effects via pyfixest.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fml
|
str
|
pyfixest formula. E.g. |
required |
data
|
DataFrame
|
Input dataset. |
required |
vcov
|
str or dict
|
Variance-covariance estimator (
|
None
|
weights
|
str
|
Column name for regression weights (not supported with the extended
|
None
|
ssc
|
optional
|
Small-sample correction. |
None
|
fixef_rm
|
str
|
Singleton fixed effect handling. |
"none"
|
collin_tol
|
float
|
Collinearity tolerance. |
1e-6
|
iwls_tol
|
float
|
IWLS convergence tolerance. |
1e-8
|
iwls_maxiter
|
int
|
Max IWLS iterations. |
25
|
cluster
|
str
|
Cluster id column for the extended |
None
|
wild_reps
|
int
|
Replications for |
9999
|
wild_weight_type
|
str
|
Wild weight distribution ( |
"rademacher"
|
seed
|
int
|
RNG seed for sampled (non-enumerated) |
None
|
**kwargs
|
Any
|
Additional arguments passed to |
{}
|
Returns:
| Type | Description |
|---|---|
EconometricResults or list of EconometricResults
|
|
Examples:
Poisson regression (PPML-style) with firm fixed effects:
>>> import statspai as sp
>>> import numpy as np
>>> import pandas as pd
>>> rng = np.random.default_rng(0)
>>> n = 400
>>> firm = rng.integers(0, 8, n)
>>> x1 = rng.normal(size=n)
>>> mu = np.exp(0.3 + 0.5 * x1 + 0.1 * firm)
>>> df = pd.DataFrame({"y": rng.poisson(mu), "x1": x1, "firm": firm})
>>> res = sp.fepois("y ~ x1 | firm", data=df)
>>> "x1" in res.params.index
True
Bias-reduced cluster-robust SEs (matches R clubSandwich::vcovCR):
feglm ¶
feglm(fml: str, data: DataFrame, family: str = 'gaussian', vcov: Optional[Union[str, Dict[str, str]]] = None, *, cluster: Optional[str] = None, wild_reps: int = 9999, wild_weight_type: str = 'rademacher', seed: Optional[int] = None, conley_lat: Optional[str] = None, conley_lon: Optional[str] = None, conley_cutoff: Optional[float] = None, **kwargs: Any) -> Union[EconometricResults, List[EconometricResults]]
Estimate GLM (logit, probit, Gaussian) with high-dimensional fixed effects.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fml
|
str
|
pyfixest formula. |
required |
data
|
DataFrame
|
Input dataset. |
required |
family
|
str
|
GLM family: |
"gaussian"
|
vcov
|
str or dict
|
Variance-covariance estimator ( |
None
|
cluster
|
str
|
Cluster id column for the extended |
None
|
wild_reps
|
int
|
Replications for |
9999
|
wild_weight_type
|
str
|
Wild weight distribution ( |
"rademacher"
|
seed
|
int
|
RNG seed for sampled (non-enumerated) |
None
|
**kwargs
|
Any
|
Additional arguments passed to |
{}
|
Returns:
| Type | Description |
|---|---|
EconometricResults or list of EconometricResults
|
|
Examples:
Logit GLM with firm fixed effects:
>>> import statspai as sp
>>> import numpy as np
>>> import pandas as pd
>>> rng = np.random.default_rng(0)
>>> n = 500
>>> firm = rng.integers(0, 8, n)
>>> x1 = rng.normal(size=n)
>>> p = 1.0 / (1.0 + np.exp(-(0.2 + 0.8 * x1)))
>>> y = (rng.random(n) < p).astype(int)
>>> df = pd.DataFrame({"y": y, "x1": x1, "firm": firm})
>>> res = sp.feglm("y ~ x1 | firm", data=df, family="logit")
>>> "x1" in res.params.index
True
etable ¶
etable(*results: EconometricResults, **kwargs: Any) -> Any
Display a pyfixest-style regression table for StatsPAI results.
If the results carry a _pyfixest_fit reference, uses pyfixest's
native etable. Otherwise falls back to a simple pandas summary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*results
|
EconometricResults
|
One or more fitted results. |
()
|
**kwargs
|
Any
|
Passed to |
{}
|
Returns:
| Type | Description |
|---|---|
str or DataFrame
|
|
Examples:
Side-by-side comparison of nested specifications:
>>> import numpy as np
>>> import pandas as pd
>>> import statspai as sp
>>> rng = np.random.default_rng(1)
>>> n = 200
>>> df = pd.DataFrame({"x1": rng.normal(size=n), "x2": rng.normal(size=n),
... "firm": rng.integers(0, 10, n)})
>>> df["wage"] = 1.0 + 0.5 * df["x1"] - 0.3 * df["x2"] + rng.normal(0, 0.5, n)
>>> r1 = sp.regress("wage ~ x1", data=df)
>>> r2 = sp.regress("wage ~ x1 + x2", data=df)
>>> tab = sp.etable(r1, r2) # DataFrame: one coefficient column per model
>>> print(tab.round(2))
With sp.feols fits (requires the fixest extra), pyfixest's
native styled table is returned instead: