r""" Fit regression coefficients via maximum likelihood. Parameters ---------- X : :py:class:`ndarray ` of shape `(N, M)` A dataset consisting of `N` examples, each of dimension `M`. y : :py:class:`ndarray ` of shape
(self, X, y, weights=None)
| 170 | beta += S_inv @ X.T @ (y - X @ beta) |
| 171 | |
| 172 | def fit(self, X, y, weights=None): |
| 173 | r""" |
| 174 | Fit regression coefficients via maximum likelihood. |
| 175 | |
| 176 | Parameters |
| 177 | ---------- |
| 178 | X : :py:class:`ndarray <numpy.ndarray>` of shape `(N, M)` |
| 179 | A dataset consisting of `N` examples, each of dimension `M`. |
| 180 | y : :py:class:`ndarray <numpy.ndarray>` of shape `(N, K)` |
| 181 | The targets for each of the `N` examples in `X`, where each target |
| 182 | has dimension `K`. |
| 183 | weights : :py:class:`ndarray <numpy.ndarray>` of shape `(N,)` or None |
| 184 | Weights associated with the examples in `X`. Examples |
| 185 | with larger weights exert greater influence on model fit. When |
| 186 | `y` is a vector (i.e., `K = 1`), weights should be set to the |
| 187 | reciporical of the variance for each measurement (i.e., :math:`w_i |
| 188 | = 1/\sigma^2_i`). When `K > 1`, it is assumed that all columns of |
| 189 | `y` share the same weight :math:`w_i`. If None, examples are |
| 190 | weighted equally, resulting in the standard linear least squares |
| 191 | update. Default is None. |
| 192 | |
| 193 | Returns |
| 194 | ------- |
| 195 | self : :class:`LinearRegression <numpy_ml.linear_models.LinearRegression>` instance |
| 196 | """ # noqa: E501 |
| 197 | N = X.shape[0] |
| 198 | |
| 199 | weights = np.ones(N) if weights is None else np.atleast_1d(weights) |
| 200 | weights = np.squeeze(weights) if weights.size > 1 else weights |
| 201 | err_str = f"weights must have shape ({N},) but got {weights.shape}" |
| 202 | assert weights.shape == (N,), err_str |
| 203 | |
| 204 | # scale X and y by the weight associated with each example |
| 205 | W = np.diag(np.sqrt(weights)) |
| 206 | X, y = W @ X, W @ y |
| 207 | |
| 208 | # convert X to a design matrix if we're fitting an intercept |
| 209 | if self.fit_intercept: |
| 210 | X = np.c_[np.sqrt(weights), X] |
| 211 | |
| 212 | self.sigma_inv = np.linalg.pinv(X.T @ X) |
| 213 | self.beta = np.atleast_2d(self.sigma_inv @ X.T @ y) |
| 214 | |
| 215 | self._is_fit = True |
| 216 | return self |
| 217 | |
| 218 | def predict(self, X): |
| 219 | """ |
no outgoing calls