@@ -15,7 +15,105 @@ fit2 = pf.feols("Y ~ X1 + X2", data = df)
1515fit3 = pf.feols("Y ~ X1 + X2 | f1", data = df)
1616```
1717
18- ## PyFixest 0.41.0 (In Development)
18+ ## PyFixest 0.50.0 (In Development)
19+
20+ ::: {.callout-tip}
21+ You can install the latest pre-release to try out the new features:
22+
23+ ``` {.bash .code-copy}
24+ pip install pyfixest==0.50.0a1
25+ pip install --pre pyfixest
26+ ```
27+ :::
28+
29+ ### Reworked Formula Parsing and New ` i() ` Operator
30+
31+ The formula parsing module has been significantly reworked. The new implementation introduces a cleaner ` Formula ` class,
32+ a rewritten ` i() ` operator that closely follows R's ` fixest ` syntax, and new multiple estimation operators.
33+
34+ #### New ` i() ` operator
35+
36+ The ` i() ` operator now follows the ` fixest ` naming convention, using ` :: ` to separate variable names from levels. It further
37+ provides two new arguments: ` ref2 ` and ` bin2 ` that allow to set
38+ reference levels for interacted variables and to bin categoricals.
39+
40+ ** Simple categorical encoding:**
41+
42+ ``` {python}
43+ # Coefficient per level, first level dropped when intercept is present
44+ fit = pf.feols("Y ~ i(f1, ref=1)", data=df)
45+ fit.coef().head()
46+ ```
47+
48+ ** Factor x Continuous interaction:**
49+
50+ ``` {python}
51+ # Each level of f1 gets its own slope on X1
52+ fit = pf.feols("Y ~ i(f1, X1, ref=1)", data=df)
53+ fit.coef().head()
54+ ```
55+
56+ ** Factor x Factor interaction** with ` ref2 ` :
57+
58+ The ` ref2 ` argument controls the reference level of the second variable in a factor-by-factor interaction.
59+
60+ ``` {python}
61+ import numpy as np
62+ df["group"] = np.where(df["f1"] < 15, "A", "B")
63+
64+ # Full interaction: f1 levels x group levels
65+ # ref drops from f1, ref2 drops from group
66+ fit = pf.feols("Y ~ i(f1, group, ref=1, ref2='A')", data=df)
67+ fit.coef().head()
68+ ```
69+
70+ ** Binning** with ` bin ` and ` bin2 ` :
71+
72+ The ` bin ` parameter merges categorical levels before encoding. This is useful for collapsing sparse categories.
73+ Values not in the mapping are kept unchanged, matching R ` fixest ` behavior.
74+
75+ ``` {python}
76+ df["size"] = np.where(df["f1"] < 10, "small", np.where(df["f1"] < 20, "medium", "large"))
77+
78+ # Merge 'small' and 'medium' into 'not_large', then use as reference
79+ fit = pf.feols("Y ~ i(size, bin={'not_large': ['small','medium']}, ref='not_large')", data=df)
80+ fit.coef()
81+ ```
82+
83+ ` bin2 ` applies binning to the second variable in a factor-by-factor interaction.
84+
85+ #### ` mvsw() ` and multiple estimation
86+
87+
88+ ` mvsw() ` for ** multiverse stepwise** — generates all $2^k$ combinations of the provided variables, including the intercept-only model.
89+
90+ ``` {python}
91+ # mvsw: all combinations of X1 and X2
92+ fits = pf.feols("Y ~ mvsw(X1, X2)", data=df)
93+ pf.etable(fits)
94+ ```
95+
96+ Multiple estimation operators can be combined:
97+
98+ ``` {python}
99+ # mvsw: all combinations of X1 and X2
100+ fits = pf.feols("Y ~ sw(X1, X2) + csw(f1,f2)", data=df)
101+ pf.etable(fits)
102+ ```
103+
104+ Last, you can run operations within the operators:
105+
106+ ``` {python}
107+ # mvsw: all combinations of X1 and X2
108+ fits = pf.feols("Y ~ sw(X1, f1 + X2)", data=df)
109+ pf.etable(fits)
110+ ```
111+
112+ #### Deprecations
113+
114+ - ` FixestFormulaParser ` is deprecated in favor of ` Formula.parse() ` . A ` FutureWarning ` is emitted when the old class is used.
115+ - ` model_matrix_fixest() ` is deprecated in favor of ` create_model_matrix() ` .
116+
19117
20118### Migration to maketables
21119
0 commit comments