81
81
("Y~X1|f2^f3" ),
82
82
("Y~X1|f1 + f2^f3" ),
83
83
("Y~X1|f2^f3^f1" ),
84
+ # empty models
85
+ ("Y ~ 1 | f1" ),
86
+ ("Y ~ 1 | f1 + f2" ),
87
+ ("Y ~ 0 | f1" ),
88
+ ("Y ~ 0 | f1 + f2" ),
84
89
]
85
90
86
91
iv_fmls = [
@@ -122,15 +127,11 @@ def check_absolute_diff(x1, x2, tol, msg=None):
122
127
@pytest .mark .parametrize ("error_type" , ["2" ])
123
128
@pytest .mark .parametrize ("dropna" , [False ])
124
129
@pytest .mark .parametrize ("inference" , ["iid" , "hetero" , {"CRV1" : "group_id" }])
125
- # @pytest.mark.parametrize("inference", ["iid", {"CRV1": "group_id"}])
126
130
@pytest .mark .parametrize ("weights" , [None , "weights" ])
127
131
@pytest .mark .parametrize ("f3_type" , ["str" , "object" , "int" , "categorical" , "float" ])
128
132
@pytest .mark .parametrize ("fml" , ols_fmls + ols_but_not_poisson_fml )
129
133
@pytest .mark .parametrize ("adj" , [False , True ])
130
- # see here for why not test against cluster_adj = True
131
- # it triggers the N / (N-1) correction, not sure why
132
- # https://github.com/lrberge/fixest/issues/518#issuecomment-2227365516
133
- @pytest .mark .parametrize ("cluster_adj" , [False ])
134
+ @pytest .mark .parametrize ("cluster_adj" , [False , True ])
134
135
def test_single_fit_feols (
135
136
N ,
136
137
seed ,
@@ -197,9 +198,8 @@ def test_single_fit_feols(
197
198
py_confint = mod .confint ().xs ("X1" ).values
198
199
py_nobs = mod ._N
199
200
py_vcov = mod ._vcov [0 , 0 ]
200
-
201
- py_resid = mod ._u_hat .flatten () # noqa: F841
202
- # TODO: test residuals
201
+ py_resid = mod .resid ()
202
+ py_predict = mod .predict ()
203
203
204
204
df_X1 = _get_r_df (r_fixest )
205
205
@@ -209,16 +209,32 @@ def test_single_fit_feols(
209
209
r_tstat = df_X1 ["statistic" ]
210
210
r_confint = df_X1 [["conf.low" , "conf.high" ]].values .astype (np .float64 )
211
211
r_nobs = int (stats .nobs (r_fixest )[0 ])
212
- r_resid = r_fixest .rx2 ("working_residuals" ) # noqa: F841
213
212
r_vcov = stats .vcov (r_fixest )[0 , 0 ]
213
+ r_resid = stats .residuals (r_fixest )
214
+ r_predict = stats .predict (r_fixest )
215
+
216
+ if not mod ._X_is_empty :
217
+ if inference == "iid" and adj and cluster_adj :
218
+ check_absolute_diff (py_nobs , r_nobs , 1e-08 , "py_nobs != r_nobs" )
219
+ check_absolute_diff (py_coef , r_coef , 1e-08 , "py_coef != r_coef" )
220
+
221
+ check_absolute_diff (py_vcov , r_vcov , 1e-08 , "py_vcov != r_vcov" )
222
+ check_absolute_diff (py_se , r_se , 1e-08 , "py_se != r_se" )
223
+ check_absolute_diff (py_pval , r_pval , 1e-08 , "py_pval != r_pval" )
224
+ check_absolute_diff (py_tstat , r_tstat , 1e-07 , "py_tstat != r_tstat" )
225
+ check_absolute_diff (py_confint , r_confint , 1e-08 , "py_confint != r_confint" )
226
+
227
+ # residuals invariant so to vcov type
228
+ if inference == "iid" and adj and not cluster_adj :
229
+ check_absolute_diff (
230
+ (py_resid )[0 :5 ], (r_resid )[0 :5 ], 1e-07 , "py_resid != r_resid"
231
+ )
232
+ check_absolute_diff (
233
+ py_predict [0 :5 ], r_predict [0 :5 ], 1e-07 , "py_predict != r_predict"
234
+ )
214
235
215
- check_absolute_diff (py_nobs , r_nobs , 1e-08 , "py_nobs != r_nobs" )
216
- check_absolute_diff (py_coef , r_coef , 1e-08 , "py_coef != r_coef" )
217
- check_absolute_diff (py_vcov , r_vcov , 1e-08 , "py_vcov != r_vcov" )
218
- check_absolute_diff (py_se , r_se , 1e-08 , "py_se != r_se" )
219
- check_absolute_diff (py_pval , r_pval , 1e-08 , "py_pval != r_pval" )
220
- check_absolute_diff (py_tstat , r_tstat , 1e-07 , "py_tstat != r_tstat" )
221
- check_absolute_diff (py_confint , r_confint , 1e-08 , "py_confint != r_confint" )
236
+ if mod ._X_is_empty :
237
+ assert mod ._beta_hat .size == 0
222
238
223
239
if not weights :
224
240
py_r2 = mod ._r2
@@ -296,9 +312,7 @@ def test_single_fit_fepois(
296
312
py_nobs = mod ._N
297
313
py_vcov = mod ._vcov [0 , 0 ]
298
314
py_deviance = mod .deviance
299
-
300
- py_resid = mod ._u_hat .flatten () # noqa: F841
301
- # TODO: test residuals
315
+ py_resid = mod .resid ()
302
316
303
317
df_X1 = _get_r_df (r_fixest )
304
318
@@ -308,19 +322,29 @@ def test_single_fit_fepois(
308
322
r_tstat = df_X1 ["statistic" ]
309
323
r_confint = df_X1 [["conf.low" , "conf.high" ]].values .astype (np .float64 )
310
324
r_nobs = int (stats .nobs (r_fixest )[0 ])
311
- r_resid = r_fixest . rx2 ( "working_residuals" ) # noqa: F841
325
+ r_resid = stats . residuals ( r_fixest )
312
326
r_vcov = stats .vcov (r_fixest )[0 , 0 ]
313
327
r_deviance = r_fixest .rx2 ("deviance" )
314
328
315
- check_absolute_diff (py_nobs , r_nobs , 1e-08 , "py_nobs != r_nobs" )
316
- check_absolute_diff (py_coef , r_coef , 1e-08 , "py_coef != r_coef" )
329
+ if inference == "iid" and adj and cluster_adj :
330
+ check_absolute_diff (py_nobs , r_nobs , 1e-08 , "py_nobs != r_nobs" )
331
+ check_absolute_diff (py_coef , r_coef , 1e-08 , "py_coef != r_coef" )
332
+ check_absolute_diff ((py_resid )[0 :5 ], (r_resid )[0 :5 ], 1e-07 , "py_coef != r_coef" )
333
+
317
334
check_absolute_diff (py_vcov , r_vcov , 1e-06 , "py_vcov != r_vcov" )
318
335
check_absolute_diff (py_se , r_se , 1e-06 , "py_se != r_se" )
319
336
check_absolute_diff (py_pval , r_pval , 1e-06 , "py_pval != r_pval" )
320
337
check_absolute_diff (py_tstat , r_tstat , 1e-06 , "py_tstat != r_tstat" )
321
338
check_absolute_diff (py_confint , r_confint , 1e-06 , "py_confint != r_confint" )
322
339
check_absolute_diff (py_deviance , r_deviance , 1e-08 , "py_deviance != r_deviance" )
323
340
341
+ if not mod ._has_fixef :
342
+ py_predict = mod .predict ()
343
+ r_predict = stats .predict (r_fixest )
344
+ check_absolute_diff (
345
+ py_predict [0 :5 ], r_predict [0 :5 ], 1e-07 , "py_predict != r_predict"
346
+ )
347
+
324
348
325
349
@pytest .mark .parametrize ("N" , [1000 ])
326
350
@pytest .mark .parametrize ("seed" , [76540251 ])
@@ -398,9 +422,8 @@ def test_single_fit_iv(
398
422
py_confint = mod .confint ().xs ("X1" ).values
399
423
py_nobs = mod ._N
400
424
py_vcov = mod ._vcov [0 , 0 ]
401
-
402
- py_resid = mod ._u_hat .flatten () # noqa: F841
403
- # TODO: test residuals
425
+ py_resid = mod .resid ()
426
+ py_predict = mod .predict ()
404
427
405
428
df_X1 = _get_r_df (r_fixest )
406
429
@@ -410,11 +433,16 @@ def test_single_fit_iv(
410
433
r_tstat = df_X1 ["statistic" ]
411
434
r_confint = df_X1 [["conf.low" , "conf.high" ]].values .astype (np .float64 )
412
435
r_nobs = int (stats .nobs (r_fixest )[0 ])
413
- r_resid = r_fixest .rx2 ("working_residuals" ) # noqa: F841
436
+ r_resid = stats .resid (r_fixest )
437
+ r_predict = stats .predict (r_fixest )
414
438
r_vcov = stats .vcov (r_fixest )[0 , 0 ]
415
439
416
- check_absolute_diff (py_nobs , r_nobs , 1e-08 , "py_nobs != r_nobs" )
417
- check_absolute_diff (py_coef , r_coef , 1e-08 , "py_coef != r_coef" )
440
+ if inference == "iid" and adj and cluster_adj :
441
+ check_absolute_diff (py_nobs , r_nobs , 1e-08 , "py_nobs != r_nobs" )
442
+ check_absolute_diff (py_coef , r_coef , 1e-08 , "py_coef != r_coef" )
443
+ check_absolute_diff (py_predict [0 :5 ], r_predict [0 :5 ], 1e-07 , "py_coef != r_coef" )
444
+ check_absolute_diff ((py_resid )[0 :5 ], (r_resid )[0 :5 ], 1e-07 , "py_coef != r_coef" )
445
+
418
446
check_absolute_diff (py_vcov , r_vcov , 1e-07 , "py_vcov != r_vcov" )
419
447
check_absolute_diff (py_se , r_se , 1e-07 , "py_se != r_se" )
420
448
check_absolute_diff (py_pval , r_pval , 1e-06 , "py_pval != r_pval" )
0 commit comments