Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[MRG + 1] FIX Calculation of standard deviation of predictions in ARDRegression #10153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Nov 22, 2017
5 changes: 5 additions & 0 deletions doc/whats_new/v0.20.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ random sampling procedures.
- :class:`neural_network.BaseMultilayerPerceptron` (bug fix)
- :class:`neural_network.MLPRegressor` (bug fix)
- :class:`neural_network.MLPClassifier` (bug fix)
- :class:`linear_model.ARDRegression` (bug fix)

Details are listed in the changelog below.

Expand Down Expand Up @@ -140,6 +141,10 @@ Classifiers and regressors
broken when setting ``normalize=False``.
by `Alexandre Gramfort`_.

- Fixed a bug in :class:`linear_model.ARDRegression` which caused incorrectly
updated estimates for the standard deviation and the coefficients.
:issue:`10153` by :user:`Jörg Döpfert <jdoepfert>`.

Decomposition, manifold learning and clustering

- Fix for uninformative error in :class:`decomposition.IncrementalPCA`:
Expand Down
18 changes: 15 additions & 3 deletions sklearn/linear_model/bayes.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,8 @@ def fit(self, X, y):
self.scores_ = list()
coef_old_ = None

# Iterative procedure of ARDRegression
for iter_ in range(self.n_iter):
# Compute mu and sigma (using Woodbury matrix identity)
# Compute sigma and mu (using Woodbury matrix identity)
def update_sigma(X, alpha_, lambda_, keep_lambda, n_samples):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am not sure what is the best: keep the function here or make a private method.
@jnothman WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine leaving it here if the object still pickles

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this tested somewhere?

sigma_ = pinvh(np.eye(n_samples) / alpha_ +
np.dot(X[:, keep_lambda] *
np.reshape(1. / lambda_[keep_lambda], [1, -1]),
Expand All @@ -481,8 +480,17 @@ def fit(self, X, y):
sigma_ = - np.dot(np.reshape(1. / lambda_[keep_lambda], [-1, 1]) *
X[:, keep_lambda].T, sigma_)
sigma_.flat[::(sigma_.shape[1] + 1)] += 1. / lambda_[keep_lambda]
return sigma_

def update_coeff(X, y, coef_, alpha_, keep_lambda, sigma_):
coef_[keep_lambda] = alpha_ * np.dot(
sigma_, np.dot(X[:, keep_lambda].T, y))
return coef_

# Iterative procedure of ARDRegression
for iter_ in range(self.n_iter):
sigma_ = update_sigma(X, alpha_, lambda_, keep_lambda, n_samples)
coef_ = update_coeff(X, y, coef_, alpha_, keep_lambda, sigma_)

# Update alpha and lambda
rmse_ = np.sum((y - np.dot(X, coef_)) ** 2)
Expand Down Expand Up @@ -513,6 +521,10 @@ def fit(self, X, y):
break
coef_old_ = np.copy(coef_)

# update sigma and mu using updated parameters from the last iteration
sigma_ = update_sigma(X, alpha_, lambda_, keep_lambda, n_samples)
coef_ = update_coeff(X, y, coef_, alpha_, keep_lambda, sigma_)

self.coef_ = coef_
self.alpha_ = alpha_
self.sigma_ = sigma_
Expand Down
16 changes: 16 additions & 0 deletions sklearn/linear_model/tests/test_bayes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from sklearn.utils.testing import assert_array_almost_equal
from sklearn.utils.testing import assert_almost_equal
from sklearn.utils.testing import assert_array_less
from sklearn.utils.testing import assert_equal
from sklearn.utils.testing import SkipTest
from sklearn.utils import check_random_state
from sklearn.linear_model.bayes import BayesianRidge, ARDRegression
Expand Down Expand Up @@ -110,6 +111,21 @@ def test_std_bayesian_ridge_ard_with_constant_input():
assert_array_less(y_std, expected_upper_boundary)


def test_update_of_sigma_in_ard():
# Checks that `sigma_` is updated correctly after the last iteration
# of the ARDRegression algorithm. See issue #10128.
X = np.array([[1, 0],
[0, 0]])
y = np.array([0, 0])
clf = ARDRegression(n_iter=1)
clf.fit(X, y)
# With the inputs above, ARDRegression prunes one of the two coefficients
# in the first iteration. Hence, the expected shape of `sigma_` is (1, 1).
assert_equal(clf.sigma_.shape, (1, 1))
# Ensure that no error is thrown at prediction stage
clf.predict(X, return_std=True)


def test_toy_ard_object():
# Test BayesianRegression ARD classifier
X = np.array([[1], [2], [3]])
Expand Down