import numpy as np
import geopandas as gp
import multiprocessing as mp
import pysal.lib as ps
import sys
sys.path.append('/Users/Ziqi/Desktop/mgwr/')
from pysal.model.mgwr.gwr import GWR,MGWR
from pysal.model.mgwr.sel_bw import Sel_BW

#Load Berlin example
prenz = gp.read_file(ps.examples.get_path('prenzlauer.zip'))

b_y = np.log(prenz['price'].values.reshape((-1, 1)))
b_X = prenz[['review_sco','accommodat','bathrooms']].values 
b_X = (b_X - b_X.mean(axis=0)) / b_X.std(axis=0)
b_y = (b_y - b_y.mean(axis=0)) / b_y.std(axis=0)
u = prenz['X']
v = prenz['Y']
b_coords = list(zip(u, v))

#This might be needed to turn off the OpenMP multi-threading
%env OMP_NUM_THREADS = 1

env: OMP_NUM_THREADS=1

GWR No Parallel

%%time
gwr_selector = Sel_BW(b_coords, b_y, b_X)
gwr_bw = gwr_selector.search()
print(gwr_bw)
gwr_results = GWR(b_coords, b_y, b_X, gwr_bw).fit()

192.0
CPU times: user 13.9 s, sys: 116 ms, total: 14 s
Wall time: 14.2 s

MGWR No Parallel

%%time
mgwr_selector = Sel_BW(b_coords, b_y, b_X, multi=True)
mgwr_bw = mgwr_selector.search()
print(mgwr_bw)
mgwr_results = MGWR(b_coords, b_y, b_X, selector=mgwr_selector).fit()

[ 191. 1279.   79. 2200.]
CPU times: user 3min 37s, sys: 2.73 s, total: 3min 40s
Wall time: 3min 18s
#Parrallelization is more favored when you your data are large and/or your machine have many many cores.
#mgwr has soft dependency of numba, please install numba if you need better performance (pip install numba).

n_proc = 2 #two processors
pool = mp.Pool(n_proc) 

GWR Parallel

%%time
gwr_selector = Sel_BW(b_coords, b_y, b_X)
gwr_bw = gwr_selector.search(pool=pool) #add pool to Sel_BW.search
print(gwr_bw)
gwr_results = GWR(b_coords, b_y, b_X, gwr_bw).fit(pool=pool) #add pool to GWR.fit

192.0
CPU times: user 303 ms, sys: 42.3 ms, total: 346 ms
Wall time: 7.05 s

MGWR Parallel

%%time
mgwr_selector = Sel_BW(b_coords, b_y, b_X, multi=True)
mgwr_bw = mgwr_selector.search(pool=pool) #add pool to Sel_BW.search
print(mgwr_bw)
mgwr_results = MGWR(b_coords, b_y, b_X, selector=mgwr_selector).fit(pool=pool) #add pool to MGWR.fit

[ 191. 1279.   79. 2200.]
CPU times: user 5.08 s, sys: 388 ms, total: 5.46 s
Wall time: 2min 2s
pool.close() # Close the pool when you finish
pool.join()