You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix degrees-of-freedom reporting and improve API/docs
Main fix: residual dof no longer subtracts the intercept twice — it is now
N-K (and G-1 for clustered standard errors), matching Stata. The standard
errors themselves were already correct.
Also:
- Collinearity detection is scale-invariant, so small-scale independent
regressors are no longer wrongly dropped.
- dof_fes ignores continuous-FE groups (fe(id)&x) whose interaction is all zero.
- coeftable labels the confidence-interval columns with the requested level.
- partial_out: deprecate method=:gpu and default tol to 1e-6 (so its residuals
match reg).
- Clearer errors (malformed formulas), new docstrings (fe, has_iv, has_fe,
dof_fes, FixedEffectModel, collinear-omitted NaN convention), and small
README fixes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
reg(df, @formula(Sales ~ NDI +fe(State) +fe(Year)), method =:Metal)
140
140
```
141
141
142
+
GPU methods default to single precision (`Float32`) for the demeaning step. On CUDA you can pass `double_precision = true` to use `Float64`; Metal supports only `Float32`.
143
+
142
144
## Solution method
143
145
Denote the model `y = X β + D θ + e` where X is a matrix with few columns and D is the design matrix from categorical variables. Estimates for `β`, along with their standard errors, are obtained in two steps:
144
146
145
147
1.`y, X` are regressed on `D` using the package [FixedEffects.jl](https://github.com/FixedEffects/FixedEffects.jl)
146
148
2. Estimates for `β`, along with their standard errors, are obtained by regressing the projected `y` on the projected `X` (an application of the Frisch Waugh-Lovell Theorem)
147
-
3. With the option `save = true`, estimates for the high dimensional fixed effects are obtained after regressing the residuals of the full model minus the residuals of the partialed out models on `D` using the package [FixedEffects.jl](https://github.com/FixedEffects/FixedEffects.jl)
149
+
3. With the option `save = :fe` (or `save = :all`), estimates for the high dimensional fixed effects are obtained after regressing the residuals of the full model minus the residuals of the partialed out models on `D` using the package [FixedEffects.jl](https://github.com/FixedEffects/FixedEffects.jl)
Copy file name to clipboardExpand all lines: src/fit.jl
+9-2Lines changed: 9 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -23,6 +23,8 @@ Estimate a linear model with high dimensional categorical variables / instrument
23
23
### Details
24
24
Models with instruments variables are estimated using 2SLS. `reg` tests for weak instruments by computing the Kleibergen-Paap rk Wald F statistic, a generalization of the Cragg-Donald Wald F statistic for non i.i.d. errors. The statistic is similar to the one returned by the Stata command `ivreg2`.
25
25
26
+
Regressors that are collinear with other regressors (or with the fixed effects) are dropped from the estimation. A dropped coefficient is reported as `0` with a `NaN` standard error (and `NaN` t-statistic, p-value, and confidence interval).
27
+
26
28
### Examples
27
29
```julia
28
30
using RDatasets, FixedEffectModels
@@ -325,9 +327,14 @@ function StatsAPI.fit(::Type{FixedEffectModel},
325
327
# Compute Fstat
326
328
F =Fstat(coef, matrix_vcov, has_intercept)
327
329
328
-
# dof_ is the number of estimated coefficients beyond the intercept.
330
+
# dof_ is the number of estimated coefficients beyond the intercept (F-stat numerator).
Copy file name to clipboardExpand all lines: src/partial_out.jl
+13-6Lines changed: 13 additions & 6 deletions
Original file line number
Diff line number
Diff line change
@@ -5,17 +5,19 @@ Partial out variables in a Dataframe
5
5
* `df`: A table
6
6
* `formula::FormulaTerm`: A formula created using `@formula`
7
7
* `add_mean::Bool`: Should the initial mean added to the returned variable?
8
-
* `method::Symbol`: A symbol for the method. Default is :cpu. Alternatively, :gpu requires `CuArrays`. In this case, use the option `double_precision = false` to use `Float32`.
8
+
* `method::Symbol`: A symbol for the method. Default is `:cpu`. Alternatively, use `:CUDA` or `:Metal` (load the respective package — CUDA.jl or Metal.jl — before `using FixedEffectModels`).
9
9
* `maxiter::Integer`: Maximum number of iterations
10
10
* `double_precision::Bool`: Should the demeaning operation use Float64 rather than Float32? Default to true.
11
-
* `tol::Real`: Tolerance
11
+
* `tol::Real`: Tolerance for the iterative demeaning. Default `1e-6`, matching `reg` (so that `partial_out` and `reg(...; save = :residuals)` return the same residuals).
12
12
* `align::Bool`: Should the returned DataFrame align with the original DataFrame in case of missing values? Default to true.
13
13
* `drop_singletons::Bool=false`: Should singletons be dropped?
14
14
15
15
### Returns
16
-
* `::DataFrame`: a dataframe with as many columns as there are dependent variables and as many rows as the original dataframe.
17
-
* `::Vector{Int}`: a vector of iterations for each column
18
-
* `::Vector{Bool}`: a vector of success for each column
16
+
* `::DataFrame`: residuals, one column per dependent variable, aligned with the original dataframe.
17
+
* `::BitVector`: the estimation-sample mask (the rows actually used).
18
+
* `::Vector{Int}`: number of demeaning iterations for each column.
19
+
* `::Vector{Bool}`: convergence flag for each column.
20
+
* `::Int`: degrees of freedom absorbed by the fixed effects.
19
21
20
22
### Details
21
23
`partial_out` returns the residuals of a set of variables after regressing them on a set of regressors. The syntax is similar to `reg` - but it accepts multiple dependent variables. It returns a dataframe with as many columns as there are dependent variables and as many rows as the original dataframe.
has_iv(@nospecialize(f::FormulaTerm)) =any(x -> x isa FormulaTerm, eachterm(f.rhs))
16
16
functionparse_iv(@nospecialize(f::FormulaTerm))
17
+
f.lhs isa FormulaTerm &&throw(ArgumentError("Malformed formula: the left-hand side cannot contain `~`. The instrumental-variable syntax is `y ~ exogenous + (endogenous ~ instruments)`."))
17
18
ifhas_iv(f)
18
19
i =findfirst(x -> x isa FormulaTerm, eachterm(f.rhs))
0 commit comments