Skip to content

Commit fe5b074

Browse files
Ariadnaazs3alfisc
andauthored
Added log-likelihood, pseudo r2 and pearson chi2 to fepois and tests for the first two against fixest (#1083)
* Implement log-likelihood, pearson chi2 and pseudo R2 * Included log-likelihood and pseudo R-squared in tests against fixest * rename and fix tests * run pre commit * update changelog --------- Co-authored-by: Alexander Fischer <[email protected]>
1 parent 15cd034 commit fe5b074

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

docs/changelog.qmd

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ fit2 = pf.feols("Y ~ X1 + X2", data = df)
1111
fit3 = pf.feols("Y ~ X1 + X2 | f1", data = df)
1212
```
1313

14-
## PyFixest 0.40.0
14+
## PyFixest 0.41.0 (In Development)
15+
16+
- Adds the following statistics to the `Fepois` class: `_loglik`, `_loglik_null`, `_pseudo_r2`.
17+
18+
19+
## PyFixest 0.40.1
1520

1621
### Breaking Changes for compatibility with `fixest` 0.13
1722

pyfixest/estimation/fepois_.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import numpy as np
77
import pandas as pd
8+
from scipy.special import gammaln
89

910
from pyfixest.errors import (
1011
NonConvergenceError,
@@ -338,6 +339,20 @@ def get_fit(self) -> None:
338339
self._u_hat_working = resid
339340
self._u_hat_response = self._Y - np.exp(eta)
340341

342+
y = self._Y.flatten()
343+
self._y_hat_null = np.full_like(y, np.mean(y), dtype=float)
344+
345+
self._loglik = np.sum(
346+
y * np.log(self._Y_hat_response) - self._Y_hat_response - gammaln(y + 1)
347+
)
348+
self._loglik_null = np.sum(
349+
y * np.log(self._y_hat_null) - self._y_hat_null - gammaln(y + 1)
350+
)
351+
self._pseudo_r2 = 1 - (self._loglik / self._loglik_null)
352+
self._pearson_chi2 = np.sum(
353+
(y - self._Y_hat_response) ** 2 / self._Y_hat_response
354+
)
355+
341356
self._Y = WZ
342357
self._X = WX
343358
self._Z = self._X

tests/test_vs_fixest.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,9 @@ def test_single_fit_fepois(data_fepois, dropna, inference, f3_type, fml, k_adj,
555555
py_df_k = int(mod._df_k)
556556
py_df_t = int(mod._df_t)
557557
py_n_coefs = mod.coef().values.size
558+
py_loglik = mod._loglik
559+
py_loglik_null = mod._loglik_null
560+
py_pseudo_r2 = mod._pseudo_r2
558561

559562
df_X1 = _get_r_df(r_fixest)
560563
ro.globalenv["r_fixest"] = r_fixest
@@ -572,6 +575,9 @@ def test_single_fit_fepois(data_fepois, dropna, inference, f3_type, fml, k_adj,
572575
r_df_k = int(ro.r('attr(r_fixest$cov.scaled, "df.K")')[0])
573576
r_df_t = int(ro.r('attr(r_fixest$cov.scaled, "df.t")')[0])
574577
r_n_coefs = int(df_X1["n_coef"])
578+
r_loglik = float(ro.r("r_fixest$loglik"))
579+
r_loglik_null = float(ro.r("r_fixest$ll_null"))
580+
r_pseudo_r2 = float(ro.r('fixest::r2(r_fixest)["pr2"]'))
575581

576582
if inference == "iid" and k_adj and G_adj:
577583
check_absolute_diff(py_nobs, r_nobs, 1e-08, "py_nobs != r_nobs")
@@ -600,6 +606,11 @@ def test_single_fit_fepois(data_fepois, dropna, inference, f3_type, fml, k_adj,
600606
check_absolute_diff(py_tstat, r_tstat, 1e-06, "py_tstat != r_tstat")
601607
check_absolute_diff(py_confint, r_confint, 1e-06, "py_confint != r_confint")
602608
check_absolute_diff(py_deviance, r_deviance, 1e-08, "py_deviance != r_deviance")
609+
check_absolute_diff(py_loglik, r_loglik, 1e-08, "py_ll != r_loglik")
610+
check_absolute_diff(
611+
py_loglik_null, r_loglik_null, 1e-08, "py_loglik_null != r_loglik_null"
612+
)
613+
check_absolute_diff(py_pseudo_r2, r_pseudo_r2, 1e-08, "py_pseudo_r2 != r_pseudo_r2")
603614

604615
if not mod._has_fixef:
605616
py_predict_response = mod.predict(type="response")

0 commit comments

Comments
 (0)