From 2b88cb4c60a90db948a3048f823062a57982ecee Mon Sep 17 00:00:00 2001 From: "Kshitij Chawla (kchawla-pi)" Date: Fri, 10 Jan 2020 17:04:27 +0100 Subject: [PATCH 01/10] Renamed resid methods to resdiuals --- nistats/regression.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/nistats/regression.py b/nistats/regression.py index 670e7676..be2e470d 100644 --- a/nistats/regression.py +++ b/nistats/regression.py @@ -18,6 +18,8 @@ __docformat__ = 'restructuredtext en' +import warnings + import numpy as np from nibabel.onetime import setattr_on_read @@ -279,6 +281,15 @@ def __init__(self, theta, Y, model, wY, wresid, cov=None, dispersion=1., @setattr_on_read def resid(self): + warnings.warn(FutureWarning, + "'RegressionResults.resid method has been deprecated " + "and will be removed. " + "Please use RegressionResults.residuals()'.") + return self.resdiuals() + + + @setattr_on_read + def residuals(self): """ Residuals from the fit. """ @@ -354,6 +365,13 @@ def logL(self, Y): raise ValueError('can not use this method for simple results') def resid(self, Y): + warnings.warn(FutureWarning, + "'SimpleRegressionResults.resid method has been deprecated " + "and will be removed. " + "Please use SimpleRegressionResults.residuals()'.") + return self.residuals(Y) + + def residuals(self, Y): """ Residuals from the fit. """ From aa0ca874be356f6851054984a239db355610d3e6 Mon Sep 17 00:00:00 2001 From: "Kshitij Chawla (kchawla-pi)" Date: Mon, 13 Jan 2020 12:57:04 +0100 Subject: [PATCH 02/10] Fixed typo and call --- nistats/regression.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/nistats/regression.py b/nistats/regression.py index 939bf6d1..2ab6bf97 100644 --- a/nistats/regression.py +++ b/nistats/regression.py @@ -282,12 +282,12 @@ def __init__(self, theta, Y, model, wY, wresid, cov=None, dispersion=1., @setattr_on_read def resid(self): - warnings.warn(FutureWarning, - "'RegressionResults.resid method has been deprecated " + warnings.warn("'RegressionResults.resid()' method has been deprecated " "and will be removed. " - "Please use RegressionResults.residuals()'.") - return self.resdiuals() - + "Please use 'RegressionResults.residuals()'.", + FutureWarning, + ) + return self.residuals @setattr_on_read def residuals(self): @@ -373,10 +373,11 @@ def logL(self, Y): raise ValueError('can not use this method for simple results') def resid(self, Y): - warnings.warn(FutureWarning, - "'SimpleRegressionResults.resid method has been deprecated " + warnings.warn("'SimpleRegressionResults.resid()' method has been deprecated " "and will be removed. " - "Please use SimpleRegressionResults.residuals()'.") + "Please use 'SimpleRegressionResults.residuals()'.", + FutureWarning, + ) return self.residuals(Y) def residuals(self, Y): From 21d5127ca0c949db80340b647bd8570c33456813 Mon Sep 17 00:00:00 2001 From: "Kshitij Chawla (kchawla-pi)" Date: Mon, 13 Jan 2020 14:15:37 +0100 Subject: [PATCH 03/10] Added residuals and resid to tests --- nistats/regression.py | 4 ++-- nistats/tests/test_regression.py | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/nistats/regression.py b/nistats/regression.py index 2ab6bf97..58c9ead3 100644 --- a/nistats/regression.py +++ b/nistats/regression.py @@ -282,9 +282,9 @@ def __init__(self, theta, Y, model, wY, wresid, cov=None, dispersion=1., @setattr_on_read def resid(self): - warnings.warn("'RegressionResults.resid()' method has been deprecated " + warnings.warn("'RegressionResults.resid' method has been deprecated " "and will be removed. " - "Please use 'RegressionResults.residuals()'.", + "Please use 'RegressionResults.residuals'.", FutureWarning, ) return self.residuals diff --git a/nistats/tests/test_regression.py b/nistats/tests/test_regression.py index b96bcba1..436d6c0d 100644 --- a/nistats/tests/test_regression.py +++ b/nistats/tests/test_regression.py @@ -3,6 +3,7 @@ """ import numpy as np +import pytest from numpy.testing import (assert_array_almost_equal, assert_almost_equal, @@ -21,16 +22,20 @@ def test_OLS(): model = OLSModel(design=X) results = model.fit(Y) assert results.df_resid == 30 - assert results.resid.shape[0] == 40 + assert results.residuals.shape[0] == 40 assert results.predicted.shape[0] == 40 + with pytest.warns(FutureWarning): + assert results.resid.shape[0] == 40 def test_AR(): model = ARModel(design=X, rho=0.4) results = model.fit(Y) assert results.df_resid == 30 - assert results.resid.shape[0] == 40 + assert results.residuals.shape[0] == 40 assert results.predicted.shape[0] == 40 + with pytest.warns(FutureWarning): + assert results.resid.shape[0] == 40 def test_residuals(): @@ -42,7 +47,7 @@ def test_residuals(): Xintercept[:, 0] = 1 model = OLSModel(design=Xintercept) results = model.fit(Y) - assert_almost_equal(results.resid.mean(), 0) + assert_almost_equal(results.residuals.mean(), 0) def test_predicted_r_square(): @@ -54,7 +59,7 @@ def test_predicted_r_square(): # rounding errors) model = OLSModel(design=Xshort) results = model.fit(Yshort) - assert_almost_equal(results.resid.sum(), 0) + assert_almost_equal(results.residuals.sum(), 0) assert_array_almost_equal(results.predicted, Yshort) assert_almost_equal(results.r_square, 1.0) From 71313bcfdc4b070847ac21d0e499f8b7f243c57e Mon Sep 17 00:00:00 2001 From: "Kshitij Chawla (kchawla-pi)" Date: Tue, 14 Jan 2020 17:02:52 +0100 Subject: [PATCH 04/10] Renamed norm_resid to normalized_resuiduals --- nistats/first_level_model.py | 2 +- nistats/regression.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/nistats/first_level_model.py b/nistats/first_level_model.py index ef4e770c..b67c0d53 100644 --- a/nistats/first_level_model.py +++ b/nistats/first_level_model.py @@ -596,7 +596,7 @@ def _get_voxelwise_model_attribute(self, attribute, result_as_time_series): ---------- attribute : str an attribute of a RegressionResults instance. - possible values include: resid, norm_resid, predicted, + possible values include: resid, norm_residuals, predicted, SSE, r_square, MSE. result_as_time_series : bool whether the RegressionResult attribute has a value diff --git a/nistats/regression.py b/nistats/regression.py index 58c9ead3..bea55744 100644 --- a/nistats/regression.py +++ b/nistats/regression.py @@ -298,6 +298,15 @@ def residuals(self): @setattr_on_read def norm_resid(self): + warnings.warn("'RegressionResults.norm_resid' method has been deprecated " + "and will be removed. " + "Please use 'RegressionResults.normalized_residuals'.", + FutureWarning, + ) + return self.normalized_residuals + + @setattr_on_read + def normalized_residuals(self): """ Residuals, normalized to have unit length. @@ -387,6 +396,14 @@ def residuals(self, Y): return Y - self.predicted def norm_resid(self, Y): + warnings.warn("'SimpleRegressionResults.norm_resid' method has been deprecated " + "and will be removed. " + "Please use 'SimpleRegressionResults.normalized_residuals'.", + FutureWarning, + ) + return self.normalized_residuals(Y) + + def normalized_residuals(self, Y): """ Residuals, normalized to have unit length. From 1093cca254208877fe388f6a29ce6b8c64348885 Mon Sep 17 00:00:00 2001 From: "Kshitij Chawla (kchawla-pi)" Date: Tue, 14 Jan 2020 17:04:03 +0100 Subject: [PATCH 05/10] Undid inadvertent option string change --- nistats/first_level_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nistats/first_level_model.py b/nistats/first_level_model.py index b67c0d53..ef4e770c 100644 --- a/nistats/first_level_model.py +++ b/nistats/first_level_model.py @@ -596,7 +596,7 @@ def _get_voxelwise_model_attribute(self, attribute, result_as_time_series): ---------- attribute : str an attribute of a RegressionResults instance. - possible values include: resid, norm_residuals, predicted, + possible values include: resid, norm_resid, predicted, SSE, r_square, MSE. result_as_time_series : bool whether the RegressionResult attribute has a value From 867cd49bac8f70adee19511d259426b1039be0b2 Mon Sep 17 00:00:00 2001 From: "Kshitij Chawla (kchawla-pi)" Date: Wed, 15 Jan 2020 16:58:47 +0100 Subject: [PATCH 06/10] Reanmed *_resid to *_residuals and added deprecation warning --- nistats/contrasts.py | 2 +- nistats/model.py | 23 +++++++++++++++-------- nistats/regression.py | 20 ++++++++++++++++---- nistats/tests/test_regression.py | 8 ++++---- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/nistats/contrasts.py b/nistats/contrasts.py index f7e0ecae..b4339711 100644 --- a/nistats/contrasts.py +++ b/nistats/contrasts.py @@ -90,7 +90,7 @@ def compute_contrast(labels, regression_result, con_val, contrast_type=None): effect_[:, label_mask] = wcbeta var_[label_mask] = rss - dof_ = regression_result[label_].df_resid + dof_ = regression_result[label_].df_residuals return Contrast(effect=effect_, variance=var_, dim=dim, dof=dof_, contrast_type=contrast_type) diff --git a/nistats/model.py b/nistats/model.py index fba86006..e164dfa8 100644 --- a/nistats/model.py +++ b/nistats/model.py @@ -3,6 +3,7 @@ Author: Bertrand Thirion, 2011--2015 """ +import warnings import numpy as np @@ -72,8 +73,14 @@ def __init__(self, theta, Y, model, cov=None, dispersion=1., nuisance=None, self.df_total = Y.shape[0] self.df_model = model.df_model # put this as a parameter of LikelihoodModel - self.df_resid = self.df_total - self.df_model - + self.df_residuals = self.df_total - self.df_model + + @setattr_on_read + def df_resid(self): + warnings.warn("The attribute 'df_resid' from LikelihoodModelResults" + "has been deprecated. Please use 'df_residuals'.") + return self.df_residuals + @setattr_on_read def logL(self): """ @@ -200,7 +207,7 @@ def Tcontrast(self, matrix, store=('t', 'effect', 'sd'), dispersion=None): if 't' in store: st_t = np.squeeze(effect * positive_reciprocal(sd)) return TContrastResults(effect=st_effect, t=st_t, sd=st_sd, - df_den=self.df_resid) + df_den=self.df_residuals) def Fcontrast(self, matrix, dispersion=None, invcov=None): """ Compute an Fcontrast for a contrast matrix `matrix`. @@ -262,7 +269,7 @@ def Fcontrast(self, matrix, dispersion=None, invcov=None): return FContrastResults( effect=ctheta, covariance=self.vcov( matrix=matrix, dispersion=dispersion[np.newaxis]), - F=F, df_den=self.df_resid, df_num=invcov.shape[0]) + F=F, df_den=self.df_residuals, df_num=invcov.shape[0]) def conf_int(self, alpha=.05, cols=None, dispersion=None): ''' The confidence interval of the specified theta estimates. @@ -306,18 +313,18 @@ def conf_int(self, alpha=.05, cols=None, dispersion=None): ''' if cols is None: - lower = self.theta - inv_t_cdf(1 - alpha / 2, self.df_resid) *\ + lower = self.theta - inv_t_cdf(1 - alpha / 2, self.df_residuals) * \ np.sqrt(np.diag(self.vcov(dispersion=dispersion))) - upper = self.theta + inv_t_cdf(1 - alpha / 2, self.df_resid) *\ + upper = self.theta + inv_t_cdf(1 - alpha / 2, self.df_residuals) * \ np.sqrt(np.diag(self.vcov(dispersion=dispersion))) else: lower, upper = [], [] for i in cols: lower.append( - self.theta[i] - inv_t_cdf(1 - alpha / 2, self.df_resid) * + self.theta[i] - inv_t_cdf(1 - alpha / 2, self.df_residuals) * np.sqrt(self.vcov(column=i, dispersion=dispersion))) upper.append( - self.theta[i] + inv_t_cdf(1 - alpha / 2, self.df_resid) * + self.theta[i] + inv_t_cdf(1 - alpha / 2, self.df_residuals) * np.sqrt(self.vcov(column=i, dispersion=dispersion))) return np.asarray(list(zip(lower, upper))) diff --git a/nistats/regression.py b/nistats/regression.py index bea55744..691577fe 100644 --- a/nistats/regression.py +++ b/nistats/regression.py @@ -60,7 +60,7 @@ class OLSModel(object): normalized_cov_beta : ndarray ``np.dot(calc_beta, calc_beta.T)`` - df_resid : scalar + df_residuals : scalar Degrees of freedom of the residuals. Number of observations less the rank of the design. @@ -92,7 +92,13 @@ def initialize(self, design): eps = np.abs(self.design).sum() * np.finfo(np.float).eps self.df_model = matrix_rank(self.design, eps) - self.df_resid = self.df_total - self.df_model + self.df_residuals = self.df_total - self.df_model + + @setattr_on_read + def df_resid(self): + warnings.warn("The attribute 'df_resid' from OLSModel" + "has been deprecated. Please use 'df_residuals'.") + return self.df_residuals def logL(self, beta, Y, nuisance=None): r''' Returns the value of the loglikelihood function at beta. @@ -350,7 +356,7 @@ def r_square(self): @setattr_on_read def MSE(self): """ Mean square (error) """ - return self.SSE / self.df_resid + return self.SSE / self.df_residuals class SimpleRegressionResults(LikelihoodModelResults): @@ -373,7 +379,7 @@ def __init__(self, results): self.df_total = results.Y.shape[0] self.df_model = results.model.df_model # put this as a parameter of LikelihoodModel - self.df_resid = self.df_total - self.df_model + self.df_residuals = self.df_total - self.df_model def logL(self, Y): """ @@ -395,6 +401,12 @@ def residuals(self, Y): """ return Y - self.predicted + @setattr_on_read + def df_resid(self): + warnings.warn("The attribute 'df_resid' from OLSModel" + "has been deprecated. Please use 'df_residuals'.") + return self.df_residuals + def norm_resid(self, Y): warnings.warn("'SimpleRegressionResults.norm_resid' method has been deprecated " "and will be removed. " diff --git a/nistats/tests/test_regression.py b/nistats/tests/test_regression.py index 436d6c0d..6a9fd3b7 100644 --- a/nistats/tests/test_regression.py +++ b/nistats/tests/test_regression.py @@ -21,7 +21,7 @@ def test_OLS(): model = OLSModel(design=X) results = model.fit(Y) - assert results.df_resid == 30 + assert results.df_residuals == 30 assert results.residuals.shape[0] == 40 assert results.predicted.shape[0] == 40 with pytest.warns(FutureWarning): @@ -31,7 +31,7 @@ def test_OLS(): def test_AR(): model = ARModel(design=X, rho=0.4) results = model.fit(Y) - assert results.df_resid == 30 + assert results.df_residuals == 30 assert results.residuals.shape[0] == 40 assert results.predicted.shape[0] == 40 with pytest.warns(FutureWarning): @@ -69,7 +69,7 @@ def test_OLS_degenerate(): Xd[:, 0] = Xd[:, 1] + Xd[:, 2] model = OLSModel(design=Xd) results = model.fit(Y) - assert results.df_resid == 31 + assert results.df_residuals == 31 def test_AR_degenerate(): @@ -77,4 +77,4 @@ def test_AR_degenerate(): Xd[:, 0] = Xd[:, 1] + Xd[:, 2] model = ARModel(design=Xd, rho=0.9) results = model.fit(Y) - assert results.df_resid == 31 + assert results.df_residuals == 31 From 73a8bb2320bdd56f08bb6a1939c1af08571c6fed Mon Sep 17 00:00:00 2001 From: "Kshitij Chawla (kchawla-pi)" Date: Wed, 15 Jan 2020 18:32:53 +0100 Subject: [PATCH 07/10] Reanmed *_resid to *_residuals and .resid to .residuals --- nistats/first_level_model.py | 4 ++-- nistats/regression.py | 22 ++++++++++++++++------ nistats/tests/test_first_level_model.py | 6 +++--- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/nistats/first_level_model.py b/nistats/first_level_model.py index ef4e770c..a75bce83 100644 --- a/nistats/first_level_model.py +++ b/nistats/first_level_model.py @@ -133,8 +133,8 @@ def run_glm(Y, X, noise_model='ar1', bins=100, n_jobs=1, verbose=0): if noise_model == 'ar1': # compute and discretize the AR1 coefs - ar1 = ((ols_result.resid[1:] * ols_result.resid[:-1]).sum(axis=0) / - (ols_result.resid ** 2).sum(axis=0)) + ar1 = ((ols_result.residuals[1:] * ols_result.residuals[:-1]).sum(axis=0) / + (ols_result.residuals ** 2).sum(axis=0)) del ols_result ar1 = (ar1 * bins).astype(np.int) * 1. / bins # Fit the AR model acccording to current AR(1) estimates diff --git a/nistats/regression.py b/nistats/regression.py index 691577fe..98936bae 100644 --- a/nistats/regression.py +++ b/nistats/regression.py @@ -265,6 +265,7 @@ def whiten(self, X): _X[(i + 1):] = _X[(i + 1):] - self.rho[i] * X[0: - (i + 1)] return _X +from nistats._utils.helpers import replace_parameters class RegressionResults(LikelihoodModelResults): """ @@ -272,8 +273,8 @@ class RegressionResults(LikelihoodModelResults): It handles the output of contrasts, estimates of covariance, etc. """ - - def __init__(self, theta, Y, model, wY, wresid, cov=None, dispersion=1., + @replace_parameters({'wresid': 'wresdiuals'}, lib_name='Nistats') + def __init__(self, theta, Y, model, wY, wresiduals, cov=None, dispersion=1., nuisance=None): """See LikelihoodModelResults constructor. @@ -283,9 +284,18 @@ def __init__(self, theta, Y, model, wY, wresid, cov=None, dispersion=1., LikelihoodModelResults.__init__(self, theta, Y, model, cov, dispersion, nuisance) self.wY = wY - self.wresid = wresid + self.wresiduals = wresiduals self.wdesign = model.wdesign + @setattr_on_read + def wresid(self): + warnings.warn("'RegressionResults.wresid' method has been deprecated " + "and will be removed. " + "Please use 'RegressionResults.wresiduals'.", + FutureWarning, + ) + return self.wresiduals + @setattr_on_read def resid(self): warnings.warn("'RegressionResults.resid' method has been deprecated " @@ -329,7 +339,7 @@ def normalized_residuals(self): See: Montgomery and Peck 3.2.1 p. 68 Davidson and MacKinnon 15.2 p 662 """ - return self.resid * positive_reciprocal(np.sqrt(self.dispersion)) + return self.residuals * positive_reciprocal(np.sqrt(self.dispersion)) @setattr_on_read def predicted(self): @@ -344,7 +354,7 @@ def predicted(self): def SSE(self): """Error sum of squares. If not from an OLS model this is "pseudo"-SSE. """ - return (self.wresid ** 2).sum(0) + return (self.wresiduals ** 2).sum(0) @setattr_on_read def r_square(self): @@ -432,7 +442,7 @@ def normalized_residuals(self, Y): See: Montgomery and Peck 3.2.1 p. 68 Davidson and MacKinnon 15.2 p 662 """ - return self.resid(Y) * positive_reciprocal(np.sqrt(self.dispersion)) + return self.residuals(Y) * positive_reciprocal(np.sqrt(self.dispersion)) def predicted(self): """ Return linear predictor values from a design matrix. diff --git a/nistats/tests/test_first_level_model.py b/nistats/tests/test_first_level_model.py index 09165151..2b5c7262 100644 --- a/nistats/tests/test_first_level_model.py +++ b/nistats/tests/test_first_level_model.py @@ -606,9 +606,9 @@ def test_first_level_model_residuals(): noise_model='ols') model.fit(fmri_data, design_matrices=design_matrices) - resid = model.residuals[0] - mean_resids = model.masker_.transform(resid).mean(0) - assert_array_almost_equal(mean_resids, 0) + residuals = model.residuals[0] + mean_residuals = model.masker_.transform(residuals).mean(0) + assert_array_almost_equal(mean_residuals, 0) def test_first_level_model_predictions_r_square(): From cfcebed64aea332463d9ce09ade9c765dbc3d9a2 Mon Sep 17 00:00:00 2001 From: "Kshitij Chawla (kchawla-pi)" Date: Tue, 21 Jan 2020 17:02:05 +0100 Subject: [PATCH 08/10] Added tests for renamed attributes and associated warnings - Reduced verbosity in warning message. - Renamed wresiduals to whitened_residuals. --- nistats/model.py | 5 +++-- nistats/regression.py | 36 ++++++++++++++++---------------- nistats/tests/test_regression.py | 23 ++++++++++++++++---- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/nistats/model.py b/nistats/model.py index e164dfa8..098d9aa5 100644 --- a/nistats/model.py +++ b/nistats/model.py @@ -77,8 +77,9 @@ def __init__(self, theta, Y, model, cov=None, dispersion=1., nuisance=None, @setattr_on_read def df_resid(self): - warnings.warn("The attribute 'df_resid' from LikelihoodModelResults" - "has been deprecated. Please use 'df_residuals'.") + warnings.warn("'df_resid' from LikelihoodModelResults " + "has been deprecated. Please use 'df_residuals'.", + FutureWarning) return self.df_residuals @setattr_on_read diff --git a/nistats/regression.py b/nistats/regression.py index 98936bae..95f2b8e4 100644 --- a/nistats/regression.py +++ b/nistats/regression.py @@ -27,6 +27,7 @@ import scipy.linalg as spl from .model import LikelihoodModelResults +from nistats._utils.helpers import replace_parameters from .utils import positive_reciprocal @@ -265,7 +266,6 @@ def whiten(self, X): _X[(i + 1):] = _X[(i + 1):] - self.rho[i] * X[0: - (i + 1)] return _X -from nistats._utils.helpers import replace_parameters class RegressionResults(LikelihoodModelResults): """ @@ -273,8 +273,8 @@ class RegressionResults(LikelihoodModelResults): It handles the output of contrasts, estimates of covariance, etc. """ - @replace_parameters({'wresid': 'wresdiuals'}, lib_name='Nistats') - def __init__(self, theta, Y, model, wY, wresiduals, cov=None, dispersion=1., + @replace_parameters({'wresid': 'whitened_residuals'}, lib_name='Nistats') + def __init__(self, theta, Y, model, wY, whitened_residuals, cov=None, dispersion=1., nuisance=None): """See LikelihoodModelResults constructor. @@ -284,23 +284,23 @@ def __init__(self, theta, Y, model, wY, wresiduals, cov=None, dispersion=1., LikelihoodModelResults.__init__(self, theta, Y, model, cov, dispersion, nuisance) self.wY = wY - self.wresiduals = wresiduals + self.whitened_residuals = whitened_residuals self.wdesign = model.wdesign @setattr_on_read def wresid(self): - warnings.warn("'RegressionResults.wresid' method has been deprecated " - "and will be removed. " - "Please use 'RegressionResults.wresiduals'.", + warnings.warn("'wresid' from RegressionResults " + "has been deprecated and will be removed. " + "Please use 'whitened_residuals' instead.", FutureWarning, ) - return self.wresiduals + return self.whitened_residuals @setattr_on_read def resid(self): - warnings.warn("'RegressionResults.resid' method has been deprecated " - "and will be removed. " - "Please use 'RegressionResults.residuals'.", + warnings.warn("'resid' from RegressionResults " + "has been deprecated and will be removed. " + "Please use 'residuals' instead.", FutureWarning, ) return self.residuals @@ -314,9 +314,9 @@ def residuals(self): @setattr_on_read def norm_resid(self): - warnings.warn("'RegressionResults.norm_resid' method has been deprecated " - "and will be removed. " - "Please use 'RegressionResults.normalized_residuals'.", + warnings.warn("'norm_resid' from RegressionResults " + "has been deprecated and will be removed. " + "Please use 'normalized_residuals' instead.", FutureWarning, ) return self.normalized_residuals @@ -354,7 +354,7 @@ def predicted(self): def SSE(self): """Error sum of squares. If not from an OLS model this is "pseudo"-SSE. """ - return (self.wresiduals ** 2).sum(0) + return (self.whitened_residuals ** 2).sum(0) @setattr_on_read def r_square(self): @@ -398,9 +398,9 @@ def logL(self, Y): raise ValueError('can not use this method for simple results') def resid(self, Y): - warnings.warn("'SimpleRegressionResults.resid()' method has been deprecated " - "and will be removed. " - "Please use 'SimpleRegressionResults.residuals()'.", + warnings.warn("'resid()' from SimpleRegressionResults" + " has been deprecated and will be removed. " + "Please use 'residuals()'.", FutureWarning, ) return self.residuals(Y) diff --git a/nistats/tests/test_regression.py b/nistats/tests/test_regression.py index 6a9fd3b7..8a03bb78 100644 --- a/nistats/tests/test_regression.py +++ b/nistats/tests/test_regression.py @@ -24,8 +24,6 @@ def test_OLS(): assert results.df_residuals == 30 assert results.residuals.shape[0] == 40 assert results.predicted.shape[0] == 40 - with pytest.warns(FutureWarning): - assert results.resid.shape[0] == 40 def test_AR(): @@ -34,8 +32,6 @@ def test_AR(): assert results.df_residuals == 30 assert results.residuals.shape[0] == 40 assert results.predicted.shape[0] == 40 - with pytest.warns(FutureWarning): - assert results.resid.shape[0] == 40 def test_residuals(): @@ -48,6 +44,7 @@ def test_residuals(): model = OLSModel(design=Xintercept) results = model.fit(Y) assert_almost_equal(results.residuals.mean(), 0) + assert len(results.whitened_residuals) == 40 def test_predicted_r_square(): @@ -78,3 +75,21 @@ def test_AR_degenerate(): model = ARModel(design=Xd, rho=0.9) results = model.fit(Y) assert results.df_residuals == 31 + + +def test_resid_rename_warnings_ols(): + model = OLSModel(design=X) + results_ols = model.fit(Y) + with pytest.warns(FutureWarning, match="'df_resid'"): + assert results_ols.df_resid == 30 + with pytest.warns(FutureWarning, match="'resid'"): + assert results_ols.resid.shape[0] == 40 + + +def test_resid_rename_warnings_ar(): + model = ARModel(design=X, rho=0.4) + results_ar = model.fit(Y) + with pytest.warns(FutureWarning, match="'resid'"): + assert results_ar.resid.shape[0] == 40 + with pytest.warns(FutureWarning, match="'wresid"): + assert len(results_ar.wresid) == 40 From 53514d6db3d3758f62e7711db3618d96b8d7d8a2 Mon Sep 17 00:00:00 2001 From: "Kshitij Chawla (kchawla-pi)" Date: Wed, 22 Jan 2020 14:34:27 +0100 Subject: [PATCH 09/10] Renamed wX and wY to whitened_X, whitened_Y --- nistats/regression.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/nistats/regression.py b/nistats/regression.py index 95f2b8e4..dc74ef6f 100644 --- a/nistats/regression.py +++ b/nistats/regression.py @@ -176,7 +176,7 @@ def whiten(self, X): Returns ------- - wX : array + whitened_X : array This matrix is the matrix whose pseudoinverse is ultimately used in estimating the coefficients. For OLSModel, it is does nothing. For WLSmodel, ARmodel, it pre-applies @@ -257,14 +257,14 @@ def whiten(self, X): Returns ------- - wX : ndarray + whitened_X : ndarray X whitened with order self.order AR """ X = np.asarray(X, np.float64) - _X = X.copy() + whitened_X = X.copy() for i in range(self.order): - _X[(i + 1):] = _X[(i + 1):] - self.rho[i] * X[0: - (i + 1)] - return _X + whitened_X[(i + 1):] = whitened_X[(i + 1):] - self.rho[i] * X[0: - (i + 1)] + return whitened_X class RegressionResults(LikelihoodModelResults): @@ -273,8 +273,8 @@ class RegressionResults(LikelihoodModelResults): It handles the output of contrasts, estimates of covariance, etc. """ - @replace_parameters({'wresid': 'whitened_residuals'}, lib_name='Nistats') - def __init__(self, theta, Y, model, wY, whitened_residuals, cov=None, dispersion=1., + @replace_parameters({'wresid': 'whitened_residuals', 'wY': 'whitened_Y'}, lib_name='Nistats') + def __init__(self, theta, Y, model, whitened_Y, whitened_residuals, cov=None, dispersion=1., nuisance=None): """See LikelihoodModelResults constructor. @@ -283,10 +283,19 @@ def __init__(self, theta, Y, model, wY, whitened_residuals, cov=None, dispersion """ LikelihoodModelResults.__init__(self, theta, Y, model, cov, dispersion, nuisance) - self.wY = wY + self.whitened_Y = whitened_Y self.whitened_residuals = whitened_residuals self.wdesign = model.wdesign + @setattr_on_read + def wY(self): + warnings.warn("'wY' from RegressionResults " + "has been deprecated and will be removed. " + "Please use 'whitened_Y' instead.", + FutureWarning, + ) + return self.whitened_Y + @setattr_on_read def wresid(self): warnings.warn("'wresid' from RegressionResults " @@ -361,7 +370,7 @@ def r_square(self): """Proportion of explained variance. If not from an OLS model this is "pseudo"-R2. """ - return np.var(self.predicted, 0) / np.var(self.wY, 0) + return np.var(self.predicted, 0) / np.var(self.whitened_Y, 0) @setattr_on_read def MSE(self): From 59a9730be9763628e6950f12af8d502de66d6561 Mon Sep 17 00:00:00 2001 From: "Kshitij Chawla (kchawla-pi)" Date: Wed, 22 Jan 2020 20:08:04 +0100 Subject: [PATCH 10/10] Replaced wdesign with whitened_design, improved tests --- nistats/model.py | 3 +- nistats/regression.py | 55 ++++++++++++++++++++++---------- nistats/tests/test_regression.py | 15 ++++++--- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/nistats/model.py b/nistats/model.py index 098d9aa5..63b14a84 100644 --- a/nistats/model.py +++ b/nistats/model.py @@ -78,7 +78,8 @@ def __init__(self, theta, Y, model, cov=None, dispersion=1., nuisance=None, @setattr_on_read def df_resid(self): warnings.warn("'df_resid' from LikelihoodModelResults " - "has been deprecated. Please use 'df_residuals'.", + "has been deprecated and will be removed. " + "Please use 'df_residuals'.", FutureWarning) return self.df_residuals diff --git a/nistats/regression.py b/nistats/regression.py index dc74ef6f..8f772691 100644 --- a/nistats/regression.py +++ b/nistats/regression.py @@ -50,8 +50,8 @@ class OLSModel(object): design : ndarray This is the design, or X, matrix. - wdesign : ndarray - This is the whitened design matrix. `design` == `wdesign` by default + whitened_design : ndarray + This is the whitened design matrix. `design` == `whitened_design` by default for the OLSModel, though models that inherit from the OLSModel will whiten the design. @@ -85,11 +85,11 @@ def initialize(self, design): # PLEASE don't assume we have a constant... # TODO: handle case for noconstant regression self.design = design - self.wdesign = self.whiten(self.design) - self.calc_beta = spl.pinv(self.wdesign) + self.whitened_design = self.whiten(self.design) + self.calc_beta = spl.pinv(self.whitened_design) self.normalized_cov_beta = np.dot(self.calc_beta, np.transpose(self.calc_beta)) - self.df_total = self.wdesign.shape[0] + self.df_total = self.whitened_design.shape[0] eps = np.abs(self.design).sum() * np.finfo(np.float).eps self.df_model = matrix_rank(self.design, eps) @@ -97,10 +97,20 @@ def initialize(self, design): @setattr_on_read def df_resid(self): - warnings.warn("The attribute 'df_resid' from OLSModel" - "has been deprecated. Please use 'df_residuals'.") + warnings.warn("'df_resid' from OLSModel" + "has been deprecated and will be removed. " + "Please use 'df_residuals'.", + FutureWarning) return self.df_residuals + @setattr_on_read + def wdesign(self): + warnings.warn("'wdesign' from OLSModel" + "has been deprecated and will be removed. " + "Please use 'whitened_design'.", + FutureWarning) + return self.whitened_design + def logL(self, beta, Y, nuisance=None): r''' Returns the value of the loglikelihood function at beta. @@ -154,7 +164,7 @@ def logL(self, beta, Y, nuisance=None): .. [1] W. Green. "Econometric Analysis," 5th ed., Pearson, 2003. ''' # This is overwriting an abstract method of LikelihoodModel - X = self.wdesign + X = self.whitened_design wY = self.whiten(Y) r = wY - np.dot(X, beta) n = self.df_total @@ -204,9 +214,9 @@ def fit(self, Y): # squares models assume covariance is diagonal, i.e. heteroscedastic). wY = self.whiten(Y) beta = np.dot(self.calc_beta, wY) - wresid = wY - np.dot(self.wdesign, beta) - dispersion = np.sum(wresid ** 2, 0) / (self.wdesign.shape[0] - - self.wdesign.shape[1]) + wresid = wY - np.dot(self.whitened_design, beta) + dispersion = np.sum(wresid ** 2, 0) / (self.whitened_design.shape[0] - + self.whitened_design.shape[1]) lfit = RegressionResults(beta, Y, self, wY, wresid, dispersion=dispersion, cov=self.normalized_cov_beta) @@ -285,7 +295,16 @@ def __init__(self, theta, Y, model, whitened_Y, whitened_residuals, cov=None, di dispersion, nuisance) self.whitened_Y = whitened_Y self.whitened_residuals = whitened_residuals - self.wdesign = model.wdesign + self.whitened_design = model.whitened_design + + @setattr_on_read + def wdesign(self): + warnings.warn("'wdesign' from RegressionResults" + "has been deprecated and will be removed. " + "Please use 'whitened_design'.", + FutureWarning) + return self.whitened_design + @setattr_on_read def wY(self): @@ -356,7 +375,7 @@ def predicted(self): """ beta = self.theta # the LikelihoodModelResults has parameters named 'theta' - X = self.wdesign + X = self.whitened_design return np.dot(X, beta) @setattr_on_read @@ -423,13 +442,15 @@ def residuals(self, Y): @setattr_on_read def df_resid(self): warnings.warn("The attribute 'df_resid' from OLSModel" - "has been deprecated. Please use 'df_residuals'.") + "has been deprecated and will be removed. " + "Please use 'df_residuals'.", + FutureWarning) return self.df_residuals def norm_resid(self, Y): - warnings.warn("'SimpleRegressionResults.norm_resid' method has been deprecated " - "and will be removed. " - "Please use 'SimpleRegressionResults.normalized_residuals'.", + warnings.warn("'SimpleRegressionResults.norm_resid' method " + "has been deprecated and will be removed. " + "Please use 'normalized_residuals'.", FutureWarning, ) return self.normalized_residuals(Y) diff --git a/nistats/tests/test_regression.py b/nistats/tests/test_regression.py index 8a03bb78..f1d27f48 100644 --- a/nistats/tests/test_regression.py +++ b/nistats/tests/test_regression.py @@ -81,15 +81,22 @@ def test_resid_rename_warnings_ols(): model = OLSModel(design=X) results_ols = model.fit(Y) with pytest.warns(FutureWarning, match="'df_resid'"): - assert results_ols.df_resid == 30 + assert_array_equal(results_ols.df_resid, results_ols.df_residuals) with pytest.warns(FutureWarning, match="'resid'"): - assert results_ols.resid.shape[0] == 40 + assert_array_equal(results_ols.resid, results_ols.residuals) + with pytest.warns(FutureWarning, match="'wY'"): + assert_array_equal(results_ols.wY, results_ols.whitened_Y) + with pytest.warns(FutureWarning, match="'wdesign'"): + assert_array_equal(results_ols.wdesign, results_ols.whitened_design) + with pytest.warns(FutureWarning, match="'wdesign'"): + assert_array_equal(model.wdesign, model.whitened_design) + def test_resid_rename_warnings_ar(): model = ARModel(design=X, rho=0.4) results_ar = model.fit(Y) with pytest.warns(FutureWarning, match="'resid'"): - assert results_ar.resid.shape[0] == 40 + assert_array_equal(results_ar.resid, results_ar.residuals) with pytest.warns(FutureWarning, match="'wresid"): - assert len(results_ar.wresid) == 40 + assert_array_equal(results_ar.wresid, results_ar.whitened_residuals)