diff --git a/mgwr/sel_bw.py b/mgwr/sel_bw.py index f5a7fe0..adc18d5 100755 --- a/mgwr/sel_bw.py +++ b/mgwr/sel_bw.py @@ -1,6 +1,6 @@ # GWR Bandwidth selection class -#x_glob parameter does not yet do anything; it is for semiparametric +# x_glob parameter does not yet do anything; it is for semiparametric __author__ = "Taylor Oshan Tayoshan@gmail.com" @@ -10,7 +10,7 @@ from scipy.spatial.distance import pdist from scipy.optimize import minimize_scalar from spglm.family import Gaussian, Poisson, Binomial -from .kernels import Kernel,local_cdist +from .kernels import Kernel, local_cdist from .gwr import GWR from .search import golden_section, equal_interval, multi_bw from .diagnostics import get_AICc, get_AIC, get_BIC, get_CV @@ -141,7 +141,7 @@ class Sel_BW(object): >>> pov = np.array(data.by_col('PctPov')).reshape((-1,1)) >>> african_amer = np.array(data.by_col('PctBlack')).reshape((-1,1)) >>> X = np.hstack([rural, pov, african_amer]) - + Golden section search AICc - adaptive bisquare >>> bw = Sel_BW(coords, y, X).search(criterion='AICc') @@ -175,23 +175,27 @@ class Sel_BW(object): """ - def __init__(self, coords, y, X_loc, X_glob=None, family=Gaussian(), - offset=None, kernel='bisquare', fixed=False, multi=False, - constant=True, spherical=False,n_jobs=-1): + def __init__(self, + coords: list[tuple], + y: np.array, + X_loc: np.array, + X_glob: np.array = None, + family=Gaussian(), + offset: np.array = None, + kernel: str = 'bisquare', + fixed: bool = False, + multi: bool = False, + constant: bool = True, + spherical: bool = False, + n_jobs: int = -1) -> None: self.coords = np.array(coords) self.y = y self.X_loc = X_loc - if X_glob is not None: - self.X_glob = X_glob - else: - self.X_glob = [] + self.X_glob = X_glob if X_glob is not None else [] self.family = family self.fixed = fixed self.kernel = kernel - if offset is None: - self.offset = np.ones((len(y), 1)) - else: - self.offset = offset * 1.0 + self.offset = np.ones((len(y), 1)) if offset is None else offset * 1.0 self.multi = multi self._functions = [] self.constant = constant @@ -199,12 +203,23 @@ def __init__(self, coords, y, X_loc, X_glob=None, family=Gaussian(), self.n_jobs = n_jobs self.search_params = {} - def search(self, search_method='golden_section', criterion='AICc', - bw_min=None, bw_max=None, interval=0.0, tol=1.0e-6, - max_iter=200, init_multi=None, tol_multi=1.0e-5, - rss_score=False, max_iter_multi=200, multi_bw_min=[None], - multi_bw_max=[None - ], bws_same_times=5, verbose=False,pool=None): + def search(self, + search_method: str = 'golden_section', + criterion: str = 'AICc', + bw_min: float = None, + bw_max: float = None, + interval: int = 0.0, + tol: float = 1.0e-6, + max_iter: int = 200, + init_multi: float = None, + tol_multi: float = 1.0e-5, + rss_score: bool = False, + max_iter_multi: int = 200, + multi_bw_min: list = [None], + multi_bw_max: list = [None], + bws_same_times: int = 5, + verbose: bool = False, + pool: int = None): """ Method to select one unique bandwidth for a gwr model or a bandwidth vector for a mgwr model. @@ -219,7 +234,7 @@ def search(self, search_method='golden_section', criterion='AICc', min value used in bandwidth search bw_max : float max value used in bandwidth search - multi_bw_min : list + multi_bw_min : list min values used for each covariate in mgwr bandwidth search. Must be either a single value or have one value for each covariate including the intercept @@ -263,7 +278,7 @@ def search(self, search_method='golden_section', criterion='AICc', designs matrix, X """ k = self.X_loc.shape[1] - if self.constant: #k is the number of covariates + if self.constant: # k is the number of covariates k += 1 self.search_method = search_method self.criterion = criterion @@ -295,7 +310,6 @@ def search(self, search_method='golden_section', criterion='AICc', if pool: warnings.warn("The pool parameter is no longer used and will have no effect; parallelization is default and implemented using joblib instead.", RuntimeWarning, stacklevel=2) - self.interval = interval self.tol = tol self.max_iter = max_iter @@ -310,16 +324,15 @@ def search(self, search_method='golden_section', criterion='AICc', self.search_params['interval'] = interval self.search_params['tol'] = tol self.search_params['max_iter'] = max_iter - #self._check_min_max() + # self._check_min_max() self.int_score = not self.fixed if self.multi: self._mbw() - self.params = self.bw[3] #params n by k - self.sel_hist = self.bw[-2] #bw searching history - self.bw_init = self.bw[ - -1] #scalar, optimal bw from initial gwr model + self.params = self.bw[3] # params n by k + self.sel_hist = self.bw[-2] # bw searching history + self.bw_init = self.bw[-1] # scalar, optimal bw from initial gwr model else: self._bw() self.sel_hist = self.bw[-1] @@ -337,7 +350,7 @@ def _bw(self): if self.search_method == 'golden_section': a, c = self._init_section(self.X_glob, self.X_loc, self.coords, self.constant) - delta = 0.38197 #1 - (np.sqrt(5.0)-1.0)/2.0 + delta = 0.38197 # 1 - (np.sqrt(5.0)-1.0)/2.0 self.bw = golden_section(a, c, delta, gwr_func, self.tol, self.max_iter, self.bw_max, self.int_score, self.verbose) @@ -359,9 +372,14 @@ def _bw(self): self.search_method) def _mbw(self): + + # TODO: Do we need to assign these self variables to local variables here? + # TODO: These local variables refer to the same ram locations as it is not a deepcopy. + # TODO: Recommend to use self variables directly in gwr_func, bw_func, and sel_func. + y = self.y if self.constant: - X,keep_x,warn = USER.check_constant(self.X_loc) + X, keep_x, warn = USER.check_constant(self.X_loc) else: X = self.X_loc n, k = X.shape @@ -369,12 +387,12 @@ def _mbw(self): offset = self.offset kernel = self.kernel fixed = self.fixed - spherical = self.spherical + # spherical = self.spherical, TODO: Need to delete this line as it is not used coords = self.coords search_method = self.search_method criterion = self.criterion - bw_min = self.bw_min - bw_max = self.bw_max + # bw_min = self.bw_min TODO: Need to delete this line as it is not used + # bw_max = self.bw_max TODO: Need to delete this line as it is not used multi_bw_min = self.multi_bw_min multi_bw_max = self.multi_bw_max interval = self.interval @@ -385,13 +403,13 @@ def _mbw(self): def gwr_func(y, X, bw): return GWR(coords, y, X, bw, family=family, kernel=kernel, fixed=fixed, offset=offset, constant=False, - spherical=self.spherical, hat_matrix=False,n_jobs=self.n_jobs).fit( + spherical=self.spherical, hat_matrix=False, n_jobs=self.n_jobs).fit( lite=True) def bw_func(y, X): selector = Sel_BW(coords, y, X, X_glob=[], family=family, kernel=kernel, fixed=fixed, offset=offset, - constant=False, spherical=self.spherical,n_jobs=self.n_jobs) + constant=False, spherical=self.spherical, n_jobs=self.n_jobs) return selector def sel_func(bw_func, bw_min=None, bw_max=None): @@ -405,19 +423,10 @@ def sel_func(bw_func, bw_min=None, bw_max=None): bw_func, sel_func, multi_bw_min, multi_bw_max, bws_same_times, verbose=self.verbose) - def _init_section(self, X_glob, X_loc, coords, constant): - if len(X_glob) > 0: - n_glob = X_glob.shape[1] - else: - n_glob = 0 - if len(X_loc) > 0: - n_loc = X_loc.shape[1] - else: - n_loc = 0 - if constant: - n_vars = n_glob + n_loc + 1 - else: - n_vars = n_glob + n_loc + def _init_section(self, X_glob, X_loc, coords, constant) -> tuple: + n_glob = X_glob.shape[1] if len(X_glob) > 0 else 0 + n_loc = X_loc.shape[1] if len(X_loc) > 0 else 0 + n_vars = n_glob + n_loc + 1 if constant else n_glob + n_loc n = np.array(coords).shape[0] if self.int_score: @@ -425,12 +434,12 @@ def _init_section(self, X_glob, X_loc, coords, constant): c = n else: min_dist = np.min(np.array([np.min(np.delete( - local_cdist(coords[i],coords,spherical=self.spherical),i)) + local_cdist(coords[i], coords, spherical=self.spherical), i)) for i in range(n)])) max_dist = np.max(np.array([np.max( - local_cdist(coords[i],coords,spherical=self.spherical)) + local_cdist(coords[i], coords, spherical=self.spherical)) for i in range(n)])) - + a = min_dist / 2.0 c = max_dist * 2.0 @@ -439,4 +448,5 @@ def _init_section(self, X_glob, X_loc, coords, constant): if self.bw_max is not None and self.bw_max is not np.inf: c = self.bw_max - return a, c + # use tuple or list in the return if multiple outputs are needed + return (a, c) diff --git a/mgwr/summary.py b/mgwr/summary.py index 1822071..71c8f66 100755 --- a/mgwr/summary.py +++ b/mgwr/summary.py @@ -4,7 +4,7 @@ from .diagnostics import get_AICc -def summaryModel(self): +def summaryModel(self) -> str: summary = '=' * 75 + '\n' summary += "%-54s %20s\n" % ('Model type', self.family.__class__.__name__) summary += "%-60s %14d\n" % ('Number of observations:', self.n) @@ -12,8 +12,9 @@ def summaryModel(self): return summary -def summaryGLM(self): +def summaryGLM(self) -> str: + # if name_x is not None, use the names in name_x, otherwise use X0, X1, ... if self.name_x is not None: XNames = list(self.name_x) if len(XNames) < self.k: @@ -58,7 +59,9 @@ def summaryGLM(self): return summary -def summaryGWR(self): +def summaryGWR(self) -> str: + + # if name_x is not None, use the names in name_x, otherwise use X0, X1, ... if self.name_x is not None: XNames = list(self.name_x) if len(XNames) < self.k: @@ -131,8 +134,9 @@ def summaryGWR(self): return summary -def summaryMGWR(self): +def summaryMGWR(self) -> str: + # if name_x is not None, use the names in name_x, otherwise use X0, X1, ... if self.name_x is not None: XNames = list(self.name_x) if len(XNames) < self.k: diff --git a/mgwr/tests/test_gwr.py b/mgwr/tests/test_gwr.py index 6af7a07..68728c6 100644 --- a/mgwr/tests/test_gwr.py +++ b/mgwr/tests/test_gwr.py @@ -66,10 +66,10 @@ def test_BS_F(self): BIC = get_BIC(rslt) CV = get_CV(rslt) - self.assertAlmostEquals(np.floor(AICc), 894.0) - self.assertAlmostEquals(np.floor(AIC), 890.0) - self.assertAlmostEquals(np.floor(BIC), 944.0) - self.assertAlmostEquals(np.round(CV, 2), 18.25) + self.assertAlmostEqual(np.floor(AICc), 894.0) + self.assertAlmostEqual(np.floor(AIC), 890.0) + self.assertAlmostEqual(np.floor(BIC), 944.0) + self.assertAlmostEqual(np.round(CV, 2), 18.25) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-04) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-04) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-04) @@ -135,12 +135,12 @@ def test_BS_NN(self): np.testing.assert_allclose( adj_alpha, np.array([0.02034978, 0.01017489, 0.0002035]), rtol=1e-04) - self.assertAlmostEquals(critical_t, 2.6011011542649394) - self.assertAlmostEquals(np.around(R2, 4), 0.5924) - self.assertAlmostEquals(np.floor(AICc), 896.0) - self.assertAlmostEquals(np.floor(AIC), 892.0) - self.assertAlmostEquals(np.floor(BIC), 941.0) - self.assertAlmostEquals(np.around(CV, 2), 19.19) + self.assertAlmostEqual(critical_t, 2.6011011542649394) + self.assertAlmostEqual(np.around(R2, 4), 0.5924) + self.assertAlmostEqual(np.floor(AICc), 896.0) + self.assertAlmostEqual(np.floor(AIC), 892.0) + self.assertAlmostEqual(np.floor(BIC), 941.0) + self.assertAlmostEqual(np.around(CV, 2), 19.19) np.testing.assert_allclose(corr1, corr2, rtol=1e-04) np.testing.assert_allclose(vif1, vif2, rtol=1e-04) np.testing.assert_allclose(cn1, cn2, rtol=1e-04) @@ -202,10 +202,10 @@ def test_GS_F(self): BIC = get_BIC(rslt) CV = get_CV(rslt) - self.assertAlmostEquals(np.floor(AICc), 895.0) - self.assertAlmostEquals(np.floor(AIC), 890.0) - self.assertAlmostEquals(np.floor(BIC), 943.0) - self.assertAlmostEquals(np.around(CV, 2), 18.21) + self.assertAlmostEqual(np.floor(AICc), 895.0) + self.assertAlmostEqual(np.floor(AIC), 890.0) + self.assertAlmostEqual(np.floor(BIC), 943.0) + self.assertAlmostEqual(np.around(CV, 2), 18.21) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-04) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-04) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-04) @@ -254,10 +254,10 @@ def test_GS_NN(self): BIC = get_BIC(rslt) CV = get_CV(rslt) - self.assertAlmostEquals(np.floor(AICc), 896.0) - self.assertAlmostEquals(np.floor(AIC), 894.0) - self.assertAlmostEquals(np.floor(BIC), 922.0) - self.assertAlmostEquals(np.around(CV, 2), 17.91) + self.assertAlmostEqual(np.floor(AICc), 896.0) + self.assertAlmostEqual(np.floor(AIC), 894.0) + self.assertAlmostEqual(np.floor(BIC), 922.0) + self.assertAlmostEqual(np.around(CV, 2), 17.91) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-04) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-04) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-04) @@ -473,11 +473,11 @@ def test_BS_NN_longlat(self): CV = get_CV(rslt) R2 = rslt.R2 - self.assertAlmostEquals(np.around(R2, 4), 0.5921) - self.assertAlmostEquals(np.floor(AICc), 896.0) - self.assertAlmostEquals(np.floor(AIC), 892.0) - self.assertAlmostEquals(np.floor(BIC), 941.0) - self.assertAlmostEquals(np.around(CV, 2), 19.11) + self.assertAlmostEqual(np.around(R2, 4), 0.5921) + self.assertAlmostEqual(np.floor(AICc), 896.0) + self.assertAlmostEqual(np.floor(AIC), 892.0) + self.assertAlmostEqual(np.floor(BIC), 941.0) + self.assertAlmostEqual(np.around(CV, 2), 19.11) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-04) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-04) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-04) @@ -557,9 +557,9 @@ def test_BS_F(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 13294.0) - self.assertAlmostEquals(np.floor(AIC), 13247.0) - self.assertAlmostEquals(np.floor(BIC), 13485.0) + self.assertAlmostEqual(np.floor(AICc), 13294.0) + self.assertAlmostEqual(np.floor(AIC), 13247.0) + self.assertAlmostEqual(np.floor(BIC), 13485.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-05) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-03) @@ -607,10 +607,10 @@ def test_BS_NN(self): BIC = get_BIC(rslt) D2 = rslt.D2 - self.assertAlmostEquals(np.floor(AICc), 13285) - self.assertAlmostEquals(np.floor(AIC), 13259.0) - self.assertAlmostEquals(np.floor(BIC), 13442.0) - self.assertAlmostEquals(np.round(D2, 3), 0.747) + self.assertAlmostEqual(np.floor(AICc), 13285) + self.assertAlmostEqual(np.floor(AIC), 13259.0) + self.assertAlmostEqual(np.floor(BIC), 13442.0) + self.assertAlmostEqual(np.round(D2, 3), 0.747) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-04) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-02) @@ -659,10 +659,10 @@ def test_BS_NN_Offset(self): BIC = get_BIC(rslt) D2 = rslt.D2 - self.assertAlmostEquals(np.floor(AICc), 367.0) - self.assertAlmostEquals(np.floor(AIC), 361.0) - self.assertAlmostEquals(np.floor(BIC), 451.0) - self.assertAlmostEquals(np.round(D2, 3), 0.676) + self.assertAlmostEqual(np.floor(AICc), 367.0) + self.assertAlmostEqual(np.floor(AIC), 361.0) + self.assertAlmostEqual(np.floor(BIC), 451.0) + self.assertAlmostEqual(np.round(D2, 3), 0.676) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-02, atol=1e-02) @@ -724,9 +724,9 @@ def test_GS_F(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 11283.0) - self.assertAlmostEquals(np.floor(AIC), 11211.0) - self.assertAlmostEquals(np.floor(BIC), 11497.0) + self.assertAlmostEqual(np.floor(AICc), 11283.0) + self.assertAlmostEqual(np.floor(AIC), 11211.0) + self.assertAlmostEqual(np.floor(BIC), 11497.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-03) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-02) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-02) @@ -772,9 +772,9 @@ def test_GS_NN(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 21070.0) - self.assertAlmostEquals(np.floor(AIC), 21069.0) - self.assertAlmostEquals(np.floor(BIC), 21111.0) + self.assertAlmostEqual(np.floor(AICc), 21070.0) + self.assertAlmostEqual(np.floor(AIC), 21069.0) + self.assertAlmostEqual(np.floor(BIC), 21111.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-04) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-02) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-02) @@ -859,9 +859,9 @@ def test_BS_F(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 275.0) - self.assertAlmostEquals(np.floor(AIC), 271.0) - self.assertAlmostEquals(np.floor(BIC), 349.0) + self.assertAlmostEqual(np.floor(AICc), 275.0) + self.assertAlmostEqual(np.floor(AIC), 271.0) + self.assertAlmostEqual(np.floor(BIC), 349.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-00) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-00) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-00) @@ -923,10 +923,10 @@ def test_BS_NN(self): BIC = get_BIC(rslt) D2 = rslt.D2 - self.assertAlmostEquals(np.floor(AICc), 277.0) - self.assertAlmostEquals(np.floor(AIC), 271.0) - self.assertAlmostEquals(np.floor(BIC), 358.0) - self.assertAlmostEquals(np.round(D2, 3), 0.319) + self.assertAlmostEqual(np.floor(AICc), 277.0) + self.assertAlmostEqual(np.floor(AIC), 271.0) + self.assertAlmostEqual(np.floor(BIC), 358.0) + self.assertAlmostEqual(np.round(D2, 3), 0.319) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-00) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-00) @@ -989,9 +989,9 @@ def test_GS_F(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 276.0) - self.assertAlmostEquals(np.floor(AIC), 272.0) - self.assertAlmostEquals(np.floor(BIC), 341.0) + self.assertAlmostEqual(np.floor(AICc), 276.0) + self.assertAlmostEqual(np.floor(AIC), 272.0) + self.assertAlmostEqual(np.floor(BIC), 341.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-00) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-00) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-00) @@ -1052,9 +1052,9 @@ def test_GS_NN(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 276.0) - self.assertAlmostEquals(np.floor(AIC), 273.0) - self.assertAlmostEquals(np.floor(BIC), 331.0) + self.assertAlmostEqual(np.floor(AICc), 276.0) + self.assertAlmostEqual(np.floor(AIC), 273.0) + self.assertAlmostEqual(np.floor(BIC), 331.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-00) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-00) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-00) diff --git a/mgwr/tests/test_parallel.py b/mgwr/tests/test_parallel.py index a485cdf..fb3b2b6 100644 --- a/mgwr/tests/test_parallel.py +++ b/mgwr/tests/test_parallel.py @@ -84,12 +84,12 @@ def test_BS_NN_Parallel(self): np.testing.assert_allclose( adj_alpha, np.array([0.02034978, 0.01017489, 0.0002035]), rtol=1e-04) - self.assertAlmostEquals(critical_t, 2.6011011542649394) - self.assertAlmostEquals(np.around(R2, 4), 0.5924) - self.assertAlmostEquals(np.floor(AICc), 896.0) - self.assertAlmostEquals(np.floor(AIC), 892.0) - self.assertAlmostEquals(np.floor(BIC), 941.0) - self.assertAlmostEquals(np.around(CV, 2), 19.19) + self.assertAlmostEqual(critical_t, 2.6011011542649394) + self.assertAlmostEqual(np.around(R2, 4), 0.5924) + self.assertAlmostEqual(np.floor(AICc), 896.0) + self.assertAlmostEqual(np.floor(AIC), 892.0) + self.assertAlmostEqual(np.floor(BIC), 941.0) + self.assertAlmostEqual(np.around(CV, 2), 19.19) np.testing.assert_allclose(corr1, corr2, rtol=1e-04) np.testing.assert_allclose(vif1, vif2, rtol=1e-04) np.testing.assert_allclose(cn1, cn2, rtol=1e-04) @@ -152,10 +152,10 @@ def test_GS_F_Parallel(self): BIC = get_BIC(rslt) CV = get_CV(rslt) - self.assertAlmostEquals(np.floor(AICc), 895.0) - self.assertAlmostEquals(np.floor(AIC), 890.0) - self.assertAlmostEquals(np.floor(BIC), 943.0) - self.assertAlmostEquals(np.around(CV, 2), 18.21) + self.assertAlmostEqual(np.floor(AICc), 895.0) + self.assertAlmostEqual(np.floor(AIC), 890.0) + self.assertAlmostEqual(np.floor(BIC), 943.0) + self.assertAlmostEqual(np.around(CV, 2), 18.21) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-04) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-04) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-04) @@ -364,11 +364,11 @@ def test_BS_NN_longlat_Parallel(self): CV = get_CV(rslt) R2 = rslt.R2 - self.assertAlmostEquals(np.around(R2, 4), 0.5921) - self.assertAlmostEquals(np.floor(AICc), 896.0) - self.assertAlmostEquals(np.floor(AIC), 892.0) - self.assertAlmostEquals(np.floor(BIC), 941.0) - self.assertAlmostEquals(np.around(CV, 2), 19.11) + self.assertAlmostEqual(np.around(R2, 4), 0.5921) + self.assertAlmostEqual(np.floor(AICc), 896.0) + self.assertAlmostEqual(np.floor(AIC), 892.0) + self.assertAlmostEqual(np.floor(BIC), 941.0) + self.assertAlmostEqual(np.around(CV, 2), 19.11) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-04) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-04) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-04) @@ -449,9 +449,9 @@ def test_BS_F_Parallel(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 13294.0) - self.assertAlmostEquals(np.floor(AIC), 13247.0) - self.assertAlmostEquals(np.floor(BIC), 13485.0) + self.assertAlmostEqual(np.floor(AICc), 13294.0) + self.assertAlmostEqual(np.floor(AIC), 13247.0) + self.assertAlmostEqual(np.floor(BIC), 13485.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-05) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-03) @@ -500,10 +500,10 @@ def test_BS_NN(self): BIC = get_BIC(rslt) D2 = rslt.D2 - self.assertAlmostEquals(np.floor(AICc), 13285) - self.assertAlmostEquals(np.floor(AIC), 13259.0) - self.assertAlmostEquals(np.floor(BIC), 13442.0) - self.assertAlmostEquals(np.round(D2, 3), 0.747) + self.assertAlmostEqual(np.floor(AICc), 13285) + self.assertAlmostEqual(np.floor(AIC), 13259.0) + self.assertAlmostEqual(np.floor(BIC), 13442.0) + self.assertAlmostEqual(np.round(D2, 3), 0.747) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-04) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-02) @@ -553,10 +553,10 @@ def test_BS_NN_Offset_Parallel(self): BIC = get_BIC(rslt) D2 = rslt.D2 - self.assertAlmostEquals(np.floor(AICc), 367.0) - self.assertAlmostEquals(np.floor(AIC), 361.0) - self.assertAlmostEquals(np.floor(BIC), 451.0) - self.assertAlmostEquals(np.round(D2, 3), 0.676) + self.assertAlmostEqual(np.floor(AICc), 367.0) + self.assertAlmostEqual(np.floor(AIC), 361.0) + self.assertAlmostEqual(np.floor(BIC), 451.0) + self.assertAlmostEqual(np.round(D2, 3), 0.676) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-02, atol=1e-02) @@ -619,9 +619,9 @@ def test_GS_F_Parallel(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 11283.0) - self.assertAlmostEquals(np.floor(AIC), 11211.0) - self.assertAlmostEquals(np.floor(BIC), 11497.0) + self.assertAlmostEqual(np.floor(AICc), 11283.0) + self.assertAlmostEqual(np.floor(AIC), 11211.0) + self.assertAlmostEqual(np.floor(BIC), 11497.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-03) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-02) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-02) @@ -668,9 +668,9 @@ def test_GS_NN_Parallel(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 21070.0) - self.assertAlmostEquals(np.floor(AIC), 21069.0) - self.assertAlmostEquals(np.floor(BIC), 21111.0) + self.assertAlmostEqual(np.floor(AICc), 21070.0) + self.assertAlmostEqual(np.floor(AIC), 21069.0) + self.assertAlmostEqual(np.floor(BIC), 21111.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-04) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-02) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-02) @@ -756,9 +756,9 @@ def test_BS_F_Parallel(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 275.0) - self.assertAlmostEquals(np.floor(AIC), 271.0) - self.assertAlmostEquals(np.floor(BIC), 349.0) + self.assertAlmostEqual(np.floor(AICc), 275.0) + self.assertAlmostEqual(np.floor(AIC), 271.0) + self.assertAlmostEqual(np.floor(BIC), 349.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-00) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-00) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-00) @@ -821,10 +821,10 @@ def test_BS_NN_Parallel(self): BIC = get_BIC(rslt) D2 = rslt.D2 - self.assertAlmostEquals(np.floor(AICc), 277.0) - self.assertAlmostEquals(np.floor(AIC), 271.0) - self.assertAlmostEquals(np.floor(BIC), 358.0) - self.assertAlmostEquals(np.round(D2, 3), 0.319) + self.assertAlmostEqual(np.floor(AICc), 277.0) + self.assertAlmostEqual(np.floor(AIC), 271.0) + self.assertAlmostEqual(np.floor(BIC), 358.0) + self.assertAlmostEqual(np.round(D2, 3), 0.319) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-00) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-00) @@ -888,9 +888,9 @@ def test_GS_F_Parallel(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 276.0) - self.assertAlmostEquals(np.floor(AIC), 272.0) - self.assertAlmostEquals(np.floor(BIC), 341.0) + self.assertAlmostEqual(np.floor(AICc), 276.0) + self.assertAlmostEqual(np.floor(AIC), 272.0) + self.assertAlmostEqual(np.floor(BIC), 341.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-00) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-00) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-00) @@ -952,9 +952,9 @@ def test_GS_NN_Parallel(self): AIC = get_AIC(rslt) BIC = get_BIC(rslt) - self.assertAlmostEquals(np.floor(AICc), 276.0) - self.assertAlmostEquals(np.floor(AIC), 273.0) - self.assertAlmostEquals(np.floor(BIC), 331.0) + self.assertAlmostEqual(np.floor(AICc), 276.0) + self.assertAlmostEqual(np.floor(AIC), 273.0) + self.assertAlmostEqual(np.floor(BIC), 331.0) np.testing.assert_allclose(est_Int, rslt.params[:, 0], rtol=1e-00) np.testing.assert_allclose(se_Int, rslt.bse[:, 0], rtol=1e-00) np.testing.assert_allclose(t_Int, rslt.tvalues[:, 0], rtol=1e-00) diff --git a/mgwr/utils.py b/mgwr/utils.py index 39f4a92..a22eafd 100755 --- a/mgwr/utils.py +++ b/mgwr/utils.py @@ -1,9 +1,14 @@ import numpy as np from libpysal.common import requires +import matplotlib as mpl @requires('matplotlib') -def shift_colormap(cmap, start=0, midpoint=0.5, stop=1.0, name='shiftedcmap'): +def shift_colormap(cmap, + start: float = 0, + midpoint: float = 0.5, + stop: float = 1.0, + name: str = 'shiftedcmap') -> mpl.colors.LinearSegmentedColormap: ''' Function to offset the "center" of a colormap. Useful for data with a negative min and positive max and you want the @@ -24,13 +29,12 @@ def shift_colormap(cmap, start=0, midpoint=0.5, stop=1.0, name='shiftedcmap'): stop : Offset from highets point in the colormap's range. Defaults to 1.0 (no upper ofset). Should be between `midpoint` and 1.0. - + Returns ------- - new_cmap : A new colormap that has been shifted. + new_cmap : A new colormap that has been shifted. ''' - import matplotlib as mpl import matplotlib.pyplot as plt cdict = {'red': [], 'green': [], 'blue': [], 'alpha': []} @@ -59,7 +63,10 @@ def shift_colormap(cmap, start=0, midpoint=0.5, stop=1.0, name='shiftedcmap'): @requires('matplotlib') -def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100): +def truncate_colormap(cmap, + minval: float = 0.0, + maxval: float = 1.0, + n: int = 100) -> mpl.colors.LinearSegmentedColormap: ''' Function to truncate a colormap by selecting a subset of the original colormap's values @@ -69,14 +76,12 @@ def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100): minval : Minimum value of the original colormap to include in the truncated colormap maxval : Maximum value of the original colormap to include in the truncated colormap n : Number of intervals between the min and max values for the gradient of the truncated colormap - + Returns ------- - new_cmap : A new colormap that has been shifted. + new_cmap : A new colormap that has been shifted. ''' - import matplotlib as mpl - new_cmap = mpl.colors.LinearSegmentedColormap.from_list( 'trunc({n},{a:.2f},{b:.2f})'.format(n=cmap.name, a=minval, b=maxval), cmap(np.linspace(minval, maxval, n))) @@ -85,8 +90,17 @@ def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100): @requires('matplotlib') @requires('geopandas') -def compare_surfaces(data, var1, var2, gwr_t, gwr_bw, mgwr_t, mgwr_bw, name, - kwargs1, kwargs2, savefig=None): +def compare_surfaces(data, + var1: str, + var2: str, + gwr_t: str, + gwr_bw: float, + mgwr_t: str, + mgwr_bw: float, + name: str, + kwargs1, + kwargs2, + savefig: str = None) -> None: ''' Function that creates comparative visualization of GWR and MGWR surfaces. @@ -126,10 +140,10 @@ def compare_surfaces(data, var1, var2, gwr_t, gwr_bw, mgwr_t, mgwr_bw, name, ax1.set_title('MGWR ' + name + ' Surface (BW: ' + str(mgwr_bw) + ')', fontsize=40) - #Set color map + # Set color map cmap = plt.cm.seismic - #Find min and max values of the two combined datasets + # Find min and max values of the two combined datasets gwr_min = data[var1].min() gwr_max = data[var1].max() mgwr_min = data[var2].min() @@ -137,32 +151,32 @@ def compare_surfaces(data, var1, var2, gwr_t, gwr_bw, mgwr_t, mgwr_bw, name, vmin = np.min([gwr_min, mgwr_min]) vmax = np.max([gwr_max, mgwr_max]) - #If all values are negative use the negative half of the colormap + # If all values are negative use the negative half of the colormap if (vmin < 0) & (vmax < 0): cmap = truncate_colormap(cmap, 0.0, 0.5) - #If all values are positive use the positive half of the colormap + # If all values are positive use the positive half of the colormap elif (vmin > 0) & (vmax > 0): cmap = truncate_colormap(cmap, 0.5, 1.0) - #Otherwise, there are positive and negative values so the colormap so zero is the midpoint + # Otherwise, there are positive and negative values so the colormap so zero is the midpoint else: cmap = shift_colormap(cmap, start=0.0, midpoint=1 - vmax / (vmax + abs(vmin)), stop=1.) - #Create scalar mappable for colorbar and stretch colormap across range of data values + # Create scalar mappable for colorbar and stretch colormap across range of data values sm = plt.cm.ScalarMappable(cmap=cmap, norm=plt.Normalize( vmin=vmin, vmax=vmax)) - #Plot GWR parameters + # Plot GWR parameters data.plot(var1, cmap=sm.cmap, ax=ax0, vmin=vmin, vmax=vmax, **kwargs1) if (gwr_t == 0).any(): data[gwr_t == 0].plot(color='lightgrey', ax=ax0, **kwargs2) - #Plot MGWR parameters + # Plot MGWR parameters data.plot(var2, cmap=sm.cmap, ax=ax1, vmin=vmin, vmax=vmax, **kwargs1) if (mgwr_t == 0).any(): data[mgwr_t == 0].plot(color='lightgrey', ax=ax1, **kwargs2) - #Set figure options and plot + # Set figure options and plot fig.tight_layout() fig.subplots_adjust(right=0.9) cax = fig.add_axes([0.92, 0.14, 0.03, 0.75])