Skip to content

Commit

Permalink
ENH: first version of RLMDetS
Browse files Browse the repository at this point in the history
  • Loading branch information
josef-pkt committed Apr 23, 2024
1 parent 021cd2d commit c1a2574
Showing 1 changed file with 92 additions and 0 deletions.
92 changes: 92 additions & 0 deletions statsmodels/robust/resistant_linear_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""
Created on Apr. 19, 2024 12:17:03 p.m.
Author: Josef Perktold
License: BSD-3
"""

import numpy as np
from statsmodels.base.model import Model
from statsmodels.regression.linear_model import OLS
from statsmodels.tools.testing import Holder

Check warning on line 11 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L8-L11

Added lines #L8 - L11 were not covered by tests

from statsmodels.robust.robust_linear_model import RLM
import statsmodels.robust.norms as rnorms
import statsmodels.robust.scale as rscale
from statsmodels.robust.covariance import _get_detcov_startidx

Check warning on line 16 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L13-L16

Added lines #L13 - L16 were not covered by tests


class RLMDetS(Model):

Check warning on line 19 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L19

Added line #L19 was not covered by tests
"""S-estimator for linear model with deterministic starts.
"""

def __init__(self, endog, exog, norm=None, breakdown_point=0.5,

Check warning on line 23 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L23

Added line #L23 was not covered by tests
col_indices=None, include_endog=False):
super().__init__(endog, exog)

Check warning on line 25 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L25

Added line #L25 was not covered by tests

if norm is None:
norm = rnorms.TukeyBiweight(c=1.547)
scale_bias = 0.1995
self.mscale = rscale.MScale(norm, scale_bias)

Check warning on line 30 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L28-L30

Added lines #L28 - L30 were not covered by tests
else:
raise ValueError()

Check warning on line 32 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L32

Added line #L32 was not covered by tests

self.norm = norm

Check warning on line 34 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L34

Added line #L34 was not covered by tests
# need tuning params for given breakdown point
# if type(norm) is a class then create an instance
# if norm is an instance, then just use it
# self.norm._set_tuning_param(???)
# data for robust mahalanobis distance of starting sets
self.breakdown_point = breakdown_point

Check warning on line 40 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L40

Added line #L40 was not covered by tests

if col_indices is None:
exog_start = self.exog[:, 1:]

Check warning on line 43 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L43

Added line #L43 was not covered by tests
else:
exog_start = self.exog[:, col_indices]

Check warning on line 45 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L45

Added line #L45 was not covered by tests

if include_endog:
self.data_start = np.column_stack(endog, exog_start)

Check warning on line 48 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L48

Added line #L48 was not covered by tests
else:
self.data_start = exog_start

Check warning on line 50 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L50

Added line #L50 was not covered by tests

def _get_start_params(self, h):

Check warning on line 52 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L52

Added line #L52 was not covered by tests
# I think we should use iterator with yield
starts = _get_detcov_startidx(

Check warning on line 54 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L54

Added line #L54 was not covered by tests
self.data_start, h, options_start=None, methods_cov="all")

start_params_all = [
OLS(self.endog[idx], self.exog[idx]).fit().params
for (idx, method) in starts
]
return start_params_all

Check warning on line 61 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L61

Added line #L61 was not covered by tests

def _fit_once(self, start_params, maxiter=100):
mod = RLM(self.endog, self.exog, M=self.norm)
res = mod.fit(start_params=start_params,

Check warning on line 65 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L63-L65

Added lines #L63 - L65 were not covered by tests
scale_est=self.mscale,
maxiter=maxiter)
return res

Check warning on line 68 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L68

Added line #L68 was not covered by tests

def fit(self, h, maxiter=100, maxiter_step=5):

Check warning on line 70 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L70

Added line #L70 was not covered by tests

res = {}

Check warning on line 72 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L72

Added line #L72 was not covered by tests
for ii, sp in enumerate(self._get_start_params(h)):
res_ii = self._fit_once(sp, maxiter=maxiter_step)
res[ii] = Holder(

Check warning on line 75 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L74-L75

Added lines #L74 - L75 were not covered by tests
scale=res_ii.scale,
params=res_ii.params,
method=ii, # method # TODO need start set method
)

scale_all = np.array([i.scale for i in res.values()])
scale_sorted = np.argsort(scale_all)
best_idx = scale_sorted[0]

Check warning on line 83 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L82-L83

Added lines #L82 - L83 were not covered by tests

# TODO: iterate until convergence if start fits are not converged
res_best = self._fit_once(res[best_idx].params, maxiter=maxiter)

Check warning on line 86 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L86

Added line #L86 was not covered by tests

# TODO: add extra start and convergence info
res_best._results.results_iter = res

Check warning on line 89 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L89

Added line #L89 was not covered by tests
# results instance of _fit_once has RLM as `model`
res_best.model_dets = self
return res_best

Check warning on line 92 in statsmodels/robust/resistant_linear_model.py

View check run for this annotation

Codecov / codecov/patch

statsmodels/robust/resistant_linear_model.py#L91-L92

Added lines #L91 - L92 were not covered by tests

0 comments on commit c1a2574

Please sign in to comment.