├── .DS_Store ├── .gitignore ├── LICENSE.md ├── README.md ├── Zillow-test-dataset ├── .DS_Store ├── fake_zillow_1k_singular.csv ├── zillow_100k.csv ├── zillow_10k.csv ├── zillow_15k.csv ├── zillow_1k.csv ├── zillow_20k.csv ├── zillow_2k.csv ├── zillow_50k.csv └── zillow_5k.csv ├── fastgwr ├── .DS_Store ├── FastGWR.py ├── FastMGWR.py ├── __init__.py ├── __main__.py └── fastgwr_mpi.py ├── paper ├── .DS_Store ├── figure maker.ipynb ├── paper.bib ├── paper.md └── scalability.png ├── requirements.txt ├── setup.py └── validation notebook ├── .DS_Store ├── GWR Results Validation against mgwr.ipynb ├── GWR scalability test Mac.ipynb ├── MGWR Results Validation against mgwr.ipynb └── MGWR scalability test Mac.ipynb /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ziqi-Li/FastGWR/a765df41bd75197e7d3ed2c0f54bb47875525ece/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ziqi Li 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![PyPI](https://img.shields.io/pypi/v/fastgwr) 2 | ![GitHub](https://img.shields.io/github/license/Ziqi-Li/fastgwr) 3 | 4 | # FastGWR 5 | A command line tool for fast parallel computation of Geographically Weighted Regression models (GWR and MGWR). 6 | ### New feature: 7 | Multi-scale GWR model added! 8 | 9 | ### Installation: 10 | 11 | The `fastgwr` program is dependent on `mpi4py` package and a working MPI implementation. The easiest way to install both dependencies is to use `conda`: 12 | 13 | ```bash 14 | $ conda install mpi4py 15 | ``` 16 | 17 | By installing `mpi4py`, `conda` will also install an MPI implementation based on your computer system (OpenMPI for Mac/Linux; MPICH/MS-MPI for Windows). Users may want to check whether the MPI implementation is successfully installed and is on your path by running the `mpiexec` command. Then the `fastgwr` program can be installed from PyPi: 18 | 19 | ```bash 20 | $ pip install fastgwr 21 | ``` 22 | 23 | After sucessful installation, users can test the functionalities from the command line by running: 24 | 25 | ```bash 26 | # Using zillow sample data for testing MGWR model fitting. 27 | $ fastgwr testgwr 28 | ``` 29 | or 30 | 31 | ```bash 32 | # Using zillow sample data for testing MGWR model fitting. 33 | $ fastgwr testmgwr 34 | ``` 35 | 36 | 37 | ## Examples 38 | Example call to the `fastgwr` to fit GWR model: 39 | 40 | ```bash 41 | $ fastgwr run -np 4 -data input.csv 42 | ``` 43 | 44 | Example call to the `fastgwr` to fit MGWR model: 45 | 46 | ```bash 47 | $ fastgwr run -np 4 -data input.csv -mgwr 48 | ``` 49 | where: 50 | 51 | ```bash 52 | -np 4 Number of processors (e.g. 4). 53 | -data input.csv Input data matrix. (e.g. input.csv) 54 | Can also be an URL (e.g. https://raw.github.com/ 55 | Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_1k.csv) 56 | -out results.csv Output GWR results matrix including local parameter 57 | estimates, standard errors and local diagnostics. 58 | -adaptive/-fixed Adaptive Bisquare kernel (defualt) or Fixed Gaussian kernel. 59 | -bw 1000 Pre-defined bandwidth parameter. If missing, it will 60 | search (golden-section) for the optimal bandwidth and use 61 | that to fit the GWR model. 62 | -minbw 45 Lower bound in golden-section search. (e.g. 45) 63 | -mgwr Fitting an MGWR model. 64 | -chunks Number of chunks for MGWR computation (set to a larger 65 | number to reduce memory footprint). 66 | -estonly Allowing MGWR to output parameter estimation only. 67 | ``` 68 | 69 | The input needs to be prepared in this order: 70 | 71 | | | X-coord | y-coord | y | X1 | X2 | X3 | Xk | 72 | |---|---------|---------|------|-----|-----|-----|-----| 73 | | | ... | ... | ... | ... | ... | ... | ... | 74 | | | ... | ... | ... | ... | ... | ... | ... | 75 | | | | | | | | | | 76 | 77 | ``` 78 | where: 79 | X-coord: X coordinate of the location point 80 | Y-coord: Y coordinate of the location point 81 | y: dependent variable 82 | X1...Xk: independent variables 83 | ``` 84 | See the example Zillow datasets in the repository. 85 | 86 | ## Results Validation 87 | 88 | The results are validated against the [mgwr](https://github.com/pysal/mgwr), which can be seen in the [notebooks here](https://github.com/Ziqi-Li/FastGWR/tree/master/validation%20notebook). 89 | 90 | 91 | ## Citations 92 | 93 | This program is developed based on these two papers: 94 | 95 | [FastGWR](https://www.tandfonline.com/doi/full/10.1080/13658816.2018.1521523) 96 | 97 | Li, Z., Fotheringham, A. S., Li, W., Oshan, T. (2019). Fast Geographically Weighted Regression (FastGWR): A Scalable Algorithm to Investigate Spatial Process Heterogeneity in Millions of Observations. International Journal of Geographic Information Science. doi: 10.1080/13658816.2018.1521523. 98 | 99 | [FastMGWR](https://www.tandfonline.com/doi/abs/10.1080/13658816.2020.1720692) 100 | 101 | Li, Z., & Fotheringham, A. S. (2020). Computational improvements to multi-scale geographically weighted regression. International Journal of Geographical Information Science, 34(7), 1378-1397. 102 | -------------------------------------------------------------------------------- /Zillow-test-dataset/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ziqi-Li/FastGWR/a765df41bd75197e7d3ed2c0f54bb47875525ece/Zillow-test-dataset/.DS_Store -------------------------------------------------------------------------------- /Zillow-test-dataset/fake_zillow_1k_singular.csv: -------------------------------------------------------------------------------- 1 | utmX,utmY,value,nbaths,nbeds,area,age 2 | 374161.3338299581,3757568.371599861,56.976,1.0,2.0,954.0,71.0 3 | 412657.8229095078,3761734.396889214,157.982,2.0,4.0,1614.0,45.0 4 | 391600.47563964856,3782212.352299701,512.612,4.0,8.0,2962.0,54.0 5 | 375056.06468059175,3748579.027776389,111.437,2.0,4.0,1292.0,65.0 6 | 388693.6930384363,3779864.515395684,128.327,1.0,2.0,1169.0,78.0 7 | 375793.815752129,3776387.6740309927,358.32,4.0,8.0,2592.0,70.0 8 | 381322.6153527129,3756299.0748972856,55.0,2.0,4.0,1284.0,91.0 9 | 395606.9843442598,3744610.4556239983,173.0,3.0,6.0,2311.0,74.0 10 | 347563.6113271611,3784036.870623684,162.914,2.0,4.0,1397.0,57.0 11 | 421447.4741792208,3760500.9994065566,207.444,3.0,6.0,1714.0,31.0 12 | 400866.2361005518,3746640.1635673824,149.791,2.0,4.0,1102.0,46.0 13 | 393765.6537783711,3776581.694009944,176.619,2.0,4.0,1713.0,85.0 14 | 374660.5101875234,3746222.700396216,113.173,1.0,2.0,1112.0,62.0 15 | 401923.3835518493,3749116.905669943,262.632,3.0,6.0,2480.0,44.0 16 | 424890.6589758038,3765598.584579292,126.0,2.0,4.0,1501.0,44.0 17 | 377171.4876813308,3783684.732768399,105.734,1.0,2.0,944.0,91.0 18 | 403470.4269743543,3776154.4976744535,577.205,3.0,6.0,3481.0,35.0 19 | 350973.6562377601,3785198.789579441,102.168,2.0,4.0,1570.0,59.0 20 | 353616.6114592056,3786722.58364526,47.609,2.0,4.0,1380.0,63.0 21 | 396208.5494669181,3759157.414228688,29.591,2.0,4.0,1201.0,66.0 22 | 404917.55761750985,3753589.1146361222,81.239,2.0,4.0,1222.0,63.0 23 | 432984.4284737403,3775652.517115668,134.991,2.0,4.0,1880.0,54.0 24 | 385235.4864940413,3746405.007239224,35.181,2.0,4.0,1362.0,52.0 25 | 356326.03549082275,3767924.56524556,1248.282,6.0,12.0,10213.0,17.0 26 | 393571.6719334308,3784709.6746129473,26.25,1.0,2.0,962.0,63.0 27 | 432298.490291539,3773590.8923641415,123.0,2.0,4.0,1156.0,62.0 28 | 378445.54110481887,3775755.9379923022,74.95,2.0,4.0,2046.0,55.0 29 | 378174.4416567921,3738553.626969249,147.649,2.0,4.0,1852.0,57.0 30 | 380421.8530909507,3775467.012934098,270.818,3.0,6.0,2335.0,80.0 31 | 377134.8909545669,3787029.4240853274,703.69,5.0,10.0,3984.0,17.0 32 | 372190.4537645829,3788550.9988525775,39.325,2.0,4.0,1240.0,53.0 33 | 397099.8855798669,3741999.128307819,102.31,1.0,2.0,946.0,64.0 34 | 429199.4163809132,3766683.637316913,235.03,3.0,6.0,2128.0,36.0 35 | 398600.3467996887,3746704.301626943,231.094,3.0,6.0,2278.0,51.0 36 | 359622.06790795067,3792855.7659296873,132.426,2.0,4.0,1590.0,60.0 37 | 418347.4583523388,3773691.330139759,196.133,2.0,4.0,1814.0,61.0 38 | 369118.3763404677,3781313.51881151,29.799,1.0,2.0,1128.0,89.0 39 | 399086.7886879219,3778681.407698194,121.109,1.0,2.0,1202.0,76.0 40 | 370216.2115559691,3752099.579895245,905.416,4.0,8.0,3352.0,11.0 41 | 372111.8737299118,3744951.455726242,185.434,2.0,4.0,1859.0,75.0 42 | 374825.3541407259,3753984.350819225,70.415,1.0,2.0,875.0,69.0 43 | 379716.4806782944,3765079.587215344,96.0,1.0,2.0,1276.0,107.0 44 | 368780.864417054,3761528.676853744,228.89,2.0,4.0,1876.0,49.0 45 | 415780.1089712789,3773904.768674882,92.976,2.0,4.0,1144.0,63.0 46 | 378901.508225316,3762787.6663013143,92.787,1.0,2.0,1996.0,107.0 47 | 406609.0402442732,3758141.604111293,152.379,4.0,8.0,2925.0,52.0 48 | 407874.1536982555,3779923.1568561248,368.199,5.0,10.0,3262.0,12.0 49 | 377795.3607614269,3759024.93945119,108.626,3.0,6.0,1888.0,79.0 50 | 403616.03386181896,3775277.57243856,688.121,4.0,8.0,4708.0,28.0 51 | 382890.50007528544,3743570.087400525,147.109,2.0,4.0,1287.0,36.0 52 | 398279.6856757865,3744429.039986624,177.668,2.0,4.0,1607.0,64.0 53 | 365876.4967417836,3766516.368379775,74.293,2.0,4.0,1492.0,71.0 54 | 397425.7220209519,3753636.967879854,99.229,1.0,2.0,1324.0,64.0 55 | 349864.6963352292,3781659.049089192,156.799,3.0,6.0,2274.0,62.0 56 | 388918.579835922,3741222.659636767,77.074,1.0,2.0,1451.0,76.0 57 | 388780.935606496,3752311.3716406752,16.125,1.0,2.0,1048.0,69.0 58 | 411188.8259777032,3760133.238134401,399.698,5.0,10.0,3687.0,47.0 59 | 391494.0727818544,3742741.124567216,87.986,1.0,2.0,1551.0,81.0 60 | 368827.8724529829,3793940.961289189,97.249,2.0,4.0,960.0,61.0 61 | 395593.55154316936,3742067.969536335,111.196,2.0,4.0,1679.0,67.0 62 | 348244.54895535426,3784725.575862383,215.701,2.0,4.0,1570.0,58.0 63 | 385564.3133157657,3752740.526079594,82.842,1.0,2.0,1016.0,67.0 64 | 417085.8709895163,3773851.051634636,70.705,2.0,4.0,1281.0,63.0 65 | 374050.9321188358,3752453.976262711,114.424,1.0,2.0,1527.0,68.0 66 | 385005.9467658771,3774343.244680665,69.334,2.0,4.0,903.0,93.0 67 | 409465.9163408808,3771427.447611169,47.168,1.0,2.0,1010.0,69.0 68 | 398240.2399625927,3772398.570740441,84.099,1.0,2.0,1228.0,75.0 69 | 376097.13281616935,3765495.767666793,18.404,1.0,2.0,1112.0,73.0 70 | 378786.994074377,3770081.986081555,200.0,3.0,6.0,2649.0,98.0 71 | 386524.0432546979,3777490.538238064,154.0,2.0,4.0,1286.0,69.0 72 | 419367.15726856585,3771390.1801540414,224.722,2.0,4.0,2458.0,60.0 73 | 374656.1867687845,3751521.775472483,36.0,1.0,2.0,360.0,71.0 74 | 384068.3248131221,3775362.43093697,101.733,1.0,2.0,856.0,87.0 75 | 429681.7393844291,3773566.6926273615,97.293,2.0,4.0,1326.0,61.0 76 | 348974.8499045742,3785968.0569888633,147.733,3.0,6.0,2470.0,46.0 77 | 353218.89878049365,3792221.041221476,145.005,2.0,4.0,1916.0,53.0 78 | 388759.57036103343,3775412.11644478,73.232,1.0,2.0,1072.0,92.0 79 | 356431.32534801343,3786426.422365444,33.524,1.0,2.0,1133.0,65.0 80 | 420626.919576265,3776174.705210617,158.247,2.0,4.0,1734.0,44.0 81 | 359119.5783614289,3767474.306045064,176.961,2.0,4.0,1942.0,68.0 82 | 402155.77476900094,3763192.640753906,40.359,2.0,4.0,1814.0,66.0 83 | 396208.3907248233,3735184.0740175606,353.622,5.0,10.0,2628.0,67.0 84 | 361706.5437791343,3787450.317714009,90.0,2.0,4.0,1246.0,65.0 85 | 390060.4977292951,3776494.57493177,147.468,2.0,4.0,1333.0,102.0 86 | 373471.8008286054,3759863.8316974174,37.4,1.0,2.0,1154.0,65.0 87 | 393047.2001304803,3784617.593603832,123.048,1.0,2.0,1565.0,93.0 88 | 374084.0731228904,3768119.21959988,147.211,1.0,2.0,1086.0,92.0 89 | 373198.7988716441,3745251.1139318375,65.903,2.0,4.0,1660.0,58.0 90 | 430777.5902693224,3772078.2096941434,59.97,2.0,4.0,1240.0,64.0 91 | 374251.788983406,3774479.718240551,624.141,5.0,10.0,3149.0,4.0 92 | 398032.791657882,3755866.338152264,67.184,2.0,4.0,1796.0,66.0 93 | 386998.3842818188,3777377.2538777497,76.473,1.0,2.0,708.0,92.0 94 | 393434.97787536576,3745227.9352965066,59.302,1.0,2.0,1180.0,65.0 95 | 399491.9405106472,3780043.924875387,37.047,1.0,2.0,883.0,72.0 96 | 357810.67924302054,3790873.7187612434,180.41,3.0,6.0,2001.0,54.0 97 | 397722.20474995545,3752906.1713507934,131.982,2.0,4.0,1439.0,66.0 98 | 397815.32635212375,3757369.4581199936,65.683,2.0,4.0,1546.0,66.0 99 | 390729.3674210344,3754832.3549017655,80.0,1.0,2.0,768.0,58.0 100 | 351112.3488216533,3782835.870259615,192.424,3.0,6.0,2430.0,57.0 101 | 367767.7091068902,3770301.8170224014,459.777,4.0,8.0,3608.0,82.0 102 | 390003.417473866,3756300.865018441,96.46,2.0,4.0,1669.0,71.0 103 | 421794.800554549,3775235.878546315,152.305,2.0,4.0,1845.0,57.0 104 | 407047.69956746727,3776221.868631165,53.477,2.0,4.0,1806.0,70.0 105 | 421990.3963520165,3759157.7395271086,101.439,2.0,4.0,1288.0,54.0 106 | 422585.5535061749,3774903.768457427,84.92,2.0,4.0,1541.0,54.0 107 | 415034.7420117343,3767972.210891305,29.379,2.0,4.0,1102.0,64.0 108 | 414001.80395182257,3773841.315514062,41.266,2.0,4.0,1232.0,22.0 109 | 371692.5479131462,3737063.847806597,395.3,3.0,6.0,3216.0,38.0 110 | 387650.4515977912,3752394.992652429,63.272,1.0,2.0,1494.0,70.0 111 | 391527.9821074776,3774856.590967041,213.832,1.0,2.0,4283.0,107.0 112 | 408273.13450269937,3766798.091731991,108.225,2.0,4.0,1233.0,94.0 113 | 427099.2617371969,3764146.83150786,352.022,3.0,6.0,2647.0,29.0 114 | 376244.6951537856,3769730.234573865,16.333,2.0,4.0,1845.0,94.0 115 | 365973.8065698552,3797043.975469349,127.78,2.0,4.0,1161.0,62.0 116 | 387982.63412952377,3751441.088734982,73.3,1.0,2.0,976.0,20.0 117 | 379302.0415144456,3764561.1651256927,10.121,1.0,2.0,1433.0,104.0 118 | 371420.47815247526,3775145.468456988,714.119,7.0,14.0,5524.0,52.0 119 | 406359.23636229534,3751001.935000936,112.539,2.0,4.0,1320.0,62.0 120 | 398852.6389831227,3759613.656999465,209.897,2.0,4.0,1829.0,67.0 121 | 408721.90268645214,3763201.9682648736,222.0,2.0,4.0,2192.0,91.0 122 | 377805.681126663,3761192.3767225696,60.253,2.0,4.0,912.0,94.0 123 | 432155.1687743912,3766175.041668168,88.93,2.0,4.0,1849.0,47.0 124 | 399050.621198468,3750752.537124948,28.61,1.0,2.0,1082.0,68.0 125 | 396478.2678675731,3780732.154705797,199.699,2.0,4.0,1376.0,76.0 126 | 364115.5723266966,3768435.629642,1272.505,5.0,10.0,3606.0,18.0 127 | 371719.36892167525,3747237.446152132,156.656,1.0,2.0,1199.0,94.0 128 | 369907.8722619424,3795078.5413635103,129.322,2.0,4.0,1300.0,60.0 129 | 411454.78851585655,3762699.149490804,89.97,2.0,4.0,1200.0,62.0 130 | 394647.7093670788,3785118.8650021534,102.517,1.0,2.0,1053.0,76.0 131 | 427188.0080398333,3777408.028569369,264.043,3.0,6.0,2660.0,31.0 132 | 412282.8867296259,3761404.187090241,76.607,3.0,6.0,2044.0,53.0 133 | 421703.5846308979,3773071.134725383,204.161,3.0,6.0,2157.0,26.0 134 | 408756.553404812,3753502.857701093,148.0,2.0,4.0,1249.0,57.0 135 | 371356.52512693655,3737478.3924282114,210.569,4.0,8.0,2958.0,49.0 136 | 416119.1657471917,3771794.2101423326,254.0,3.0,6.0,2066.0,60.0 137 | 358393.5665806425,3794206.6675510095,348.168,3.0,6.0,1935.0,43.0 138 | 396599.5260765801,3757373.439002656,625.893,7.0,14.0,4669.0,22.0 139 | 377386.0570118289,3782660.3257437535,75.241,1.0,2.0,930.0,78.0 140 | 381019.82350658113,3783400.965145672,97.403,1.0,2.0,1180.0,97.0 141 | 380674.46318589145,3765455.1769629647,65.881,2.0,4.0,1462.0,61.0 142 | 372213.307670991,3774374.9317797087,1035.534,4.0,8.0,3182.0,49.0 143 | 406442.3862121431,3750439.9949040553,61.346,2.0,4.0,1382.0,60.0 144 | 435309.2971322514,3774760.24456563,213.304,2.0,4.0,1838.0,40.0 145 | 373605.0804840801,3774792.8225336126,155.418,2.0,4.0,1144.0,95.0 146 | 349978.12634272256,3780625.517455624,193.187,2.0,4.0,2012.0,59.0 147 | 377220.2692896148,3766092.6617030874,84.468,1.0,2.0,1150.0,93.0 148 | 374416.71243911167,3752051.083933776,54.112,1.0,2.0,704.0,65.0 149 | 407540.3751219096,3767089.681846394,213.588,3.0,6.0,2027.0,36.0 150 | 370719.17090694513,3787451.804396017,176.45,2.0,4.0,1129.0,65.0 151 | 397347.1934806792,3763765.158990241,44.589,1.0,2.0,972.0,103.0 152 | 376032.4051303377,3752920.213307455,21.004,1.0,2.0,832.0,70.0 153 | 378519.48199575365,3733032.7017100593,312.07,2.0,4.0,1919.0,67.0 154 | 374944.5849836108,3782953.1413962655,32.808,1.0,2.0,906.0,68.0 155 | 396427.1551685126,3767077.452496068,86.0,1.0,2.0,1414.0,68.0 156 | 395506.4161083364,3746449.8958348334,148.0,3.0,6.0,2434.0,67.0 157 | 364883.26413709647,3785816.349759375,199.099,3.0,6.0,2003.0,51.0 158 | 360726.4142069728,3784505.124248013,96.71,2.0,4.0,1993.0,61.0 159 | 370072.7233637043,3759074.139397041,142.856,2.0,4.0,1556.0,72.0 160 | 418441.724890048,3774436.0486324728,103.867,1.0,2.0,960.0,63.0 161 | 415160.2930415716,3774335.38519418,94.608,2.0,4.0,1412.0,59.0 162 | 373551.9814830707,3776122.481302655,228.431,2.0,4.0,1615.0,69.0 163 | 394672.7263051135,3755278.923868668,91.622,1.0,2.0,1095.0,70.0 164 | 399878.3888810412,3754870.116568729,79.0,1.0,2.0,1047.0,62.0 165 | 398059.0833956505,3740599.080124627,126.094,2.0,4.0,1263.0,66.0 166 | 429528.7452402518,3771152.883166232,218.275,3.0,6.0,1501.0,40.0 167 | 402430.0867587648,3781306.3023911305,45.234,1.0,2.0,1110.0,69.0 168 | 380426.4358411104,3745253.721846258,13.643,1.0,2.0,835.0,64.0 169 | 346839.93663528864,3783034.314871417,156.882,2.0,4.0,2046.0,51.0 170 | 387956.083547098,3740706.489399184,109.633,2.0,4.0,1550.0,76.0 171 | 370756.63438722247,3737056.844948862,302.139,3.0,6.0,2521.0,50.0 172 | 400894.2657162003,3770508.310756641,168.067,3.0,6.0,2176.0,67.0 173 | 379549.2691596567,3747932.802099386,163.825,2.0,4.0,1704.0,54.0 174 | 370223.05294937,3784248.208220169,231.07,2.0,4.0,1395.0,70.0 175 | 383492.763765372,3744544.7357371454,121.745,2.0,4.0,1613.0,54.0 176 | 356213.3154691985,3779058.963051477,337.61,4.0,8.0,3347.0,47.0 177 | 371903.6404836096,3748999.066780896,101.931,2.0,4.0,1120.0,65.0 178 | 368393.38154996646,3755060.921619762,73.734,2.0,4.0,1786.0,66.0 179 | 395493.19370689336,3739499.608388532,91.315,1.0,2.0,871.0,70.0 180 | 383482.67843591433,3772282.896885165,25.451,1.0,2.0,855.0,95.0 181 | 400611.0013706864,3748032.785792694,140.715,3.0,6.0,2025.0,70.0 182 | 405892.7084389143,3752430.754674239,208.0,2.0,4.0,1452.0,58.0 183 | 382244.52231624565,3790158.785109791,243.66,3.0,6.0,2360.0,81.0 184 | 410920.8044372517,3778821.1077367486,161.681,4.0,8.0,2523.0,42.0 185 | 394650.5161775607,3785582.522546112,139.136,1.0,2.0,1215.0,70.0 186 | 424003.6368244791,3771052.614650796,452.561,5.0,10.0,2957.0,40.0 187 | 378987.58701538894,3792239.712895733,86.357,1.0,2.0,872.0,62.0 188 | 374237.1542927885,3757668.1811024575,31.83,2.0,4.0,1158.0,91.0 189 | 373386.82232422254,3791193.169430849,233.507,2.0,4.0,1600.0,55.0 190 | 372882.5018469828,3779349.511891874,897.15,1.0,2.0,1312.0,78.0 191 | 354378.14263702644,3785829.666798661,95.978,2.0,4.0,1293.0,62.0 192 | 399103.7633938677,3754829.307423172,187.403,2.0,4.0,2185.0,67.0 193 | 380905.7443758856,3757337.605123051,54.112,1.0,2.0,1364.0,78.0 194 | 378039.3077349518,3740145.3784473343,124.171,3.0,6.0,1956.0,72.0 195 | 353884.3264531661,3784235.594288657,103.344,2.0,4.0,1380.0,61.0 196 | 360641.3758555616,3785184.55242947,59.895,2.0,4.0,1764.0,66.0 197 | 399395.1571121698,3763713.2099875016,83.138,1.0,2.0,1098.0,58.0 198 | 372768.00554508,3746283.5314506274,77.229,3.0,6.0,2111.0,47.0 199 | 389144.26193255774,3754386.291710618,89.382,1.0,2.0,871.0,77.0 200 | 378467.7280265462,3766000.343758747,149.0,1.0,2.0,1350.0,111.0 201 | 379371.649468271,3734173.625159903,150.152,2.0,4.0,1592.0,77.0 202 | 381514.02094094886,3744653.00041798,68.802,2.0,4.0,1408.0,58.0 203 | 365626.7598212317,3763056.288388681,182.04,1.0,2.0,1107.0,94.0 204 | 388353.59444170457,3757618.2533513415,71.088,2.0,4.0,1244.0,87.0 205 | 370531.5659609288,3759088.043177633,58.454,2.0,4.0,1363.0,73.0 206 | 394218.1494875807,3740438.210683509,29.837,1.0,2.0,957.0,74.0 207 | 417493.8671153663,3768985.588780647,169.102,2.0,4.0,1658.0,62.0 208 | 360819.6212544301,3767593.298142068,524.194,4.0,8.0,3752.0,36.0 209 | 371773.0804700827,3741474.965228503,65.63,2.0,4.0,2307.0,63.0 210 | 427019.2591135188,3764154.101948544,209.143,3.0,6.0,2777.0,28.0 211 | 381172.9731606412,3756344.2019442506,63.468,1.0,2.0,1033.0,77.0 212 | 363630.69666272285,3788195.816502433,101.0,2.0,4.0,1840.0,59.0 213 | 371485.9828888066,3767693.267488067,254.031,3.0,6.0,1913.0,66.0 214 | 403917.2499181765,3781947.400640737,109.796,2.0,4.0,1545.0,38.0 215 | 380191.8445942851,3763945.296070162,165.0,2.0,4.0,2821.0,107.0 216 | 395289.77763261367,3772397.932920299,170.468,3.0,6.0,1972.0,106.0 217 | 392389.8511329389,3782716.990333374,170.0,2.0,4.0,2029.0,57.0 218 | 401278.7787713202,3764665.268096748,131.395,2.0,4.0,1461.0,64.0 219 | 399041.4937587115,3777785.481844485,319.674,2.0,4.0,2197.0,66.0 220 | 378542.45067254704,3760231.6460564714,69.793,2.0,4.0,1581.0,86.0 221 | 369843.9202273822,3772313.976953044,129.339,5.0,10.0,4535.0,92.0 222 | 359993.5824478747,3768951.604016707,1093.928,4.0,8.0,4277.0,86.0 223 | 360412.271129603,3782412.619496231,274.117,3.0,6.0,2397.0,6.0 224 | 407880.8872853703,3755409.4812818686,103.815,1.0,2.0,1062.0,65.0 225 | 402088.6992937469,3762485.3677455713,81.0,1.0,2.0,932.0,68.0 226 | 397242.22832708654,3758961.27694975,23.792,1.0,2.0,1056.0,67.0 227 | 370172.03800744674,3778776.939059781,156.798,2.0,4.0,1664.0,57.0 228 | 390704.8514983706,3745471.377620148,131.796,2.0,4.0,1434.0,70.0 229 | 383540.7768396632,3741424.042156744,18.611,1.0,2.0,888.0,67.0 230 | 363539.67372683913,3772057.917541826,2072.41,5.0,10.0,8416.0,24.0 231 | 347959.9011462344,3784366.55888668,50.743,2.0,4.0,1160.0,57.0 232 | 393326.6649229835,3750773.612804553,131.886,2.0,4.0,1102.0,58.0 233 | 367731.5939877079,3787842.722455072,83.086,1.0,2.0,750.0,68.0 234 | 394577.2918078069,3771228.8722298057,101.956,2.0,4.0,1205.0,101.0 235 | 381911.4639922999,3757682.024784201,59.024,2.0,4.0,1220.0,72.0 236 | 420320.32172155153,3767421.248356384,727.124,3.0,6.0,3193.0,26.0 237 | 400778.53969393903,3778419.991533535,87.499,2.0,4.0,1415.0,76.0 238 | 350112.89773475664,3779297.03213065,316.326,3.0,6.0,2739.0,49.0 239 | 389727.8450459144,3776403.086467608,256.709,2.0,4.0,1385.0,91.0 240 | 394131.88819992536,3780940.492366492,46.384,1.0,2.0,1756.0,116.0 241 | 377103.5905581628,3748652.154174855,71.447,2.0,4.0,1141.0,66.0 242 | 364750.0468603196,3778232.614067401,204.716,3.0,6.0,2290.0,62.0 243 | 371537.7205820746,3739955.825078982,286.336,2.0,4.0,2005.0,61.0 244 | 358039.51880010945,3789032.81607774,104.477,1.0,2.0,1483.0,65.0 245 | 393283.6762979578,3767972.923083755,60.449,2.0,4.0,1620.0,60.0 246 | 371234.6275780868,3749301.902663915,41.816,2.0,4.0,1896.0,62.0 247 | 423602.760551055,3772813.144942756,90.667,2.0,4.0,1346.0,41.0 248 | 398629.1904628298,3739789.2357573113,58.359,2.0,4.0,1663.0,64.0 249 | 375918.7870208495,3748255.4170725048,294.274,3.0,6.0,2358.0,51.0 250 | 397730.6087916932,3745805.151889024,43.037,2.0,4.0,1259.0,63.0 251 | 421702.90019531193,3773133.129012078,197.687,2.0,4.0,2624.0,56.0 252 | 395641.7855806474,3781998.705336226,144.368,1.0,2.0,1004.0,94.0 253 | 432741.0050559781,3772286.334105624,28.975,2.0,4.0,1251.0,58.0 254 | 387938.80846905446,3751214.59130948,136.41,1.0,2.0,2243.0,96.0 255 | 384966.004889932,3749973.0905901217,33.186,2.0,4.0,1691.0,63.0 256 | 433412.7063023457,3771628.212706886,258.442,2.0,4.0,1809.0,62.0 257 | 386573.96277061314,3789127.965529592,73.402,1.0,2.0,994.0,62.0 258 | 378380.9653786607,3743973.6304580863,216.593,3.0,6.0,2214.0,27.0 259 | 420504.0656593259,3778270.1777521023,113.5,2.0,4.0,1906.0,107.0 260 | 357913.16225325153,3794204.407229974,95.284,2.0,4.0,1429.0,45.0 261 | 416775.5662179373,3778810.196893054,332.184,3.0,6.0,2192.0,3.0 262 | 400919.9847294269,3747962.802227752,264.198,3.0,6.0,2661.0,11.0 263 | 373636.594977396,3767692.6450052615,65.136,1.0,2.0,1263.0,71.0 264 | 360709.6834269365,3792393.622697586,84.773,2.0,4.0,1514.0,64.0 265 | 402127.9483592287,3778819.738836868,647.759,5.0,10.0,3648.0,70.0 266 | 373995.30072557775,3767935.62683026,154.496,2.0,4.0,1664.0,84.0 267 | 427364.0429579825,3776416.63478168,196.608,3.0,6.0,2196.0,52.0 268 | 394633.3539489256,3763875.6284568086,39.092,1.0,2.0,1015.0,77.0 269 | 382348.84660064994,3774160.659279064,147.268,2.0,4.0,1567.0,80.0 270 | 393220.4619768424,3746587.1747798016,33.68,1.0,2.0,1174.0,65.0 271 | 395979.5013266261,3757727.668722126,224.701,2.0,4.0,1861.0,67.0 272 | 377630.9426261468,3732751.032073009,260.0,2.0,4.0,1910.0,56.0 273 | 405512.36136859714,3766032.167803061,57.689,1.0,2.0,940.0,62.0 274 | 365703.9903666501,3759650.367523587,552.217,5.0,10.0,3469.0,19.0 275 | 381949.2069014765,3744699.607135778,97.756,2.0,4.0,1524.0,62.0 276 | 378309.4480826504,3748953.054300372,104.0,2.0,4.0,1157.0,63.0 277 | 384985.5709055185,3750214.065928505,74.192,1.0,2.0,1247.0,68.0 278 | 406460.0777156319,3755874.727120865,54.885,1.0,2.0,834.0,67.0 279 | 371462.0368035678,3759071.157794332,96.734,2.0,4.0,1367.0,75.0 280 | 427144.0278570784,3767808.822346463,90.0,2.0,4.0,2050.0,48.0 281 | 420541.8570575513,3775340.067361067,60.66,2.0,4.0,1604.0,51.0 282 | 401290.69179115695,3761461.094868337,137.429,1.0,2.0,1680.0,74.0 283 | 431219.651575715,3765838.16274402,69.989,1.0,2.0,942.0,61.0 284 | 420712.62363238254,3765196.797728442,295.766,3.0,6.0,2384.0,42.0 285 | 368512.1444349241,3754731.089128026,4.94,1.0,2.0,676.0,96.0 286 | 397474.5808100199,3745444.611565591,61.569,1.0,2.0,1066.0,67.0 287 | 367560.0870771261,3770773.5624766434,930.524,3.0,6.0,3090.0,71.0 288 | 368284.01524812006,3777060.1469345232,216.367,3.0,6.0,3035.0,40.0 289 | 393635.9204496844,3765526.018644818,58.283,1.0,2.0,1039.0,89.0 290 | 417509.3180456033,3763310.437717756,57.274,1.0,2.0,881.0,59.0 291 | 421187.44912705774,3765048.447158748,124.366,3.0,6.0,2188.0,50.0 292 | 389410.1835716948,3762030.404459837,98.0,2.0,4.0,1825.0,76.0 293 | 406449.7253366137,3774386.779838271,121.83,1.0,2.0,1040.0,70.0 294 | 370106.7523689894,3736124.066414577,183.29,3.0,6.0,2600.0,44.0 295 | 411861.00908672216,3759725.5249209153,57.211,3.0,6.0,2493.0,44.0 296 | 364547.6184377016,3784166.9524078704,224.939,2.0,4.0,1683.0,69.0 297 | 378999.5610923496,3784599.092251427,198.077,2.0,4.0,1815.0,66.0 298 | 428569.49908533104,3771287.17716544,163.558,3.0,6.0,2337.0,34.0 299 | 390932.0244755491,3776702.477967496,50.959,2.0,4.0,1071.0,59.0 300 | 361173.2812546947,3791168.9365585926,173.267,3.0,6.0,2271.0,57.0 301 | 374345.5706714047,3783804.957215587,129.801,2.0,4.0,1448.0,67.0 302 | 367557.8851482178,3783345.6151357945,82.468,2.0,4.0,1125.0,68.0 303 | 376633.3011753617,3744902.429901395,42.224,2.0,4.0,1543.0,66.0 304 | 398924.5390235737,3768877.1344107375,131.001,2.0,4.0,1593.0,97.0 305 | 389768.97791615175,3755319.784948044,78.216,2.0,4.0,1228.0,76.0 306 | 375682.3120048673,3771632.189886592,34.354,2.0,4.0,1819.0,76.0 307 | 372785.8817304479,3752994.995255008,30.861,2.0,4.0,1767.0,62.0 308 | 395536.6644644758,3736171.046110413,28.346,2.0,4.0,1931.0,76.0 309 | 383301.4346569795,3746956.872943912,85.459,2.0,4.0,1465.0,57.0 310 | 397451.0561227537,3756262.305980054,223.683,2.0,4.0,2620.0,63.0 311 | 372682.5757779272,3784250.2625366254,99.9,1.0,2.0,1671.0,79.0 312 | 377971.2291736872,3748332.661202064,48.645,2.0,4.0,1503.0,61.0 313 | 382632.8909002791,3772513.252018544,356.657,1.0,2.0,1578.0,94.0 314 | 378589.9019150306,3753321.022793967,93.517,2.0,4.0,1291.0,62.0 315 | 347841.2133703756,3782342.3905040217,239.38,2.0,4.0,2161.0,55.0 316 | 377190.2363496985,3732045.2427150407,192.826,3.0,6.0,2487.0,55.0 317 | 370896.61200084304,3759041.3588896953,326.608,4.0,8.0,2600.0,75.0 318 | 389158.9535974569,3777234.896563416,51.137,2.0,4.0,1680.0,90.0 319 | 408663.84590297664,3761846.953329144,681.823,6.0,12.0,5264.0,10.0 320 | 380089.7921326914,3763508.729693818,14.677,2.0,4.0,1604.0,95.0 321 | 381245.4626280588,3756080.116433287,15.505,1.0,2.0,944.0,92.0 322 | 395211.0453000203,3766733.763754044,85.501,2.0,4.0,1405.0,68.0 323 | 400775.6597072948,3782332.5928099374,670.415,7.0,14.0,4798.0,28.0 324 | 361139.11640779214,3794821.3092188663,173.255,3.0,6.0,2208.0,53.0 325 | 377995.5923556711,3758118.911381045,64.934,2.0,4.0,1506.0,75.0 326 | 430628.2155124,3766024.120428128,113.7,2.0,4.0,1320.0,60.0 327 | 397307.8919655632,3758284.639862417,127.2,2.0,4.0,1469.0,70.0 328 | 435622.47309316485,3775886.610628412,140.811,2.0,4.0,1551.0,40.0 329 | 360609.5569950391,3791234.65108236,86.707,2.0,4.0,1488.0,59.0 330 | 379707.9156805438,3762241.8106420375,24.951,1.0,2.0,988.0,76.0 331 | 397853.5481413246,3741893.985289712,43.791,2.0,4.0,1331.0,65.0 332 | 379600.0003682445,3741898.9939085897,146.463,3.0,6.0,1792.0,49.0 333 | 372850.3308353333,3739915.384317639,189.228,2.0,4.0,1600.0,61.0 334 | 378155.02959053626,3735647.103217205,167.62,3.0,6.0,1789.0,61.0 335 | 381670.5787997321,3756220.530895802,34.327,1.0,2.0,1338.0,94.0 336 | 370711.4990353758,3750118.6396045513,58.378,3.0,6.0,2014.0,48.0 337 | 417027.40766869177,3769049.115389066,234.514,3.0,6.0,2546.0,38.0 338 | 376655.2589130378,3782829.379846629,103.805,2.0,4.0,1692.0,70.0 339 | 378863.7309688949,3758823.564065115,50.158,2.0,4.0,1337.0,91.0 340 | 408135.3349318731,3780177.995910789,62.29,1.0,2.0,1448.0,72.0 341 | 364448.04785184446,3766808.2715907968,10.275,1.0,2.0,1116.0,106.0 342 | 388188.8680903596,3755867.6135525946,53.304,2.0,4.0,1043.0,88.0 343 | 413176.9547123903,3778548.5079300217,146.217,2.0,4.0,1292.0,63.0 344 | 396005.98355302,3738405.562798621,219.072,3.0,6.0,2834.0,59.0 345 | 394476.2174465132,3765336.608592034,17.371,1.0,2.0,892.0,75.0 346 | 410781.0289547482,3771106.739486549,95.542,2.0,4.0,1260.0,40.0 347 | 383883.576305335,3757420.323493879,52.5,1.0,2.0,1266.0,97.0 348 | 403991.77501171466,3776874.778420045,514.774,5.0,10.0,4468.0,67.0 349 | 384542.60616715456,3764666.516266727,99.741,1.0,2.0,1349.0,115.0 350 | 365019.7968547663,3780345.8140317863,489.519,4.0,8.0,3350.0,11.0 351 | 378403.2567945828,3771124.916769407,400.892,4.0,8.0,3116.0,95.0 352 | 376707.6601255758,3754837.09200889,103.323,1.0,2.0,1260.0,78.0 353 | 384660.6484819485,3774571.162582289,47.236,1.0,2.0,912.0,107.0 354 | 414732.76160587865,3759886.1978154583,286.187,2.0,4.0,2535.0,34.0 355 | 373562.97944199375,3775601.712909452,462.432,3.0,6.0,2892.0,95.0 356 | 408875.5423197257,3754485.336132248,140.085,2.0,4.0,2153.0,57.0 357 | 428376.46792894014,3776445.695671332,82.816,4.0,8.0,2161.0,52.0 358 | 375611.1903395547,3792061.779353709,368.535,2.0,4.0,1688.0,54.0 359 | 378500.345644004,3759535.2476728656,25.034,2.0,4.0,1394.0,94.0 360 | 396384.60938629153,3774717.425743376,883.103,3.0,6.0,3053.0,84.0 361 | 387564.9643319374,3767830.330325745,63.321,1.0,2.0,1214.0,116.0 362 | 376845.28499197465,3770907.4462450873,584.412,4.0,8.0,4242.0,89.0 363 | 368079.2022614499,3799154.880187426,121.868,2.0,4.0,2050.0,51.0 364 | 390170.10057929147,3770343.793000249,17.99,1.0,2.0,918.0,76.0 365 | 380944.9897095936,3756444.214632412,36.264,1.0,2.0,787.0,78.0 366 | 367971.8563754536,3773879.268719372,806.181,3.0,6.0,2856.0,65.0 367 | 379929.6088929601,3740990.753176186,56.307,3.0,6.0,2330.0,52.0 368 | 393551.9349246775,3737967.531334937,52.28,2.0,4.0,1206.0,97.0 369 | 382112.22169421456,3753660.1278061713,14.266,1.0,2.0,821.0,64.0 370 | 407122.0824876666,3775160.1799827786,300.4,2.0,4.0,1856.0,69.0 371 | 403184.04075027705,3779856.147525737,324.583,3.0,6.0,2666.0,66.0 372 | 395298.97368154034,3779895.474397977,51.809,1.0,2.0,1140.0,107.0 373 | 390627.751087819,3740068.626550197,81.0,1.0,2.0,1025.0,96.0 374 | 382088.0788383924,3754157.8327397313,51.431,2.0,4.0,1532.0,69.0 375 | 405541.2177484162,3768575.956458959,157.409,2.0,4.0,1184.0,68.0 376 | 385378.452668852,3788963.274535325,91.342,2.0,4.0,1178.0,66.0 377 | 415864.1378324705,3760044.744725391,57.738,2.0,4.0,1410.0,56.0 378 | 357825.32406817074,3788060.608240367,118.383,2.0,4.0,1636.0,53.0 379 | 379290.9827296734,3792187.7735329736,146.213,2.0,4.0,1235.0,64.0 380 | 390588.5499182134,3745488.905233898,102.384,2.0,4.0,1557.0,70.0 381 | 347919.152468079,3782013.671983652,61.278,2.0,4.0,1936.0,54.0 382 | 366128.115482769,3782020.455014118,97.51,2.0,4.0,1294.0,69.0 383 | 387767.40256793937,3768838.4795805705,82.736,1.0,2.0,1164.0,113.0 384 | 358382.79394771555,3792063.132608921,167.43,2.0,4.0,1788.0,56.0 385 | 368746.7606000035,3796212.583435335,194.148,3.0,6.0,2023.0,68.0 386 | 368433.7114034309,3790348.221877196,82.142,2.0,4.0,1376.0,69.0 387 | 393091.8880739004,3750111.303695821,269.149,4.0,8.0,4904.0,40.0 388 | 351547.352740232,3787601.228914296,92.0,2.0,4.0,1320.0,58.0 389 | 368864.796761106,3786342.532501167,83.354,2.0,4.0,1769.0,51.0 390 | 409423.3890984944,3761643.7033246937,267.601,3.0,6.0,2784.0,55.0 391 | 374206.417918056,3792127.0104757976,730.258,4.0,8.0,3801.0,13.0 392 | 419163.86733332137,3776883.892263189,63.085,2.0,4.0,1436.0,64.0 393 | 390335.9163138779,3777960.0697475206,148.825,3.0,6.0,2089.0,109.0 394 | 395282.8681981915,3739520.435317957,114.272,2.0,4.0,1450.0,70.0 395 | 378811.7132649246,3784918.497670264,409.441,4.0,8.0,3051.0,66.0 396 | 423478.4352721642,3766477.185357182,338.596,3.0,6.0,1976.0,29.0 397 | 351507.7280212067,3779452.506058992,481.634,3.0,6.0,2701.0,36.0 398 | 368386.6824058878,3768120.9240695154,125.205,1.0,2.0,1491.0,90.0 399 | 386421.21073311975,3751217.312864179,151.0,3.0,6.0,1548.0,17.0 400 | 381624.9691646165,3781845.805330755,157.847,2.0,4.0,1628.0,90.0 401 | 384109.56511608034,3754592.6225416535,52.27,1.0,2.0,1097.0,73.0 402 | 384036.629842125,3743484.9740404426,174.459,2.0,4.0,1483.0,53.0 403 | 391025.7212708038,3743858.670592176,145.935,2.0,4.0,1882.0,70.0 404 | 422489.37649854633,3772966.391447139,191.83,3.0,6.0,2101.0,32.0 405 | 408384.05046074535,3767325.6540680975,166.533,3.0,6.0,2201.0,30.0 406 | 384444.7378514028,3748614.208408117,84.78,2.0,4.0,1498.0,51.0 407 | 379083.4839144072,3774667.69421587,207.789,2.0,4.0,1966.0,45.0 408 | 397920.9006203596,3776419.0664636334,481.066,4.0,8.0,3383.0,79.0 409 | 393191.7899164351,3764342.833005378,86.815,1.0,2.0,1144.0,75.0 410 | 378142.9329880931,3764780.435107717,9.294,1.0,2.0,908.0,94.0 411 | 415138.9583790496,3767376.5537564815,169.037,2.0,4.0,1723.0,62.0 412 | 371643.6722939871,3787532.94560725,108.357,2.0,4.0,1787.0,67.0 413 | 418595.9090024713,3765979.387302225,145.595,3.0,6.0,2046.0,31.0 414 | 399749.8302152974,3757643.786161032,118.337,2.0,4.0,1135.0,67.0 415 | 411003.5789970065,3766658.864866131,61.206,2.0,4.0,1394.0,62.0 416 | 394935.6349789497,3784918.119427344,118.0,1.0,2.0,1140.0,70.0 417 | 361873.1947089207,3786177.052825547,179.401,2.0,4.0,1464.0,69.0 418 | 399151.3069526899,3748579.9012773135,299.785,3.0,6.0,2787.0,16.0 419 | 401085.6481361882,3760739.076774731,66.605,1.0,2.0,1642.0,132.0 420 | 370057.36421826587,3751649.462650487,20.893,2.0,4.0,1213.0,68.0 421 | 394222.0285734034,3750901.2254807935,95.82,2.0,4.0,1854.0,68.0 422 | 379472.8473025878,3745186.453609312,127.792,1.0,2.0,1044.0,64.0 423 | 432910.41927682055,3777471.2957285577,253.053,3.0,6.0,2564.0,48.0 424 | 418361.1744291906,3769967.763690985,180.178,4.0,8.0,2717.0,62.0 425 | 369187.8148460752,3767408.381071432,1269.062,5.0,10.0,3962.0,8.0 426 | 405811.937844797,3771617.371635139,89.02,2.0,4.0,1158.0,31.0 427 | 367947.9238460883,3787187.927670514,138.784,2.0,4.0,1779.0,67.0 428 | 403793.4804504052,3773856.8137100935,110.529,2.0,4.0,1175.0,60.0 429 | 403890.2247412369,3748121.722877932,112.692,2.0,4.0,1100.0,46.0 430 | 374004.1343219181,3740540.548708976,250.807,2.0,4.0,1669.0,61.0 431 | 373925.3475584318,3782305.941613356,75.128,1.0,2.0,964.0,69.0 432 | 405408.2140468126,3766041.416004403,41.421,2.0,4.0,1156.0,62.0 433 | 408107.2839681829,3781147.073134599,398.0,3.0,6.0,2632.0,59.0 434 | 421020.8812376033,3761586.72552388,330.283,3.0,6.0,2304.0,42.0 435 | 351895.5364899534,3781513.583433362,110.686,4.0,8.0,1701.0,67.0 436 | 352847.70154590096,3792265.91060995,106.0,2.0,4.0,1879.0,41.0 437 | 347861.66081842803,3784049.343629669,74.78,2.0,4.0,1167.0,57.0 438 | 386101.2699802199,3775796.894797291,164.975,2.0,4.0,1234.0,18.0 439 | 357234.5458844295,3778779.199034357,1269.399,7.0,14.0,5454.0,16.0 440 | 361087.6023830089,3780660.8452031855,344.837,3.0,6.0,2346.0,56.0 441 | 375534.3983336316,3754390.039645884,126.419,2.0,4.0,1639.0,62.0 442 | 367439.1212698804,3781852.804316503,78.267,2.0,4.0,2069.0,58.0 443 | 376797.0334447716,3783694.294312336,73.89,1.0,2.0,933.0,76.0 444 | 370416.5479277739,3774857.8708349126,972.0,4.0,8.0,3217.0,62.0 445 | 387042.0646218623,3755608.495675556,136.734,2.0,4.0,923.0,69.0 446 | 395439.3190927304,3751796.112509912,88.282,2.0,4.0,1256.0,63.0 447 | 396142.7628188469,3758078.646758257,36.225,2.0,4.0,1470.0,68.0 448 | 384287.2289461236,3775550.166566267,171.173,2.0,4.0,1263.0,92.0 449 | 415262.077530582,3770653.899691412,145.324,2.0,4.0,1980.0,64.0 450 | 407994.7451455385,3769636.070769169,27.427,1.0,2.0,1032.0,62.0 451 | 380844.42690864345,3751747.109461624,79.604,1.0,2.0,1247.0,69.0 452 | 370014.1649649021,3763873.521002262,134.888,2.0,4.0,1088.0,75.0 453 | 390167.5953373655,3755624.241156755,88.958,1.0,2.0,873.0,76.0 454 | 426870.4297543285,3777193.587294037,218.683,3.0,6.0,2660.0,31.0 455 | 385983.2804849927,3781367.381065813,194.515,3.0,6.0,2183.0,39.0 456 | 400459.7821770563,3753921.823032819,86.774,1.0,2.0,749.0,68.0 457 | 351993.8687089088,3779740.681227524,370.72,4.0,8.0,3551.0,36.0 458 | 365377.5032507954,3781468.270111455,140.012,1.0,2.0,882.0,75.0 459 | 382101.6693671375,3773333.605696922,51.54,2.0,4.0,1488.0,96.0 460 | 389407.5261205466,3753296.502386689,113.384,2.0,4.0,1444.0,78.0 461 | 384034.52904980816,3751181.6068966,22.716,1.0,2.0,1036.0,70.0 462 | 373208.8557123204,3754808.678002355,148.842,1.0,2.0,1368.0,77.0 463 | 409092.170379665,3755849.351287005,69.596,2.0,4.0,1897.0,56.0 464 | 407868.9314868666,3767108.20744232,79.2,1.0,2.0,1289.0,77.0 465 | 399983.8807510596,3782729.028745272,295.315,3.0,6.0,2686.0,19.0 466 | 405807.1360190581,3776776.4855602505,386.772,3.0,6.0,3874.0,31.0 467 | 418162.0751722684,3769824.995087036,124.734,2.0,4.0,2443.0,66.0 468 | 374407.2219040767,3742889.204427796,158.0,2.0,4.0,1526.0,57.0 469 | 378047.79734743,3765094.643830718,64.67,1.0,2.0,711.0,64.0 470 | 425526.29219178495,3768638.699677631,159.574,2.0,4.0,1521.0,61.0 471 | 377065.786866694,3754784.643709862,137.731,2.0,4.0,2125.0,70.0 472 | 375578.8342204299,3781850.685483896,55.744,1.0,2.0,1146.0,78.0 473 | 420266.8756819672,3764050.718248935,203.708,2.0,4.0,2060.0,37.0 474 | 371995.7558879185,3765343.1252690624,58.695,2.0,4.0,1790.0,76.0 475 | 369511.43485098775,3754926.802093797,58.568,2.0,4.0,1469.0,96.0 476 | 411570.7459673707,3761804.706921488,55.894,2.0,4.0,1796.0,54.0 477 | 423030.8324056669,3776603.4212092,609.15,4.0,8.0,4322.0,26.0 478 | 399582.7992214486,3755816.4184227353,92.833,1.0,2.0,1057.0,65.0 479 | 370612.36504858045,3787477.12346126,93.4,2.0,4.0,1038.0,64.0 480 | 372818.83394454094,3742495.488703637,109.811,2.0,4.0,1418.0,67.0 481 | 380362.4049027271,3731948.461551151,122.8,1.0,2.0,812.0,65.0 482 | 396337.1964614081,3774021.597860636,105.967,2.0,4.0,1717.0,91.0 483 | 383417.75437982375,3740569.942481501,121.253,2.0,4.0,2046.0,64.0 484 | 364597.54149233294,3761259.178058147,8.462,1.0,2.0,768.0,84.0 485 | 419169.9657556847,3775380.903610952,59.629,1.0,2.0,1396.0,66.0 486 | 375872.6981336047,3760593.6665567206,11.158,1.0,2.0,756.0,94.0 487 | 404928.1474383641,3755227.032750014,126.094,1.0,2.0,1088.0,67.0 488 | 378160.1865176337,3732346.131552728,60.891,2.0,4.0,1522.0,63.0 489 | 394252.9871413123,3750957.3280046335,73.139,1.0,2.0,1461.0,111.0 490 | 402244.35024505167,3778787.920507547,161.648,1.0,2.0,1487.0,67.0 491 | 402232.0469308295,3747732.20034261,125.3,2.0,4.0,1221.0,48.0 492 | 387841.7926982724,3741639.055550517,96.7,1.0,2.0,944.0,75.0 493 | 403200.6764689872,3775367.2231216407,741.31,4.0,8.0,4025.0,24.0 494 | 374484.81775629567,3749022.5275350944,161.749,3.0,6.0,1868.0,38.0 495 | 395796.9930711701,3747358.170647247,167.121,2.0,4.0,1556.0,75.0 496 | 394368.8952642277,3781653.48585845,134.015,2.0,4.0,1729.0,106.0 497 | 360997.04943553486,3783927.214893297,258.978,3.0,6.0,3094.0,62.0 498 | 379493.9741738328,3734028.685112026,40.317,1.0,2.0,899.0,68.0 499 | 403649.8820036518,3767009.6785005736,43.0,1.0,2.0,796.0,67.0 500 | 379287.7256762401,3759585.6241134894,49.876,1.0,2.0,1183.0,87.0 501 | 339587.6029523917,3779054.7072022553,272.087,4.0,8.0,2087.0,9.0 502 | 413228.883600572,3769673.4431869434,170.257,2.0,4.0,1856.0,61.0 503 | 378710.68596640666,3768481.7830350953,229.5,2.0,4.0,2408.0,94.0 504 | 388118.2280961227,3765810.195285781,44.696,1.0,2.0,740.0,93.0 505 | 377701.9586333935,3764303.457186002,66.252,3.0,6.0,2408.0,61.0 506 | 389753.902674621,3782080.670139084,260.607,3.0,6.0,2580.0,58.0 507 | 391763.5188618206,3738362.1518809632,37.983,2.0,4.0,1128.0,92.0 508 | 362713.85170213296,3767812.3670835895,1474.408,6.0,12.0,4950.0,9.0 509 | 399544.3602279334,3744270.005953024,142.836,2.0,4.0,1332.0,78.0 510 | 391286.3290528706,3751351.1301828334,70.19,1.0,2.0,812.0,65.0 511 | 382957.8725256374,3764475.612752977,98.783,2.0,4.0,1200.0,45.0 512 | 395037.29721537896,3735999.866897722,62.295,1.0,2.0,928.0,92.0 513 | 351551.646562704,3786130.727749944,46.163,2.0,4.0,1628.0,61.0 514 | 361210.6485426401,3785849.738963041,39.591,1.0,2.0,852.0,67.0 515 | 378492.7465047446,3749252.814779883,86.276,3.0,6.0,2480.0,54.0 516 | 369904.53605087113,3772934.9203926143,1904.762,4.0,8.0,4477.0,48.0 517 | 368569.5889918226,3763804.866012931,62.67,3.0,6.0,2002.0,87.0 518 | 417036.5050114511,3772706.95447848,176.0,2.0,4.0,1645.0,61.0 519 | 378579.0773135719,3763035.905723301,15.925,1.0,2.0,1774.0,105.0 520 | 382780.73481479415,3772811.527345311,96.403,2.0,4.0,1604.0,77.0 521 | 420831.4144391438,3777538.6293724426,121.061,2.0,4.0,1683.0,65.0 522 | 351624.2691419453,3780543.718787736,124.105,1.0,2.0,1344.0,57.0 523 | 373515.2268831916,3784217.2740470367,189.738,2.0,4.0,1539.0,73.0 524 | 395363.5199957988,3745907.960230153,63.011,2.0,4.0,1768.0,67.0 525 | 378148.31580298377,3792055.275768552,104.023,1.0,2.0,1056.0,62.0 526 | 418493.4453511074,3773611.554333705,141.018,2.0,4.0,1718.0,60.0 527 | 399031.29734147846,3779877.2944194153,168.212,4.0,8.0,3234.0,57.0 528 | 377255.0599270562,3747507.538555255,82.097,2.0,4.0,1280.0,67.0 529 | 401524.0971257861,3773695.492998197,161.517,2.0,4.0,1606.0,76.0 530 | 364241.1041008663,3767784.635815015,208.028,3.0,6.0,2588.0,80.0 531 | 401145.88906946254,3746877.118801844,150.92,2.0,4.0,1271.0,69.0 532 | 358854.06231227244,3793138.7364250543,76.741,2.0,4.0,1680.0,59.0 533 | 417344.806650057,3758746.920800851,91.335,2.0,4.0,1202.0,43.0 534 | 397844.9378999035,3745629.262751872,66.57,2.0,4.0,1725.0,67.0 535 | 355577.65808045655,3790475.591669376,116.056,2.0,4.0,1435.0,60.0 536 | 365812.14889186434,3787153.783527751,90.022,2.0,4.0,1196.0,62.0 537 | 396129.6809206216,3746638.2487826394,91.94,1.0,2.0,1512.0,66.0 538 | 396968.56394053454,3766140.085271251,132.198,3.0,6.0,2291.0,40.0 539 | 366837.0305550337,3767483.928173167,164.46,2.0,4.0,1602.0,59.0 540 | 372486.1086721732,3779821.820247274,87.379,2.0,4.0,2574.0,71.0 541 | 415887.6661295103,3770190.312478013,84.74,2.0,4.0,1795.0,65.0 542 | 359807.69926581875,3767369.345126713,809.0,2.0,4.0,2183.0,70.0 543 | 398013.65786804,3781682.108146851,109.647,1.0,2.0,932.0,91.0 544 | 390719.83646344405,3749046.0393287577,266.599,3.0,6.0,2820.0,77.0 545 | 421290.7926476487,3764651.928069727,156.676,2.0,4.0,1960.0,53.0 546 | 403102.3529709157,3779578.4090746497,582.582,5.0,10.0,3523.0,66.0 547 | 369449.0629687493,3771789.601296416,381.863,4.0,8.0,2889.0,68.0 548 | 357835.2827999637,3787763.185253837,269.995,4.0,8.0,3984.0,66.0 549 | 402315.4087914384,3775344.865786537,99.733,3.0,6.0,1462.0,64.0 550 | 429597.6838684757,3770560.99603129,166.688,2.0,4.0,1550.0,68.0 551 | 368335.4715421113,3758818.9604247976,147.619,2.0,4.0,1372.0,70.0 552 | 384378.42598751007,3749999.518940781,84.379,1.0,2.0,1073.0,67.0 553 | 386378.26343039866,3781829.073441798,193.574,3.0,6.0,1761.0,79.0 554 | 356318.76521558524,3780226.579524932,233.432,3.0,6.0,2802.0,53.0 555 | 389426.5485334778,3753349.95670966,124.661,2.0,4.0,2000.0,79.0 556 | 402685.594455419,3777855.340270974,177.98,2.0,4.0,1975.0,70.0 557 | 405521.8409890333,3758257.953842307,234.3,2.0,4.0,1630.0,66.0 558 | 401680.41590842407,3759769.9643134526,101.109,1.0,2.0,1169.0,70.0 559 | 409294.27978230274,3755498.434998935,180.153,2.0,4.0,1752.0,62.0 560 | 413659.6981488596,3761132.149932956,237.914,3.0,6.0,2009.0,33.0 561 | 391451.7920004737,3774392.783076559,111.832,1.0,2.0,992.0,66.0 562 | 401356.5518989186,3744877.8318775687,71.037,1.0,2.0,1036.0,59.0 563 | 410763.1766946119,3774085.450664282,77.217,1.0,2.0,830.0,61.0 564 | 356214.28656206187,3785185.965347488,57.149,2.0,4.0,1404.0,64.0 565 | 372068.8090709,3747475.1842889423,149.0,2.0,4.0,1330.0,54.0 566 | 349045.0240550676,3784806.5199651313,192.897,2.0,4.0,1570.0,58.0 567 | 365876.1610294782,3762611.756396028,19.817,1.0,2.0,1204.0,95.0 568 | 384386.6836512041,3753905.745599017,9.705,1.0,2.0,676.0,75.0 569 | 368453.8087806738,3763057.927406965,144.608,1.0,2.0,975.0,89.0 570 | 348582.31510452647,3779690.480075621,604.008,4.0,8.0,3182.0,48.0 571 | 399134.9584323932,3754989.776237212,86.579,1.0,2.0,1012.0,67.0 572 | 403536.913812462,3780525.459880338,112.761,3.0,6.0,1681.0,44.0 573 | 399297.7924386241,3748637.4559129504,114.372,2.0,4.0,1950.0,53.0 574 | 358819.44885051064,3767701.0671704886,218.43,2.0,4.0,2204.0,77.0 575 | 408444.23790056485,3760648.310290716,252.992,2.0,4.0,2086.0,42.0 576 | 404049.15167609655,3772092.592271225,119.4,1.0,2.0,989.0,67.0 577 | 388584.311908672,3753490.447567504,96.339,2.0,4.0,1162.0,78.0 578 | 411999.0429179586,3773523.900205181,160.105,3.0,6.0,1578.0,41.0 579 | 394147.6746168712,3749788.968481876,44.803,1.0,2.0,760.0,75.0 580 | 421759.7394242884,3762527.0357769527,53.824,2.0,4.0,1753.0,53.0 581 | 358265.5760983407,3790420.4756404296,147.578,3.0,6.0,1902.0,63.0 582 | 399168.6251872499,3750987.6037543,106.515,3.0,6.0,1666.0,68.0 583 | 409964.1156478816,3756801.921120386,196.816,2.0,4.0,1777.0,62.0 584 | 394790.0092845415,3772412.256698554,41.234,1.0,2.0,780.0,95.0 585 | 396971.3758232599,3780604.746811632,57.756,2.0,4.0,2624.0,93.0 586 | 389236.0942878336,3742470.458029941,75.935,1.0,2.0,1036.0,73.0 587 | 397239.8795683565,3744969.846239756,121.118,2.0,4.0,1552.0,67.0 588 | 376437.2594997477,3769611.256860656,35.181,2.0,4.0,1854.0,93.0 589 | 367073.95583055983,3784870.455079249,110.838,2.0,4.0,1862.0,91.0 590 | 349694.5534332504,3781432.705393328,163.17,2.0,4.0,1497.0,65.0 591 | 385714.9289426213,3788757.869212409,64.183,2.0,4.0,1516.0,57.0 592 | 391698.785539294,3745837.734840105,15.505,1.0,2.0,812.0,75.0 593 | 382396.3806586857,3782442.7936898367,100.375,1.0,2.0,1680.0,92.0 594 | 400822.9700365641,3763150.9607725535,266.7,2.0,4.0,1832.0,79.0 595 | 373633.5569958108,3741907.601970348,270.998,3.0,6.0,2190.0,64.0 596 | 378941.2528071515,3756695.391076558,29.666,1.0,2.0,961.0,77.0 597 | 375384.4153843032,3770871.505170331,210.022,3.0,6.0,2286.0,88.0 598 | 365224.0821857352,3762654.1853572056,200.0,1.0,2.0,1553.0,107.0 599 | 376487.19892177696,3768574.0443548337,51.346,1.0,2.0,1246.0,94.0 600 | 365223.1424433589,3778210.077521407,340.745,2.0,4.0,1644.0,58.0 601 | 417020.2659325378,3770703.589578049,40.568,1.0,2.0,1451.0,64.0 602 | 363217.97516746575,3767007.678738344,46.43,3.0,6.0,3800.0,94.0 603 | 399805.4837392443,3780146.7117667473,266.008,2.0,4.0,1642.0,77.0 604 | 380534.5000044347,3766721.616323358,23.703,1.0,2.0,2412.0,116.0 605 | 365304.4660767224,3797588.114520116,278.906,2.0,4.0,2084.0,65.0 606 | 367668.1121546572,3770907.473031152,296.376,5.0,10.0,3643.0,82.0 607 | 370850.24784424045,3749859.776740351,355.138,3.0,6.0,3020.0,66.0 608 | 398133.46701385686,3745198.555791033,233.164,3.0,6.0,2324.0,67.0 609 | 391697.00792075146,3778403.341526038,116.358,3.0,6.0,2227.0,91.0 610 | 411239.502504312,3769462.500261999,86.0,2.0,4.0,1082.0,59.0 611 | 395623.0948562369,3736688.868823944,248.525,2.0,4.0,1966.0,56.0 612 | 397067.7326278626,3746062.481269797,81.325,1.0,2.0,1082.0,66.0 613 | 357785.67721174675,3792721.744314039,245.69,2.0,4.0,1920.0,52.0 614 | 398216.0228594759,3740704.6384728015,117.623,2.0,4.0,1218.0,66.0 615 | 365724.5699661202,3793150.6226086463,224.448,1.0,2.0,1080.0,63.0 616 | 422101.49860182224,3762093.962422771,163.918,2.0,4.0,2000.0,38.0 617 | 370711.9159438366,3759179.7431678153,184.185,2.0,4.0,1796.0,73.0 618 | 398557.7207365802,3749134.7091161264,153.596,2.0,4.0,1512.0,41.0 619 | 386463.9080363861,3786152.97548036,94.194,1.0,2.0,718.0,95.0 620 | 374912.0716940761,3768707.574312069,136.759,4.0,8.0,2415.0,89.0 621 | 363852.6700644594,3762276.079015945,137.058,1.0,2.0,768.0,112.0 622 | 347060.4240579661,3781388.327642444,835.155,6.0,12.0,5522.0,38.0 623 | 389846.1446202507,3750552.940764735,44.306,1.0,2.0,1280.0,88.0 624 | 361334.3641242024,3785022.4439202007,256.143,3.0,6.0,2310.0,70.0 625 | 422399.1816736161,3771669.59068102,154.556,2.0,4.0,1635.0,42.0 626 | 389430.108475373,3758720.7480545794,55.467,1.0,2.0,1288.0,80.0 627 | 379567.7544355667,3736580.057545037,51.132,2.0,4.0,1430.0,56.0 628 | 362206.9668213866,3777930.978565622,154.065,3.0,6.0,2610.0,51.0 629 | 377779.36615657614,3770455.6569985705,468.59,5.0,10.0,4737.0,101.0 630 | 406558.1325324746,3771754.115976261,36.634,2.0,4.0,1215.0,53.0 631 | 391466.4566099239,3748296.23558233,90.187,1.0,2.0,1240.0,67.0 632 | 426595.828616558,3761493.165452675,251.988,3.0,6.0,3253.0,32.0 633 | 379357.75717060704,3757298.400983797,23.24,1.0,2.0,1149.0,88.0 634 | 370537.5245986456,3738371.179155483,512.438,4.0,8.0,3706.0,40.0 635 | 394490.65918191103,3782129.1137313135,106.644,2.0,4.0,1376.0,32.0 636 | 397059.02509963576,3742475.3120224304,133.681,2.0,4.0,1724.0,67.0 637 | 361367.35231285775,3792918.063061482,85.149,1.0,2.0,1136.0,65.0 638 | 361782.1799596505,3778719.293171561,304.183,3.0,6.0,2783.0,53.0 639 | 391268.1261954319,3761347.015893656,44.794,1.0,2.0,1416.0,87.0 640 | 359841.90941153263,3783379.0163071607,21.299,1.0,2.0,1123.0,66.0 641 | 412860.65180244576,3764279.743464517,53.663,2.0,4.0,996.0,61.0 642 | 375204.8677152348,3763579.0158532034,108.409,2.0,4.0,1955.0,58.0 643 | 399836.2890119898,3761737.205836054,43.944,2.0,4.0,1610.0,68.0 644 | 383817.421663197,3756796.0799775855,85.146,1.0,2.0,1208.0,72.0 645 | 387607.5023436992,3775542.352099071,219.589,2.0,4.0,1384.0,59.0 646 | 382230.4342089273,3757014.402479698,72.748,1.0,2.0,716.0,77.0 647 | 419861.661706205,3767859.93460803,388.773,3.0,6.0,2856.0,29.0 648 | 412834.1510048135,3767623.321133688,68.641,1.0,2.0,1241.0,64.0 649 | 382411.8088905526,3750592.142603017,89.968,1.0,2.0,878.0,62.0 650 | 367529.3082046589,3769560.4834722094,112.589,2.0,4.0,2104.0,85.0 651 | 382123.2743405186,3790895.311533197,152.913,2.0,4.0,2671.0,58.0 652 | 354351.0223553254,3787354.296635944,121.913,2.0,4.0,1743.0,61.0 653 | 357238.35686543304,3768635.811692776,147.341,2.0,4.0,1909.0,61.0 654 | 354370.43871774734,3782710.720898279,285.647,3.0,6.0,2360.0,57.0 655 | 375532.7200429974,3754233.904138166,27.935,2.0,4.0,1084.0,70.0 656 | 388638.3529569805,3754494.799774332,39.054,1.0,2.0,676.0,91.0 657 | 388793.1001393832,3778344.380266414,66.668,2.0,4.0,2840.0,93.0 658 | 353474.4700085964,3781424.9517955896,504.472,3.0,6.0,3327.0,28.0 659 | 373254.33992632944,3746322.0686751306,181.405,3.0,6.0,2177.0,43.0 660 | 380243.8427539945,3759491.416450853,49.929,1.0,2.0,1166.0,97.0 661 | 373198.5802317368,3745234.702615275,89.782,2.0,4.0,1188.0,58.0 662 | 428569.38356828335,3775848.9705754938,167.979,2.0,4.0,1778.0,40.0 663 | 402776.401304955,3762165.88022831,188.621,2.0,4.0,1964.0,75.0 664 | 372625.9247548074,3774089.181900194,715.764,8.0,16.0,6366.0,16.0 665 | 369386.62256018806,3785023.566768231,232.58,2.0,4.0,1428.0,69.0 666 | 370039.2162978535,3778147.5597642967,250.12,3.0,6.0,2314.0,38.0 667 | 392973.5428126671,3750747.198403067,84.19,1.0,2.0,1218.0,74.0 668 | 416887.2535113794,3771715.218979618,46.677,2.0,4.0,1597.0,64.0 669 | 369634.27293768886,3780798.472461127,60.449,2.0,4.0,1787.0,64.0 670 | 363715.9998588468,3764652.735945306,22.048,1.0,2.0,1038.0,73.0 671 | 385496.5618257136,3780779.8321025698,193.869,2.0,4.0,1967.0,89.0 672 | 384345.2839755964,3756364.0888215047,19.649,1.0,2.0,1351.0,73.0 673 | 408759.02247316064,3765306.7267486574,129.21,2.0,4.0,1944.0,78.0 674 | 393928.07931253023,3747797.803142512,70.0,1.0,2.0,1126.0,67.0 675 | 380061.8610491,3792499.5153839695,46.774,1.0,2.0,846.0,64.0 676 | 376352.3860362117,3751075.989725689,141.177,2.0,4.0,1722.0,66.0 677 | 399977.8245814901,3760847.3078062106,69.796,1.0,2.0,802.0,67.0 678 | 404651.5836714381,3773716.2363178,134.619,1.0,2.0,1154.0,69.0 679 | 385467.6985837137,3758199.88527122,59.6,1.0,2.0,1075.0,65.0 680 | 365097.7262374631,3782017.550059829,70.306,2.0,4.0,2036.0,65.0 681 | 371202.0491849757,3788350.342419809,102.037,2.0,4.0,1417.0,37.0 682 | 395504.6203181295,3768725.834985864,98.111,2.0,4.0,1243.0,61.0 683 | 382936.9294776306,3766736.5738693406,65.537,2.0,4.0,1603.0,93.0 684 | 400973.6323164302,3761034.790732421,163.759,2.0,4.0,1898.0,56.0 685 | 376833.3993061911,3767519.768466339,115.573,2.0,4.0,2880.0,95.0 686 | 366855.4191284858,3764712.156148309,40.073,2.0,4.0,1082.0,67.0 687 | 348641.83190344623,3783838.84702518,127.708,2.0,4.0,1160.0,57.0 688 | 382869.9933950761,3749127.774369221,162.446,2.0,4.0,2018.0,54.0 689 | 377359.7662970948,3763826.215078051,163.01,1.0,2.0,1365.0,81.0 690 | 409367.703950385,3760989.1848161113,214.881,3.0,6.0,2472.0,53.0 691 | 372149.59580285446,3771131.6155959503,151.9,2.0,4.0,1949.0,92.0 692 | 396533.2443440623,3768620.463601355,98.405,3.0,6.0,1452.0,66.0 693 | 415520.3683837734,3776161.019272055,133.582,3.0,6.0,1807.0,61.0 694 | 427621.27217993536,3770232.635151277,138.916,1.0,2.0,1396.0,53.0 695 | 367899.8023480918,3763955.8327726144,63.142,2.0,4.0,1090.0,69.0 696 | 392810.9230291805,3773456.289887756,10.745,1.0,2.0,934.0,96.0 697 | 427676.6590014817,3775478.6443180176,202.757,2.0,4.0,1452.0,40.0 698 | 411745.4671706022,3762493.720183936,155.403,3.0,6.0,1812.0,62.0 699 | 423922.114589847,3774088.696175332,26.279,1.0,2.0,1162.0,58.0 700 | 359241.54005068867,3786737.587520341,192.999,2.0,4.0,1824.0,33.0 701 | 376771.5014314136,3772324.3931493415,710.675,7.0,14.0,4405.0,3.0 702 | 391751.26923712937,3738988.195019605,8.094,1.0,2.0,896.0,94.0 703 | 385735.0217758302,3745932.3224574695,86.707,2.0,4.0,1362.0,52.0 704 | 370003.7440684793,3790443.555097307,141.0,3.0,6.0,1766.0,67.0 705 | 372430.0967162079,3747314.506008684,79.458,2.0,4.0,1052.0,62.0 706 | 393400.4835982541,3752842.820423129,116.713,1.0,2.0,1230.0,106.0 707 | 351988.2836883704,3792724.598360303,429.764,3.0,6.0,3946.0,11.0 708 | 394936.4673522141,3746952.7710073353,70.852,1.0,2.0,1176.0,67.0 709 | 404552.96838659234,3758477.921689061,34.326,1.0,2.0,676.0,70.0 710 | 396409.61703090667,3780375.028916788,68.48,1.0,2.0,1890.0,105.0 711 | 431594.1770739771,3771567.041545896,91.634,2.0,4.0,1574.0,58.0 712 | 409223.5473086118,3776880.774220358,20.063,1.0,2.0,972.0,68.0 713 | 387044.8466179573,3786787.565646472,185.384,2.0,4.0,1839.0,87.0 714 | 389169.2879004059,3752483.606184533,91.754,2.0,4.0,1224.0,52.0 715 | 374105.56231266144,3742491.817514797,37.629,2.0,4.0,1590.0,57.0 716 | 403635.6754793976,3769109.554179684,109.283,2.0,4.0,1648.0,77.0 717 | 395287.4489325143,3773874.612834706,107.28,2.0,4.0,1660.0,94.0 718 | 359749.7810177752,3780447.325368993,76.661,3.0,6.0,2359.0,60.0 719 | 373943.6541247304,3771893.168340466,90.801,3.0,6.0,1094.0,93.0 720 | 391966.7845599754,3776470.8497046377,135.684,2.0,4.0,1540.0,57.0 721 | 382183.24702150165,3754309.254719218,74.0,1.0,2.0,1048.0,69.0 722 | 379594.91351464496,3754210.324155625,14.724,2.0,4.0,1745.0,104.0 723 | 388791.0152428333,3781872.08699303,436.557,3.0,6.0,2456.0,8.0 724 | 395672.7541865173,3746861.383229175,90.845,2.0,4.0,1442.0,67.0 725 | 346629.2157538729,3775726.2969487966,271.376,2.0,4.0,2052.0,53.0 726 | 410361.4039211815,3761135.750747921,209.781,2.0,4.0,2124.0,37.0 727 | 385254.7660688516,3753087.727545568,121.4,1.0,2.0,1160.0,63.0 728 | 376702.5772466335,3762102.5950269047,57.358,1.0,2.0,1356.0,68.0 729 | 406075.6952447248,3753832.7493211874,87.13,1.0,2.0,1114.0,61.0 730 | 412836.8279327768,3765641.846234752,160.5,2.0,4.0,1252.0,55.0 731 | 429911.0481811593,3778125.113930076,205.831,3.0,6.0,1907.0,30.0 732 | 368752.2203075064,3774888.337242091,764.513,5.0,10.0,5306.0,63.0 733 | 361088.7008105415,3791620.6408949634,290.952,3.0,6.0,2415.0,57.0 734 | 364488.1689430737,3790024.644591718,124.286,2.0,4.0,1660.0,30.0 735 | 370092.5840871701,3749936.871378192,38.187,1.0,2.0,912.0,71.0 736 | 350976.16083852027,3786198.525877036,106.37,2.0,4.0,1358.0,61.0 737 | 372888.6899499599,3783141.9947966943,77.717,1.0,2.0,1070.0,97.0 738 | 370458.6249604244,3780662.523773943,69.219,2.0,4.0,1760.0,62.0 739 | 397273.1972378846,3749330.265060037,83.119,3.0,6.0,2227.0,51.0 740 | 361886.096867384,3767314.661483212,176.849,4.0,8.0,3054.0,90.0 741 | 395212.5169875186,3781750.843942177,259.953,2.0,4.0,1008.0,95.0 742 | 370497.3407828959,3784628.8538365937,111.571,2.0,4.0,1800.0,64.0 743 | 377453.6471261083,3777063.443846441,410.29,3.0,6.0,2460.0,53.0 744 | 393027.5919782807,3781121.675226111,12.45,1.0,2.0,1168.0,110.0 745 | 391691.0677821605,3760315.112862816,18.818,1.0,2.0,938.0,94.0 746 | 390254.14916912734,3777575.186136621,268.036,2.0,4.0,2112.0,96.0 747 | 389678.89080721897,3778883.8214654136,173.458,3.0,6.0,1914.0,65.0 748 | 383952.5887276082,3754676.16622114,57.951,1.0,2.0,801.0,73.0 749 | 398544.5805234424,3759862.480072264,178.264,3.0,6.0,1836.0,66.0 750 | 378419.16718208406,3791283.467483222,115.774,2.0,4.0,1426.0,63.0 751 | 417361.85832207615,3775531.549116284,72.486,2.0,4.0,1145.0,63.0 752 | 376866.3076975321,3742451.853042217,235.903,3.0,6.0,2517.0,53.0 753 | 366616.885202524,3797021.804344325,177.668,1.0,2.0,1416.0,70.0 754 | 395976.12106446805,3735996.91083874,389.332,5.0,10.0,3976.0,55.0 755 | 389138.9030066819,3757975.897444977,42.083,1.0,2.0,768.0,90.0 756 | 370309.1761548526,3764748.224088117,332.134,4.0,8.0,2871.0,90.0 757 | 376606.6571837642,3781999.068456039,91.238,2.0,4.0,1356.0,81.0 758 | 417909.382791637,3775376.9445400406,80.668,1.0,2.0,945.0,63.0 759 | 396473.0490258468,3743687.8781698607,33.52,2.0,4.0,1199.0,75.0 760 | 400859.9764073895,3753955.3382282914,101.139,2.0,4.0,1080.0,65.0 761 | 360103.0967418384,3768167.5664240015,840.42,2.0,4.0,3483.0,29.0 762 | 407965.8623379365,3770535.608748732,67.365,1.0,2.0,996.0,65.0 763 | 377581.7921937498,3742364.888351449,162.0,2.0,4.0,1920.0,50.0 764 | 422494.39266533696,3779145.4853232526,383.552,3.0,6.0,3020.0,45.0 765 | 379302.51004057017,3764597.8694416494,77.0,1.0,2.0,1397.0,103.0 766 | 355551.5260962309,3768486.654049108,592.906,3.0,6.0,3474.0,52.0 767 | 400716.4856355018,3777266.286480336,308.727,3.0,6.0,5219.0,66.0 768 | 394350.1168309752,3753577.2209236417,154.794,1.0,2.0,1761.0,68.0 769 | 350372.5254920757,3790878.2595834592,369.729,4.0,8.0,2553.0,12.0 770 | 363185.2464732349,3788114.787361981,193.654,3.0,6.0,2421.0,66.0 771 | 369407.6793528834,3758797.243903287,82.001,2.0,4.0,1610.0,57.0 772 | 432179.27436516446,3766742.392511401,70.635,2.0,4.0,1209.0,47.0 773 | 416942.8741479215,3773074.946976836,76.533,2.0,4.0,1148.0,63.0 774 | 362461.7707900833,3768014.574744858,840.518,4.0,8.0,4636.0,90.0 775 | 394551.18358285865,3766063.6126861065,207.371,4.0,8.0,2835.0,68.0 776 | 406327.9796042189,3766589.174545258,308.331,2.0,4.0,1879.0,56.0 777 | 368312.4778409352,3769724.658074735,770.86,4.0,8.0,3198.0,27.0 778 | 377588.8426181822,3748323.71353262,47.819,2.0,4.0,1473.0,61.0 779 | 376729.3569467211,3770949.442110578,621.32,3.0,6.0,4543.0,91.0 780 | 350795.8797804816,3779787.225384933,171.794,3.0,6.0,2530.0,48.0 781 | 389382.23245100456,3749822.397208282,61.254,2.0,4.0,1788.0,72.0 782 | 402530.2904956905,3746837.991845466,88.969,3.0,6.0,2175.0,45.0 783 | 404326.56343041017,3758586.110411979,79.749,2.0,4.0,1376.0,88.0 784 | 390615.4411367808,3744616.044225412,148.0,2.0,4.0,1904.0,80.0 785 | 368901.2062874479,3787787.7063379623,502.5,2.0,4.0,2212.0,65.0 786 | 397243.4103101741,3739555.885923781,43.069,1.0,2.0,1112.0,65.0 787 | 404705.47837076377,3766186.32058972,87.012,1.0,2.0,1235.0,69.0 788 | 395911.1416987745,3738378.5406176,239.807,2.0,4.0,2366.0,63.0 789 | 383326.8344472123,3740373.317826728,115.098,2.0,4.0,1433.0,65.0 790 | 356638.6132091537,3794595.212925062,386.0,3.0,6.0,3050.0,47.0 791 | 398587.2521713438,3780405.082225909,98.254,2.0,4.0,1777.0,81.0 792 | 411878.7827990927,3771079.343972813,117.326,2.0,4.0,1086.0,59.0 793 | 389818.0180409435,3775643.3343133824,197.883,2.0,4.0,1114.0,97.0 794 | 382448.2922181306,3759071.0869986834,37.182,1.0,2.0,744.0,92.0 795 | 387176.0609650961,3744012.6321473615,89.096,2.0,4.0,1201.0,76.0 796 | 368761.5551103166,3764538.658910006,63.199,3.0,6.0,1908.0,89.0 797 | 421394.8569412595,3764618.682239624,171.111,2.0,4.0,2189.0,53.0 798 | 385889.1822413965,3755695.0489933854,32.709,1.0,2.0,608.0,95.0 799 | 388338.05036613136,3782300.341471917,73.5,2.0,4.0,2013.0,61.0 800 | 394602.0488318271,3773468.477185661,99.922,1.0,2.0,1556.0,91.0 801 | 411619.1973889044,3767529.594660226,67.712,2.0,4.0,1116.0,62.0 802 | 402675.2711492422,3752654.264272459,100.354,2.0,4.0,1293.0,43.0 803 | 370406.6210550639,3760114.567396509,157.001,2.0,4.0,1828.0,67.0 804 | 377803.5553713169,3757402.931459159,57.213,1.0,2.0,1201.0,70.0 805 | 354636.203099897,3784859.63217192,139.08,2.0,4.0,1680.0,64.0 806 | 366322.83252798894,3793621.232353652,89.626,1.0,2.0,1030.0,69.0 807 | 358696.2362486654,3788899.996209367,99.088,1.0,2.0,971.0,77.0 808 | 366093.9922242989,3762461.1561386506,246.649,4.0,8.0,2720.0,70.0 809 | 404561.9550536943,3780779.8284697896,203.05,2.0,4.0,1778.0,67.0 810 | 355239.0414188568,3790457.853726503,55.479,2.0,4.0,1393.0,59.0 811 | 400781.3780216461,3742696.528305745,299.86,3.0,6.0,2406.0,53.0 812 | 418001.4008070365,3767837.534074741,463.2,5.0,10.0,4268.0,16.0 813 | 368916.06181922654,3796417.515043349,121.285,2.0,4.0,1448.0,62.0 814 | 403221.9691646866,3770224.094880568,117.888,2.0,4.0,1218.0,60.0 815 | 369894.7289026128,3750606.366026829,327.673,2.0,4.0,2539.0,54.0 816 | 387567.9414733914,3744797.604972244,112.36,2.0,4.0,1469.0,66.0 817 | 387595.6730753223,3759527.4137896136,144.819,1.0,2.0,1989.0,89.0 818 | 410243.4088065898,3767970.733178389,91.003,2.0,4.0,1430.0,61.0 819 | 400769.89272781246,3775691.832229029,150.117,2.0,4.0,1721.0,69.0 820 | 379718.45801163645,3747550.369981996,108.779,1.0,2.0,1110.0,67.0 821 | 434631.51834040286,3772306.306116468,65.379,2.0,4.0,1664.0,64.0 822 | 368544.63063486654,3786589.58502654,128.8,2.0,4.0,1962.0,44.0 823 | 397630.816302246,3743124.432041564,95.916,2.0,4.0,1814.0,64.0 824 | 359767.66705764947,3786980.8369402094,57.651,2.0,4.0,1200.0,63.0 825 | 390299.3152815859,3755392.1540871216,99.315,2.0,4.0,1226.0,77.0 826 | 391541.60474643926,3764467.63838726,24.444,1.0,2.0,836.0,93.0 827 | 398262.756701703,3776585.71087544,697.533,2.0,4.0,3670.0,91.0 828 | 403979.7759501071,3774032.351151295,123.682,2.0,4.0,1123.0,56.0 829 | 380056.5746964473,3792086.659298355,28.975,1.0,2.0,1132.0,70.0 830 | 395781.26124336594,3746276.876105816,78.24,2.0,4.0,1026.0,67.0 831 | 383993.1065334262,3753082.323819181,114.841,1.0,2.0,832.0,73.0 832 | 373146.7813650415,3741031.809957495,475.964,5.0,10.0,3840.0,26.0 833 | 399133.00706566847,3771161.097200028,19.441,1.0,2.0,1187.0,71.0 834 | 372348.7418499974,3787238.719711002,200.0,3.0,6.0,1662.0,68.0 835 | 372419.1691092171,3786963.3595328657,205.628,2.0,4.0,1640.0,67.0 836 | 420510.49783066375,3766172.4517774456,241.397,3.0,6.0,2201.0,29.0 837 | 373511.5038139237,3782948.0323811714,134.101,1.0,2.0,1267.0,62.0 838 | 365805.6872222856,3793169.314358407,114.249,1.0,2.0,1722.0,66.0 839 | 371650.8593885279,3767508.021659616,189.113,1.0,2.0,1516.0,68.0 840 | 405068.9581388884,3774935.67064217,470.966,5.0,10.0,4894.0,28.0 841 | 412992.0222648387,3768126.4329479374,85.714,2.0,4.0,1138.0,61.0 842 | 379306.81657158525,3738652.021090595,235.511,3.0,6.0,2132.0,55.0 843 | 367591.31106599024,3793895.255825118,31.568,1.0,2.0,808.0,73.0 844 | 377453.5337467177,3783642.7849824736,124.3,1.0,2.0,1006.0,78.0 845 | 400740.615134073,3751717.264111436,207.8,3.0,6.0,1991.0,41.0 846 | 381193.9066899353,3782152.029442136,19.874,1.0,2.0,906.0,94.0 847 | 372158.4372976456,3747589.98871407,34.149,2.0,4.0,1490.0,48.0 848 | 386150.2069206253,3755747.030490547,40.568,1.0,2.0,684.0,103.0 849 | 369898.8660262572,3772965.388879215,1997.979,4.0,8.0,3458.0,46.0 850 | 370407.7077917216,3782406.6907808166,266.11,3.0,6.0,2245.0,69.0 851 | 400047.2364362247,3775893.76965123,220.389,2.0,4.0,2276.0,70.0 852 | 384017.0658273244,3743459.3722423767,88.825,1.0,2.0,1210.0,62.0 853 | 371670.792381825,3794509.9358923417,88.322,2.0,4.0,1000.0,34.0 854 | 394651.0695874402,3769165.8380897,66.839,1.0,2.0,995.0,64.0 855 | 381748.3494015719,3771668.763307446,18.03,2.0,4.0,1112.0,95.0 856 | 373039.038413559,3746594.887485893,268.528,2.0,4.0,1826.0,45.0 857 | 384886.2311426338,3751381.628597304,19.441,1.0,2.0,1109.0,67.0 858 | 397757.399033556,3737095.1521103326,155.21,3.0,6.0,1978.0,57.0 859 | 368485.0468236965,3792528.910385644,199.474,1.0,2.0,1094.0,70.0 860 | 398001.9676353952,3755638.77522469,49.267,2.0,4.0,1866.0,63.0 861 | 420181.5861196264,3773378.64990344,103.07,2.0,4.0,1356.0,56.0 862 | 373854.4746292009,3742930.1130403634,44.709,3.0,6.0,1561.0,62.0 863 | 380735.02620925376,3791613.501170103,23.175,1.0,2.0,1031.0,79.0 864 | 389723.9927968617,3740933.176645736,108.329,2.0,4.0,1946.0,78.0 865 | 388261.7566157887,3781286.901764013,482.348,5.0,10.0,3700.0,24.0 866 | 393877.0972846195,3783342.321269552,207.0,2.0,4.0,1484.0,82.0 867 | 380807.6377721115,3784961.826939297,110.955,1.0,2.0,1023.0,92.0 868 | 416904.9416506914,3774056.911085111,28.975,1.0,2.0,1027.0,62.0 869 | 390437.1254573327,3761647.825854392,29.827,1.0,2.0,1198.0,90.0 870 | 397560.9795628095,3759957.573114062,57.908,1.0,2.0,1095.0,67.0 871 | 416447.6463745696,3763634.689482786,119.0,2.0,4.0,1025.0,57.0 872 | 409990.0648887417,3772522.738522073,212.6,3.0,6.0,1509.0,10.0 873 | 371307.3183468087,3778010.349252736,223.444,5.0,10.0,4625.0,64.0 874 | 379484.9511688682,3731549.1456887103,84.697,1.0,2.0,1093.0,64.0 875 | 408356.6661592954,3762718.8934369097,353.86,3.0,6.0,2616.0,70.0 876 | 399146.8468412448,3753847.079658561,138.653,1.0,2.0,1138.0,65.0 877 | 399301.743430994,3778484.8067504456,132.971,1.0,2.0,1520.0,79.0 878 | 407565.06098359707,3753978.366141609,89.096,3.0,6.0,1653.0,56.0 879 | 397232.9416577149,3743280.976670995,114.2,2.0,4.0,1781.0,67.0 880 | 357578.9388227598,3779919.0189776807,148.039,3.0,6.0,2655.0,51.0 881 | 349902.01892678364,3786008.2068287954,259.968,3.0,6.0,2255.0,37.0 882 | 408460.5019202149,3753988.981130945,109.811,2.0,4.0,1436.0,57.0 883 | 372273.0322343875,3768194.114726728,187.241,2.0,4.0,1790.0,82.0 884 | 399772.0375805615,3757384.2738343207,33.652,2.0,4.0,1539.0,67.0 885 | 379539.6079877904,3756240.0431056144,50.781,2.0,4.0,1420.0,76.0 886 | 379682.723447927,3754463.627148961,31.203,2.0,4.0,1390.0,58.0 887 | 420443.8314352261,3774741.408912695,106.103,3.0,6.0,1974.0,40.0 888 | 346956.5011828485,3784179.4118363024,159.199,3.0,6.0,3078.0,50.0 889 | 364568.0709720908,3776956.358568991,840.729,5.0,10.0,4961.0,40.0 890 | 358044.5753242315,3785755.3211753904,34.149,1.0,2.0,1276.0,67.0 891 | 430162.52003676665,3770774.5846153297,131.547,2.0,4.0,1420.0,81.0 892 | 387048.8602639118,3776910.622085917,128.575,1.0,2.0,917.0,93.0 893 | 380463.24062700936,3752864.938641829,43.074,1.0,2.0,1080.0,70.0 894 | 329490.6538670326,3767272.635228912,1131.771,4.0,8.0,3213.0,69.0 895 | 392826.6578832294,3782353.6672301833,88.057,1.0,2.0,1064.0,80.0 896 | 394906.3734396361,3758551.844627777,80.386,2.0,4.0,1536.0,65.0 897 | 386711.7420077726,3785349.118876581,81.108,2.0,4.0,1497.0,62.0 898 | 395539.27616157656,3768061.932949096,126.379,2.0,4.0,1498.0,64.0 899 | 389996.9835111892,3754725.925978198,106.798,1.0,2.0,1059.0,69.0 900 | 375933.221574029,3781991.4069724753,99.492,1.0,2.0,809.0,64.0 901 | 398402.1508087532,3742306.416106316,94.2,2.0,4.0,1340.0,64.0 902 | 370805.3255486023,3740678.411084504,123.391,4.0,8.0,2417.0,65.0 903 | 378887.7339281912,3781463.872096057,73.335,2.0,4.0,1785.0,73.0 904 | 365039.0660000796,3770382.481158813,146.103,4.0,8.0,2912.0,85.0 905 | 393391.99004287866,3751345.005553715,25.451,1.0,2.0,640.0,70.0 906 | 390603.9001881557,3742797.661670685,107.0,1.0,2.0,1110.0,72.0 907 | 381783.4626376582,3789706.972188048,64.46,2.0,4.0,1697.0,56.0 908 | 410499.99345481175,3772735.0183672495,74.79,2.0,4.0,1367.0,68.0 909 | 383167.8031317669,3763579.119617964,75.0,1.0,2.0,784.0,28.0 910 | 414450.5341953798,3771434.37566118,235.583,3.0,6.0,1914.0,63.0 911 | 353501.1021729638,3767622.993127313,128.268,3.0,6.0,1753.0,61.0 912 | 398430.015990601,3782482.414353925,91.298,3.0,6.0,2218.0,77.0 913 | 378716.8060845995,3736217.643474907,92.021,2.0,4.0,1403.0,44.0 914 | 356571.27668042347,3791243.788695686,181.59,4.0,8.0,3528.0,52.0 915 | 350216.15808974294,3779439.590716875,503.225,3.0,6.0,2739.0,48.0 916 | 418185.3336960148,3769878.465425152,228.477,4.0,8.0,2965.0,65.0 917 | 403698.5604044276,3756081.353955595,113.014,2.0,4.0,1370.0,45.0 918 | 404684.40483839647,3755338.26683234,161.928,3.0,6.0,2785.0,62.0 919 | 367914.0865013831,3792332.079531692,183.515,2.0,4.0,2405.0,48.0 920 | 372234.9850096645,3775082.259234733,131.982,1.0,2.0,576.0,63.0 921 | 421346.5110519148,3761680.0446775192,416.207,3.0,6.0,2984.0,34.0 922 | 363112.9298623955,3769004.35851269,1238.248,7.0,14.0,5227.0,95.0 923 | 367273.19141180353,3763318.425933881,207.111,2.0,4.0,1170.0,76.0 924 | 386978.2563855096,3752944.170892173,91.5,1.0,2.0,912.0,95.0 925 | 378533.1900623242,3780573.510118093,177.85,2.0,4.0,2048.0,75.0 926 | 367480.3394843272,3765812.731606335,141.224,2.0,4.0,1796.0,66.0 927 | 396866.6092120827,3780180.918318888,199.029,2.0,4.0,1593.0,70.0 928 | 427973.6395836698,3776106.227075753,185.252,2.0,4.0,1609.0,46.0 929 | 392723.6980977564,3784403.910497273,86.041,1.0,2.0,1150.0,67.0 930 | 379016.0551757933,3738953.589928336,317.1,2.0,4.0,1756.0,69.0 931 | 377028.8559710968,3759690.3213546514,49.493,2.0,4.0,1115.0,92.0 932 | 364704.2905711432,3761500.5536334673,773.752,3.0,6.0,2052.0,93.0 933 | 374029.3727727073,3782577.1706060176,24.0,2.0,4.0,1385.0,80.0 934 | 371446.9504721064,3750103.115888325,112.578,2.0,4.0,1778.0,64.0 935 | 353161.84207971446,3785279.790043123,34.492,1.0,2.0,768.0,68.0 936 | 396389.2313444549,3767895.756897377,68.677,2.0,4.0,1428.0,63.0 937 | 357904.73786319257,3789805.1040681456,158.48,3.0,6.0,2060.0,56.0 938 | 408410.6956554059,3751279.125280533,108.416,2.0,4.0,1357.0,59.0 939 | 368066.9403685092,3781891.000460555,363.086,3.0,6.0,2453.0,57.0 940 | 402564.94404466485,3760233.796052036,130.903,3.0,6.0,1624.0,64.0 941 | 350003.6144424546,3784538.803475452,190.3,2.0,4.0,1853.0,60.0 942 | 356563.0349066344,3779360.98944084,286.04,4.0,8.0,2597.0,50.0 943 | 383385.1113225222,3780823.9682759983,136.148,2.0,4.0,1242.0,94.0 944 | 362808.8597842431,3789625.1334719504,150.073,2.0,4.0,1804.0,58.0 945 | 365221.83346369816,3771086.843984265,337.583,4.0,8.0,2268.0,80.0 946 | 389361.6268906118,3765988.307344564,118.257,2.0,4.0,1170.0,35.0 947 | 390925.72447870014,3761063.277066745,73.49,1.0,2.0,1465.0,96.0 948 | 390399.6956754433,3776665.627952635,123.441,1.0,2.0,1312.0,107.0 949 | 398609.1075643916,3757690.18857312,122.077,2.0,4.0,1346.0,67.0 950 | 409997.6523221368,3770503.8117865967,52.096,2.0,4.0,1056.0,69.0 951 | 414952.7244098897,3771745.88214832,101.036,2.0,4.0,1209.0,62.0 952 | 390509.2058889546,3743361.0052277674,148.148,4.0,8.0,1849.0,108.0 953 | 394608.6474394821,3757023.6330334544,167.238,2.0,4.0,1871.0,65.0 954 | 360090.6584203566,3793419.115412459,190.762,3.0,6.0,2316.0,63.0 955 | 378692.8921213432,3741030.1460460415,47.194,2.0,4.0,1979.0,53.0 956 | 372339.6458792223,3759061.176109091,116.505,2.0,4.0,1670.0,70.0 957 | 360104.48933968524,3783357.1339716576,185.728,2.0,4.0,1278.0,66.0 958 | 410025.68510861584,3764493.0399253257,304.575,4.0,8.0,4185.0,9.0 959 | 361303.92056639993,3795473.525557953,133.385,2.0,4.0,1878.0,57.0 960 | 396886.6147929776,3764383.110056237,89.647,2.0,4.0,1504.0,81.0 961 | 417296.0925490428,3765212.432267635,150.363,2.0,4.0,1433.0,39.0 962 | 374204.9976863889,3778104.3829660183,47.402,1.0,2.0,1232.0,90.0 963 | 379386.7178934968,3762799.989769128,16.542,1.0,2.0,1630.0,106.0 964 | 376870.1822116556,3772369.242680431,132.394,2.0,4.0,1458.0,94.0 965 | 375097.663500008,3786754.968206545,102.286,1.0,2.0,974.0,61.0 966 | 389222.3005610788,3757417.863741805,116.89,1.0,2.0,1006.0,76.0 967 | 370112.7803759815,3751826.492713768,1195.05,6.0,12.0,3973.0,10.0 968 | 400743.16169406375,3777478.489687623,95.867,3.0,6.0,2742.0,67.0 969 | 369970.0871258064,3750563.85418331,1061.039,5.0,10.0,4371.0,16.0 970 | 435453.93267088255,3776377.226248687,478.033,4.0,8.0,3723.0,16.0 971 | 395517.29914466257,3741647.9542882782,261.0,3.0,6.0,2012.0,65.0 972 | 353359.18519814406,3786224.556897612,177.479,2.0,4.0,2311.0,66.0 973 | 359486.0597940482,3767498.3518686574,1286.597,5.0,10.0,3822.0,66.0 974 | 364170.72859002656,3779438.974941021,206.233,4.0,8.0,3432.0,56.0 975 | 371196.0782367833,3788425.403148667,134.964,1.0,2.0,1068.0,65.0 976 | 361491.2780816312,3793096.920196276,104.0,2.0,4.0,1184.0,64.0 977 | 373408.0290705234,3759738.469100284,273.845,3.0,6.0,2835.0,67.0 978 | 384634.9128814682,3759001.618509803,56.636,1.0,2.0,1149.0,70.0 979 | 398950.1206591943,3768447.12578601,68.48,2.0,4.0,1634.0,53.0 980 | 419680.1077492923,3763809.283859933,101.046,2.0,4.0,1326.0,52.0 981 | 359128.5730894191,3792716.0923340577,168.381,3.0,6.0,2003.0,57.0 982 | 386529.5559950643,3782846.1475082007,149.285,3.0,6.0,1893.0,68.0 983 | 373252.1930529477,3759956.4939115862,170.0,3.0,6.0,2077.0,64.0 984 | 361566.4121938904,3791170.552543719,223.707,4.0,8.0,3117.0,61.0 985 | 384742.4265135023,3764838.3096724898,75.867,1.0,2.0,1010.0,104.0 986 | 377890.0023150542,3752585.933147154,180.0,2.0,4.0,1291.0,61.0 987 | 363482.8915436983,3785736.5602103258,154.294,2.0,4.0,1311.0,67.0 988 | 338175.5410621052,3781822.257427508,90.337,3.0,6.0,2347.0,40.0 989 | 375896.8858566599,3767651.4754396966,177.567,1.0,2.0,1367.0,86.0 990 | 359659.0183384856,3784668.537543018,107.446,2.0,4.0,1679.0,45.0 991 | 365804.7619241448,3795705.826682048,149.772,3.0,6.0,2206.0,55.0 992 | 422028.3254515887,3771085.367373166,369.287,3.0,6.0,2701.0,48.0 993 | 362856.285222525,3763366.6780661726,265.6,3.0,6.0,1884.0,114.0 994 | 397608.72847902274,3774962.332624095,195.01,2.0,4.0,1972.0,87.0 995 | 408879.95124067634,3780206.461358153,73.622,1.0,2.0,1129.0,67.0 996 | 388296.0133039427,3760517.360261932,103.0,2.0,4.0,1232.0,95.0 997 | 420383.7526691944,3778271.749277607,128.632,2.0,4.0,1576.0,96.0 998 | 375790.4881537063,3750833.447924287,114.792,3.0,6.0,1635.0,66.0 999 | 366723.0664134448,3765734.2047621454,465.0,2.0,4.0,2155.0,67.0 1000 | 388762.7638539943,3781813.863003311,86.55,2.0,4.0,1813.0,48.0 1001 | 397042.7919903408,3758626.643876979,88.0,1.0,2.0,1283.0,67.0 1002 | -------------------------------------------------------------------------------- /fastgwr/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ziqi-Li/FastGWR/a765df41bd75197e7d3ed2c0f54bb47875525ece/fastgwr/.DS_Store -------------------------------------------------------------------------------- /fastgwr/FastGWR.py: -------------------------------------------------------------------------------- 1 | #FastGWR Class 2 | #Author: Ziqi Li 3 | #Email: liziqi1992@gmail.com 4 | 5 | from mpi4py import MPI 6 | import math 7 | import numpy as np 8 | from scipy.spatial.distance import cdist,pdist 9 | import argparse 10 | 11 | 12 | class FastGWR: 13 | """ 14 | FastGWR class. 15 | 16 | Parameters 17 | ---------- 18 | comm : MPI communicators initialized with mpi4py. 19 | parser : The parser object contains model arguments. 20 | 21 | Attributes 22 | ---------- 23 | comm : MPI communicators initialized with mpi4py. 24 | parser : The parser object contains model arguments. 25 | y : array 26 | n*1, dependent variable 27 | 28 | X : array 29 | n*k, independent variables (include constant, if any) 30 | coords : array 31 | n*2, collection of n sets of (x,y) coordinates used for 32 | calibration locations 33 | n : int 34 | number of observations 35 | k : int 36 | number of independent variables 37 | minbw : float 38 | lower-bound bandwidth in the search range 39 | maxbw : float 40 | upper-bound bandwidth in the search range 41 | bw : float 42 | user-specified bandwidth 43 | 44 | 45 | """ 46 | def __init__(self, comm, parser): 47 | """ 48 | Class Initialization 49 | """ 50 | self.comm = comm 51 | self.parser = parser 52 | self.X = None 53 | self.y = None 54 | self.coords = None 55 | self.n = None 56 | self.k = None 57 | self.iter = None 58 | self.minbw = None 59 | self.maxbw = None 60 | self.bw = None 61 | 62 | self.parse_gwr_args() 63 | 64 | 65 | if self.comm.rank ==0: 66 | self.read_file() 67 | self.k = self.X.shape[1] 68 | self.iter = np.arange(self.n) 69 | 70 | #broadcast data to other nodes 71 | self.X = comm.bcast(self.X,root=0) 72 | self.y = comm.bcast(self.y,root=0) 73 | self.coords = comm.bcast(self.coords,root=0) 74 | self.iter = comm.bcast(self.iter,root=0) 75 | self.n = comm.bcast(self.n,root=0) 76 | self.k = comm.bcast(self.k,root=0) 77 | 78 | #split arrays to chunks for parralel processing 79 | m = int(math.ceil(float(len(self.iter)) / self.comm.size)) 80 | self.x_chunk = self.iter[self.comm.rank*m:(self.comm.rank+1)*m] 81 | 82 | 83 | def parse_gwr_args(self): 84 | """ 85 | Parsing arguments from the command line 86 | """ 87 | parser_arg = self.parser.parse_args() 88 | self.fname = parser_arg.data 89 | self.fout = parser_arg.out 90 | self.fixed = parser_arg.fixed 91 | self.constant = parser_arg.constant 92 | self.estonly = parser_arg.estonly 93 | 94 | if parser_arg.bw: 95 | if self.fixed: 96 | self.bw = float(parser_arg.bw) 97 | else: 98 | self.bw = int(parser_arg.bw) 99 | 100 | if parser_arg.minbw: 101 | if self.fixed: 102 | self.minbw = float(parser_arg.minbw) 103 | else: 104 | self.minbw = int(parser_arg.minbw) 105 | 106 | if self.comm.rank == 0: 107 | print("-"*60,flush=True) 108 | print("Starting FastGWR with",self.comm.size,"Processors",flush=True) 109 | if self.fixed: 110 | print("Spatial Kernel: Fixed Gaussian",flush=True) 111 | else: 112 | print("Spatial Kernel: Adaptive Bisquare",flush=True) 113 | 114 | print("Data Input Path:",self.fname,flush=True) 115 | print("Output Result Path:",self.fout,flush=True) 116 | print("Intercept:",self.constant,flush=True) 117 | 118 | 119 | def read_file(self): 120 | """ 121 | Read file from the path 122 | """ 123 | input = np.genfromtxt(self.fname, dtype=float, delimiter=',',skip_header=True) 124 | #Converting things into matrices 125 | self.y = input[:,2].reshape(-1,1) 126 | self.n = input.shape[0] 127 | if self.constant: 128 | self.X = np.hstack([np.ones((self.n,1)),input[:,3:]]) 129 | else: 130 | self.X = input[:,3:] 131 | self.coords = input[:,:2] 132 | 133 | 134 | def set_search_range(self,init_mgwr=False,mgwr=False): 135 | """ 136 | Define the search range in golden section 137 | """ 138 | if self.fixed: 139 | max_dist = np.max(np.array([np.max(cdist([self.coords[i]],self.coords)) for i in range(self.n)])) 140 | self.maxbw = max_dist*2 141 | 142 | if self.minbw is None: 143 | min_dist = np.min(np.array([np.min(np.delete( cdist(self.coords[[i]],self.coords),i)) for i in range(self.n)])) 144 | 145 | self.minbw = min_dist/2 146 | 147 | else: 148 | self.maxbw = self.n 149 | 150 | if self.minbw is None: 151 | self.minbw = 40 + 2 * self.k 152 | if not init_mgwr and mgwr: 153 | self.minbw = 40 + 2 154 | 155 | 156 | def build_wi(self, i, bw): 157 | """ 158 | Build the local weight matrix for location i 159 | """ 160 | 161 | dist = cdist([self.coords[i]], self.coords).reshape(-1) 162 | #dist = np.sqrt(np.sum((self.coords[i] - self.coords)**2, axis=1)).reshape(-1) 163 | 164 | #fixed gaussian 165 | if self.fixed: 166 | wi = np.exp(-0.5*(dist/bw)**2).reshape(-1,1) 167 | #adaptive bisquare 168 | else: 169 | maxd = np.partition(dist, int(bw)-1)[int(bw)-1]*1.0000001 170 | zs = dist/maxd 171 | zs[zs>=1] = 1 172 | wi = ((1-(zs)**2)**2).reshape(-1,1) 173 | 174 | return wi 175 | 176 | 177 | def local_fit(self, i, y, X, bw, final=False, mgwr=False): 178 | """ 179 | Fit the local regression model at location i 180 | """ 181 | 182 | wi = self.build_wi(i, bw) 183 | #Last fitting, return more stats 184 | if final: 185 | xT = (X * wi).T 186 | try: 187 | xtx_inv_xt = np.dot(np.linalg.inv(np.dot(xT, X)), xT) 188 | except np.linalg.LinAlgError as e: 189 | xtx_inv_xt = np.dot(np.linalg.pinv(np.dot(xT, X)), xT) 190 | # xtx_inv_xt = np.dot(np.linalg.inv(np.dot(xT, X)), xT) 191 | betas = np.dot(xtx_inv_xt, y).reshape(-1) 192 | if mgwr: 193 | return betas 194 | 195 | ri = np.dot(X[i],xtx_inv_xt) 196 | predy = np.dot(X[i],betas) 197 | err = y[i][0] - predy 198 | CCT = np.diag(np.dot(xtx_inv_xt,xtx_inv_xt.T)) 199 | 200 | return np.concatenate(([i,err,ri[i]],betas,CCT)) 201 | 202 | #During bandwidth selection, return selected stats 203 | else: 204 | X_new = X*np.sqrt(wi) 205 | Y_new = y*np.sqrt(wi) 206 | try: 207 | temp = np.dot(np.linalg.inv(np.dot(X_new.T,X_new)),X_new.T) 208 | except np.linalg.LinAlgError as e: 209 | temp = np.dot(np.linalg.pinv(np.dot(X_new.T,X_new)),X_new.T) 210 | # temp = np.dot(np.linalg.inv(np.dot(X_new.T,X_new)),X_new.T) 211 | hat = np.dot(X_new[i],temp[:,i]) 212 | yhat = np.sum(np.dot(X_new,temp[:,i]).reshape(-1,1)*Y_new) 213 | err = Y_new[i][0]-yhat 214 | return err*err,hat 215 | 216 | 217 | 218 | def golden_section(self, a, c, function): 219 | """ 220 | Golden-section search bandwidth optimization 221 | """ 222 | delta = 0.38197 223 | b = a + delta * np.abs(c-a) 224 | d = c - delta * np.abs(c-a) 225 | opt_bw = None 226 | score = None 227 | diff = 1.0e9 228 | iters = 0 229 | dict = {} 230 | while np.abs(diff) > 1.0e-6 and iters < 200: 231 | iters += 1 232 | if not self.fixed: 233 | b = np.round(b) 234 | d = np.round(d) 235 | 236 | if b in dict: 237 | score_b = dict[b] 238 | else: 239 | score_b = function(b) 240 | dict[b] = score_b 241 | 242 | if d in dict: 243 | score_d = dict[d] 244 | else: 245 | score_d = function(d) 246 | dict[d] = score_d 247 | 248 | if self.comm.rank == 0: 249 | if score_b <= score_d: 250 | opt_score = score_b 251 | opt_bw = b 252 | c = d 253 | d = b 254 | b = a + delta * np.abs(c-a) 255 | else: 256 | opt_score = score_d 257 | opt_bw = d 258 | a = b 259 | b = d 260 | d = c - delta * np.abs(c-a) 261 | 262 | diff = score_b - score_d 263 | score = opt_score 264 | 265 | b = self.comm.bcast(b,root=0) 266 | d = self.comm.bcast(d,root=0) 267 | opt_bw = self.comm.bcast(opt_bw,root=0) 268 | diff = self.comm.bcast(diff,root=0) 269 | score = self.comm.bcast(score,root=0) 270 | 271 | return opt_bw 272 | 273 | 274 | def mpi_gwr_fit(self, y, X, bw, final=False, mgwr=False): 275 | """ 276 | Fit the GWR model given a bandwidth 277 | """ 278 | k = X.shape[1] 279 | #Need Parameter estimates 280 | if final: 281 | if mgwr: 282 | sub_Betas = np.empty((self.x_chunk.shape[0],k), dtype=np.float64) 283 | else: 284 | sub_Betas = np.empty((self.x_chunk.shape[0],2*k+3), dtype=np.float64) 285 | 286 | 287 | pos = 0 288 | for i in self.x_chunk: 289 | sub_Betas[pos] = self.local_fit(i, y, X, bw, final=True,mgwr=mgwr) 290 | pos+=1 291 | 292 | ''' 293 | offset = rank*sub_Betas.nbytes 294 | 295 | fh.Write_at_all(offset, sub_Betas.reshape(-1)) 296 | fh.Close() 297 | ''' 298 | 299 | Betas_list = self.comm.gather(sub_Betas, root=0) 300 | 301 | if mgwr: 302 | Betas_list = self.comm.bcast(Betas_list, root=0) 303 | data = np.vstack(Betas_list) 304 | 305 | return data 306 | 307 | if self.comm.rank ==0: 308 | data = np.vstack(Betas_list) 309 | 310 | print("Fitting GWR Using Bandwidth:",bw,flush=True) 311 | 312 | RSS = np.sum(data[:,1]**2) 313 | TSS = np.sum((y - np.mean(y))**2) 314 | R2 = 1- RSS/TSS 315 | trS = np.sum(data[:,2]) 316 | #trSTS = np.sum(data[:,4]) 317 | #sigma2_v1v2 = RSS/(n-2*trS+trSTS) 318 | sigma2_v1 = RSS/(self.n-trS) 319 | aicc = self.compute_aicc(RSS, trS) 320 | data[:,-k:] = np.sqrt(data[:,-k:]*sigma2_v1) 321 | 322 | 323 | header="index,residual,influ," 324 | varNames = np.genfromtxt(self.fname, dtype=str, delimiter=',',names=True, max_rows=1).dtype.names[3:] 325 | if self.constant: 326 | varNames = ['intercept'] + list(varNames) 327 | for x in varNames: 328 | header += ("b_"+x+',') 329 | for x in varNames: 330 | header += ("se_"+x+',') 331 | 332 | 333 | #print and save results 334 | self.output_diag(aicc,trS,R2) 335 | self.save_results(data,header) 336 | 337 | return 338 | 339 | #Not final run 340 | sub_RSS = 0 341 | sub_trS = 0 342 | for i in self.x_chunk: 343 | err2,hat = self.local_fit(i,y,X,bw,final=False) 344 | sub_RSS += err2 345 | sub_trS += hat 346 | 347 | RSS_list = self.comm.gather(sub_RSS, root=0) 348 | trS_list = self.comm.gather(sub_trS, root=0) 349 | 350 | if self.comm.rank == 0: 351 | RSS = sum(RSS_list) 352 | trS = sum(trS_list) 353 | aicc = self.compute_aicc(RSS, trS) 354 | if not mgwr: 355 | print("BW, AICc",bw, aicc,flush=True) 356 | return aicc 357 | 358 | return 359 | 360 | 361 | def fit(self, y=None, X=None, init_mgwr=False, mgwr=False): 362 | """ 363 | Fit the model if given bandwidth then call self.mpi_gwr_fit() 364 | If not, then using golden-section search for finding the optimal bandwidth 365 | which minimizes AICc. 366 | """ 367 | if y is None: 368 | y = self.y 369 | X = self.X 370 | if self.bw: 371 | self.mpi_gwr_fit(y,X,self.bw,final=True) 372 | return 373 | 374 | if self.comm.rank ==0: 375 | self.set_search_range(init_mgwr=init_mgwr,mgwr=mgwr) 376 | if not mgwr: 377 | print("Optimal Bandwidth Searching...",flush=True) 378 | print("Range:",self.minbw,self.maxbw,flush=True) 379 | self.minbw = self.comm.bcast(self.minbw,root=0) 380 | self.maxbw = self.comm.bcast(self.maxbw,root=0) 381 | 382 | 383 | gwr_func = lambda bw: self.mpi_gwr_fit(y,X,bw,mgwr=mgwr) 384 | opt_bw = self.golden_section(self.minbw, self.maxbw, gwr_func) 385 | if self.fixed: 386 | opt_bw = round(opt_bw,2) 387 | 388 | data = self.mpi_gwr_fit(y,X,opt_bw,final=True,mgwr=mgwr) 389 | return data,opt_bw 390 | 391 | 392 | def compute_aicc(self, RSS, trS): 393 | """ 394 | Compute AICc 395 | """ 396 | aicc = self.n*np.log(RSS/self.n) + self.n*np.log(2*np.pi) + self.n*(self.n+trS)/(self.n-trS-2.0) 397 | return aicc 398 | 399 | def output_diag(self,aicc,trS,R2): 400 | """ 401 | Output diagnostics to screen 402 | """ 403 | if self.comm.rank == 0: 404 | print("Diagnostic Information:") 405 | print("AICc:",aicc) 406 | print("ENP:",trS) 407 | print("R2:",R2) 408 | 409 | def save_results(self,data,header): 410 | """ 411 | Save results to .csv file 412 | """ 413 | if self.comm.rank == 0: 414 | np.savetxt(self.fout, data, delimiter=',',header=header[:-1],comments='') 415 | 416 | 417 | -------------------------------------------------------------------------------- /fastgwr/FastMGWR.py: -------------------------------------------------------------------------------- 1 | #FastMGWR MPI Script 2 | #Author: Ziqi Li 3 | #Email: liziqi1992@gmail.com 4 | 5 | import math 6 | import numpy as np 7 | from mpi4py import MPI 8 | from scipy.spatial.distance import cdist,pdist 9 | import argparse 10 | from copy import deepcopy 11 | from FastGWR import FastGWR 12 | 13 | 14 | class FastMGWR(FastGWR): 15 | """ 16 | FastMGWR class. 17 | 18 | Parameters 19 | ---------- 20 | comm : MPI communicators initialized with mpi4py. 21 | parser : The parser object contains model arguments. 22 | 23 | Attributes 24 | ---------- 25 | comm : MPI communicators initialized with mpi4py. 26 | parser : The parser object contains model arguments. 27 | y : array 28 | n*1, dependent variable 29 | 30 | X : array 31 | n*k, independent variables (include constant, if any) 32 | coords : array 33 | n*2, collection of n sets of (x,y) coordinates used for 34 | calibration locations 35 | n : int 36 | number of observations 37 | k : int 38 | number of independent variables 39 | minbw : float 40 | lower-bound bandwidth in the search range 41 | maxbw : float 42 | upper-bound bandwidth in the search range 43 | 44 | """ 45 | def __init__(self, comm, parser): 46 | """ 47 | Initialize class 48 | """ 49 | 50 | FastGWR.__init__(self, comm, parser) 51 | 52 | #Standardizaing data 53 | if self.constant: 54 | stds = np.std(self.X, axis=0) 55 | stds[0] = 1 56 | self.X = (self.X - np.mean(self.X,axis=0))/stds 57 | self.X[:,0] = 1 58 | else: 59 | self.X = (self.X - np.mean(self.X,axis=0))/np.std(self.X, axis=0) 60 | self.y = (self.y - np.mean(self.y,axis=0))/np.std(self.y, axis=0) 61 | 62 | 63 | def backfitting(self): 64 | """ 65 | Backfitting MGWR model and obtain parameter estimates 66 | and covariate-specific bandwidths. 67 | see Fotheringham et al. 2017. Annals of AAG. 68 | """ 69 | 70 | if self.comm.rank ==0: 71 | print("MGWR Backfitting...",flush=True) 72 | print("Data are standardized",flush=True) 73 | 74 | #Initalization 75 | betas,bw = self.fit(init_mgwr=True,mgwr=True) 76 | 77 | self.bw_init = bw 78 | 79 | if self.comm.rank ==0: 80 | print("Initialization Done...",flush=True) 81 | XB = betas*self.X 82 | err = self.y.reshape(-1) - np.sum(XB,axis=1) 83 | bws = [None]*self.k 84 | bw_stable_counter = 0 85 | bws_history = [] 86 | 87 | for mgwr_iters in range(1,201): 88 | newXB = np.empty(XB.shape, dtype=np.float64) 89 | newbetas = np.empty(XB.shape, dtype=np.float64) 90 | 91 | for j in range(self.k): 92 | temp_y = (XB[:,j] + err).reshape(-1,1) 93 | temp_X = self.X[:,j].reshape(-1,1) 94 | 95 | if bw_stable_counter >= 5: 96 | #If in backfitting, all bws not changing in bws_same_times (default 5) iterations 97 | bw_j = bws[j] 98 | betas = self.mpi_gwr_fit(temp_y,temp_X,bw_j,final=True,mgwr=True) 99 | else: 100 | betas,bw_j = self.fit(y=temp_y,X=temp_X,init_mgwr=False,mgwr=True) 101 | XB_j = (betas*temp_X).reshape(-1) 102 | err = temp_y.reshape(-1) - XB_j 103 | newXB[:,j] = XB_j 104 | newbetas[:,j] = betas.reshape(-1) 105 | bws[j] = bw_j 106 | 107 | if (mgwr_iters > 1) and np.all(bws_history[-1] == bws): 108 | bw_stable_counter += 1 109 | else: 110 | bw_stable_counter = 0 111 | 112 | bws_history.append(deepcopy(bws)) 113 | num = np.sum((newXB - XB)**2) / self.n 114 | den = np.sum(np.sum(newXB, axis=1)**2) 115 | score = (num / den)**0.5 116 | XB = newXB 117 | 118 | if self.comm.rank ==0: 119 | print("Iter:",mgwr_iters,"SOC:","{:.2e}".format(score),flush=True) 120 | print("bws:",bws,flush=True) 121 | 122 | if score < 1e-5: 123 | break 124 | 125 | self.bws_history = np.array(bws_history) 126 | self.RSS = np.sum(err**2) 127 | self.TSS = np.sum((self.y - np.mean(self.y))**2) 128 | self.R2 = 1 - self.RSS/self.TSS 129 | self.err = err 130 | self.params = newbetas 131 | 132 | if self.comm.rank == 0 and self.estonly: 133 | header="index,residual," 134 | varNames = np.genfromtxt(self.fname, dtype=str, delimiter=',',names=True, max_rows=1).dtype.names[3:] 135 | if self.constant: 136 | varNames = ['intercept'] + list(varNames) 137 | for x in varNames: 138 | header += ("b_"+x+',') 139 | 140 | self.output_diag(None,None,self.R2) 141 | index = np.arange(self.n).reshape(-1,1) 142 | output = np.hstack([index,self.err.reshape(-1,1),self.params]) 143 | self.save_results(output,header) 144 | 145 | 146 | def _chunk_compute_R(self, chunk_id=0): 147 | """ 148 | Compute MGWR inference by chunks to reduce memory footprint. 149 | See Li and Fotheringham, 2020. IJGIS and Yu et al., 2019. GA. 150 | """ 151 | 152 | n = self.n 153 | k = self.k 154 | n_chunks = self.n_chunks 155 | chunk_size = int(np.ceil(float(n / n_chunks))) 156 | ENP_j = np.zeros(k) 157 | CCT = np.zeros((n, k)) 158 | 159 | chunk_index = np.arange(n)[chunk_id * chunk_size:(chunk_id + 1) * 160 | chunk_size] 161 | 162 | init_pR = np.zeros((n, len(chunk_index))) 163 | init_pR[chunk_index, :] = np.eye(len(chunk_index)) 164 | pR = np.zeros((n, len(chunk_index),k)) #partial R: n by chunk_size by k 165 | 166 | for i in range(n): 167 | wi = self.build_wi(i, self.bw_init).reshape(-1, 1) 168 | xT = (self.X * wi).T 169 | P = np.linalg.solve(xT.dot(self.X), xT).dot(init_pR).T 170 | pR[i, :, :] = P * self.X[i] 171 | 172 | err = init_pR - np.sum(pR, axis=2) #n by chunk_size 173 | 174 | for iter_i in range(self.bws_history.shape[0]): 175 | for j in range(k): 176 | pRj_old = pR[:, :, j] + err 177 | Xj = self.X[:, j] 178 | n_chunks_Aj = n_chunks 179 | chunk_size_Aj = int(np.ceil(float(n / n_chunks_Aj))) 180 | for chunk_Aj in range(n_chunks_Aj): 181 | chunk_index_Aj = np.arange(n)[chunk_Aj * chunk_size_Aj:( 182 | chunk_Aj + 1) * chunk_size_Aj] 183 | pAj = np.empty((len(chunk_index_Aj), n)) 184 | for i in range(len(chunk_index_Aj)): 185 | index = chunk_index_Aj[i] 186 | wi = self.build_wi(index, self.bws_history[iter_i, j]).reshape(-1) 187 | xw = Xj * wi 188 | pAj[i, :] = Xj[index] / np.sum(xw * Xj) * xw 189 | 190 | pR[chunk_index_Aj, :, j] = pAj.dot(pRj_old) 191 | err = pRj_old - pR[:, :, j] 192 | 193 | for j in range(k): 194 | CCT[:, j] += ((pR[:, :, j] / self.X[:, j].reshape(-1, 1))**2).sum(axis=1) 195 | for i in range(len(chunk_index)): 196 | ENP_j += pR[chunk_index[i], i, :] 197 | 198 | return ENP_j, CCT 199 | 200 | 201 | def mgwr_fit(self,n_chunks=2): 202 | """ 203 | Fit MGWR model and output results 204 | """ 205 | if self.estonly: 206 | return 207 | if self.comm.rank ==0: 208 | print("Computing Inference with",n_chunks,"Chunk(s)",flush=True) 209 | self.n_chunks = self.comm.size * n_chunks 210 | self.chunks = np.arange(self.comm.rank*n_chunks, (self.comm.rank+1)*n_chunks) 211 | 212 | ENP_list = [] 213 | CCT_list = [] 214 | for r in self.chunks: 215 | ENP_j_r, CCT_r = self._chunk_compute_R(r) 216 | ENP_list.append(ENP_j_r) 217 | CCT_list.append(CCT_r) 218 | 219 | ENP_list = np.array(self.comm.gather(ENP_list, root=0)) 220 | CCT_list = np.array(self.comm.gather(CCT_list, root=0)) 221 | 222 | if self.comm.rank == 0: 223 | ENP_j = np.sum(np.vstack(ENP_list), axis=0) 224 | CCT = np.sum(np.vstack(CCT_list), axis=0) 225 | 226 | header="index,residual," 227 | varNames = np.genfromtxt(self.fname, dtype=str, delimiter=',',names=True, max_rows=1).dtype.names[3:] 228 | if self.constant: 229 | varNames = ['intercept'] + list(varNames) 230 | for x in varNames: 231 | header += ("b_"+x+',') 232 | for x in varNames: 233 | header += ("se_"+x+',') 234 | 235 | 236 | trS = np.sum(ENP_j) 237 | sigma2_v1 = self.RSS/(self.n-trS) 238 | aicc = self.compute_aicc(self.RSS, trS) 239 | self.output_diag(aicc,ENP_j,self.R2) 240 | 241 | bse = np.sqrt(CCT*sigma2_v1) 242 | index = np.arange(self.n).reshape(-1,1) 243 | output = np.hstack([index,self.err.reshape(-1,1),self.params,bse]) 244 | 245 | self.save_results(output,header) 246 | 247 | return 248 | -------------------------------------------------------------------------------- /fastgwr/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /fastgwr/__main__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import click 3 | import fastgwr 4 | 5 | @click.group() 6 | @click.version_option("0.2.9") 7 | def main(): 8 | pass 9 | 10 | @main.command() 11 | @click.option("-np", default=4, required=True) 12 | @click.option("-data", required=True) 13 | @click.option("-out", default="fastgwr_rslt.csv", required=False) 14 | @click.option("-adaptive/-fixed" ,default=True, required=True) 15 | @click.option("-bw", required=False) 16 | @click.option("-minbw", required=False) 17 | @click.option("-mgwr", default=False, required=False, is_flag=True) 18 | @click.option("-chunks", required=False) 19 | @click.option("-estonly", default=False, is_flag=True) 20 | def run(np, data, out, adaptive, bw, minbw, mgwr, chunks, estonly): 21 | """ 22 | Fast(M)GWR 23 | 24 | -np: number of processors to use. (default: 4) 25 | 26 | -data: input data matrix containing y and X. Can be URL: 27 | e.g. https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_1k.csv 28 | 29 | -out: output GWR results (default: "fastgwr_rslt.csv"). 30 | 31 | -adaptive/-fixed: using an adaptive bisquare kernel (default) or a fixed gaussian kernel. 32 | 33 | -bw: using a pre-specified bandwidth to fit GWR. 34 | 35 | -minbw: lower bound in the golden section search in GWR. 36 | 37 | -mgwr: fitting an MGWR model. 38 | 39 | -chunks: number of chunks for MGWR computation (default: 1). 40 | Increase the number if run out of memory but should keep it as low as possible. 41 | 42 | -estonly: output the parameter estimation only for MGWR, no standard errors of the estimates 43 | and model diagnostics. Ideal for quick model checking (default: False). 44 | 45 | """ 46 | 47 | mpi_path = os.path.dirname(fastgwr.__file__) + '/fastgwr_mpi.py' 48 | 49 | command = 'mpiexec ' + ' -np ' + str(np) + ' python ' + mpi_path + ' -data ' + data + ' -out ' + out 50 | command += ' -c ' 51 | 52 | if mgwr: 53 | command += ' -mgwr ' 54 | if adaptive: 55 | command += ' -a ' 56 | else: 57 | command += ' -f ' 58 | if bw: 59 | command += (' -bw ' + bw) 60 | if minbw: 61 | command += (' -minbw ' + minbw) 62 | if chunks: 63 | command += (' -chunks ' + chunks) 64 | if estonly: 65 | command += (' -estonly ') 66 | 67 | os.system(command) 68 | pass 69 | 70 | 71 | @main.command() 72 | def testgwr(): 73 | """ 74 | Testing GWR with zillow data 75 | """ 76 | print("Testing GWR with zillow data:") 77 | mpi_path = os.path.dirname(fastgwr.__file__) + '/fastgwr_mpi.py' 78 | 79 | command = "mpiexec -np 2 python " + mpi_path + " -data https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_1k.csv -c" 80 | os.system(command) 81 | pass 82 | 83 | 84 | @main.command() 85 | def testmgwr(): 86 | """ 87 | Testing MGWR with zillow data 88 | """ 89 | print("Testing MGWR with zillow data:") 90 | mpi_path = os.path.dirname(fastgwr.__file__) + '/fastgwr_mpi.py' 91 | 92 | command = "mpiexec -np 2 python " + mpi_path + " -data https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_1k.csv -mgwr -c" 93 | os.system(command) 94 | pass 95 | 96 | 97 | if __name__ == '__main__': 98 | main() 99 | -------------------------------------------------------------------------------- /fastgwr/fastgwr_mpi.py: -------------------------------------------------------------------------------- 1 | #FastGWR MPI Script 2 | #Author: Ziqi Li 3 | #Email: liziqi1992@gmail.com 4 | 5 | import argparse 6 | import numpy as np 7 | from mpi4py import MPI 8 | from FastGWR import FastGWR 9 | from FastMGWR import FastMGWR 10 | 11 | #Direct Example Call: 12 | #You can direct call this script by: 13 | #mpiexec -np 4 python fastgwr_mpi.py -data ../Zillow-test-dataset/zillow_1k.csv 14 | #mpiexec -np 4 python fastgwr_mpi.py -data ../Zillow-test-dataset/zillow_1k.csv -mgwr -c 15 | 16 | if __name__ == "__main__": 17 | 18 | #Initializing MPI 19 | comm = MPI.COMM_WORLD 20 | rank = comm.Get_rank() 21 | size = comm.Get_size() 22 | 23 | #Parsing arguments 24 | parser = argparse.ArgumentParser() 25 | parser.add_argument("-data") 26 | parser.add_argument("-out",default="fastgwr_rslt.csv") 27 | parser.add_argument("-bw") 28 | parser.add_argument("-minbw") 29 | parser.add_argument("-chunks",default=1) 30 | 31 | parser.add_argument('-estonly',action='store_true') 32 | parser.add_argument('-mgwr',action='store_true') 33 | parser.add_argument('-f','--fixed',action='store_true') 34 | parser.add_argument('-a','--adaptive',action='store_true') 35 | parser.add_argument('-c','--constant',action='store_true') 36 | 37 | 38 | #Timing starts 39 | t1 = MPI.Wtime() 40 | n_chunks = parser.parse_args().chunks 41 | 42 | #Fitting MGWR model, if mgwr in the arguments 43 | if parser.parse_args().mgwr: 44 | mgwr_model = FastMGWR(comm,parser) 45 | mgwr_model.backfitting() 46 | mgwr_model.mgwr_fit(int(n_chunks)) 47 | 48 | #Fitting GWR model 49 | else: 50 | FastGWR(comm,parser).fit() 51 | #Timing ends 52 | t_last = MPI.Wtime() 53 | 54 | wt = comm.gather(t_last-t1, root=0) 55 | if rank ==0: 56 | print("Total Time Elapsed:",np.round(max(wt),2),"seconds") 57 | print("-"*60) 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /paper/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ziqi-Li/FastGWR/a765df41bd75197e7d3ed2c0f54bb47875525ece/paper/.DS_Store -------------------------------------------------------------------------------- /paper/figure maker.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import matplotlib.pyplot as plt\n", 10 | "import numpy as np" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 2, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "gwr = np.array([18.0,31.07,57.89,107.72,210.04,673.0])\n", 20 | "\n", 21 | "mgwr = np.array([888.39,1165.61,1735.79, 2762.86, 4825.57, 22451.34])\n", 22 | "\n", 23 | "mgwr_2 = np.array([163.48,317.79,621.77,1243.5, 2429.0, 12047])\n", 24 | "\n", 25 | "mgwr_3 = mgwr - mgwr_2\n", 26 | "\n", 27 | "nproc = [80,40,20,10,5,1]" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 3, 33 | "metadata": {}, 34 | "outputs": [ 35 | { 36 | "data": { 37 | "image/png": "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y5cPT09PChUqRI0aNfjyyy/vWv+ECRPo27dv6mjjixYtokqVKpl6D44fP45SiqioqExtl1atWrVo2LAhn3/++X3vQwjhuCSg0rJaIOxP2DDF+G3N2rmg0qpRowZz585Nt2zu3Lm3DDuzd+9eGjVqhJOTE8HBwcTHx3P48GGGDRuWOpttnTp1KFGiRLpx/DKaHj4hIYF///033fh9ffv25fLly8TFxTFp0iReeeWVO87VFBcXx5IlS3jhhRce5OVnmQEDBjBz5szbDoQrhMi5JKCus1pgaVf4cQCsf9/4vbRrtoXUU089xa5du1KnUr906RI//vhj6sjg1w0fPpzGjRuzcOFCqlatirOzM25ubnTu3JmlS5cCxmGv65MYXhcUFMSoUaMICwsjNjYWgE2bNqG1pk2bNrfU4+TkRLdu3ShatCgZjXV43V9//YWPjw/ly5cH4J9//mHo0KEcPXo0dar36wF3fabdwoUL4+fnl24W4Xr16gFQvXp1PD09mThxIgBjx46lUqVKeHp6UrlyZT799NM7vo+tW7fm9OnTd5zSXgiRM+XqCQtZPQZO7723dRMuQMxB0La/xJOuwPFN8FVL8LiHifNK1YEuH95zaW5ubjz33HPMnz+fyZMns2zZMtq0aUPp0qVT17l69SobNmy45+nh33nnHQBSUlLYuHEj8+bNo3nz5gQHB9O1a1eCgoJo1qwZBQoUuGV7i8XCihUriImJoXr16rd9npunh2/evDmzZs1i0qRJhIeHpy4/duwYnTt35quvvqJ3795s376dRx55hCJFivD000/z33//UbFiRcLCwihXrlzqdjVr1iQkJITSpUuzfv16Hn30UWrUqEGnTp0yrCd//vxUrVqVnTt30rBhw7u+T0KInENaUNclXb4RTtdpq7E8mwwaNIiFCxeSkpLCnDlzGDRoULrHL1y4gMViSTc9/O7du/Hy8sLLyws3NzciIiIAY1qOkydPcvDgQbZt20a5cuUoWbJkupZVUFDQLdNzLF26NHVfPXv25L333uPxxx+/bc33Oj38smXLaNiwIf369cPFxYVmzZoxZMgQ5s2bd8ftevfuTZkyZVJbhY8++mi6lmFGZHp4IXKn3N2CykSLhrA/jcN6SVduLHMtAI9Mheqds742jBHEK1SowMSJEzl79iydO3dm2bJlqY97e3vj7OycriNB/fr1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\n", 38 | "text/plain": [ 39 | "
" 40 | ] 41 | }, 42 | "metadata": { 43 | "needs_background": "light" 44 | }, 45 | "output_type": "display_data" 46 | } 47 | ], 48 | "source": [ 49 | "gwr = gwr[-1]/gwr\n", 50 | "mgwr = mgwr[-1]/mgwr\n", 51 | "mgwr_2 = mgwr_2[-1]/mgwr_2\n", 52 | "mgwr_3 = mgwr_3[-1]/mgwr_3\n", 53 | "\n", 54 | "flg = plt.figure(figsize=(6, 6))\n", 55 | "\n", 56 | "plt.plot(nproc,gwr,marker=\"o\",label=\"GWR (total)\",markersize=5)\n", 57 | "plt.plot(nproc,mgwr,marker=\"o\",label=\"MGWR (total)\",markersize=5)\n", 58 | "plt.plot(nproc,mgwr_2,marker=\"o\",label=\"MGWR (estimation only)\",markersize=5)\n", 59 | "#plt.plot(nproc,mgwr_3,marker=\"o\",label=\"MGWR (estimation only)\",markersize=5)\n", 60 | "plt.ylim(-3,83)\n", 61 | "plt.ylabel('Speed-up',fontsize=13)\n", 62 | "plt.xlabel('Number of Processors',fontsize=13)\n", 63 | "plt.legend(loc='upper left',fontsize=13)\n", 64 | "#plt.title('(b)',pad=-390)\n", 65 | "\n", 66 | "plt.tight_layout()\n", 67 | "plt.savefig('scalability.png', format='png', dpi=900)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": null, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [] 76 | } 77 | ], 78 | "metadata": { 79 | "kernelspec": { 80 | "display_name": "Python 3", 81 | "language": "python", 82 | "name": "python3" 83 | }, 84 | "language_info": { 85 | "codemirror_mode": { 86 | "name": "ipython", 87 | "version": 3 88 | }, 89 | "file_extension": ".py", 90 | "mimetype": "text/x-python", 91 | "name": "python", 92 | "nbconvert_exporter": "python", 93 | "pygments_lexer": "ipython3", 94 | "version": "3.7.6" 95 | } 96 | }, 97 | "nbformat": 4, 98 | "nbformat_minor": 4 99 | } 100 | -------------------------------------------------------------------------------- /paper/paper.bib: -------------------------------------------------------------------------------- 1 | @article{li2019fast, 2 | title={Fast Geographically Weighted Regression (FastGWR): a scalable algorithm to investigate spatial process heterogeneity in millions of observations}, 3 | author={Li, Ziqi and Fotheringham, A Stewart and Li, Wenwen and Oshan, Taylor}, 4 | journal={International Journal of Geographical Information Science}, 5 | volume={33}, 6 | number={1}, 7 | pages={155--175}, 8 | year={2019}, 9 | publisher={Taylor \& Francis} 10 | } 11 | 12 | @article{li2020computational, 13 | title={Computational improvements to multi-scale geographically weighted regression}, 14 | author={Li, Ziqi and Fotheringham, A Stewart}, 15 | journal={International Journal of Geographical Information Science}, 16 | volume={34}, 17 | number={7}, 18 | pages={1378--1397}, 19 | year={2020}, 20 | publisher={Taylor \& Francis} 21 | } 22 | 23 | @book{fotheringham2003geographically, 24 | title={Geographically weighted regression: the analysis of spatially varying relationships}, 25 | author={Fotheringham, A Stewart and Brunsdon, Chris and Charlton, Martin}, 26 | year={2003}, 27 | publisher={John Wiley \& Sons} 28 | } 29 | 30 | @article{fotheringham2017multiscale, 31 | title={Multiscale geographically weighted regression (MGWR)}, 32 | author={Fotheringham, A Stewart and Yang, Wenbai and Kang, Wei}, 33 | journal={Annals of the American Association of Geographers}, 34 | volume={107}, 35 | number={6}, 36 | pages={1247--1265}, 37 | year={2017}, 38 | publisher={Taylor \& Francis} 39 | } 40 | 41 | @article{dalcin2008mpi, 42 | title={MPI for Python: Performance improvements and MPI-2 extensions}, 43 | author={Dalc{\'\i}n, Lisandro and Paz, Rodrigo and Storti, Mario and D’El{\'\i}a, Jorge}, 44 | journal={Journal of Parallel and Distributed Computing}, 45 | volume={68}, 46 | number={5}, 47 | pages={655--662}, 48 | year={2008}, 49 | publisher={Elsevier} 50 | } 51 | 52 | @article{wang2020cuda, 53 | title={A CUDA-Based Parallel Geographically Weighted Regression for Large-Scale Geographic Data}, 54 | author={Wang, Dongchao and Yang, Yi and Qiu, Agen and Kang, Xiaochen and Han, Jiakuan and Chai, Zhengyuan}, 55 | journal={ISPRS International Journal of Geo-Information}, 56 | volume={9}, 57 | number={11}, 58 | pages={653}, 59 | year={2020}, 60 | publisher={Multidisciplinary Digital Publishing Institute} 61 | } 62 | 63 | @article{que2021parallel, 64 | title={Parallel computing for Fast Spatiotemporal Weighted Regression}, 65 | author={Que, Xiang and Ma, Chao and Ma, Xiaogang and Chen, Qiyu}, 66 | journal={Computers \& Geosciences}, 67 | pages={104723}, 68 | year={2021}, 69 | publisher={Elsevier} 70 | } 71 | 72 | @article{bilgel2020guns, 73 | title={Guns and homicides: a multiscale geographically weighted instrumental variables approach}, 74 | author={Bilgel, Firat}, 75 | journal={Geographical Analysis}, 76 | volume={52}, 77 | number={4}, 78 | pages={588--616}, 79 | year={2020}, 80 | publisher={Wiley Online Library} 81 | } 82 | 83 | @article{tasyurek2020rnn, 84 | title={RNN-GWR: A geographically weighted regression approach for frequently updated data}, 85 | author={Tasyurek, Murat and Celik, Mete}, 86 | journal={Neurocomputing}, 87 | volume={399}, 88 | pages={258--270}, 89 | year={2020}, 90 | publisher={Elsevier} 91 | } 92 | 93 | @article{tacsyurek2021fastgtwr, 94 | title={FastGTWR: H{\i}zl{\i} co{\u{g}}rafi ve zamansal a{\u{g}}{\i}rl{\i}kl{\i} regresyon yakla{\c{s}}{\i}m{\i}}, 95 | author={Ta{\c{s}}y{\"u}rek, Murat and {\c{C}}elik, Mete}, 96 | journal={Gazi {\"U}niversitesi M{\"u}hendislik Mimarl{\i}k Fak{\"u}ltesi Dergisi}, 97 | volume={36}, 98 | number={2}, 99 | pages={715--726}, 100 | year={2021} 101 | } 102 | 103 | @article{oshan2019mgwr, 104 | title={mgwr: A Python implementation of multiscale geographically weighted regression for investigating process spatial heterogeneity and scale}, 105 | author={Oshan, Taylor M and Li, Ziqi and Kang, Wei and Wolf, Levi J and Fotheringham, A Stewart}, 106 | journal={ISPRS International Journal of Geo-Information}, 107 | volume={8}, 108 | number={6}, 109 | pages={269}, 110 | year={2019}, 111 | publisher={Multidisciplinary Digital Publishing Institute} 112 | } 113 | 114 | @article{gollini2013gwmodel, 115 | title={GWmodel: an R package for exploring spatial heterogeneity using geographically weighted models}, 116 | author={Gollini, Isabella and Lu, Binbin and Charlton, Martin and Brunsdon, Christopher and Harris, Paul}, 117 | journal={arXiv preprint arXiv:1306.0413}, 118 | year={2013} 119 | } 120 | 121 | @article{li2010investigating, 122 | title={Investigating spatial non-stationary and scale-dependent relationships between urban surface temperature and environmental factors using geographically weighted regression}, 123 | author={Li, Shuangcheng and Zhao, Zhiqiang and Miaomiao, Xie and Wang, Yanglin}, 124 | journal={Environmental Modelling \& Software}, 125 | volume={25}, 126 | number={12}, 127 | pages={1789--1800}, 128 | year={2010}, 129 | publisher={Elsevier} 130 | } 131 | 132 | @article{cahill2007using, 133 | title={Using geographically weighted regression to explore local crime patterns}, 134 | author={Cahill, Meagan and Mulligan, Gordon}, 135 | journal={Social Science Computer Review}, 136 | volume={25}, 137 | number={2}, 138 | pages={174--193}, 139 | year={2007}, 140 | publisher={Sage Publications Sage CA: Los Angeles, CA} 141 | } 142 | 143 | @article{windle2010exploring, 144 | title={Exploring spatial non-stationarity of fisheries survey data using geographically weighted regression (GWR): an example from the Northwest Atlantic}, 145 | author={Windle, Matthew JS and Rose, George A and Devillers, Rodolphe and Fortin, Marie-Josee}, 146 | journal={ICES Journal of Marine Science}, 147 | volume={67}, 148 | number={1}, 149 | pages={145--154}, 150 | year={2010}, 151 | publisher={Oxford University Press} 152 | } 153 | 154 | @article{stewart2021scale, 155 | title={Scale, Context, and Heterogeneity: A Spatial Analytical Perpective on the 2016 US Presidential Election}, 156 | author={Fotheringham, A Stewart and Li, Ziqi and Wolf, Levi John}, 157 | journal={Annals of the American Association of Geographers}, 158 | pages={1--20}, 159 | year={2021}, 160 | publisher={Taylor \& Francis} 161 | } 162 | 163 | @article{lin2011using, 164 | title={Using geographically weighted regression (GWR) to explore spatial varying relationships of immature mosquitoes and human densities with the incidence of dengue}, 165 | author={Lin, Chia-Hsien and Wen, Tzai-Hung}, 166 | journal={International journal of environmental research and public health}, 167 | volume={8}, 168 | number={7}, 169 | pages={2798--2815}, 170 | year={2011}, 171 | publisher={Molecular Diversity Preservation International} 172 | } 173 | 174 | @book{gropp1999using, 175 | title={Using MPI: portable parallel programming with the message-passing interface}, 176 | author={Gropp, William and Gropp, William D and Lusk, Ewing and Skjellum, Anthony and Lusk, Argonne Distinguished Fellow Emeritus Ewing}, 177 | volume={1}, 178 | year={1999}, 179 | publisher={MIT press} 180 | } 181 | 182 | @inproceedings{gabriel2004open, 183 | title={Open MPI: Goals, concept, and design of a next generation MPI implementation}, 184 | author={Gabriel, Edgar and Fagg, Graham E and Bosilca, George and Angskun, Thara and Dongarra, Jack J and Squyres, Jeffrey M and Sahay, Vishal and Kambadur, Prabhanjan and Barrett, Brian and Lumsdaine, Andrew and others}, 185 | booktitle={European Parallel Virtual Machine/Message Passing Interface Users’ Group Meeting}, 186 | pages={97--104}, 187 | year={2004}, 188 | organization={Springer} 189 | } 190 | 191 | @misc{gropp1996user, 192 | title={User’s Guide for mpich, a Portable Implementation of MPI}, 193 | author={Gropp, William and Lusk, Ewing}, 194 | year={1996}, 195 | publisher={Mathematics and Computer Science Division, Argonne National Laboratory~…} 196 | } 197 | 198 | @article{van2011numpy, 199 | title={The NumPy array: a structure for efficient numerical computation}, 200 | author={Van Der Walt, Stefan and Colbert, S Chris and Varoquaux, Gael}, 201 | journal={Computing in science \& engineering}, 202 | volume={13}, 203 | number={2}, 204 | pages={22--30}, 205 | year={2011}, 206 | publisher={IEEE} 207 | } 208 | 209 | @article{virtanen2020scipy, 210 | title={SciPy 1.0: fundamental algorithms for scientific computing in Python}, 211 | author={Virtanen, Pauli and Gommers, Ralf and Oliphant, Travis E and Haberland, Matt and Reddy, Tyler and Cournapeau, David and Burovski, Evgeni and Peterson, Pearu and Weckesser, Warren and Bright, Jonathan and others}, 212 | journal={Nature methods}, 213 | volume={17}, 214 | number={3}, 215 | pages={261--272}, 216 | year={2020}, 217 | publisher={Nature Publishing Group} 218 | } 219 | -------------------------------------------------------------------------------- /paper/paper.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'fastgwr: A python-based command-line interface for fast and parallel fitting of Geographically Weighted Regression models' 3 | tags: 4 | - python 5 | - spatial analysis 6 | - geography 7 | - MPI 8 | - parallel 9 | authors: 10 | - name: Ziqi Li 11 | orcid: 0000-0002-6345-4347 12 | affiliation: 1 13 | 14 | affiliations: 15 | - name: Department of Geography and Geographic Information Science, University of Illinois, Urbana-Champaign 16 | index: 1 17 | date: 23 March 2020 18 | bibliography: paper.bib 19 | --- 20 | 21 | 22 | # Summary 23 | 24 | `fastgwr` is a command-line interface (CLI) tool for fast and parallel fitting of Geographically Weighted Regression (GWR) models. The single-bandwidth GWR, as well as the multi-bandwidth Multiscale GWR (MGWR) model, are both available in the current version of the software. GWR models are typically computationally intensive in memory and time. To address these challenges, `fastgwr` uses Message Passing Interface (MPI, @gropp1999using) to implement the parallel algorithms developed in @li2019fast and @li2020computational. The program builds on top of the `mpi4py` package [@dalcin2008mpi] which provides bindings of the MPI with python to allow the algorithm to be executed on multiple processors across nodes. The goal of `fastgwr` is to enable studies of spatial non-stationary processes using large-scale and fine-resolution geospatial datasets. 25 | 26 | # Statement of need 27 | 28 | GWR models [@fotheringham2003geographically], as one of the fundamental methods in spatial analysis and geography, have been widely applied to examine spatially varying relationships in fields such as environmental studies [@li2010investigating], crime analysis [@cahill2007using], ecology [@windle2010exploring], public health [@lin2011using], and political science [@stewart2021scale]. A recent advancement of GWR named MGWR [@fotheringham2017multiscale] removes the single bandwidth assumption in GWR so that multi-scale processes can be simultaneously modeled. This more advanced and flexible model brings additional challenges in parameter estimation which requires to iteratively fit thousands of GWR models through a backffiting process. The complexity of the calibration makes the model hard to be applied to moderate-sized datasets. For instance, it may take several days of running time to complete the model fitting for a sample size of 5000 observations. 29 | 30 | As geospatial data are increasingly available from different sources such as remote sensing, GPS in mobile devices, IoT networks, and so on. The computation demand of GWRs poses a limitation for applying such models in real scientific applications, especially when involving large datasets. To address this problem, @li2019fast and @li2020computational developed parallel fitting algorithms for GWR and MGWR respectively. `fastgwr` incorporates these efforts and provides a simple CLI for users to calibrate large-size GWR models on both desktops and clusters. Recently, `fastgwr` has benefited and enabled a few scholarly publications (e.g. @tasyurek2020rnn; @bilgel2020guns; @wang2020cuda). Additionally, new methods and software have been developed based on the `fastgwr` parallelization framework (see @oshan2019mgwr; @que2021parallel; @tacsyurek2021fastgtwr). 31 | 32 | # State of the Field 33 | 34 | There are currently existing packages that allow users to fit GWR and MGWR models. Two most popular open-source options are `mgwr` in python [@oshan2019mgwr] and `GWmodel` in R [@gollini2013gwmodel], both of which provide friendly APIs and are actively maintained. `GWmodel` supports a wide array of geographically weighted models and analysis tools; however, the performance of `GWmodel` is lagged behind and not suitable for large datasets. A comprehensive performance comparison between `GWmodel` and `fastgwr` can be found in @li2019fast and @li2020computational. As for `mgwr`, the parallelism of `fastgwr` has been built into `mgwr` by leveraging the `multiprocessing` package. For small and moderate sized problems, the performance between `mgwr` and `fastgwr` is comparable. Nevertheless, the major advantage of `fastgwr` is that the use of MPI-based parallelism allows the program to run in parallel across multiple computer nodes. In this way, `fastgwr` is the only option if the analyst wants to run the GWR program on a high performance computing cluster, and it empowers larger-scale analysis that is impossible for a single workstation. To demostrate this, `fastgwr` was executed on the University of Arizona's [Ocelote](https://public.confluence.arizona.edu/display/UAHPC/Ocelote+Quick+Start) cluster using the [Zillow datasets](https://github.com/Ziqi-Li/FastGWR/tree/master/Zillow-test-dataset), and the scalability can be seen in \autoref{fig:example}. It is expected that the scalability will further increase with larger datasets because the data transfer among processes will take a relative smaller proportion in the total computation time. Additionally, the model fitting results of `fastgwr` have been validated against `mgwr` which can be found in the [notebooks](https://github.com/Ziqi-Li/FastGWR/tree/master/validation%20notebook) in the attached [Gituhb repository](https://github.com/Ziqi-Li/FastGWR). 35 | 36 | ![Scalability of `fastgwr`. The GWR model is fitted with 50,000 Zillow records and the MGWR model is fitted with 10,000 Zillow records. \label{fig:example}](scalability.png){ width=50%} 37 | 38 | 39 | # Installation 40 | 41 | `fastgwr` is dependent on the `mpi4py` package and a working MPI implementation. The easiest way to install both dependencies is to use `conda`: 42 | 43 | ```bash 44 | $ conda install mpi4py 45 | ``` 46 | 47 | By installing `mpi4py`, `conda` will also install an MPI implementation based on your computer system (OpenMPI for Mac/Linux; MPICH/MS-MPI for Windows). Users may want to check wether the MPI implementation is successfully installed and is on your path by running the `mpiexec` command. Then the `fastgwr` program can be installed from PyPi: 48 | 49 | ```bash 50 | $ pip install fastgwr 51 | ``` 52 | 53 | After sucessful installation, users can test the functionalities from the command line by running: 54 | 55 | ```bash 56 | # Using zillow sample data for testing MGWR model fitting. 57 | $ fastgwr testgwr 58 | ``` 59 | or 60 | 61 | ```bash 62 | # Using zillow sample data for testing MGWR model fitting. 63 | $ fastgwr testmgwr 64 | ``` 65 | 66 | 67 | # Examples 68 | An example call to `fastgwr` to fit a GWR model: 69 | 70 | ```bash 71 | $ fastgwr run -np 4 -data input.csv 72 | ``` 73 | 74 | An example call to `fastgwr` to fit an MGWR model: 75 | 76 | ```bash 77 | $ fastgwr run -np 4 -data input.csv -mgwr 78 | ``` 79 | where: 80 | 81 | ```bash 82 | -np 4 Number of processors (e.g. 4). 83 | -data input.csv Input data matrix. (e.g. input.csv) 84 | Can also be an URL (e.g. https://raw.github.com/ 85 | Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_1k.csv) 86 | -out results.csv Output GWR results matrix including local parameter 87 | estimates, standard errors and local diagnostics. 88 | -adaptive/-fixed Adaptive Bisquare kernel (defualt) or Fixed Gaussian kernel. 89 | -bw 1000 Pre-defined bandwidth parameter. If missing, it will 90 | search (golden-section) for the optimal bandwidth and use 91 | that to fit the GWR model. 92 | -minbw 45 Lower bound in golden-section search. (e.g. 45) 93 | -mgwr Fitting an MGWR model. 94 | -chunks Number of chunks for MGWR computation (set to a larger 95 | number to reduce memory footprint). 96 | -estonly Allowing MGWR to output parameter estimation only. 97 | ``` 98 | 99 | Alternatively, users can call the CLI from a Jupyter Notebook by prefixing `fastgwr` command the `!` character. [Examples notebooks](https://github.com/Ziqi-Li/FastGWR/tree/master/validation%20notebook) are available in the [Gituhb repository](https://github.com/Ziqi-Li/FastGWR). 100 | 101 | 102 | # Dependencies 103 | 104 | `fastgwr` is based on the following dependencies: 105 | 106 | - Any MPI Implementation (e.g. [OpenMPI](https://www.open-mpi.org): @gabriel2004open, [MPICH](https://www.mpich.org): @gropp1996user, [MS-MPI](https://docs.microsoft.com/en-us/message-passing-interface/microsoft-mpi)) 107 | - `mpi4py` [@dalcin2008mpi] 108 | - `numpy` [@van2011numpy] 109 | - `scipy` [@virtanen2020scipy] 110 | - `click`: https://github.com/pallets/click 111 | 112 | # References 113 | -------------------------------------------------------------------------------- /paper/scalability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ziqi-Li/FastGWR/a765df41bd75197e7d3ed2c0f54bb47875525ece/paper/scalability.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | mpi4py 2 | scipy 3 | numpy 4 | click 5 | twine 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from io import open 3 | from os import path 4 | 5 | import pathlib 6 | # The directory containing this file 7 | HERE = pathlib.Path(__file__).parent 8 | 9 | # The text of the README file 10 | README = (HERE / "README.md").read_text() 11 | 12 | # automatically captured required modules for install_requires in requirements.txt 13 | with open(path.join(HERE, 'requirements.txt'), encoding='utf-8') as f: 14 | all_reqs = f.read().split('\n') 15 | 16 | install_requires = [x.strip() for x in all_reqs if ('git+' not in x) and ( 17 | not x.startswith('#')) and (not x.startswith('-'))] 18 | dependency_links = [x.strip().replace('git+', '') for x in all_reqs \ 19 | if 'git+' not in x] 20 | 21 | 22 | setup( 23 | name="fastgwr", 24 | version='0.2.9', 25 | description="Fast Parallel Computation of Geographically Weighted Regression", 26 | long_description="A MPI-based command line tool for calibrating Geographically Weighted Regression models.", 27 | author="Ziqi Li", 28 | author_email="liziqi1992@gmail.com", 29 | url="https://github.com/Ziqi-Li/FastGWR", 30 | license="MIT", 31 | entry_points={'console_scripts': ['fastgwr=fastgwr.__main__:main',],}, 32 | dependency_links=dependency_links, 33 | install_requires = install_requires, 34 | packages = find_packages(), 35 | classifiers=[ 36 | "License :: OSI Approved :: MIT License", 37 | "Programming Language :: Python :: 2.7", 38 | "Programming Language :: Python :: 3", 39 | "Programming Language :: Python :: 3.7", 40 | ] 41 | ) 42 | 43 | -------------------------------------------------------------------------------- /validation notebook/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ziqi-Li/FastGWR/a765df41bd75197e7d3ed2c0f54bb47875525ece/validation notebook/.DS_Store -------------------------------------------------------------------------------- /validation notebook/GWR Results Validation against mgwr.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import math\n", 10 | "import sys,os\n", 11 | "import numpy as np\n", 12 | "import pandas as pd\n", 13 | "\n", 14 | "from mgwr.gwr import GWR,GWRResults\n", 15 | "from mgwr.sel_bw import Sel_BW" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 2, 21 | "metadata": {}, 22 | "outputs": [ 23 | { 24 | "data": { 25 | "text/html": [ 26 | "
\n", 27 | "\n", 40 | "\n", 41 | " \n", 42 | " \n", 43 | " \n", 44 | " \n", 45 | " \n", 46 | " \n", 47 | " \n", 48 | " \n", 49 | " \n", 50 | " \n", 51 | " \n", 52 | " \n", 53 | " \n", 54 | " \n", 55 | " \n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | "
utmXutmYvaluenbathsnbedsareaage
0379979.9572853.752562e+0687.3972.03.01311.061.0
1411210.6235783.762339e+06121.2112.04.01200.062.0
2400287.4863563.743925e+0676.1451.02.0724.070.0
3391029.6808993.776406e+06136.3202.03.01890.054.0
4371824.1111603.750099e+06100.4994.05.02166.071.0
\n", 106 | "
" 107 | ], 108 | "text/plain": [ 109 | " utmX utmY value nbaths nbeds area age\n", 110 | "0 379979.957285 3.752562e+06 87.397 2.0 3.0 1311.0 61.0\n", 111 | "1 411210.623578 3.762339e+06 121.211 2.0 4.0 1200.0 62.0\n", 112 | "2 400287.486356 3.743925e+06 76.145 1.0 2.0 724.0 70.0\n", 113 | "3 391029.680899 3.776406e+06 136.320 2.0 3.0 1890.0 54.0\n", 114 | "4 371824.111160 3.750099e+06 100.499 4.0 5.0 2166.0 71.0" 115 | ] 116 | }, 117 | "execution_count": 2, 118 | "metadata": {}, 119 | "output_type": "execute_result" 120 | } 121 | ], 122 | "source": [ 123 | "zillow = pd.read_csv(\"Zillow-test-dataset/zillow_5k.csv\",sep=',')\n", 124 | "zillow.head()" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 3, 130 | "metadata": {}, 131 | "outputs": [], 132 | "source": [ 133 | "#Converting things into matrices\n", 134 | "y = zillow.value.values.reshape(-1,1)\n", 135 | "X = zillow.iloc[:,3:].values\n", 136 | "k = zillow.shape[1]\n", 137 | "u = zillow.utmX\n", 138 | "v = zillow.utmY\n", 139 | "n = zillow.shape[0]\n", 140 | "coords = np.array(list(zip(u,v)))" 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "metadata": {}, 146 | "source": [ 147 | "### `mgwr`" 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": {}, 153 | "source": [ 154 | "#### Adaptive Bisquare Kernel" 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": 6, 160 | "metadata": {}, 161 | "outputs": [ 162 | { 163 | "name": "stdout", 164 | "output_type": "stream", 165 | "text": [ 166 | "Bandwidth: 1941.0 , score: 62998.99\n", 167 | "Bandwidth: 3109.0 , score: 63155.34\n", 168 | "Bandwidth: 1218.0 , score: 62834.64\n", 169 | "Bandwidth: 772.0 , score: 62623.87\n", 170 | "Bandwidth: 496.0 , score: 62394.91\n", 171 | "Bandwidth: 326.0 , score: 62176.77\n", 172 | "Bandwidth: 220.0 , score: 62010.24\n", 173 | "Bandwidth: 155.0 , score: 61900.35\n", 174 | "Bandwidth: 115.0 , score: 61877.92\n", 175 | "Bandwidth: 90.0 , score: 61928.28\n", 176 | "Bandwidth: 130.0 , score: 61872.72\n", 177 | "Bandwidth: 140.0 , score: 61880.08\n", 178 | "Bandwidth: 125.0 , score: 61868.41\n", 179 | "Bandwidth: 121.0 , score: 61867.18\n", 180 | "Bandwidth: 119.0 , score: 61869.76\n", 181 | "Bandwidth: 123.0 , score: 61868.12\n", 182 | "Optimal Bandwidth: 121.0\n", 183 | "CPU times: user 3min 28s, sys: 20.9 s, total: 3min 49s\n", 184 | "Wall time: 34.3 s\n" 185 | ] 186 | } 187 | ], 188 | "source": [ 189 | "%%time\n", 190 | "#Bandwidth searching\n", 191 | "opt_bw_adap = Sel_BW(coords,y,X).search(verbose=True)\n", 192 | "print(\"Optimal Bandwidth:\",opt_bw_adap)\n", 193 | "\n", 194 | "#Fitting the model with optimal bandwidth\n", 195 | "pysal_result_adap=GWR(coords,y,X,opt_bw_adap).fit()" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 7, 201 | "metadata": {}, 202 | "outputs": [ 203 | { 204 | "name": "stdout", 205 | "output_type": "stream", 206 | "text": [ 207 | "Bandwidth: 85088.9 , score: 63401.59\n", 208 | "Bandwidth: 137674.41 , score: 63412.23\n", 209 | "Bandwidth: 52587.49 , score: 63376.05\n", 210 | "Bandwidth: 32501.41 , score: 63319.11\n", 211 | "Bandwidth: 20086.84 , score: 63189.10\n", 212 | "Bandwidth: 12414.56 , score: 62823.09\n", 213 | "Bandwidth: 7672.57 , score: 62284.31\n", 214 | "Bandwidth: 4741.99 , score: 61925.83\n", 215 | "Bandwidth: 2930.69 , score: 61529.61\n", 216 | "Bandwidth: 1811.3 , score: 61093.24\n", 217 | "Bandwidth: 1119.44 , score: 61264.26\n", 218 | "Bandwidth: 2238.85 , score: 61276.52\n", 219 | "Bandwidth: 1547.02 , score: 61014.93\n", 220 | "Bandwidth: 1383.71 , score: 61028.14\n", 221 | "Bandwidth: 1647.97 , score: 61035.32\n", 222 | "Bandwidth: 1484.65 , score: 61012.03\n", 223 | "Bandwidth: 1446.09 , score: 61014.87\n", 224 | "Bandwidth: 1508.47 , score: 61012.11\n", 225 | "Bandwidth: 1469.91 , score: 61012.67\n", 226 | "Bandwidth: 1493.74 , score: 61011.91\n", 227 | "Bandwidth: 1499.37 , score: 61011.93\n", 228 | "Bandwidth: 1490.27 , score: 61011.93\n", 229 | "Bandwidth: 1495.89 , score: 61011.91\n", 230 | "Bandwidth: 1497.22 , score: 61011.91\n", 231 | "Bandwidth: 1495.07 , score: 61011.90\n", 232 | "Bandwidth: 1494.56 , score: 61011.90\n", 233 | "Bandwidth: 1495.38 , score: 61011.90\n", 234 | "Bandwidth: 1494.88 , score: 61011.90\n", 235 | "Bandwidth: 1495.19 , score: 61011.90\n", 236 | "Bandwidth: 1495.0 , score: 61011.90\n", 237 | "Bandwidth: 1495.12 , score: 61011.90\n", 238 | "Bandwidth: 1495.04 , score: 61011.90\n", 239 | "Optimal Bandwidth: 1495.04\n", 240 | "CPU times: user 6min 36s, sys: 38.2 s, total: 7min 14s\n", 241 | "Wall time: 1min 4s\n" 242 | ] 243 | } 244 | ], 245 | "source": [ 246 | "%%time\n", 247 | "#Bandwidth searching\n", 248 | "opt_bw_fixed = Sel_BW(coords,y,X,fixed=True,kernel=\"gaussian\").search(verbose=True)\n", 249 | "print(\"Optimal Bandwidth:\",opt_bw_fixed)\n", 250 | "\n", 251 | "#Fitting the model with optimal bandwidth\n", 252 | "pysal_result_fixed=GWR(coords,y,X,opt_bw_fixed,fixed=True,kernel=\"gaussian\").fit()" 253 | ] 254 | }, 255 | { 256 | "cell_type": "markdown", 257 | "metadata": {}, 258 | "source": [ 259 | "### FastGWR" 260 | ] 261 | }, 262 | { 263 | "cell_type": "markdown", 264 | "metadata": {}, 265 | "source": [ 266 | "#### Adaptive Kernel" 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": 8, 272 | "metadata": {}, 273 | "outputs": [ 274 | { 275 | "name": "stdout", 276 | "output_type": "stream", 277 | "text": [ 278 | "------------------------------------------------------------\n", 279 | "Starting FastGWR with 1 Processors\n", 280 | "Spatial Kernel: Adaptive Bisquare\n", 281 | "Data Input Path: Zillow-test-dataset/zillow_5k.csv\n", 282 | "Output Result Path: results_adap.csv\n", 283 | "Constant: True\n", 284 | "Optimal Bandwidth Searching...\n", 285 | "Range: 50 5000\n", 286 | "BW, AICc 1941.0 62998.99119669126\n", 287 | "BW, AICc 3109.0 63155.33894463485\n", 288 | "BW, AICc 1218.0 62834.63981029019\n", 289 | "BW, AICc 772.0 62623.87488968963\n", 290 | "BW, AICc 496.0 62394.91059361154\n", 291 | "BW, AICc 326.0 62176.772952292216\n", 292 | "BW, AICc 220.0 62010.24083279318\n", 293 | "BW, AICc 155.0 61900.34904388845\n", 294 | "BW, AICc 115.0 61877.92073505618\n", 295 | "BW, AICc 90.0 61928.281301868126\n", 296 | "BW, AICc 130.0 61872.71759124702\n", 297 | "BW, AICc 140.0 61880.08193188456\n", 298 | "BW, AICc 125.0 61868.40676858912\n", 299 | "BW, AICc 121.0 61867.18296256345\n", 300 | "BW, AICc 119.0 61869.759931302826\n", 301 | "BW, AICc 123.0 61868.11546142209\n", 302 | "Fitting GWR Using Bandwidth: 121.0\n", 303 | "Diagnostic Information:\n", 304 | "AICc: 61867.18296256346\n", 305 | "ENP: 528.2622212380004\n", 306 | "R2: 0.7741417970962883\n", 307 | "Total Time Elapsed: 25.72 seconds\n", 308 | "------------------------------------------------------------\n" 309 | ] 310 | } 311 | ], 312 | "source": [ 313 | "#Running FastGWR 1 Processor with auto bandwidth search\n", 314 | "!fastgwr run -np 1 -data Zillow-test-dataset/zillow_5k.csv -out results_adap.csv -adaptive -constant" 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": 9, 320 | "metadata": {}, 321 | "outputs": [ 322 | { 323 | "name": "stdout", 324 | "output_type": "stream", 325 | "text": [ 326 | "------------------------------------------------------------\n", 327 | "Starting FastGWR with 4 Processors\n", 328 | "Spatial Kernel: Adaptive Bisquare\n", 329 | "Data Input Path: Zillow-test-dataset/zillow_5k.csv\n", 330 | "Output Result Path: results_adap.csv\n", 331 | "Constant: True\n", 332 | "Optimal Bandwidth Searching...\n", 333 | "Range: 50 5000\n", 334 | "BW, AICc 1941.0 62998.99119669126\n", 335 | "BW, AICc 3109.0 63155.33894463484\n", 336 | "BW, AICc 1218.0 62834.63981029017\n", 337 | "BW, AICc 772.0 62623.874889689614\n", 338 | "BW, AICc 496.0 62394.91059361154\n", 339 | "BW, AICc 326.0 62176.772952292216\n", 340 | "BW, AICc 220.0 62010.240832793184\n", 341 | "BW, AICc 155.0 61900.34904388847\n", 342 | "BW, AICc 115.0 61877.920735056185\n", 343 | "BW, AICc 90.0 61928.281301868104\n", 344 | "BW, AICc 130.0 61872.717591247\n", 345 | "BW, AICc 140.0 61880.08193188456\n", 346 | "BW, AICc 125.0 61868.40676858913\n", 347 | "BW, AICc 121.0 61867.18296256346\n", 348 | "BW, AICc 119.0 61869.75993130282\n", 349 | "BW, AICc 123.0 61868.11546142208\n", 350 | "Fitting GWR Using Bandwidth: 121.0\n", 351 | "Diagnostic Information:\n", 352 | "AICc: 61867.18296256346\n", 353 | "ENP: 528.2622212380004\n", 354 | "R2: 0.7741417970962883\n", 355 | "Total Time Elapsed: 12.28 seconds\n", 356 | "------------------------------------------------------------\n" 357 | ] 358 | } 359 | ], 360 | "source": [ 361 | "#Running FastGWR 4 Processor\n", 362 | "!fastgwr run -np 4 -data Zillow-test-dataset/zillow_5k.csv -out results_adap.csv -adaptive -constant" 363 | ] 364 | }, 365 | { 366 | "cell_type": "markdown", 367 | "metadata": {}, 368 | "source": [ 369 | "#### Fixed Gaussian kernel" 370 | ] 371 | }, 372 | { 373 | "cell_type": "code", 374 | "execution_count": 10, 375 | "metadata": {}, 376 | "outputs": [ 377 | { 378 | "name": "stdout", 379 | "output_type": "stream", 380 | "text": [ 381 | "------------------------------------------------------------\n", 382 | "Starting FastGWR with 4 Processors\n", 383 | "Spatial Kernel: Fixed Gaussian\n", 384 | "Data Input Path: Zillow-test-dataset/zillow_5k.csv\n", 385 | "Output Result Path: results_fixed.csv\n", 386 | "Constant: True\n", 387 | "Optimal Bandwidth Searching...\n", 388 | "Range: 0.0 222763.307902534\n", 389 | "BW, AICc 85088.90071953091 63401.587701945275\n", 390 | "BW, AICc 137674.4071830031 63412.23473987967\n", 391 | "BW, AICc 52587.49331169169 63376.049939236196\n", 392 | "BW, AICc 32501.40740783922 63319.11111531032\n", 393 | "BW, AICc 20086.844820266873 63189.09679320165\n", 394 | "BW, AICc 12414.562587572345 62823.090184067856\n", 395 | "BW, AICc 7672.572115997337 62284.30873222015\n", 396 | "BW, AICc 4741.990471575008 61925.82638349446\n", 397 | "BW, AICc 2930.692371147503 61529.608314945304\n", 398 | "BW, AICc 1811.2981004275057 61093.23641471484\n", 399 | "BW, AICc 1119.4365650072116 61264.25581814983\n", 400 | "BW, AICc 2238.846990876096 61276.52126845023\n", 401 | "BW, AICc 1547.0177653763492 61014.93422823765\n", 402 | "BW, AICc 1383.7069156917014 61028.14490111669\n", 403 | "BW, AICc 1647.9710955939706 61035.3151728618\n", 404 | "BW, AICc 1484.647904488971 61012.03333897104\n", 405 | "BW, AICc 1446.0867609457464 61014.87098194722\n", 406 | "BW, AICc 1508.4651496139918 61012.114571544145\n", 407 | "BW, AICc 1469.9134340653561 61012.668819781014\n", 408 | "BW, AICc 1493.7395508258794 61011.90638139832\n", 409 | "BW, AICc 1499.3676764935876 61011.92640560723\n", 410 | "BW, AICc 1490.2704158015745 61011.93140297951\n", 411 | "BW, AICc 1495.8927958270594 61011.90523225499\n", 412 | "BW, AICc 1497.2179013322932 61011.909963639686\n", 413 | "BW, AICc 1495.0681763688142 61011.904376873215\n", 414 | "BW, AICc 1494.5620258189801 61011.90464764216\n", 415 | "BW, AICc 1495.3844816070734 61011.90451517085\n", 416 | "BW, AICc 1494.8761792563582 61011.90440825117\n", 417 | "BW, AICc 1495.1903253581706 61011.904402263965\n", 418 | "BW, AICc 1494.9961736428675 61011.904378426836\n", 419 | "BW, AICc 1495.1161652274764 61011.90438264309\n", 420 | "BW, AICc 1495.0420068284404 61011.9043760202\n", 421 | "Fitting GWR Using Bandwidth: 1495.04\n", 422 | "Diagnostic Information:\n", 423 | "AICc: 61011.90437602185\n", 424 | "ENP: 897.4871734475491\n", 425 | "R2: 0.8443763943519641\n", 426 | "Total Time Elapsed: 21.84 seconds\n", 427 | "------------------------------------------------------------\n" 428 | ] 429 | } 430 | ], 431 | "source": [ 432 | "#Running FastGWR 4 Processor\n", 433 | "!fastgwr run -np 4 -data Zillow-test-dataset/zillow_5k.csv -out results_fixed.csv -fixed -constant" 434 | ] 435 | }, 436 | { 437 | "cell_type": "markdown", 438 | "metadata": {}, 439 | "source": [ 440 | "### Results validation" 441 | ] 442 | }, 443 | { 444 | "cell_type": "code", 445 | "execution_count": 11, 446 | "metadata": {}, 447 | "outputs": [ 448 | { 449 | "name": "stdout", 450 | "output_type": "stream", 451 | "text": [ 452 | "Adaptive kernel: pysal AICc - 61867.18296256348\n", 453 | "Adaptive kernel: pysal R2 - 0.7741417970962875\n", 454 | "Fixed kernel: pysal AICc - 61011.90437602184\n", 455 | "Fixed kernel: pysal R2 - 0.8443763943519637\n" 456 | ] 457 | } 458 | ], 459 | "source": [ 460 | "print(\"Adaptive kernel: pysal AICc - \", pysal_result_adap.aicc)\n", 461 | "print(\"Adaptive kernel: pysal R2 - \",pysal_result_adap.R2)\n", 462 | "\n", 463 | "print(\"Fixed kernel: pysal AICc - \", pysal_result_fixed.aicc)\n", 464 | "print(\"Fixed kernel: pysal R2 - \",pysal_result_fixed.R2)" 465 | ] 466 | }, 467 | { 468 | "cell_type": "code", 469 | "execution_count": 12, 470 | "metadata": {}, 471 | "outputs": [ 472 | { 473 | "data": { 474 | "text/html": [ 475 | "
\n", 476 | "\n", 489 | "\n", 490 | " \n", 491 | " \n", 492 | " \n", 493 | " \n", 494 | " \n", 495 | " \n", 496 | " \n", 497 | " \n", 498 | " \n", 499 | " \n", 500 | " \n", 501 | " \n", 502 | " \n", 503 | " \n", 504 | " \n", 505 | " \n", 506 | " \n", 507 | " \n", 508 | " \n", 509 | " \n", 510 | " \n", 511 | " \n", 512 | " \n", 513 | " \n", 514 | " \n", 515 | " \n", 516 | " \n", 517 | " \n", 518 | " \n", 519 | " \n", 520 | " \n", 521 | " \n", 522 | " \n", 523 | " \n", 524 | " \n", 525 | " \n", 526 | " \n", 527 | " \n", 528 | " \n", 529 | " \n", 530 | " \n", 531 | " \n", 532 | " \n", 533 | " \n", 534 | " \n", 535 | " \n", 536 | " \n", 537 | " \n", 538 | " \n", 539 | " \n", 540 | " \n", 541 | " \n", 542 | " \n", 543 | " \n", 544 | " \n", 545 | " \n", 546 | " \n", 547 | " \n", 548 | " \n", 549 | " \n", 550 | " \n", 551 | " \n", 552 | " \n", 553 | " \n", 554 | " \n", 555 | " \n", 556 | " \n", 557 | " \n", 558 | " \n", 559 | " \n", 560 | " \n", 561 | " \n", 562 | " \n", 563 | " \n", 564 | " \n", 565 | " \n", 566 | " \n", 567 | " \n", 568 | " \n", 569 | " \n", 570 | " \n", 571 | " \n", 572 | " \n", 573 | " \n", 574 | " \n", 575 | " \n", 576 | " \n", 577 | " \n", 578 | " \n", 579 | " \n", 580 | " \n", 581 | " \n", 582 | " \n", 583 | " \n", 584 | " \n", 585 | " \n", 586 | " \n", 587 | " \n", 588 | " \n", 589 | " \n", 590 | "
indexresidualinflub_interceptb_nbathsb_nbedsb_areab_agese_interceptse_nbathsse_nbedsse_arease_age
00.017.9521680.044251-77.847200-7.20795711.0625450.0906870.157855111.05345035.57151925.8934630.0606101.221988
11.087.1333870.06752991.2006903.714871-31.6889640.153827-1.974029100.21021433.22067921.4638950.0314281.175032
22.037.4813550.06998365.2929237.1319996.7218800.065560-1.352434127.31178829.50528822.6893250.0421781.544978
33.0-79.1081100.05162589.411082-8.403962-57.8249640.191006-0.82781166.51751327.88367718.3934060.0354240.564270
44.0-188.0884090.19513662.81350670.535078-0.5822260.081513-3.23961692.11104621.71597618.5916000.0298620.996363
\n", 591 | "
" 592 | ], 593 | "text/plain": [ 594 | " index residual influ b_intercept b_nbaths b_nbeds b_area \\\n", 595 | "0 0.0 17.952168 0.044251 -77.847200 -7.207957 11.062545 0.090687 \n", 596 | "1 1.0 87.133387 0.067529 91.200690 3.714871 -31.688964 0.153827 \n", 597 | "2 2.0 37.481355 0.069983 65.292923 7.131999 6.721880 0.065560 \n", 598 | "3 3.0 -79.108110 0.051625 89.411082 -8.403962 -57.824964 0.191006 \n", 599 | "4 4.0 -188.088409 0.195136 62.813506 70.535078 -0.582226 0.081513 \n", 600 | "\n", 601 | " b_age se_intercept se_nbaths se_nbeds se_area se_age \n", 602 | "0 0.157855 111.053450 35.571519 25.893463 0.060610 1.221988 \n", 603 | "1 -1.974029 100.210214 33.220679 21.463895 0.031428 1.175032 \n", 604 | "2 -1.352434 127.311788 29.505288 22.689325 0.042178 1.544978 \n", 605 | "3 -0.827811 66.517513 27.883677 18.393406 0.035424 0.564270 \n", 606 | "4 -3.239616 92.111046 21.715976 18.591600 0.029862 0.996363 " 607 | ] 608 | }, 609 | "execution_count": 12, 610 | "metadata": {}, 611 | "output_type": "execute_result" 612 | } 613 | ], 614 | "source": [ 615 | "fastGWR_result_fixed = pd.read_csv(\"results_fixed.csv\")\n", 616 | "fastGWR_result_adap = pd.read_csv(\"results_adap.csv\")\n", 617 | "fastGWR_result_adap.head()" 618 | ] 619 | }, 620 | { 621 | "cell_type": "code", 622 | "execution_count": 13, 623 | "metadata": {}, 624 | "outputs": [ 625 | { 626 | "name": "stdout", 627 | "output_type": "stream", 628 | "text": [ 629 | "True\n", 630 | "True\n" 631 | ] 632 | } 633 | ], 634 | "source": [ 635 | "#Validate model residual\n", 636 | "print(np.allclose(fastGWR_result_fixed.residual,pysal_result_fixed.resid_response.reshape(-1)))\n", 637 | "print(np.allclose(fastGWR_result_adap.residual,pysal_result_adap.resid_response.reshape(-1)))" 638 | ] 639 | }, 640 | { 641 | "cell_type": "code", 642 | "execution_count": 14, 643 | "metadata": {}, 644 | "outputs": [ 645 | { 646 | "name": "stdout", 647 | "output_type": "stream", 648 | "text": [ 649 | "True\n", 650 | "True\n" 651 | ] 652 | } 653 | ], 654 | "source": [ 655 | "#Validate parameter estimates\n", 656 | "print(np.allclose(np.array(fastGWR_result_fixed.iloc[:,3:8]),pysal_result_fixed.params))\n", 657 | "print(np.allclose(np.array(fastGWR_result_adap.iloc[:,3:8]),pysal_result_adap.params))" 658 | ] 659 | }, 660 | { 661 | "cell_type": "code", 662 | "execution_count": 15, 663 | "metadata": {}, 664 | "outputs": [ 665 | { 666 | "name": "stdout", 667 | "output_type": "stream", 668 | "text": [ 669 | "True\n", 670 | "True\n" 671 | ] 672 | } 673 | ], 674 | "source": [ 675 | "#Validate parameter estimates standard errors\n", 676 | "print(np.allclose(np.array(fastGWR_result_adap.iloc[:,8:13]),pysal_result_adap.bse))\n", 677 | "print(np.allclose(np.array(fastGWR_result_fixed.iloc[:,8:13]),pysal_result_fixed.bse))" 678 | ] 679 | }, 680 | { 681 | "cell_type": "code", 682 | "execution_count": null, 683 | "metadata": {}, 684 | "outputs": [], 685 | "source": [] 686 | }, 687 | { 688 | "cell_type": "code", 689 | "execution_count": null, 690 | "metadata": {}, 691 | "outputs": [], 692 | "source": [] 693 | } 694 | ], 695 | "metadata": { 696 | "kernelspec": { 697 | "display_name": "Python 3", 698 | "language": "python", 699 | "name": "python3" 700 | }, 701 | "language_info": { 702 | "codemirror_mode": { 703 | "name": "ipython", 704 | "version": 3 705 | }, 706 | "file_extension": ".py", 707 | "mimetype": "text/x-python", 708 | "name": "python", 709 | "nbconvert_exporter": "python", 710 | "pygments_lexer": "ipython3", 711 | "version": "3.7.6" 712 | } 713 | }, 714 | "nbformat": 4, 715 | "nbformat_minor": 2 716 | } 717 | -------------------------------------------------------------------------------- /validation notebook/GWR scalability test Mac.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Test for GWR scalability on a Mac with 2 GHz Quad-Core Intel Core i5 based on 20k Zillow records." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [ 15 | { 16 | "name": "stdout", 17 | "output_type": "stream", 18 | "text": [ 19 | "fastgwr, version 0.2.8\r\n" 20 | ] 21 | } 22 | ], 23 | "source": [ 24 | "!fastgwr --version" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "Performance of `fastgwr` with 1 processor" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 2, 37 | "metadata": {}, 38 | "outputs": [ 39 | { 40 | "name": "stdout", 41 | "output_type": "stream", 42 | "text": [ 43 | "------------------------------------------------------------\n", 44 | "Starting FastGWR with 1 Processors\n", 45 | "Spatial Kernel: Adaptive Bisquare\n", 46 | "Data Input Path: https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_20k.csv\n", 47 | "Output Result Path: fastgwr_rslt.csv\n", 48 | "Intercept: True\n", 49 | "Optimal Bandwidth Searching...\n", 50 | "Range: 50 20000\n", 51 | "BW, AICc 7670.0 251215.3542273905\n", 52 | "BW, AICc 12380.0 251887.46215700492\n", 53 | "BW, AICc 4760.0 250338.0363590131\n", 54 | "BW, AICc 2961.0 249530.96308110983\n", 55 | "BW, AICc 1849.0 248972.96316830348\n", 56 | "BW, AICc 1162.0 248372.58315837776\n", 57 | "BW, AICc 737.0 247794.44121752455\n", 58 | "BW, AICc 475.0 247274.92463894008\n", 59 | "BW, AICc 312.0 246862.23186354767\n", 60 | "BW, AICc 212.0 246573.90619644083\n", 61 | "BW, AICc 150.0 246370.13897186716\n", 62 | "BW, AICc 112.0 246331.7765445473\n", 63 | "BW, AICc 88.0 246507.08873301116\n", 64 | "BW, AICc 126.0 246314.23013786436\n", 65 | "BW, AICc 135.0 246322.2376709976\n", 66 | "BW, AICc 121.0 246320.44353618988\n", 67 | "BW, AICc 130.0 246319.64794821435\n", 68 | "BW, AICc 124.0 246322.78583452798\n", 69 | "BW, AICc 128.0 246309.68704617332\n", 70 | "Fitting GWR Using Bandwidth: 128.0\n", 71 | "Diagnostic Information:\n", 72 | "AICc: 246309.68704617335\n", 73 | "ENP: 1984.7000479255407\n", 74 | "R2: 0.7655872633750118\n", 75 | "Total Time Elapsed: 325.94 seconds\n", 76 | "------------------------------------------------------------\n" 77 | ] 78 | } 79 | ], 80 | "source": [ 81 | "!fastgwr run -np 1 -data https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_20k.csv" 82 | ] 83 | }, 84 | { 85 | "cell_type": "markdown", 86 | "metadata": {}, 87 | "source": [ 88 | "Performance of `fastgwr` with 2 processors" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 3, 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "name": "stdout", 98 | "output_type": "stream", 99 | "text": [ 100 | "------------------------------------------------------------\n", 101 | "Starting FastGWR with 2 Processors\n", 102 | "Spatial Kernel: Adaptive Bisquare\n", 103 | "Data Input Path: https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_20k.csv\n", 104 | "Output Result Path: fastgwr_rslt.csv\n", 105 | "Intercept: True\n", 106 | "Optimal Bandwidth Searching...\n", 107 | "Range: 50 20000\n", 108 | "BW, AICc 7670.0 251215.3542273905\n", 109 | "BW, AICc 12380.0 251887.462157005\n", 110 | "BW, AICc 4760.0 250338.03635901297\n", 111 | "BW, AICc 2961.0 249530.9630811097\n", 112 | "BW, AICc 1849.0 248972.96316830357\n", 113 | "BW, AICc 1162.0 248372.58315837773\n", 114 | "BW, AICc 737.0 247794.44121752447\n", 115 | "BW, AICc 475.0 247274.92463894002\n", 116 | "BW, AICc 312.0 246862.23186354764\n", 117 | "BW, AICc 212.0 246573.9061964408\n", 118 | "BW, AICc 150.0 246370.13897186713\n", 119 | "BW, AICc 112.0 246331.7765445473\n", 120 | "BW, AICc 88.0 246507.08873301113\n", 121 | "BW, AICc 126.0 246314.2301378644\n", 122 | "BW, AICc 135.0 246322.23767099762\n", 123 | "BW, AICc 121.0 246320.44353619\n", 124 | "BW, AICc 130.0 246319.64794821417\n", 125 | "BW, AICc 124.0 246322.78583452798\n", 126 | "BW, AICc 128.0 246309.68704617344\n", 127 | "Fitting GWR Using Bandwidth: 128.0\n", 128 | "Diagnostic Information:\n", 129 | "AICc: 246309.68704617335\n", 130 | "ENP: 1984.7000479255407\n", 131 | "R2: 0.7655872633750118\n", 132 | "Total Time Elapsed: 228.17 seconds\n", 133 | "------------------------------------------------------------\n" 134 | ] 135 | } 136 | ], 137 | "source": [ 138 | "!fastgwr run -np 2 -data https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_20k.csv" 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "metadata": {}, 144 | "source": [ 145 | "Performance of `fastgwr` with 4 processors" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 4, 151 | "metadata": {}, 152 | "outputs": [ 153 | { 154 | "name": "stdout", 155 | "output_type": "stream", 156 | "text": [ 157 | "------------------------------------------------------------\n", 158 | "Starting FastGWR with 4 Processors\n", 159 | "Spatial Kernel: Adaptive Bisquare\n", 160 | "Data Input Path: https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_20k.csv\n", 161 | "Output Result Path: fastgwr_rslt.csv\n", 162 | "Intercept: True\n", 163 | "Optimal Bandwidth Searching...\n", 164 | "Range: 50 20000\n", 165 | "BW, AICc 7670.0 251215.3542273905\n", 166 | "BW, AICc 12380.0 251887.462157005\n", 167 | "BW, AICc 4760.0 250338.03635901297\n", 168 | "BW, AICc 2961.0 249530.9630811097\n", 169 | "BW, AICc 1849.0 248972.96316830354\n", 170 | "BW, AICc 1162.0 248372.58315837773\n", 171 | "BW, AICc 737.0 247794.44121752444\n", 172 | "BW, AICc 475.0 247274.92463894002\n", 173 | "BW, AICc 312.0 246862.23186354773\n", 174 | "BW, AICc 212.0 246573.90619644074\n", 175 | "BW, AICc 150.0 246370.13897186713\n", 176 | "BW, AICc 112.0 246331.77654454726\n", 177 | "BW, AICc 88.0 246507.08873301116\n", 178 | "BW, AICc 126.0 246314.23013786442\n", 179 | "BW, AICc 135.0 246322.2376709976\n", 180 | "BW, AICc 121.0 246320.44353618997\n", 181 | "BW, AICc 130.0 246319.64794821417\n", 182 | "BW, AICc 124.0 246322.78583452807\n", 183 | "BW, AICc 128.0 246309.68704617338\n", 184 | "Fitting GWR Using Bandwidth: 128.0\n", 185 | "Diagnostic Information:\n", 186 | "AICc: 246309.68704617335\n", 187 | "ENP: 1984.7000479255407\n", 188 | "R2: 0.7655872633750118\n", 189 | "Total Time Elapsed: 156.34 seconds\n", 190 | "------------------------------------------------------------\n" 191 | ] 192 | } 193 | ], 194 | "source": [ 195 | "!fastgwr run -np 4 -data https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_20k.csv" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": null, 201 | "metadata": {}, 202 | "outputs": [], 203 | "source": [] 204 | } 205 | ], 206 | "metadata": { 207 | "kernelspec": { 208 | "display_name": "Python 3", 209 | "language": "python", 210 | "name": "python3" 211 | }, 212 | "language_info": { 213 | "codemirror_mode": { 214 | "name": "ipython", 215 | "version": 3 216 | }, 217 | "file_extension": ".py", 218 | "mimetype": "text/x-python", 219 | "name": "python", 220 | "nbconvert_exporter": "python", 221 | "pygments_lexer": "ipython3", 222 | "version": "3.7.6" 223 | } 224 | }, 225 | "nbformat": 4, 226 | "nbformat_minor": 2 227 | } 228 | -------------------------------------------------------------------------------- /validation notebook/MGWR Results Validation against mgwr.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import math\n", 10 | "import sys,os\n", 11 | "import numpy as np\n", 12 | "import pandas as pd\n", 13 | "\n", 14 | "from mgwr.gwr import GWR,MGWR\n", 15 | "from mgwr.sel_bw import Sel_BW" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 2, 21 | "metadata": {}, 22 | "outputs": [ 23 | { 24 | "data": { 25 | "text/html": [ 26 | "
\n", 27 | "\n", 40 | "\n", 41 | " \n", 42 | " \n", 43 | " \n", 44 | " \n", 45 | " \n", 46 | " \n", 47 | " \n", 48 | " \n", 49 | " \n", 50 | " \n", 51 | " \n", 52 | " \n", 53 | " \n", 54 | " \n", 55 | " \n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | "
utmXutmYvaluenbathsnbedsareaage
0374161.3338303.757568e+0656.9761.02.0954.071.0
1412657.8229103.761734e+06157.9822.04.01614.045.0
2391600.4756403.782212e+06512.6124.04.02962.054.0
3375056.0646813.748579e+06111.4372.03.01292.065.0
4388693.6930383.779865e+06128.3271.03.01169.078.0
\n", 106 | "
" 107 | ], 108 | "text/plain": [ 109 | " utmX utmY value nbaths nbeds area age\n", 110 | "0 374161.333830 3.757568e+06 56.976 1.0 2.0 954.0 71.0\n", 111 | "1 412657.822910 3.761734e+06 157.982 2.0 4.0 1614.0 45.0\n", 112 | "2 391600.475640 3.782212e+06 512.612 4.0 4.0 2962.0 54.0\n", 113 | "3 375056.064681 3.748579e+06 111.437 2.0 3.0 1292.0 65.0\n", 114 | "4 388693.693038 3.779865e+06 128.327 1.0 3.0 1169.0 78.0" 115 | ] 116 | }, 117 | "execution_count": 2, 118 | "metadata": {}, 119 | "output_type": "execute_result" 120 | } 121 | ], 122 | "source": [ 123 | "zillow = pd.read_csv(\"https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_1k.csv\",sep=',')\n", 124 | "zillow.head()" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 3, 130 | "metadata": {}, 131 | "outputs": [], 132 | "source": [ 133 | "#Converting things into matrices\n", 134 | "y = zillow.value.values.reshape(-1,1)\n", 135 | "X = zillow.iloc[:,3:].values\n", 136 | "k = zillow.shape[1]\n", 137 | "u = zillow.utmX\n", 138 | "v = zillow.utmY\n", 139 | "n = zillow.shape[0]\n", 140 | "coords = np.array(list(zip(u,v)))" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 4, 146 | "metadata": {}, 147 | "outputs": [], 148 | "source": [ 149 | "X = (X - np.mean(X,axis=0))/np.std(X, axis=0)\n", 150 | "y = (y - np.mean(y,axis=0))/np.std(y, axis=0)" 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "metadata": {}, 156 | "source": [ 157 | "### `mgwr`" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": 5, 163 | "metadata": {}, 164 | "outputs": [ 165 | { 166 | "data": { 167 | "application/vnd.jupyter.widget-view+json": { 168 | "model_id": "76c064a446224e43a5d427954a9ea818", 169 | "version_major": 2, 170 | "version_minor": 0 171 | }, 172 | "text/plain": [ 173 | "HBox(children=(FloatProgress(value=0.0, description='Backfitting', max=200.0, style=ProgressStyle(description_…" 174 | ] 175 | }, 176 | "metadata": {}, 177 | "output_type": "display_data" 178 | }, 179 | { 180 | "name": "stdout", 181 | "output_type": "stream", 182 | "text": [ 183 | "Current iteration: 1 ,SOC: 0.0054557\n", 184 | "Bandwidths: 133.0, 52.0, 116.0, 82.0, 50.0\n", 185 | "Current iteration: 2 ,SOC: 0.0044876\n", 186 | "Bandwidths: 158.0, 105.0, 120.0, 55.0, 50.0\n", 187 | "Current iteration: 3 ,SOC: 0.0026065\n", 188 | "Bandwidths: 182.0, 127.0, 122.0, 55.0, 43.0\n", 189 | "Current iteration: 4 ,SOC: 0.0022962\n", 190 | "Bandwidths: 202.0, 195.0, 122.0, 55.0, 43.0\n", 191 | "Current iteration: 5 ,SOC: 0.0016683\n", 192 | "Bandwidths: 202.0, 285.0, 125.0, 55.0, 43.0\n", 193 | "Current iteration: 6 ,SOC: 0.0010319\n", 194 | "Bandwidths: 202.0, 365.0, 125.0, 55.0, 43.0\n", 195 | "Current iteration: 7 ,SOC: 0.0013286\n", 196 | "Bandwidths: 202.0, 999.0, 125.0, 55.0, 43.0\n", 197 | "Current iteration: 8 ,SOC: 0.0004091\n", 198 | "Bandwidths: 202.0, 999.0, 125.0, 55.0, 43.0\n", 199 | "Current iteration: 9 ,SOC: 0.0001911\n", 200 | "Bandwidths: 202.0, 999.0, 125.0, 55.0, 43.0\n", 201 | "Current iteration: 10 ,SOC: 0.0001056\n", 202 | "Bandwidths: 202.0, 999.0, 125.0, 55.0, 43.0\n", 203 | "Current iteration: 11 ,SOC: 6.57e-05\n", 204 | "Bandwidths: 202.0, 999.0, 125.0, 55.0, 43.0\n", 205 | "Current iteration: 12 ,SOC: 4.4e-05\n", 206 | "Bandwidths: 202.0, 999.0, 125.0, 55.0, 43.0\n", 207 | "Current iteration: 13 ,SOC: 3.1e-05\n", 208 | "Bandwidths: 202.0, 999.0, 125.0, 55.0, 43.0\n", 209 | "Current iteration: 14 ,SOC: 2.25e-05\n", 210 | "Bandwidths: 202.0, 999.0, 125.0, 55.0, 43.0\n", 211 | "Current iteration: 15 ,SOC: 1.66e-05\n", 212 | "Bandwidths: 202.0, 999.0, 125.0, 55.0, 43.0\n", 213 | "Current iteration: 16 ,SOC: 1.23e-05\n", 214 | "Bandwidths: 202.0, 999.0, 125.0, 55.0, 43.0\n", 215 | "Current iteration: 17 ,SOC: 9.1e-06\n", 216 | "Bandwidths: 202.0, 999.0, 125.0, 55.0, 43.0\n", 217 | "Optimal Bandwidths: [202. 999. 125. 55. 43.]\n" 218 | ] 219 | }, 220 | { 221 | "data": { 222 | "application/vnd.jupyter.widget-view+json": { 223 | "model_id": "9da3ffa9a48e4452b4ff38ef1b89d3ec", 224 | "version_major": 2, 225 | "version_minor": 0 226 | }, 227 | "text/plain": [ 228 | "HBox(children=(FloatProgress(value=0.0, description='Inference', max=1.0, style=ProgressStyle(description_widt…" 229 | ] 230 | }, 231 | "metadata": {}, 232 | "output_type": "display_data" 233 | }, 234 | { 235 | "name": "stdout", 236 | "output_type": "stream", 237 | "text": [ 238 | "\n", 239 | "CPU times: user 6min 59s, sys: 4.98 s, total: 7min 4s\n", 240 | "Wall time: 1min 48s\n" 241 | ] 242 | } 243 | ], 244 | "source": [ 245 | "%%time\n", 246 | "#Bandwidth searching\n", 247 | "selector = Sel_BW(coords,y,X,multi=True)\n", 248 | "bws = selector.search(verbose=True)\n", 249 | "print(\"Optimal Bandwidths:\",bws)\n", 250 | "\n", 251 | "#Fitting the model with optimal bandwidth\n", 252 | "pysal_result_mgwr=MGWR(coords,y,X,selector=selector).fit()" 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": 13, 258 | "metadata": {}, 259 | "outputs": [ 260 | { 261 | "name": "stdout", 262 | "output_type": "stream", 263 | "text": [ 264 | "fastgwr, version 0.2.8\r\n" 265 | ] 266 | } 267 | ], 268 | "source": [ 269 | "!fastgwr --version" 270 | ] 271 | }, 272 | { 273 | "cell_type": "markdown", 274 | "metadata": {}, 275 | "source": [ 276 | "### FastGWR" 277 | ] 278 | }, 279 | { 280 | "cell_type": "code", 281 | "execution_count": 14, 282 | "metadata": {}, 283 | "outputs": [ 284 | { 285 | "name": "stdout", 286 | "output_type": "stream", 287 | "text": [ 288 | "------------------------------------------------------------\n", 289 | "Starting FastGWR with 4 Processors\n", 290 | "Spatial Kernel: Adaptive Bisquare\n", 291 | "Data Input Path: https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_1k.csv\n", 292 | "Output Result Path: fastgwr_rslt.csv\n", 293 | "Intercept: True\n", 294 | "MGWR Backfitting...\n", 295 | "Data are standardized\n", 296 | "Initialization Done...\n", 297 | "Iter: 1 SOC: 5.46e-03\n", 298 | "bws: [133.0, 52.0, 116.0, 82.0, 50.0]\n", 299 | "Iter: 2 SOC: 4.49e-03\n", 300 | "bws: [158.0, 105.0, 120.0, 55.0, 50.0]\n", 301 | "Iter: 3 SOC: 2.61e-03\n", 302 | "bws: [182.0, 127.0, 122.0, 55.0, 43.0]\n", 303 | "Iter: 4 SOC: 2.30e-03\n", 304 | "bws: [202.0, 195.0, 122.0, 55.0, 43.0]\n", 305 | "Iter: 5 SOC: 1.67e-03\n", 306 | "bws: [202.0, 285.0, 125.0, 55.0, 43.0]\n", 307 | "Iter: 6 SOC: 1.03e-03\n", 308 | "bws: [202.0, 365.0, 125.0, 55.0, 43.0]\n", 309 | "Iter: 7 SOC: 1.33e-03\n", 310 | "bws: [202.0, 999.0, 125.0, 55.0, 43.0]\n", 311 | "Iter: 8 SOC: 4.09e-04\n", 312 | "bws: [202.0, 999.0, 125.0, 55.0, 43.0]\n", 313 | "Iter: 9 SOC: 1.91e-04\n", 314 | "bws: [202.0, 999.0, 125.0, 55.0, 43.0]\n", 315 | "Iter: 10 SOC: 1.06e-04\n", 316 | "bws: [202.0, 999.0, 125.0, 55.0, 43.0]\n", 317 | "Iter: 11 SOC: 6.57e-05\n", 318 | "bws: [202.0, 999.0, 125.0, 55.0, 43.0]\n", 319 | "Iter: 12 SOC: 4.40e-05\n", 320 | "bws: [202.0, 999.0, 125.0, 55.0, 43.0]\n", 321 | "Iter: 13 SOC: 3.10e-05\n", 322 | "bws: [202.0, 999.0, 125.0, 55.0, 43.0]\n", 323 | "Iter: 14 SOC: 2.25e-05\n", 324 | "bws: [202.0, 999.0, 125.0, 55.0, 43.0]\n", 325 | "Iter: 15 SOC: 1.66e-05\n", 326 | "bws: [202.0, 999.0, 125.0, 55.0, 43.0]\n", 327 | "Iter: 16 SOC: 1.23e-05\n", 328 | "bws: [202.0, 999.0, 125.0, 55.0, 43.0]\n", 329 | "Iter: 17 SOC: 9.14e-06\n", 330 | "bws: [202.0, 999.0, 125.0, 55.0, 43.0]\n", 331 | "Computing Inference with 1 Chunk(s)\n", 332 | "Diagnostic Information:\n", 333 | "AICc: 1679.0150747382897\n", 334 | "ENP: [10.13917587 1.15749374 16.97300011 42.38091109 56.32981658]\n", 335 | "R2: 0.7660681409024722\n", 336 | "Total Time Elapsed: 34.19 seconds\n", 337 | "------------------------------------------------------------\n" 338 | ] 339 | } 340 | ], 341 | "source": [ 342 | "#Running FastGWR 4 Processor\n", 343 | "!fastgwr run -np 4 -data https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_1k.csv -mgwr\n" 344 | ] 345 | }, 346 | { 347 | "cell_type": "markdown", 348 | "metadata": {}, 349 | "source": [ 350 | "### Results validation" 351 | ] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": 15, 356 | "metadata": {}, 357 | "outputs": [ 358 | { 359 | "name": "stdout", 360 | "output_type": "stream", 361 | "text": [ 362 | "MGWR pysal AICc - 1679.0150747382786\n", 363 | "MGWR pysal R2 - 0.7660681409024748\n", 364 | "MGWR pysal ENP_j - [10.13917587 1.15749374 16.97300011 42.38091109 56.32981658]\n" 365 | ] 366 | } 367 | ], 368 | "source": [ 369 | "print(\"MGWR pysal AICc - \", pysal_result_mgwr.aicc)\n", 370 | "print(\"MGWR pysal R2 - \",pysal_result_mgwr.R2)\n", 371 | "print(\"MGWR pysal ENP_j - \",pysal_result_mgwr.ENP_j)" 372 | ] 373 | }, 374 | { 375 | "cell_type": "code", 376 | "execution_count": 16, 377 | "metadata": {}, 378 | "outputs": [ 379 | { 380 | "data": { 381 | "text/html": [ 382 | "
\n", 383 | "\n", 396 | "\n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | " \n", 402 | " \n", 403 | " \n", 404 | " \n", 405 | " \n", 406 | " \n", 407 | " \n", 408 | " \n", 409 | " \n", 410 | " \n", 411 | " \n", 412 | " \n", 413 | " \n", 414 | " \n", 415 | " \n", 416 | " \n", 417 | " \n", 418 | " \n", 419 | " \n", 420 | " \n", 421 | " \n", 422 | " \n", 423 | " \n", 424 | " \n", 425 | " \n", 426 | " \n", 427 | " \n", 428 | " \n", 429 | " \n", 430 | " \n", 431 | " \n", 432 | " \n", 433 | " \n", 434 | " \n", 435 | " \n", 436 | " \n", 437 | " \n", 438 | " \n", 439 | " \n", 440 | " \n", 441 | " \n", 442 | " \n", 443 | " \n", 444 | " \n", 445 | " \n", 446 | " \n", 447 | " \n", 448 | " \n", 449 | " \n", 450 | " \n", 451 | " \n", 452 | " \n", 453 | " \n", 454 | " \n", 455 | " \n", 456 | " \n", 457 | " \n", 458 | " \n", 459 | " \n", 460 | " \n", 461 | " \n", 462 | " \n", 463 | " \n", 464 | " \n", 465 | " \n", 466 | " \n", 467 | " \n", 468 | " \n", 469 | " \n", 470 | " \n", 471 | " \n", 472 | " \n", 473 | " \n", 474 | " \n", 475 | " \n", 476 | " \n", 477 | " \n", 478 | " \n", 479 | " \n", 480 | " \n", 481 | " \n", 482 | " \n", 483 | " \n", 484 | " \n", 485 | " \n", 486 | " \n", 487 | " \n", 488 | " \n", 489 | " \n", 490 | " \n", 491 | "
indexresidualb_interceptb_nbathsb_nbedsb_areab_agese_interceptse_nbathsse_nbedsse_arease_age
00.0-0.011031-0.0754630.109868-0.1017110.496562-0.1524880.0528830.0384270.0675360.1533290.140883
11.00.240776-0.1498620.102825-0.0619230.4834810.0151660.0556860.0380090.0723060.1232610.121128
22.00.879991-0.0229730.1070250.0031000.368938-0.1333180.0504380.0384610.0677550.1459230.078181
33.00.096153-0.1322490.109213-0.1798280.5476190.0453080.0533400.0384210.0759640.1515950.185564
44.00.188585-0.0282930.107749-0.0144740.279898-0.1342110.0522180.0385470.0697500.1425630.077774
\n", 492 | "
" 493 | ], 494 | "text/plain": [ 495 | " index residual b_intercept b_nbaths b_nbeds b_area b_age \\\n", 496 | "0 0.0 -0.011031 -0.075463 0.109868 -0.101711 0.496562 -0.152488 \n", 497 | "1 1.0 0.240776 -0.149862 0.102825 -0.061923 0.483481 0.015166 \n", 498 | "2 2.0 0.879991 -0.022973 0.107025 0.003100 0.368938 -0.133318 \n", 499 | "3 3.0 0.096153 -0.132249 0.109213 -0.179828 0.547619 0.045308 \n", 500 | "4 4.0 0.188585 -0.028293 0.107749 -0.014474 0.279898 -0.134211 \n", 501 | "\n", 502 | " se_intercept se_nbaths se_nbeds se_area se_age \n", 503 | "0 0.052883 0.038427 0.067536 0.153329 0.140883 \n", 504 | "1 0.055686 0.038009 0.072306 0.123261 0.121128 \n", 505 | "2 0.050438 0.038461 0.067755 0.145923 0.078181 \n", 506 | "3 0.053340 0.038421 0.075964 0.151595 0.185564 \n", 507 | "4 0.052218 0.038547 0.069750 0.142563 0.077774 " 508 | ] 509 | }, 510 | "execution_count": 16, 511 | "metadata": {}, 512 | "output_type": "execute_result" 513 | } 514 | ], 515 | "source": [ 516 | "fastGWR_result_mgwr = pd.read_csv(\"fastgwr_rslt.csv\")\n", 517 | "fastGWR_result_mgwr.head()" 518 | ] 519 | }, 520 | { 521 | "cell_type": "code", 522 | "execution_count": 17, 523 | "metadata": {}, 524 | "outputs": [ 525 | { 526 | "name": "stdout", 527 | "output_type": "stream", 528 | "text": [ 529 | "True\n" 530 | ] 531 | } 532 | ], 533 | "source": [ 534 | "#Validate model residuals\n", 535 | "print(np.allclose(fastGWR_result_mgwr.residual,\n", 536 | " pysal_result_mgwr.resid_response.reshape(-1)))\n" 537 | ] 538 | }, 539 | { 540 | "cell_type": "code", 541 | "execution_count": 18, 542 | "metadata": {}, 543 | "outputs": [ 544 | { 545 | "name": "stdout", 546 | "output_type": "stream", 547 | "text": [ 548 | "True\n" 549 | ] 550 | } 551 | ], 552 | "source": [ 553 | "#Validate parameter estimates\n", 554 | "print(np.allclose(np.array(fastGWR_result_mgwr.iloc[:,2:7]),\n", 555 | " pysal_result_mgwr.params))\n", 556 | "\n" 557 | ] 558 | }, 559 | { 560 | "cell_type": "code", 561 | "execution_count": 19, 562 | "metadata": {}, 563 | "outputs": [ 564 | { 565 | "name": "stdout", 566 | "output_type": "stream", 567 | "text": [ 568 | "True\n" 569 | ] 570 | } 571 | ], 572 | "source": [ 573 | "#Validate parameter estimates standard errors\n", 574 | "print(np.allclose(np.array(fastGWR_result_mgwr.iloc[:,7:12]),\n", 575 | " pysal_result_mgwr.bse))\n" 576 | ] 577 | }, 578 | { 579 | "cell_type": "code", 580 | "execution_count": null, 581 | "metadata": {}, 582 | "outputs": [], 583 | "source": [] 584 | } 585 | ], 586 | "metadata": { 587 | "kernelspec": { 588 | "display_name": "Python 3", 589 | "language": "python", 590 | "name": "python3" 591 | }, 592 | "language_info": { 593 | "codemirror_mode": { 594 | "name": "ipython", 595 | "version": 3 596 | }, 597 | "file_extension": ".py", 598 | "mimetype": "text/x-python", 599 | "name": "python", 600 | "nbconvert_exporter": "python", 601 | "pygments_lexer": "ipython3", 602 | "version": "3.7.6" 603 | } 604 | }, 605 | "nbformat": 4, 606 | "nbformat_minor": 2 607 | } 608 | -------------------------------------------------------------------------------- /validation notebook/MGWR scalability test Mac.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Test for MGWR scalability on a Mac with 2 GHz Quad-Core Intel Core i5 based on 5k Zillow records." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [ 15 | { 16 | "name": "stdout", 17 | "output_type": "stream", 18 | "text": [ 19 | "fastgwr, version 0.2.8\r\n" 20 | ] 21 | } 22 | ], 23 | "source": [ 24 | "!fastgwr --version" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "Performance of `fastgwr` with 1 processor" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 2, 37 | "metadata": {}, 38 | "outputs": [ 39 | { 40 | "name": "stdout", 41 | "output_type": "stream", 42 | "text": [ 43 | "------------------------------------------------------------\n", 44 | "Starting FastGWR with 1 Processors\n", 45 | "Spatial Kernel: Adaptive Bisquare\n", 46 | "Data Input Path: https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_5k.csv\n", 47 | "Output Result Path: fastgwr_rslt.csv\n", 48 | "Constant: True\n", 49 | "MGWR Backfitting...\n", 50 | "Data are standardized\n", 51 | "Initialization Done...\n", 52 | "Iter: 1 SOC: 2.74e-03\n", 53 | "bws: [135.0, 44.0, 137.0, 99.0, 117.0]\n", 54 | "Iter: 2 SOC: 1.71e-03\n", 55 | "bws: [261.0, 44.0, 165.0, 118.0, 213.0]\n", 56 | "Iter: 3 SOC: 9.55e-04\n", 57 | "bws: [344.0, 44.0, 195.0, 119.0, 305.0]\n", 58 | "Iter: 4 SOC: 6.07e-04\n", 59 | "bws: [402.0, 44.0, 234.0, 124.0, 384.0]\n", 60 | "Iter: 5 SOC: 5.09e-04\n", 61 | "bws: [445.0, 44.0, 259.0, 135.0, 500.0]\n", 62 | "Iter: 6 SOC: 4.68e-04\n", 63 | "bws: [445.0, 44.0, 259.0, 137.0, 781.0]\n", 64 | "Iter: 7 SOC: 4.38e-04\n", 65 | "bws: [445.0, 44.0, 295.0, 147.0, 1057.0]\n", 66 | "Iter: 8 SOC: 3.48e-04\n", 67 | "bws: [415.0, 44.0, 295.0, 151.0, 1299.0]\n", 68 | "Iter: 9 SOC: 3.12e-04\n", 69 | "bws: [415.0, 44.0, 295.0, 151.0, 2164.0]\n", 70 | "Iter: 10 SOC: 2.88e-04\n", 71 | "bws: [415.0, 44.0, 295.0, 153.0, 4998.0]\n", 72 | "Iter: 11 SOC: 3.70e-04\n", 73 | "bws: [415.0, 44.0, 295.0, 197.0, 4998.0]\n", 74 | "Iter: 12 SOC: 4.47e-04\n", 75 | "bws: [415.0, 44.0, 295.0, 248.0, 4998.0]\n", 76 | "Iter: 13 SOC: 4.46e-04\n", 77 | "bws: [445.0, 44.0, 295.0, 283.0, 4998.0]\n", 78 | "Iter: 14 SOC: 3.78e-04\n", 79 | "bws: [454.0, 44.0, 295.0, 301.0, 4998.0]\n", 80 | "Iter: 15 SOC: 2.89e-04\n", 81 | "bws: [454.0, 44.0, 295.0, 306.0, 4998.0]\n", 82 | "Iter: 16 SOC: 3.48e-04\n", 83 | "bws: [446.0, 44.0, 295.0, 392.0, 4998.0]\n", 84 | "Iter: 17 SOC: 3.62e-04\n", 85 | "bws: [446.0, 44.0, 295.0, 443.0, 4998.0]\n", 86 | "Iter: 18 SOC: 2.96e-04\n", 87 | "bws: [446.0, 44.0, 295.0, 454.0, 4998.0]\n", 88 | "Iter: 19 SOC: 2.33e-04\n", 89 | "bws: [446.0, 44.0, 295.0, 465.0, 4998.0]\n", 90 | "Iter: 20 SOC: 1.86e-04\n", 91 | "bws: [446.0, 44.0, 295.0, 465.0, 4998.0]\n", 92 | "Iter: 21 SOC: 1.66e-04\n", 93 | "bws: [446.0, 44.0, 295.0, 492.0, 4998.0]\n", 94 | "Iter: 22 SOC: 1.43e-04\n", 95 | "bws: [446.0, 44.0, 295.0, 492.0, 4998.0]\n", 96 | "Iter: 23 SOC: 1.13e-04\n", 97 | "bws: [446.0, 44.0, 295.0, 492.0, 4998.0]\n", 98 | "Iter: 24 SOC: 1.33e-04\n", 99 | "bws: [446.0, 44.0, 266.0, 492.0, 4998.0]\n", 100 | "Iter: 25 SOC: 1.05e-04\n", 101 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 102 | "Iter: 26 SOC: 7.46e-05\n", 103 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 104 | "Iter: 27 SOC: 5.65e-05\n", 105 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 106 | "Iter: 28 SOC: 4.44e-05\n", 107 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 108 | "Iter: 29 SOC: 3.55e-05\n", 109 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 110 | "Iter: 30 SOC: 2.88e-05\n", 111 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 112 | "Iter: 31 SOC: 2.37e-05\n", 113 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 114 | "Iter: 32 SOC: 1.98e-05\n", 115 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 116 | "Iter: 33 SOC: 1.69e-05\n", 117 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 118 | "Iter: 34 SOC: 1.45e-05\n", 119 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 120 | "Iter: 35 SOC: 1.26e-05\n", 121 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 122 | "Iter: 36 SOC: 1.10e-05\n", 123 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 124 | "Iter: 37 SOC: 9.71e-06\n", 125 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 126 | "Computing Inference with 1 Chunks\n", 127 | "Diagnostic Information:\n", 128 | "AICc: 7763.011294178303\n", 129 | "ENP: [ 26.54217903 298.69976792 42.07076758 14.31268234 1.30566251]\n", 130 | "R2: 0.765817912182932\n", 131 | "Total Time Elapsed: 3102.2 seconds\n", 132 | "------------------------------------------------------------\n" 133 | ] 134 | } 135 | ], 136 | "source": [ 137 | "!fastgwr run -np 1 -data https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_5k.csv -mgwr" 138 | ] 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "metadata": {}, 143 | "source": [ 144 | "Performance of `fastgwr` with 2 processors" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": 3, 150 | "metadata": {}, 151 | "outputs": [ 152 | { 153 | "name": "stdout", 154 | "output_type": "stream", 155 | "text": [ 156 | "------------------------------------------------------------\n", 157 | "Starting FastGWR with 2 Processors\n", 158 | "Spatial Kernel: Adaptive Bisquare\n", 159 | "Data Input Path: https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_5k.csv\n", 160 | "Output Result Path: fastgwr_rslt.csv\n", 161 | "Constant: True\n", 162 | "MGWR Backfitting...\n", 163 | "Data are standardized\n", 164 | "Initialization Done...\n", 165 | "Iter: 1 SOC: 2.74e-03\n", 166 | "bws: [135.0, 44.0, 137.0, 99.0, 117.0]\n", 167 | "Iter: 2 SOC: 1.71e-03\n", 168 | "bws: [261.0, 44.0, 165.0, 118.0, 213.0]\n", 169 | "Iter: 3 SOC: 9.55e-04\n", 170 | "bws: [344.0, 44.0, 195.0, 119.0, 305.0]\n", 171 | "Iter: 4 SOC: 6.07e-04\n", 172 | "bws: [402.0, 44.0, 234.0, 124.0, 384.0]\n", 173 | "Iter: 5 SOC: 5.09e-04\n", 174 | "bws: [445.0, 44.0, 259.0, 135.0, 500.0]\n", 175 | "Iter: 6 SOC: 4.68e-04\n", 176 | "bws: [445.0, 44.0, 259.0, 137.0, 781.0]\n", 177 | "Iter: 7 SOC: 4.38e-04\n", 178 | "bws: [445.0, 44.0, 295.0, 147.0, 1057.0]\n", 179 | "Iter: 8 SOC: 3.48e-04\n", 180 | "bws: [415.0, 44.0, 295.0, 151.0, 1299.0]\n", 181 | "Iter: 9 SOC: 3.12e-04\n", 182 | "bws: [415.0, 44.0, 295.0, 151.0, 2164.0]\n", 183 | "Iter: 10 SOC: 2.88e-04\n", 184 | "bws: [415.0, 44.0, 295.0, 153.0, 4998.0]\n", 185 | "Iter: 11 SOC: 3.70e-04\n", 186 | "bws: [415.0, 44.0, 295.0, 197.0, 4998.0]\n", 187 | "Iter: 12 SOC: 4.47e-04\n", 188 | "bws: [415.0, 44.0, 295.0, 248.0, 4998.0]\n", 189 | "Iter: 13 SOC: 4.46e-04\n", 190 | "bws: [445.0, 44.0, 295.0, 283.0, 4998.0]\n", 191 | "Iter: 14 SOC: 3.78e-04\n", 192 | "bws: [454.0, 44.0, 295.0, 301.0, 4998.0]\n", 193 | "Iter: 15 SOC: 2.89e-04\n", 194 | "bws: [454.0, 44.0, 295.0, 306.0, 4998.0]\n", 195 | "Iter: 16 SOC: 3.48e-04\n", 196 | "bws: [446.0, 44.0, 295.0, 392.0, 4998.0]\n", 197 | "Iter: 17 SOC: 3.62e-04\n", 198 | "bws: [446.0, 44.0, 295.0, 443.0, 4998.0]\n", 199 | "Iter: 18 SOC: 2.96e-04\n", 200 | "bws: [446.0, 44.0, 295.0, 454.0, 4998.0]\n", 201 | "Iter: 19 SOC: 2.33e-04\n", 202 | "bws: [446.0, 44.0, 295.0, 465.0, 4998.0]\n", 203 | "Iter: 20 SOC: 1.86e-04\n", 204 | "bws: [446.0, 44.0, 295.0, 465.0, 4998.0]\n", 205 | "Iter: 21 SOC: 1.66e-04\n", 206 | "bws: [446.0, 44.0, 295.0, 492.0, 4998.0]\n", 207 | "Iter: 22 SOC: 1.43e-04\n", 208 | "bws: [446.0, 44.0, 295.0, 492.0, 4998.0]\n", 209 | "Iter: 23 SOC: 1.13e-04\n", 210 | "bws: [446.0, 44.0, 295.0, 492.0, 4998.0]\n", 211 | "Iter: 24 SOC: 1.33e-04\n", 212 | "bws: [446.0, 44.0, 266.0, 492.0, 4998.0]\n", 213 | "Iter: 25 SOC: 1.05e-04\n", 214 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 215 | "Iter: 26 SOC: 7.46e-05\n", 216 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 217 | "Iter: 27 SOC: 5.65e-05\n", 218 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 219 | "Iter: 28 SOC: 4.44e-05\n", 220 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 221 | "Iter: 29 SOC: 3.55e-05\n", 222 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 223 | "Iter: 30 SOC: 2.88e-05\n", 224 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 225 | "Iter: 31 SOC: 2.37e-05\n", 226 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 227 | "Iter: 32 SOC: 1.98e-05\n", 228 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 229 | "Iter: 33 SOC: 1.69e-05\n", 230 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 231 | "Iter: 34 SOC: 1.45e-05\n", 232 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 233 | "Iter: 35 SOC: 1.26e-05\n", 234 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 235 | "Iter: 36 SOC: 1.10e-05\n", 236 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 237 | "Iter: 37 SOC: 9.71e-06\n", 238 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 239 | "Computing Inference with 1 Chunks\n", 240 | "Diagnostic Information:\n", 241 | "AICc: 7763.011294178303\n", 242 | "ENP: [ 26.54217903 298.69976792 42.07076758 14.31268234 1.30566251]\n", 243 | "R2: 0.765817912182932\n", 244 | "Total Time Elapsed: 1848.27 seconds\n", 245 | "------------------------------------------------------------\n" 246 | ] 247 | } 248 | ], 249 | "source": [ 250 | "!fastgwr run -np 2 -data https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_5k.csv -mgwr" 251 | ] 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "metadata": {}, 256 | "source": [ 257 | "Performance of `fastgwr` with 4 processors" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": 4, 263 | "metadata": {}, 264 | "outputs": [ 265 | { 266 | "name": "stdout", 267 | "output_type": "stream", 268 | "text": [ 269 | "------------------------------------------------------------\n", 270 | "Starting FastGWR with 4 Processors\n", 271 | "Spatial Kernel: Adaptive Bisquare\n", 272 | "Data Input Path: https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_5k.csv\n", 273 | "Output Result Path: fastgwr_rslt.csv\n", 274 | "Constant: True\n", 275 | "MGWR Backfitting...\n", 276 | "Data are standardized\n", 277 | "Initialization Done...\n", 278 | "Iter: 1 SOC: 2.74e-03\n", 279 | "bws: [135.0, 44.0, 137.0, 99.0, 117.0]\n", 280 | "Iter: 2 SOC: 1.71e-03\n", 281 | "bws: [261.0, 44.0, 165.0, 118.0, 213.0]\n", 282 | "Iter: 3 SOC: 9.55e-04\n", 283 | "bws: [344.0, 44.0, 195.0, 119.0, 305.0]\n", 284 | "Iter: 4 SOC: 6.07e-04\n", 285 | "bws: [402.0, 44.0, 234.0, 124.0, 384.0]\n", 286 | "Iter: 5 SOC: 5.09e-04\n", 287 | "bws: [445.0, 44.0, 259.0, 135.0, 500.0]\n", 288 | "Iter: 6 SOC: 4.68e-04\n", 289 | "bws: [445.0, 44.0, 259.0, 137.0, 781.0]\n", 290 | "Iter: 7 SOC: 4.38e-04\n", 291 | "bws: [445.0, 44.0, 295.0, 147.0, 1057.0]\n", 292 | "Iter: 8 SOC: 3.48e-04\n", 293 | "bws: [415.0, 44.0, 295.0, 151.0, 1299.0]\n", 294 | "Iter: 9 SOC: 3.12e-04\n", 295 | "bws: [415.0, 44.0, 295.0, 151.0, 2164.0]\n", 296 | "Iter: 10 SOC: 2.88e-04\n", 297 | "bws: [415.0, 44.0, 295.0, 153.0, 4998.0]\n", 298 | "Iter: 11 SOC: 3.70e-04\n", 299 | "bws: [415.0, 44.0, 295.0, 197.0, 4998.0]\n", 300 | "Iter: 12 SOC: 4.47e-04\n", 301 | "bws: [415.0, 44.0, 295.0, 248.0, 4998.0]\n", 302 | "Iter: 13 SOC: 4.46e-04\n", 303 | "bws: [445.0, 44.0, 295.0, 283.0, 4998.0]\n", 304 | "Iter: 14 SOC: 3.78e-04\n", 305 | "bws: [454.0, 44.0, 295.0, 301.0, 4998.0]\n", 306 | "Iter: 15 SOC: 2.89e-04\n", 307 | "bws: [454.0, 44.0, 295.0, 306.0, 4998.0]\n", 308 | "Iter: 16 SOC: 3.48e-04\n", 309 | "bws: [446.0, 44.0, 295.0, 392.0, 4998.0]\n", 310 | "Iter: 17 SOC: 3.62e-04\n", 311 | "bws: [446.0, 44.0, 295.0, 443.0, 4998.0]\n", 312 | "Iter: 18 SOC: 2.96e-04\n", 313 | "bws: [446.0, 44.0, 295.0, 454.0, 4998.0]\n", 314 | "Iter: 19 SOC: 2.33e-04\n", 315 | "bws: [446.0, 44.0, 295.0, 465.0, 4998.0]\n", 316 | "Iter: 20 SOC: 1.86e-04\n", 317 | "bws: [446.0, 44.0, 295.0, 465.0, 4998.0]\n", 318 | "Iter: 21 SOC: 1.66e-04\n", 319 | "bws: [446.0, 44.0, 295.0, 492.0, 4998.0]\n", 320 | "Iter: 22 SOC: 1.43e-04\n", 321 | "bws: [446.0, 44.0, 295.0, 492.0, 4998.0]\n", 322 | "Iter: 23 SOC: 1.13e-04\n", 323 | "bws: [446.0, 44.0, 295.0, 492.0, 4998.0]\n", 324 | "Iter: 24 SOC: 1.33e-04\n", 325 | "bws: [446.0, 44.0, 266.0, 492.0, 4998.0]\n", 326 | "Iter: 25 SOC: 1.05e-04\n", 327 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 328 | "Iter: 26 SOC: 7.46e-05\n", 329 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 330 | "Iter: 27 SOC: 5.65e-05\n", 331 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 332 | "Iter: 28 SOC: 4.44e-05\n", 333 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 334 | "Iter: 29 SOC: 3.55e-05\n", 335 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 336 | "Iter: 30 SOC: 2.88e-05\n", 337 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 338 | "Iter: 31 SOC: 2.37e-05\n", 339 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 340 | "Iter: 32 SOC: 1.98e-05\n", 341 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 342 | "Iter: 33 SOC: 1.69e-05\n", 343 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 344 | "Iter: 34 SOC: 1.45e-05\n", 345 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 346 | "Iter: 35 SOC: 1.26e-05\n", 347 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 348 | "Iter: 36 SOC: 1.10e-05\n", 349 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 350 | "Iter: 37 SOC: 9.71e-06\n", 351 | "bws: [446.0, 44.0, 259.0, 492.0, 4998.0]\n", 352 | "Computing Inference with 1 Chunks\n", 353 | "Diagnostic Information:\n", 354 | "AICc: 7763.011294178305\n", 355 | "ENP: [ 26.54217903 298.69976792 42.07076758 14.31268234 1.30566251]\n", 356 | "R2: 0.765817912182932\n", 357 | "Total Time Elapsed: 1366.85 seconds\n", 358 | "------------------------------------------------------------\n" 359 | ] 360 | } 361 | ], 362 | "source": [ 363 | "!fastgwr run -np 4 -data https://raw.github.com/Ziqi-Li/FastGWR/master/Zillow-test-dataset/zillow_5k.csv -mgwr" 364 | ] 365 | }, 366 | { 367 | "cell_type": "code", 368 | "execution_count": null, 369 | "metadata": {}, 370 | "outputs": [], 371 | "source": [] 372 | } 373 | ], 374 | "metadata": { 375 | "kernelspec": { 376 | "display_name": "Python 3", 377 | "language": "python", 378 | "name": "python3" 379 | }, 380 | "language_info": { 381 | "codemirror_mode": { 382 | "name": "ipython", 383 | "version": 3 384 | }, 385 | "file_extension": ".py", 386 | "mimetype": "text/x-python", 387 | "name": "python", 388 | "nbconvert_exporter": "python", 389 | "pygments_lexer": "ipython3", 390 | "version": "3.7.6" 391 | } 392 | }, 393 | "nbformat": 4, 394 | "nbformat_minor": 2 395 | } 396 | --------------------------------------------------------------------------------