from _api_doc_utils import *MEstimator
Low-level objective-plus-score M-estimation
1 Where it fits
Group: Estimation interfaces
MEstimator is the lowest-level public estimation interface. It minimizes a user-supplied objective with gradient and uses a user-supplied per-observation score matrix for covariance estimation:
\[ \hat\theta = \arg\min_\theta Q_n(\theta), \qquad \widehat V = H^{-1}\widehat\Omega H^{-1}. \]
The class favors flexibility over guardrails.
2 Python API
Constructor: cm.MEstimator
Construct with MEstimator(objective_fn, score_fn, max_iterations=100, tolerance=1e-6). objective_fn(theta, data) must return (objective, gradient). score_fn(theta, data) must return an (n, p) matrix. For bootstrap support, include n in data and have the objective respect optional data['indices'].
print(inspect.signature(cm.MEstimator))(objective_fn, score_fn, max_iterations=100, tolerance=1e-06)
cls = cm.MEstimator
display(HTML(html_table(["Public method"], public_methods(cls))))| Public method |
|---|
bootstrap(self, /, n_bootstrap, seed=None) |
compute_vcov(self, /) |
fit(self, /, data, theta0) |
summary(self, /) |
3 Minimal example
def obj(theta, data):
X, y = data["X"], data["y"]
idx = data.get("indices", np.arange(len(y)))
r = y[idx] - X[idx] @ theta
return 0.5*np.sum(r*r), -(X[idx].T @ r)
def score(theta, data):
r = data["y"] - data["X"] @ theta
return -data["X"] * r[:, None]
rng=np.random.default_rng(21); X=rng.normal(size=(180,2)); y=X@np.array([1.0,-.5])+rng.normal(scale=.2,size=180)
model=cm.MEstimator(obj, score, max_iterations=200); model.fit({"X":X,"y":y,"n":len(y)}, np.zeros(2))
print(model.summary()){'coef': array([ 1.03140015, -0.50873558]), 'se': array([0.43752733, 0.46881892])}
4 summary() contract
The table below is generated by fitting the live class in this repository and then inspecting summary(). Shapes are shown because most values are plain NumPy arrays or scalars.
def obj(theta, data):
X,y=data['X'],data['y']; idx=data.get('indices',np.arange(len(y))); r=y[idx]-X[idx]@theta; return .5*np.sum(r*r), -(X[idx].T@r)
def score(theta,data):
r=data['y']-data['X']@theta; return -data['X']*r[:,None]
rng=np.random.default_rng(121); X=rng.normal(size=(100,2)); y=X@np.array([1,-.5])+rng.normal(size=100)*.2
model=cm.MEstimator(obj,score,max_iterations=200); model.fit({'X':X,'y':y,'n':len(y)},np.zeros(2))
summary = model.summary()
display(HTML(html_table(["summary() key", "shape"], summary_shape_rows(summary))))| summary() key | shape |
|---|---|
coef |
(2,) |
se |
(2,) |