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

Skip to content
44 changes: 26 additions & 18 deletions mgwr/gwr.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ class GWR(GLM):
spherical : boolean
True for shperical coordinates (long-lat),
False for projected coordinates (defalut).

hat_matrix : boolean
True to store full n by n hat matrix,
False to not store full hat matrix to minimize memory footprint (defalut).
Expand Down Expand Up @@ -516,10 +516,10 @@ class GWRResults(GLMResults):

R2 : float
R-squared for the entire model (1- RSS/TSS)

adj_R2 : float
adjusted R-squared for the entire model

aic : float
Akaike information criterion

Expand Down Expand Up @@ -575,11 +575,11 @@ class GWRResults(GLMResults):
pDev : float
local percent of deviation accounted for; analogous to
r-squared for GLM's

D2 : float
percent deviance explained for GLM, equivaleng to R2 for
Gaussian.

adj_D2 : float
adjusted percent deviance explained, equivaleng to adjusted
R2 for Gaussian.
Expand Down Expand Up @@ -1438,8 +1438,8 @@ class MGWR(GWR):

"""

def __init__(self, coords, y, X, selector, sigma2_v1=True,
kernel='bisquare', fixed=False, constant=True,
def __init__(self, coords, y, X, selector, family, offset=None,
sigma2_v1=True, kernel='bisquare', fixed=False, constant=True,
spherical=False, hat_matrix=False):
"""
Initialize class
Expand All @@ -1448,17 +1448,18 @@ def __init__(self, coords, y, X, selector, sigma2_v1=True,
self.bws = self.selector.bw[0] #final set of bandwidth
self.bws_history = selector.bw[1] #bws history in backfitting
self.bw_init = self.selector.bw_init #initialization bandiwdth
self.family = Gaussian(
) # manually set since we only support Gassian MGWR for now
GWR.__init__(self, coords, y, X, self.bw_init, family=self.family,
sigma2_v1=sigma2_v1, kernel=kernel, fixed=fixed,
constant=constant, spherical=spherical,
self.family = family
self.offset = offset
# manually set since we only support Gassian MGWR for now
GWR.__init__(self, coords, y, X, self.bw_init, self.family,
self.offset,sigma2_v1=sigma2_v1, kernel=kernel,
fixed=fixed, constant=constant, spherical=spherical,
hat_matrix=hat_matrix)
self.selector = selector
self.sigma2_v1 = sigma2_v1
self.points = None
self.P = None
self.offset = None
self.family = family
self.exog_resid = None
self.exog_scale = None
self_fit_params = None
Expand Down Expand Up @@ -1520,21 +1521,28 @@ def _chunk_compute_R(self, chunk_id=0):
def fit(self, n_chunks=1, pool=None):
"""
Compute MGWR inference by chunk to reduce memory footprint.

Parameters
----------

n_chunks : integer, optional
A number of chunks parameter to reduce memory usage.
A number of chunks parameter to reduce memory usage.
e.g. n_chunks=2 should reduce overall memory usage by 2.
pool : A multiprocessing Pool object to enable parallel fitting; default is None.

Returns
-------
: MGWRResults
"""
params = self.selector.params
predy = np.sum(self.X * params, axis=1).reshape(-1, 1)
if isinstance(self.family,Poisson):
predy = self.offset*(np.exp(np.sum(self.X * params, axis=1).reshape(-1, 1)))

elif isinstance(self.family,Binomial):
predy = 1/(1+np.exp(-1*np.sum(self.X * params, axis=1).reshape(-1, 1)))

else:
predy = np.sum(self.X * params, axis=1).reshape(-1, 1)

try:
from tqdm.autonotebook import tqdm #progress bar
Expand Down Expand Up @@ -1692,7 +1700,7 @@ class MGWRResults(GWRResults):

R2 : float
R-squared for the entire model (1- RSS/TSS)

adj_R2 : float
adjusted R-squared for the entire model

Expand Down
45 changes: 39 additions & 6 deletions mgwr/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import numpy as np
from copy import deepcopy
from spglm.family import Gaussian, Binomial, Poisson


def golden_section(a, c, delta, function, tol, max_iter, int_score=False,
Expand Down Expand Up @@ -164,7 +165,7 @@ def equal_interval(l_bound, u_bound, interval, function, int_score=False,
return opt_val, opt_score, output


def multi_bw(init, y, X, n, k, family, tol, max_iter, rss_score, gwr_func,
def multi_bw(init, y, X, n, k, family, offset, tol, max_iter, rss_score, gwr_func,
bw_func, sel_func, multi_bw_min, multi_bw_max, bws_same_times,
verbose=False):
"""
Expand All @@ -180,7 +181,14 @@ def multi_bw(init, y, X, n, k, family, tol, max_iter, rss_score, gwr_func,
err = optim_model.resid_response.reshape((-1, 1))
param = optim_model.params

XB = np.multiply(param, X)
if isinstance(family, Poisson):
XB = offset*np.exp(np.multiply(param,X))
elif isinstance(family, Binomial):
XXB = 1/(1+np.exp(-1*np.multiply(param,X)))
XB = np.multiply(param, X)
else:
XB = np.multiply(param, X)

if rss_score:
rss = np.sum((err)**2)
iters = 0
Expand All @@ -199,12 +207,23 @@ def tqdm(x, desc=''): #otherwise, just passthrough the range

for iters in tqdm(range(1, max_iter + 1), desc='Backfitting'):
new_XB = np.zeros_like(X)
neww_XB = np.zeros_like(X)

params = np.zeros_like(X)

for j in range(k):
temp_y = XB[:, j].reshape((-1, 1))
temp_y = temp_y + err

if isinstance(family, Binomial):
for i in range(n):
if temp_y[i]>=0:
temp_y[i]=1
else:
temp_y[i]=0

temp_X = X[:, j].reshape((-1, 1))

bw_class = bw_func(temp_y, temp_X)

if np.all(bw_stable_counter == bws_same_times):
Expand All @@ -220,17 +239,31 @@ def tqdm(x, desc=''): #otherwise, just passthrough the range
optim_model = gwr_func(temp_y, temp_X, bw)
err = optim_model.resid_response.reshape((-1, 1))
param = optim_model.params.reshape((-1, ))
new_XB[:, j] = optim_model.predy.reshape(-1)
if isinstance(family, Binomial):
new_XB[:, j] = np.multiply(param.reshape(-1,1),temp_X).reshape(-1)
neww_XB[:, j] = optim_model.predy.reshape(-1)
else:
new_XB[:, j] = optim_model.predy.reshape(-1)
params[:, j] = param
bws[j] = bw

num = np.sum((new_XB - XB)**2) / n
den = np.sum(np.sum(new_XB, axis=1)**2)
if isinstance(family, Binomial):
num = np.sum((neww_XB - XXB)**2) / n
den = np.sum(np.sum(neww_XB, axis=1)**2)
else:
num = np.sum((new_XB - XB)**2) / n
den = np.sum(np.sum(new_XB, axis=1)**2)
score = (num / den)**0.5
XB = new_XB
XXB = neww_XB

if rss_score:
predy = np.sum(np.multiply(params, X), axis=1).reshape((-1, 1))
if isinstance(family, Poisson):
predy = offset*(np.exp(np.sum(X * params, axis=1).reshape(-1, 1)))
elif isinstance(family, Binomial):
predy = 1/(1+np.exp(-1*np.sum(X * params, axis=1).reshape(-1, 1)))
else:
predy = np.sum(np.multiply(params, X), axis=1).reshape((-1, 1))
new_rss = np.sum((y - predy)**2)
score = np.abs((new_rss - rss) / new_rss)
rss = new_rss
Expand Down
8 changes: 4 additions & 4 deletions mgwr/sel_bw.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,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')
Expand Down Expand Up @@ -213,7 +213,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
Expand Down Expand Up @@ -391,9 +391,9 @@ def sel_func(bw_func, bw_min=None, bw_max=None):
bw_min=bw_min, bw_max=bw_max, interval=interval, tol=tol,
max_iter=max_iter, pool=self.pool, verbose=False)

self.bw = multi_bw(self.init_multi, y, X, n, k, family, self.tol_multi,
self.bw = multi_bw(self.init_multi, y, X, n, k, family, offset, self.tol_multi,
self.max_iter_multi, self.rss_score, gwr_func,
bw_func, sel_func, multi_bw_min, multi_bw_max,
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):
Expand Down
Loading