├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── doc ├── Makefile ├── _static │ ├── images │ │ └── pysal_favicon.ico │ ├── pysal-styles.css │ └── references.bib ├── api.rst ├── conf.py ├── generated │ ├── spint.dispersion.alpha_disp.rst │ ├── spint.dispersion.phi_disp.rst │ ├── spint.gravity.Attraction.rst │ ├── spint.gravity.BaseGravity.rst │ ├── spint.gravity.Doubly.rst │ ├── spint.gravity.Gravity.rst │ └── spint.gravity.Production.rst ├── index.rst ├── installation.rst ├── make.bat └── references.rst ├── notebooks ├── 4d_distance.ipynb ├── Example_NYCBikes_AllFeatures.ipynb ├── NYC_Bike_Example.ipynb ├── New_DistanceBand.ipynb ├── ODW_example.ipynb ├── OD_weights.ipynb ├── autograd_test.ipynb ├── dispersion_test.ipynb ├── exampe_accessibility.ipynb ├── glm_speed.ipynb ├── local_SI.ipynb ├── netW.ipynb ├── sparse_categorical.ipynb ├── sparse_categorical_bottleneck.ipynb ├── sparse_categorical_speed.ipynb ├── sparse_grav.ipynb ├── sparse_scipy_optim.ipynb ├── sparse_vs_dense_grav.ipynb ├── test_grav.ipynb └── validate_gravity.ipynb ├── readthedocs.yml ├── requirements.txt ├── requirements_docs.txt ├── requirements_tests.txt ├── setup.cfg ├── setup.py ├── spint ├── __init__.py ├── count_model.py ├── dispersion.py ├── flow_accessibility.py ├── gravity.py ├── primer │ ├── SpIntPrimer.pdf │ ├── austria.csv │ ├── austria.dbf │ ├── austria.prj │ ├── austria.qpj │ ├── austria.shp │ └── austria.shx ├── tests │ ├── __init__.py │ ├── test_accessibility.py │ ├── test_count_model.py │ ├── test_dispersion.py │ ├── test_gravity.py │ ├── test_universal.py │ └── test_vec_SA.py ├── universal.py ├── utils.py └── vec_SA.py └── tools └── gitcount.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.swp 3 | *.pyc 4 | .rope* 5 | .idea/ 6 | notebooks/.ipynb_checkpoints/ 7 | .DS_Store 8 | .ipynb_checkpoints/ 9 | *.bak 10 | .eggs/ 11 | *.egg-info/ 12 | 13 | # Packages 14 | *.egg 15 | *.egg-info 16 | dist 17 | build 18 | eggs 19 | parts 20 | bin 21 | var 22 | sdist 23 | develop-eggs 24 | .installed.cfg 25 | lib 26 | lib64 27 | _build -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | dist: xenial 3 | sudo: true 4 | branches: 5 | only: 6 | - master 7 | python: 8 | - 3.6 9 | - 3.7 10 | 11 | env: 12 | - PYSAL_PYPI=true #testing on dependencies libpysal, esda, mapcalssify on pypi 13 | - PYSAL_PYPI=false 14 | 15 | matrix: 16 | allow_failures: 17 | - python: 3.6 18 | env: PYSAL_PYPI=false 19 | - python: 3.7 20 | env: PYSAL_PYPI=false 21 | 22 | before_install: 23 | - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh 24 | - chmod +x miniconda.sh 25 | - ./miniconda.sh -b -p ./miniconda 26 | - export PATH=`pwd`/miniconda/bin:$PATH 27 | - conda update --yes conda 28 | - conda config --append channels conda-forge 29 | - conda create -y -q -n test-env python=$TRAVIS_PYTHON_VERSION 30 | - source activate test-env 31 | 32 | install: 33 | - conda install --yes pip 34 | - pip install -r requirements.txt 35 | - pip install -r requirements_tests.txt 36 | - if "$PYSAL_PYPI"; then 37 | echo 'testing pypi libpysal spreg spglm'; 38 | else 39 | echo 'testing git libpysal spreg spglm'; 40 | git clone https://github.com/pysal/libpysal.git; 41 | cd libpysal; pip install .; cd ../; 42 | git clone https://github.com/pysal/spreg.git; 43 | cd spreg; pip install .; cd ../; 44 | git clone https://github.com/pysal/spglm.git; 45 | cd spglm; pip install .; cd ../; 46 | fi; 47 | 48 | script: 49 | - python setup.py sdist >/dev/null 50 | - python setup.py install 51 | - python -c 'import libpysal; libpysal.examples.load_example("nyc_bikes")' 52 | - nosetests --verbose --with-doctest --with-coverage --cover-package=spint; 53 | 54 | notifications: 55 | email: 56 | recipients: 57 | - tayoshan@gmail.com 58 | on_change: change 59 | on_failure: always 60 | 61 | after_success: 62 | - coveralls 63 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # Changes 3 | 4 | Version 1.0.7 (2020-09-08) 5 | 6 | We closed a total of 10 issues (enhancements and bug fixes) through 5 pull requests, since our last release on 2019-07-22. 7 | 8 | ## Issues Closed 9 | - update travis (#25) 10 | - addressing pysal/pysal#1145 (#24) 11 | - bump version for release (#23) 12 | - update log (#22) 13 | - Updates (#21) 14 | 15 | ## Pull Requests 16 | - update travis (#25) 17 | - addressing pysal/pysal#1145 (#24) 18 | - bump version for release (#23) 19 | - update log (#22) 20 | - Updates (#21) 21 | 22 | The following individuals contributed to this release: 23 | 24 | - Taylor Oshan 25 | - James Gaboardi 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Python Spatial Analysis Library 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE MANIFEST.in requirements_docs.txt requirements_tests.txt requirements.txt 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Spatial Interaction Modeling Package 2 | =========================================== 3 | 4 | [![Build Status](https://travis-ci.org/pysal/spint.svg?branch=master)](https://travis-ci.org/pysal/spint) 5 | [![Documentation Status](https://readthedocs.org/projects/spint/badge/?version=latest)](https://spint.readthedocs.io/en/latest/?badge=latest) 6 | [![PyPI version](https://badge.fury.io/py/spint.svg)](https://badge.fury.io/py/spint) 7 | 8 | 9 | The **Sp**atial **Int**eraction Modeling (SpInt) module seeks to provide a collection of tools to study spatial interaction processes and analyze spatial interaction data. 10 | 11 | The [initial development](https://github.com/pysal/pysal/wiki/SpInt-Development) of the module was carried out as a Google Summer of Code 12 | project (summer 2016). Documentation of the project progress can be found on the 13 | [project blog](https://tayloroshan.github.io/). 14 | 15 | The module currently supports the calibration of the 'family' of spatial interaction models (Wilson, 1971) which are derived using an entropy maximizing (EM) framework or the equivalent information minimizing (IM) framework. As such, it is able to derive parameters for the following Poisson count models: 16 | 17 | Models 18 | ------ 19 | 20 | - unconstrained gravity model 21 | - production-constrained model (origin-constrained) 22 | - attraction-constrained model (destination-constrained) 23 | - doubly-constrained model 24 | 25 | Calibration is carried out using iteratively weighted least squares in a generalized linear modleing framework (Cameron & Trivedi, 2013). These model results have been verified against comparable routines laid out in (Fotheringham and O’Kelly, 1989; Willimans and Fotheringham, 1984) and functions avaialble in R such as GL or Pythons statsmodels. The estimation of the constrained routines are carried out using sparse data strucutres for lower memory overhead and faster computations. 26 | 27 | Additional Features 28 | ------------------- 29 | 30 | - QuasiPoisson model estimation 31 | - Regression-based tests for overdispersion 32 | - Model fit statistics including typical GLM metrics, standardized root mean 33 | square error, and Sorensen similarit index 34 | - Vector-based Moran's I statistic for testing for spatial autcorrelation in 35 | spatial interaction data 36 | - Local subset model calibration for mappable sets of parameter estimates and model 37 | diagnostics 38 | - Three types of spatial interaction spatial weights: origin-destination 39 | contiguity weights, network-based weights, and vector-based distance weights 40 | 41 | In Progress 42 | ----------- 43 | 44 | - Spatial Autoregressive (Lag) model spatial interaction specification 45 | 46 | Future Work 47 | ----------- 48 | 49 | - Parameter estimation via maximum likelihood and gradient-based optimization 50 | - Zero-inflated Poisson model 51 | - Negative Binomial model/zero-inflated negative binomial model 52 | - Functions to compute competing destinations 53 | - Functions to compute eigenvector spatial filters 54 | - Parameter estimation via neural networks 55 | - Universal (determinsitic) models such as the Radiation model and Inverse 56 | Population Weighted model 57 | 58 | Cameron, C. A. and Trivedi, P. K. (2013). Regression analyis of count data. 59 | Cambridge University Press, 1998. 60 | 61 | Fotheringham, A. S. and O'Kelly, M. E. (1989). Spatial Interaction Models: Formulations and Applications. London: Kluwer Academic Publishers. 62 | 63 | Williams, P. A. and A. S. Fotheringham (1984), The Calibration of Spatial Interaction 64 | Models by Maximum Likelihood Estimation with Program SIMODEL, Geographic Monograph 65 | Series, 7, Department of Geography, Indiana University. 66 | 67 | Wilson, A. G. (1971). A family of spatial interaction models, and associated developments. Environment and 68 | Planning A, 3, 1–32. 69 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = spint 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | 22 | clean: 23 | rm -rf $(BUILDDIR)/* 24 | rm -rf auto_examples/ 25 | -------------------------------------------------------------------------------- /doc/_static/images/pysal_favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pysal/spint/050865acae4054b8ac30b12e6d38ca884e7a43cc/doc/_static/images/pysal_favicon.ico -------------------------------------------------------------------------------- /doc/_static/pysal-styles.css: -------------------------------------------------------------------------------- 1 | /* Make thumbnails with equal heights */ 2 | @media only screen and (min-width : 481px) { 3 | .row.equal-height { 4 | display: flex; 5 | flex-wrap: wrap; 6 | } 7 | .row.equal-height > [class*='col-'] { 8 | display: flex; 9 | flex-direction: column; 10 | } 11 | .row.equal-height.row:after, 12 | .row.equal-height.row:before { 13 | display: flex; 14 | } 15 | 16 | .row.equal-height > [class*='col-'] > .thumbnail, 17 | .row.equal-height > [class*='col-'] > .thumbnail > .caption { 18 | display: flex; 19 | flex: 1 0 auto; 20 | flex-direction: column; 21 | } 22 | .row.equal-height > [class*='col-'] > .thumbnail > .caption > .flex-text { 23 | flex-grow: 1; 24 | } 25 | .row.equal-height > [class*='col-'] > .thumbnail > img { 26 | width: 100%; 27 | height: 200px; /* force image's height */ 28 | 29 | /* force image fit inside it's "box" */ 30 | -webkit-object-fit: cover; 31 | -moz-object-fit: cover; 32 | -ms-object-fit: cover; 33 | -o-object-fit: cover; 34 | object-fit: cover; 35 | } 36 | } 37 | 38 | .row.extra-bottom-padding{ 39 | margin-bottom: 20px; 40 | } 41 | 42 | 43 | .topnavicons { 44 | margin-left: 10% !important; 45 | } 46 | 47 | .topnavicons li { 48 | margin-left: 0px !important; 49 | min-width: 100px; 50 | text-align: center; 51 | } 52 | 53 | .topnavicons .thumbnail { 54 | margin-right: 10px; 55 | border: none; 56 | box-shadow: none; 57 | text-align: center; 58 | font-size: 85%; 59 | font-weight: bold; 60 | line-height: 10px; 61 | height: 100px; 62 | } 63 | 64 | .topnavicons .thumbnail img { 65 | display: block; 66 | margin-left: auto; 67 | margin-right: auto; 68 | } 69 | 70 | 71 | /* Table with a scrollbar */ 72 | .bodycontainer { max-height: 600px; width: 100%; margin: 0; overflow-y: auto; } 73 | .table-scrollable { margin: 0; padding: 0; } -------------------------------------------------------------------------------- /doc/_static/references.bib: -------------------------------------------------------------------------------- 1 | %% This BibTeX bibliography file was created using BibDesk. 2 | %% http://bibdesk.sourceforge.net/ 3 | 4 | %% Created for Wei Kang at 2018-08-05 16:12:26 -0700 5 | 6 | 7 | %% Saved with string encoding Unicode (UTF-8) 8 | 9 | 10 | 11 | @book{Press2007, 12 | Address = {Cambridge}, 13 | Author = {Press, William H and Teukolsky, Saul A and Vetterling, William T and Flannery, Brian P}, 14 | Date-Added = {2018-06-12 22:53:57 +0000}, 15 | Date-Modified = {2018-06-12 22:54:05 +0000}, 16 | Edition = {3rd}, 17 | Keywords = {rank.py}, 18 | Publisher = {Cambridge Univ Pr}, 19 | Title = {Numerical recipes: the art of scientific computing}, 20 | Year = {2007}} 21 | -------------------------------------------------------------------------------- /doc/api.rst: -------------------------------------------------------------------------------- 1 | .. _api_ref: 2 | 3 | .. currentmodule:: spint 4 | 5 | API reference 6 | ============= 7 | 8 | .. _spint_api: 9 | 10 | Gravity-type spatial interaction models 11 | ---------------------------------------- 12 | 13 | .. autosummary:: 14 | :toctree: generated/ 15 | 16 | spint.gravity.BaseGravity 17 | spint.gravity.Gravity 18 | spint.gravity.Production 19 | spint.gravity.Attraction 20 | spint.gravity.Doubly 21 | 22 | Tests for overdispersion 23 | ------------------------- 24 | 25 | .. autosummary:: 26 | :toctree: generated/ 27 | 28 | spint.dispersion.alpha_disp 29 | spint.dispersion.phi_disp 30 | 31 | -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # giddy documentation build configuration file, created by 4 | # sphinx-quickstart on Wed Jun 6 15:54:22 2018. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | # If extensions (or modules to document with autodoc) are in another directory, 16 | # add these directories to sys.path here. If the directory is relative to the 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. 18 | # 19 | import sys, os 20 | import sphinx_bootstrap_theme 21 | 22 | 23 | sys.path.insert(0, os.path.abspath('../../')) 24 | 25 | #import your package to obtain the version info to display on the docs website 26 | import spint 27 | 28 | 29 | # -- General configuration ------------------------------------------------ 30 | 31 | # If your documentation needs a minimal Sphinx version, state it here. 32 | # 33 | # needs_sphinx = '1.0' 34 | # Add any Sphinx extension module names here, as strings. They can be 35 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 36 | # ones. 37 | extensions = [#'sphinx_gallery.gen_gallery', 38 | 'sphinx.ext.autodoc', 39 | 'sphinx.ext.autosummary', 40 | 'sphinx.ext.viewcode', 41 | 'sphinxcontrib.bibtex', 42 | 'sphinx.ext.mathjax', 43 | 'sphinx.ext.doctest', 44 | 'sphinx.ext.intersphinx', 45 | 'numpydoc', 46 | 'matplotlib.sphinxext.plot_directive'] 47 | 48 | 49 | # Add any paths that contain templates here, relative to this directory. 50 | templates_path = ['_templates'] 51 | 52 | # The suffix(es) of source filenames. 53 | # You can specify multiple suffix as a list of string: 54 | # 55 | # source_suffix = ['.rst', '.md'] 56 | source_suffix = '.rst' 57 | 58 | # The master toctree document. 59 | master_doc = 'index' 60 | 61 | # General information about the project. 62 | project = "spint" # string of your project name, for example, 'giddy' 63 | copyright = '2018, pysal developers' 64 | author = 'pysal developers' 65 | 66 | # The version info for the project you're documenting, acts as replacement for 67 | # |version| and |release|, also used in various other places throughout the 68 | # built documents. 69 | # 70 | # The full version. 71 | version = spint.__version__ #should replace it with your PACKAGE_NAME 72 | release = spint.__version__ #should replace it with your PACKAGE_NAME 73 | 74 | # The language for content autogenerated by Sphinx. Refer to documentation 75 | # for a list of supported languages. 76 | # 77 | # This is also used if you do content translation via gettext catalogs. 78 | # Usually you set "language" from the command line for these cases. 79 | language = None 80 | 81 | # List of patterns, relative to source directory, that match files and 82 | # directories to ignore when looking for source files. 83 | # This patterns also effect to html_static_path and html_extra_path 84 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'tests/*'] 85 | 86 | # The name of the Pygments (syntax highlighting) style to use. 87 | pygments_style = 'sphinx' 88 | 89 | # If true, `todo` and `todoList` produce output, else they produce nothing. 90 | todo_include_todos = False 91 | 92 | # -- Options for HTML output ---------------------------------------------- 93 | 94 | # The theme to use for HTML and HTML Help pages. See the documentation for 95 | # a list of builtin themes. 96 | # 97 | # html_theme = 'alabaster' 98 | html_theme = 'bootstrap' 99 | html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() 100 | html_title = "%s v%s Manual" % (project, version) 101 | 102 | # (Optional) Logo of your package. Should be small enough to fit the navbar (ideally 24x24). 103 | # Path should be relative to the ``_static`` files directory. 104 | #html_logo = "_static/images/package_logo.jpg" 105 | 106 | # (Optional) PySAL favicon 107 | html_favicon = "_static/images/pysal_favicon.ico" 108 | 109 | 110 | # Theme options are theme-specific and customize the look and feel of a theme 111 | # further. For a list of options available for each theme, see the 112 | # documentation. 113 | # 114 | html_theme_options = { 115 | 116 | # Navigation bar title. (Default: ``project`` value) 117 | 'navbar_title': "spint", # string of your project name, for example, 'giddy' 118 | 119 | # Render the next and previous page links in navbar. (Default: true) 120 | 'navbar_sidebarrel': False, 121 | 122 | # Render the current pages TOC in the navbar. (Default: true) 123 | #'navbar_pagenav': True, 124 | #'navbar_pagenav': False, 125 | 126 | # No sidebar 127 | 'nosidebar': True, 128 | 129 | # Tab name for the current pages TOC. (Default: "Page") 130 | #'navbar_pagenav_name': "Page", 131 | 132 | # Global TOC depth for "site" navbar tab. (Default: 1) 133 | # Switching to -1 shows all levels. 134 | 'globaltoc_depth': 2, 135 | 136 | # Include hidden TOCs in Site navbar? 137 | # 138 | # Note: If this is "false", you cannot have mixed ``:hidden:`` and 139 | # non-hidden ``toctree`` directives in the same page, or else the build 140 | # will break. 141 | # 142 | # Values: "true" (default) or "false" 143 | 'globaltoc_includehidden': "true", 144 | 145 | # HTML navbar class (Default: "navbar") to attach to
element. 146 | # For black navbar, do "navbar navbar-inverse" 147 | #'navbar_class': "navbar navbar-inverse", 148 | 149 | # Fix navigation bar to top of page? 150 | # Values: "true" (default) or "false" 151 | 'navbar_fixed_top': "true", 152 | 153 | 154 | # Location of link to source. 155 | # Options are "nav" (default), "footer" or anything else to exclude. 156 | 'source_link_position': 'footer', 157 | 158 | # Bootswatch (http://bootswatch.com/) theme. 159 | # 160 | # Options are nothing (default) or the name of a valid theme 161 | # such as "amelia" or "cosmo", "yeti", "flatly". 162 | 'bootswatch_theme': "yeti", 163 | 164 | # Choose Bootstrap version. 165 | # Values: "3" (default) or "2" (in quotes) 166 | 'bootstrap_version': "3", 167 | 168 | # Navigation bar menu 169 | 'navbar_links': [ 170 | ("Installation", "installation"), 171 | ("API", "api"), 172 | ("References", "references"), 173 | ], 174 | 175 | } 176 | 177 | # Add any paths that contain custom static files (such as style sheets) here, 178 | # relative to this directory. They are copied after the builtin static files, 179 | # so a file named "default.css" will overwrite the builtin "default.css". 180 | html_static_path = ['_static'] 181 | 182 | # Custom sidebar templates, maps document names to template names. 183 | #html_sidebars = {} 184 | # html_sidebars = {'sidebar': ['localtoc.html', 'sourcelink.html', 'searchbox.html']} 185 | 186 | # -- Options for HTMLHelp output ------------------------------------------ 187 | 188 | # Output file base name for HTML help builder. 189 | htmlhelp_basename = 'spint'+'doc' 190 | 191 | 192 | # -- Options for LaTeX output --------------------------------------------- 193 | 194 | latex_elements = { 195 | # The paper size ('letterpaper' or 'a4paper'). 196 | # 197 | # 'papersize': 'letterpaper', 198 | 199 | # The font size ('10pt', '11pt' or '12pt'). 200 | # 201 | # 'pointsize': '10pt', 202 | 203 | # Additional stuff for the LaTeX preamble. 204 | # 205 | # 'preamble': '', 206 | 207 | # Latex figure (float) alignment 208 | # 209 | # 'figure_align': 'htbp', 210 | } 211 | 212 | # Grouping the document tree into LaTeX files. List of tuples 213 | # (source start file, target name, title, 214 | # author, documentclass [howto, manual, or own class]). 215 | latex_documents = [ 216 | (master_doc, 'spint.tex', u'spint Documentation', 217 | u'pysal developers', 'manual'), 218 | ] 219 | 220 | 221 | # -- Options for manual page output --------------------------------------- 222 | 223 | # One entry per manual page. List of tuples 224 | # (source start file, name, description, authors, manual section). 225 | man_pages = [ 226 | (master_doc, 'spint', u'spint Documentation', 227 | [author], 1) 228 | ] 229 | 230 | 231 | # -- Options for Texinfo output ------------------------------------------- 232 | 233 | # Grouping the document tree into Texinfo files. List of tuples 234 | # (source start file, target name, title, author, 235 | # dir menu entry, description, category) 236 | texinfo_documents = [ 237 | (master_doc, 'spint', u'spint Documentation', 238 | author, 'spint', 'One line description of project.', 239 | 'Miscellaneous'), 240 | ] 241 | 242 | 243 | # ----------------------------------------------------------------------------- 244 | # Autosummary 245 | # ----------------------------------------------------------------------------- 246 | 247 | # Generate the API documentation when building 248 | autosummary_generate = True 249 | numpydoc_show_class_members = True 250 | class_members_toctree = True 251 | numpydoc_show_inherited_class_members = True 252 | numpydoc_use_plots = True 253 | 254 | # display the source code for Plot directive 255 | plot_include_source = True 256 | 257 | def setup(app): 258 | app.add_stylesheet("pysal-styles.css") 259 | 260 | # Example configuration for intersphinx: refer to the Python standard library. 261 | intersphinx_mapping = {'https://docs.python.org/3.6/': None} 262 | 263 | -------------------------------------------------------------------------------- /doc/generated/spint.dispersion.alpha_disp.rst: -------------------------------------------------------------------------------- 1 | spint.dispersion.alpha\_disp 2 | ============================ 3 | 4 | .. currentmodule:: spint.dispersion 5 | 6 | .. autofunction:: alpha_disp -------------------------------------------------------------------------------- /doc/generated/spint.dispersion.phi_disp.rst: -------------------------------------------------------------------------------- 1 | spint.dispersion.phi\_disp 2 | ========================== 3 | 4 | .. currentmodule:: spint.dispersion 5 | 6 | .. autofunction:: phi_disp -------------------------------------------------------------------------------- /doc/generated/spint.gravity.Attraction.rst: -------------------------------------------------------------------------------- 1 | spint.gravity.Attraction 2 | ======================== 3 | 4 | .. currentmodule:: spint.gravity 5 | 6 | .. autoclass:: Attraction 7 | 8 | 9 | .. automethod:: __init__ 10 | 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | 16 | ~Attraction.SRMSE 17 | ~Attraction.SSI 18 | ~Attraction.__init__ 19 | ~Attraction.fit 20 | ~Attraction.local 21 | ~Attraction.reshape 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /doc/generated/spint.gravity.BaseGravity.rst: -------------------------------------------------------------------------------- 1 | spint.gravity.BaseGravity 2 | ========================= 3 | 4 | .. currentmodule:: spint.gravity 5 | 6 | .. autoclass:: BaseGravity 7 | 8 | 9 | .. automethod:: __init__ 10 | 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | 16 | ~BaseGravity.SRMSE 17 | ~BaseGravity.SSI 18 | ~BaseGravity.__init__ 19 | ~BaseGravity.fit 20 | ~BaseGravity.reshape 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /doc/generated/spint.gravity.Doubly.rst: -------------------------------------------------------------------------------- 1 | spint.gravity.Doubly 2 | ==================== 3 | 4 | .. currentmodule:: spint.gravity 5 | 6 | .. autoclass:: Doubly 7 | 8 | 9 | .. automethod:: __init__ 10 | 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | 16 | ~Doubly.SRMSE 17 | ~Doubly.SSI 18 | ~Doubly.__init__ 19 | ~Doubly.fit 20 | ~Doubly.local 21 | ~Doubly.reshape 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /doc/generated/spint.gravity.Gravity.rst: -------------------------------------------------------------------------------- 1 | spint.gravity.Gravity 2 | ===================== 3 | 4 | .. currentmodule:: spint.gravity 5 | 6 | .. autoclass:: Gravity 7 | 8 | 9 | .. automethod:: __init__ 10 | 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | 16 | ~Gravity.SRMSE 17 | ~Gravity.SSI 18 | ~Gravity.__init__ 19 | ~Gravity.fit 20 | ~Gravity.local 21 | ~Gravity.reshape 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /doc/generated/spint.gravity.Production.rst: -------------------------------------------------------------------------------- 1 | spint.gravity.Production 2 | ======================== 3 | 4 | .. currentmodule:: spint.gravity 5 | 6 | .. autoclass:: Production 7 | 8 | 9 | .. automethod:: __init__ 10 | 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | 16 | ~Production.SRMSE 17 | ~Production.SSI 18 | ~Production.__init__ 19 | ~Production.fit 20 | ~Production.local 21 | ~Production.reshape 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. documentation master file 2 | 3 | SPatial INTeraction models (SPINT) 4 | 5 | .. toctree:: 6 | :hidden: 7 | :maxdepth: 3 8 | :caption: Contents: 9 | 10 | Installation 11 | API 12 | References 13 | 14 | 15 | .. _PySAL: https://github.com/pysal/pysal 16 | -------------------------------------------------------------------------------- /doc/installation.rst: -------------------------------------------------------------------------------- 1 | .. Installation 2 | 3 | Installation 4 | ============ 5 | 6 | 7 | spint supports python `3.5`_ and `3.6`_ only. Please make sure that you are 8 | operating in a python 3 environment. 9 | 10 | Installing released version 11 | --------------------------- 12 | 13 | spint is available on the `Python Package Index`_. Therefore, you can either 14 | install directly with `pip` from the command line:: 15 | 16 | pip install -U spint 17 | 18 | 19 | or download the source distribution (.tar.gz) and decompress it to your selected 20 | destination. Open a command shell and navigate to the decompressed folder. 21 | Type:: 22 | 23 | pip install . 24 | 25 | Installing development version 26 | ------------------------------ 27 | 28 | Potentially, you might want to use the newest features in the development 29 | version of spint on github - `pysal/spint`_ while have not been incorporated 30 | in the Pypi released version. You can achieve that by installing `pysal/spint`_ 31 | by running the following from a command shell:: 32 | 33 | pip install https://github.com/pysal/spint/archive/master.zip 34 | 35 | You can also `fork`_ the `pysal/spint`_ repo and create a local clone of 36 | your fork. By making changes 37 | to your local clone and submitting a pull request to `pysal/spint`_, you can 38 | contribute to the mgwr development. 39 | 40 | .. _3.5: https://docs.python.org/3.5/ 41 | .. _3.6: https://docs.python.org/3.6/ 42 | .. _Python Package Index: https://pypi.org/project/spglm/ 43 | .. _pysal/spint: https://github.com/pysal/spint 44 | .. _fork: https://help.github.com/articles/fork-a-repo/ 45 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=python -msphinx 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=spint 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed, 20 | echo.then set the SPHINXBUILD environment variable to point to the full 21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the 22 | echo.Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /doc/references.rst: -------------------------------------------------------------------------------- 1 | .. reference for the docs 2 | 3 | References 4 | ========== 5 | 6 | .. bibliography:: _static/references.bib 7 | :cited: 8 | -------------------------------------------------------------------------------- /notebooks/New_DistanceBand.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": false, 8 | "jupyter": { 9 | "outputs_hidden": false 10 | } 11 | }, 12 | "outputs": [], 13 | "source": [ 14 | "import numpy as np\n", 15 | "from scipy.spatial import distance\n", 16 | "import scipy.spatial as spatial\n", 17 | "from pysal.weights import W\n", 18 | "from pysal.weights.util import isKDTree\n", 19 | "from pysal.weights import Distance as Distance\n", 20 | "from pysal.weights import WSP, WSP2W\n", 21 | "from scipy.spatial import distance_matrix\n", 22 | "import scipy.sparse as sp\n", 23 | "from pysal.common import KDTree" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 2, 29 | "metadata": { 30 | "collapsed": false, 31 | "jupyter": { 32 | "outputs_hidden": false 33 | } 34 | }, 35 | "outputs": [], 36 | "source": [ 37 | "class DistanceBand(W):\n", 38 | " \"\"\"\n", 39 | " Spatial weights based on distance band.\n", 40 | "\n", 41 | " Parameters\n", 42 | " ----------\n", 43 | "\n", 44 | " data : array\n", 45 | " (n,k) or KDTree where KDtree.data is array (n,k)\n", 46 | " n observations on k characteristics used to measure\n", 47 | " distances between the n objects\n", 48 | " threshold : float\n", 49 | " distance band\n", 50 | " p : float\n", 51 | " Minkowski p-norm distance metric parameter:\n", 52 | " 1<=p<=infinity\n", 53 | " 2: Euclidean distance\n", 54 | " 1: Manhattan distance\n", 55 | " binary : boolean\n", 56 | " If true w_{ij}=1 if d_{i,j}<=threshold, otherwise w_{i,j}=0\n", 57 | " If false wij=dij^{alpha}\n", 58 | " alpha : float\n", 59 | " distance decay parameter for weight (default -1.0)\n", 60 | " if alpha is positive the weights will not decline with\n", 61 | " distance. If binary is True, alpha is ignored\n", 62 | "\n", 63 | " ids : list\n", 64 | " values to use for keys of the neighbors and weights dicts\n", 65 | "\n", 66 | " Attributes\n", 67 | " ----------\n", 68 | " weights : dict\n", 69 | " of neighbor weights keyed by observation id\n", 70 | "\n", 71 | " neighbors : dict\n", 72 | " of neighbors keyed by observation id\n", 73 | "\n", 74 | "\n", 75 | "\n", 76 | " \"\"\"\n", 77 | "\n", 78 | " def __init__(self, data, threshold, p=2, alpha=-1.0, binary=True, ids=None, build_sp=True):\n", 79 | " \"\"\"Casting to floats is a work around for a bug in scipy.spatial.\n", 80 | " See detail in pysal issue #126.\n", 81 | "\n", 82 | " \"\"\"\n", 83 | " self.p = p\n", 84 | " self.threshold = threshold\n", 85 | " self.binary = binary\n", 86 | " self.alpha = alpha\n", 87 | " self.build_sp = build_sp\n", 88 | " \n", 89 | " if isKDTree(data):\n", 90 | " self.kd = data\n", 91 | " self.data = self.kd.data\n", 92 | " else:\n", 93 | " if self.build_sp:\n", 94 | " try:\n", 95 | " data = np.asarray(data)\n", 96 | " if data.dtype.kind != 'f':\n", 97 | " data = data.astype(float)\n", 98 | " self.data = data\n", 99 | " self.kd = KDTree(self.data)\n", 100 | " except:\n", 101 | " raise ValueError(\"Could not make array from data\") \n", 102 | " else:\n", 103 | " self.data = data\n", 104 | " self.kd = None \n", 105 | " \n", 106 | "\n", 107 | " self._band()\n", 108 | " neighbors, weights = self._distance_to_W(ids)\n", 109 | " W.__init__(self, neighbors, weights, ids)\n", 110 | "\n", 111 | " def _band(self):\n", 112 | " \"\"\"Find all pairs within threshold.\n", 113 | "\n", 114 | " \"\"\"\n", 115 | " if self.build_sp: \n", 116 | " self.dmat = self.kd.sparse_distance_matrix(\n", 117 | " self.kd, max_distance=self.threshold)\n", 118 | " else:\n", 119 | " self.dmat = self._spdistance_matrix(self.data, self.data, self.threshold)\n", 120 | " \n", 121 | " def _distance_to_W(self, ids=None):\n", 122 | " if self.binary:\n", 123 | " self.dmat[self.dmat>0] = 1\n", 124 | " tempW = WSP2W(WSP(self.dmat))\n", 125 | " return tempW.neighbors, tempW.weights\n", 126 | "\n", 127 | " else:\n", 128 | " weighted = self.dmat.power(self.alpha)\n", 129 | " weighted[weighted==np.inf] = 0\n", 130 | " tempW = WSP2W(WSP(weighted))\n", 131 | " return tempW.neighbors, tempW.weights\n", 132 | " \n", 133 | " def _spdistance_matrix(self, x,y, threshold=None):\n", 134 | " dist = distance_matrix(x,y)\n", 135 | " if threshold is not None:\n", 136 | " zeros = dist > threshold\n", 137 | " dist[zeros] = 0\n", 138 | " return sp.csr_matrix(dist)" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 21, 144 | "metadata": { 145 | "collapsed": true, 146 | "jupyter": { 147 | "outputs_hidden": true 148 | } 149 | }, 150 | "outputs": [], 151 | "source": [ 152 | "x = np.random.randint(0, 1000, 1000)\n", 153 | "y = np.random.randint(0, 1000, 1000)\n", 154 | "w = np.random.randint(0, 1000, 1000)\n", 155 | "z = np.random.randint(0, 1000, 1000)\n", 156 | "\n", 157 | "data = zip(x.ravel(), y.ravel(), w.ravel(), z.ravel())\n", 158 | "tree = KDTree(data)" 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": 22, 164 | "metadata": { 165 | "collapsed": false, 166 | "jupyter": { 167 | "outputs_hidden": false 168 | } 169 | }, 170 | "outputs": [], 171 | "source": [ 172 | "#print np.allclose(Distance.DistanceBand(tree, threshold=500, alpha=-1.5, binary=True).full()[0], DistanceBand(tree, threshold=500, alpha=-1.5, binary=True).full()[0])\n", 173 | "#print np.allclose(Distance.DistanceBand(tree, threshold=500, alpha=-1.5, binary=False).full()[0], DistanceBand(tree, threshold=500, alpha=-1.5, binary=False).full()[0])" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": 23, 179 | "metadata": { 180 | "collapsed": false, 181 | "jupyter": { 182 | "outputs_hidden": false 183 | } 184 | }, 185 | "outputs": [ 186 | { 187 | "name": "stdout", 188 | "output_type": "stream", 189 | "text": [ 190 | "CPU times: user 1.42 s, sys: 17.9 ms, total: 1.44 s\n", 191 | "Wall time: 1.44 s\n", 192 | "CPU times: user 366 ms, sys: 11.3 ms, total: 377 ms\n", 193 | "Wall time: 376 ms\n" 194 | ] 195 | }, 196 | { 197 | "data": { 198 | "text/plain": [ 199 | "<__main__.DistanceBand at 0x10c0aedd0>" 200 | ] 201 | }, 202 | "execution_count": 23, 203 | "metadata": {}, 204 | "output_type": "execute_result" 205 | } 206 | ], 207 | "source": [ 208 | "%time Distance.DistanceBand(tree, threshold=500, alpha=-1.5, binary=True)\n", 209 | "%time DistanceBand(tree, threshold=500, alpha=-1.5, binary=True, build_sp=True)\n" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": 24, 215 | "metadata": { 216 | "collapsed": false, 217 | "jupyter": { 218 | "outputs_hidden": false 219 | } 220 | }, 221 | "outputs": [ 222 | { 223 | "name": "stdout", 224 | "output_type": "stream", 225 | "text": [ 226 | "CPU times: user 1.37 s, sys: 21.7 ms, total: 1.39 s\n", 227 | "Wall time: 1.4 s\n", 228 | "CPU times: user 69.9 ms, sys: 4.84 ms, total: 74.7 ms\n", 229 | "Wall time: 74.7 ms\n" 230 | ] 231 | }, 232 | { 233 | "data": { 234 | "text/plain": [ 235 | "<__main__.DistanceBand at 0x117d18c90>" 236 | ] 237 | }, 238 | "execution_count": 24, 239 | "metadata": {}, 240 | "output_type": "execute_result" 241 | } 242 | ], 243 | "source": [ 244 | "%time Distance.DistanceBand(tree, threshold=500, alpha=-1.5, binary=True)\n", 245 | "%time DistanceBand(tree, threshold=500, alpha=-1.5, binary=True, build_sp=False)" 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": 25, 251 | "metadata": { 252 | "collapsed": false, 253 | "jupyter": { 254 | "outputs_hidden": false 255 | } 256 | }, 257 | "outputs": [ 258 | { 259 | "name": "stdout", 260 | "output_type": "stream", 261 | "text": [ 262 | "CPU times: user 1.28 s, sys: 44 ms, total: 1.32 s\n", 263 | "Wall time: 1.3 s\n", 264 | "CPU times: user 199 ms, sys: 10.9 ms, total: 210 ms\n", 265 | "Wall time: 210 ms\n" 266 | ] 267 | }, 268 | { 269 | "data": { 270 | "text/plain": [ 271 | "<__main__.DistanceBand at 0x117d18a10>" 272 | ] 273 | }, 274 | "execution_count": 25, 275 | "metadata": {}, 276 | "output_type": "execute_result" 277 | } 278 | ], 279 | "source": [ 280 | "%time Distance.DistanceBand(tree, threshold=500, alpha=-1.5, binary=False)\n", 281 | "%time DistanceBand(tree, threshold=500, alpha=-1.5, binary=False, build_sp=True)" 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": 26, 287 | "metadata": { 288 | "collapsed": false, 289 | "jupyter": { 290 | "outputs_hidden": false 291 | } 292 | }, 293 | "outputs": [ 294 | { 295 | "name": "stdout", 296 | "output_type": "stream", 297 | "text": [ 298 | "CPU times: user 1.5 s, sys: 46.3 ms, total: 1.54 s\n", 299 | "Wall time: 1.53 s\n", 300 | "CPU times: user 67.1 ms, sys: 5.1 ms, total: 72.2 ms\n", 301 | "Wall time: 72.2 ms\n" 302 | ] 303 | }, 304 | { 305 | "data": { 306 | "text/plain": [ 307 | "<__main__.DistanceBand at 0x117d18e90>" 308 | ] 309 | }, 310 | "execution_count": 26, 311 | "metadata": {}, 312 | "output_type": "execute_result" 313 | } 314 | ], 315 | "source": [ 316 | "%time Distance.DistanceBand(tree, threshold=500, alpha=-1.5, binary=False)\n", 317 | "%time DistanceBand(tree, threshold=500, alpha=-1.5, binary=False, build_sp=False)" 318 | ] 319 | }, 320 | { 321 | "cell_type": "code", 322 | "execution_count": null, 323 | "metadata": { 324 | "collapsed": true, 325 | "jupyter": { 326 | "outputs_hidden": true 327 | } 328 | }, 329 | "outputs": [], 330 | "source": [] 331 | }, 332 | { 333 | "cell_type": "code", 334 | "execution_count": null, 335 | "metadata": { 336 | "collapsed": true, 337 | "jupyter": { 338 | "outputs_hidden": true 339 | } 340 | }, 341 | "outputs": [], 342 | "source": [] 343 | } 344 | ], 345 | "metadata": { 346 | "anaconda-cloud": {}, 347 | "kernelspec": { 348 | "display_name": "Python 3", 349 | "language": "python", 350 | "name": "python3" 351 | }, 352 | "language_info": { 353 | "codemirror_mode": { 354 | "name": "ipython", 355 | "version": 3 356 | }, 357 | "file_extension": ".py", 358 | "mimetype": "text/x-python", 359 | "name": "python", 360 | "nbconvert_exporter": "python", 361 | "pygments_lexer": "ipython3", 362 | "version": "3.9.4" 363 | } 364 | }, 365 | "nbformat": 4, 366 | "nbformat_minor": 4 367 | } 368 | -------------------------------------------------------------------------------- /notebooks/ODW_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 4, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import sys\n", 12 | "sys.path.append('/Users/toshan/dev/pysal/pysal/weights')\n", 13 | "from spintW import ODW\n", 14 | "import pysal as ps" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "# With an equal number of origins and destinations (n=16)" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 33, 27 | "metadata": { 28 | "collapsed": true 29 | }, 30 | "outputs": [], 31 | "source": [ 32 | "origins = ps.weights.lat2W(4,4)\n", 33 | "dests = ps.weights.lat2W(4,4)" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 34, 39 | "metadata": { 40 | "collapsed": false 41 | }, 42 | "outputs": [ 43 | { 44 | "data": { 45 | "text/plain": [ 46 | "16" 47 | ] 48 | }, 49 | "execution_count": 34, 50 | "metadata": {}, 51 | "output_type": "execute_result" 52 | } 53 | ], 54 | "source": [ 55 | "origins.n" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 35, 61 | "metadata": { 62 | "collapsed": false 63 | }, 64 | "outputs": [ 65 | { 66 | "data": { 67 | "text/plain": [ 68 | "16" 69 | ] 70 | }, 71 | "execution_count": 35, 72 | "metadata": {}, 73 | "output_type": "execute_result" 74 | } 75 | ], 76 | "source": [ 77 | "dests.n" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 36, 83 | "metadata": { 84 | "collapsed": true 85 | }, 86 | "outputs": [], 87 | "source": [ 88 | "ODw = ODW(origins, dests)" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 37, 94 | "metadata": { 95 | "collapsed": false 96 | }, 97 | "outputs": [ 98 | { 99 | "name": "stdout", 100 | "output_type": "stream", 101 | "text": [ 102 | "256 256\n" 103 | ] 104 | } 105 | ], 106 | "source": [ 107 | "print ODw.n, 16*16" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 38, 113 | "metadata": { 114 | "collapsed": false 115 | }, 116 | "outputs": [ 117 | { 118 | "data": { 119 | "text/plain": [ 120 | "(256, 256)" 121 | ] 122 | }, 123 | "execution_count": 38, 124 | "metadata": {}, 125 | "output_type": "execute_result" 126 | } 127 | ], 128 | "source": [ 129 | "ODw.full()[0].shape" 130 | ] 131 | }, 132 | { 133 | "cell_type": "markdown", 134 | "metadata": {}, 135 | "source": [ 136 | " # With non-equal number of origins (n=9) and destinations (m=25)" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": 39, 142 | "metadata": { 143 | "collapsed": true 144 | }, 145 | "outputs": [], 146 | "source": [ 147 | "origins = ps.weights.lat2W(3,3)" 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": 40, 153 | "metadata": { 154 | "collapsed": true 155 | }, 156 | "outputs": [], 157 | "source": [ 158 | "dests = ps.weights.lat2W(5,5)" 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": 41, 164 | "metadata": { 165 | "collapsed": false 166 | }, 167 | "outputs": [ 168 | { 169 | "data": { 170 | "text/plain": [ 171 | "9" 172 | ] 173 | }, 174 | "execution_count": 41, 175 | "metadata": {}, 176 | "output_type": "execute_result" 177 | } 178 | ], 179 | "source": [ 180 | "origins.n" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 42, 186 | "metadata": { 187 | "collapsed": false 188 | }, 189 | "outputs": [ 190 | { 191 | "data": { 192 | "text/plain": [ 193 | "25" 194 | ] 195 | }, 196 | "execution_count": 42, 197 | "metadata": {}, 198 | "output_type": "execute_result" 199 | } 200 | ], 201 | "source": [ 202 | "dests.n" 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": 43, 208 | "metadata": { 209 | "collapsed": true 210 | }, 211 | "outputs": [], 212 | "source": [ 213 | "ODw = ODW(origins, dests)" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": 44, 219 | "metadata": { 220 | "collapsed": false 221 | }, 222 | "outputs": [ 223 | { 224 | "name": "stdout", 225 | "output_type": "stream", 226 | "text": [ 227 | "225 225\n" 228 | ] 229 | } 230 | ], 231 | "source": [ 232 | "print ODw.n, 9*25" 233 | ] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "execution_count": 45, 238 | "metadata": { 239 | "collapsed": false 240 | }, 241 | "outputs": [ 242 | { 243 | "data": { 244 | "text/plain": [ 245 | "(225, 225)" 246 | ] 247 | }, 248 | "execution_count": 45, 249 | "metadata": {}, 250 | "output_type": "execute_result" 251 | } 252 | ], 253 | "source": [ 254 | "ODw.full()[0].shape" 255 | ] 256 | }, 257 | { 258 | "cell_type": "code", 259 | "execution_count": null, 260 | "metadata": { 261 | "collapsed": true 262 | }, 263 | "outputs": [], 264 | "source": [] 265 | } 266 | ], 267 | "metadata": { 268 | "kernelspec": { 269 | "display_name": "Python [Root]", 270 | "language": "python", 271 | "name": "Python [Root]" 272 | }, 273 | "language_info": { 274 | "codemirror_mode": { 275 | "name": "ipython", 276 | "version": 2 277 | }, 278 | "file_extension": ".py", 279 | "mimetype": "text/x-python", 280 | "name": "python", 281 | "nbconvert_exporter": "python", 282 | "pygments_lexer": "ipython2", 283 | "version": "2.7.12" 284 | } 285 | }, 286 | "nbformat": 4, 287 | "nbformat_minor": 0 288 | } 289 | -------------------------------------------------------------------------------- /notebooks/OD_weights.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import pysal as ps\n", 12 | "from pysal import weights as w\n", 13 | "import numpy as np\n", 14 | "import scipy.sparse as sp" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "metadata": { 21 | "collapsed": false 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "\n", 26 | "def OD(Wo, Wd):\n", 27 | " Wo = Wo.sparse\n", 28 | " Wd = Wd.sparse\n", 29 | " Ww = sp.kron(Wo, Wd)\n", 30 | " return w.WSP2W(w.WSP(Ww))" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 7, 36 | "metadata": { 37 | "collapsed": false 38 | }, 39 | "outputs": [ 40 | { 41 | "name": "stdout", 42 | "output_type": "stream", 43 | "text": [ 44 | "(256, 256)\n" 45 | ] 46 | } 47 | ], 48 | "source": [ 49 | "origins = ps.weights.lat2W(4,4)\n", 50 | "dests = ps.weights.lat2W(4,4)\n", 51 | "Ww = OD(origins, dests)\n", 52 | "Ww.transform = 'r'\n", 53 | "print Ww.full()[0].shape" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 4, 59 | "metadata": { 60 | "collapsed": false 61 | }, 62 | "outputs": [ 63 | { 64 | "name": "stdout", 65 | "output_type": "stream", 66 | "text": [ 67 | "[[ 0]\n", 68 | " [38]\n", 69 | " [36]\n", 70 | " [86]\n", 71 | " [30]\n", 72 | " [ 0]\n", 73 | " [69]\n", 74 | " [19]\n", 75 | " [84]\n", 76 | " [43]\n", 77 | " [ 0]\n", 78 | " [80]\n", 79 | " [58]\n", 80 | " [ 3]\n", 81 | " [35]\n", 82 | " [ 0]]\n", 83 | "[[ 28. ]\n", 84 | " [ 53.25]\n", 85 | " [ 53.25]\n", 86 | " [ 28. ]\n", 87 | " [ 28. ]\n", 88 | " [ 36. ]\n", 89 | " [ 36. ]\n", 90 | " [ 28. ]\n", 91 | " [ 28. ]\n", 92 | " [ 36. ]\n", 93 | " [ 36. ]\n", 94 | " [ 28. ]\n", 95 | " [ 28. ]\n", 96 | " [ 53.25]\n", 97 | " [ 53.25]\n", 98 | " [ 28. ]]\n" 99 | ] 100 | } 101 | ], 102 | "source": [ 103 | "flows = np.random.randint(0,100, (4,4))\n", 104 | "np.fill_diagonal(flows, 0)\n", 105 | "flows = flows.reshape((16,1))\n", 106 | "print flows\n", 107 | "slag = ps.lag_spatial(Ww, flows)\n", 108 | "print slag" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 5, 114 | "metadata": { 115 | "collapsed": false 116 | }, 117 | "outputs": [ 118 | { 119 | "data": { 120 | "text/plain": [ 121 | "{0: [1.0, 1.0], 1: [1.0, 1.0], 2: [1.0, 1.0], 3: [1.0, 1.0]}" 122 | ] 123 | }, 124 | "execution_count": 5, 125 | "metadata": {}, 126 | "output_type": "execute_result" 127 | } 128 | ], 129 | "source": [ 130 | "origins.weights" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 6, 136 | "metadata": { 137 | "collapsed": false 138 | }, 139 | "outputs": [], 140 | "source": [ 141 | "import os\n", 142 | "os.chdir('/Users/toshan/dev/pysal/pysal/weights')\n", 143 | "from spintW import ODW" 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": 16, 149 | "metadata": { 150 | "collapsed": false, 151 | "scrolled": true 152 | }, 153 | "outputs": [], 154 | "source": [ 155 | "origins = ps.weights.lat2W(2,2)\n", 156 | "dests = ps.weights.lat2W(2,2)\n", 157 | "Ww = ODW(origins, dests)" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": 17, 163 | "metadata": { 164 | "collapsed": false 165 | }, 166 | "outputs": [ 167 | { 168 | "data": { 169 | "text/plain": [ 170 | "array([[ 0. , 0. , 0. , 0. , 0. , 0.25, 0.25, 0. , 0. ,\n", 171 | " 0.25, 0.25, 0. , 0. , 0. , 0. , 0. ],\n", 172 | " [ 0. , 0. , 0. , 0. , 0.25, 0. , 0. , 0.25, 0.25,\n", 173 | " 0. , 0. , 0.25, 0. , 0. , 0. , 0. ],\n", 174 | " [ 0. , 0. , 0. , 0. , 0.25, 0. , 0. , 0.25, 0.25,\n", 175 | " 0. , 0. , 0.25, 0. , 0. , 0. , 0. ],\n", 176 | " [ 0. , 0. , 0. , 0. , 0. , 0.25, 0.25, 0. , 0. ,\n", 177 | " 0.25, 0.25, 0. , 0. , 0. , 0. , 0. ],\n", 178 | " [ 0. , 0.25, 0.25, 0. , 0. , 0. , 0. , 0. , 0. ,\n", 179 | " 0. , 0. , 0. , 0. , 0.25, 0.25, 0. ],\n", 180 | " [ 0.25, 0. , 0. , 0.25, 0. , 0. , 0. , 0. , 0. ,\n", 181 | " 0. , 0. , 0. , 0.25, 0. , 0. , 0.25],\n", 182 | " [ 0.25, 0. , 0. , 0.25, 0. , 0. , 0. , 0. , 0. ,\n", 183 | " 0. , 0. , 0. , 0.25, 0. , 0. , 0.25],\n", 184 | " [ 0. , 0.25, 0.25, 0. , 0. , 0. , 0. , 0. , 0. ,\n", 185 | " 0. , 0. , 0. , 0. , 0.25, 0.25, 0. ],\n", 186 | " [ 0. , 0.25, 0.25, 0. , 0. , 0. , 0. , 0. , 0. ,\n", 187 | " 0. , 0. , 0. , 0. , 0.25, 0.25, 0. ],\n", 188 | " [ 0.25, 0. , 0. , 0.25, 0. , 0. , 0. , 0. , 0. ,\n", 189 | " 0. , 0. , 0. , 0.25, 0. , 0. , 0.25],\n", 190 | " [ 0.25, 0. , 0. , 0.25, 0. , 0. , 0. , 0. , 0. ,\n", 191 | " 0. , 0. , 0. , 0.25, 0. , 0. , 0.25],\n", 192 | " [ 0. , 0.25, 0.25, 0. , 0. , 0. , 0. , 0. , 0. ,\n", 193 | " 0. , 0. , 0. , 0. , 0.25, 0.25, 0. ],\n", 194 | " [ 0. , 0. , 0. , 0. , 0. , 0.25, 0.25, 0. , 0. ,\n", 195 | " 0.25, 0.25, 0. , 0. , 0. , 0. , 0. ],\n", 196 | " [ 0. , 0. , 0. , 0. , 0.25, 0. , 0. , 0.25, 0.25,\n", 197 | " 0. , 0. , 0.25, 0. , 0. , 0. , 0. ],\n", 198 | " [ 0. , 0. , 0. , 0. , 0.25, 0. , 0. , 0.25, 0.25,\n", 199 | " 0. , 0. , 0.25, 0. , 0. , 0. , 0. ],\n", 200 | " [ 0. , 0. , 0. , 0. , 0. , 0.25, 0.25, 0. , 0. ,\n", 201 | " 0.25, 0.25, 0. , 0. , 0. , 0. , 0. ]])" 202 | ] 203 | }, 204 | "execution_count": 17, 205 | "metadata": {}, 206 | "output_type": "execute_result" 207 | } 208 | ], 209 | "source": [ 210 | "Ww.full()[0]" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": null, 216 | "metadata": { 217 | "collapsed": true 218 | }, 219 | "outputs": [], 220 | "source": [] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": null, 225 | "metadata": { 226 | "collapsed": true 227 | }, 228 | "outputs": [], 229 | "source": [] 230 | } 231 | ], 232 | "metadata": { 233 | "anaconda-cloud": {}, 234 | "kernelspec": { 235 | "display_name": "Python [Root]", 236 | "language": "python", 237 | "name": "Python [Root]" 238 | }, 239 | "language_info": { 240 | "codemirror_mode": { 241 | "name": "ipython", 242 | "version": 2 243 | }, 244 | "file_extension": ".py", 245 | "mimetype": "text/x-python", 246 | "name": "python", 247 | "nbconvert_exporter": "python", 248 | "pygments_lexer": "ipython2", 249 | "version": "2.7.12" 250 | } 251 | }, 252 | "nbformat": 4, 253 | "nbformat_minor": 0 254 | } 255 | -------------------------------------------------------------------------------- /notebooks/autograd_test.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 11, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import pandas as pd\n", 12 | "import scipy.optimize as sc\n", 13 | "import autograd.numpy as np\n", 14 | "import autograd\n", 15 | "from autograd.convenience_wrappers import multigrad\n", 16 | "import scipy.sparse" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 12, 22 | "metadata": { 23 | "collapsed": true 24 | }, 25 | "outputs": [], 26 | "source": [ 27 | "austria = pd.read_csv('http://dl.dropbox.com/u/8649795/AT_Austria.csv')\n", 28 | "austria = austria[austria['Origin'] != austria['Destination']]\n", 29 | "f = np.reshape(austria['Data'].values, (-1,1))\n", 30 | "o = austria['Origin'].values\n", 31 | "d = austria['Destination'].values\n", 32 | "dij = np.reshape(austria['Dij'].values, (-1,1))\n", 33 | "o_vars = np.reshape(austria['Oi2007'].values, (-1,1))\n", 34 | "d_vars = np.reshape(austria['Dj2007'].values, (-1,1))\n", 35 | "dij = np.reshape(austria['Dij'].values, (-1,1))\n", 36 | "o_vars = np.reshape(austria['Oi2007'].values, (-1,1))\n", 37 | "d_vars = np.reshape(austria['Dj2007'].values, (-1,1))" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 13, 43 | "metadata": { 44 | "collapsed": true 45 | }, 46 | "outputs": [], 47 | "source": [ 48 | "def newton(f, x0):\n", 49 | " # wrap scipy.optimize.newton with our automatic derivatives\n", 50 | " params = sc.fsolve(f, x0)\n", 51 | " return params\n", 52 | "\n", 53 | "def poiss_loglike(mu, sig, ep, x, inputs):\n", 54 | " a,b,c = inputs[:,0], inputs[:,1], inputs[:,2]\n", 55 | " predict = sig*a + ep*b + mu*c\n", 56 | " predict = np.reshape(predict, (-1,1))\n", 57 | " return -np.sum(x*np.log(predict)-predict)\n", 58 | "\n", 59 | "#def loglike(mu, k, x, inputs):\n", 60 | " #return np.sum(poiss_loglike(mu, k, x, inputs))\n", 61 | "\n", 62 | "\n", 63 | "def fit_maxlike(x, inputs, mu_guess, o_guess, d_guess):\n", 64 | " prime = lambda p: multigrad(poiss_loglike, argnums=[0,1,2])(p[0], p[1], p[2], x, inputs)\n", 65 | " params = newton(prime, (mu_guess, o_guess, d_guess))\n", 66 | " return params" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 15, 72 | "metadata": { 73 | "collapsed": false 74 | }, 75 | "outputs": [ 76 | { 77 | "name": "stdout", 78 | "output_type": "stream", 79 | "text": [ 80 | "[-1.14993102 0.69084953 0.68523832]\n", 81 | "(-2.7430635540781623e-10, -2.5915536383536164e-10, -4.730811298259141e-10)\n" 82 | ] 83 | } 84 | ], 85 | "source": [ 86 | "if __name__ == \"__main__\":\n", 87 | " \n", 88 | " x=np.log(f)\n", 89 | " inputs = np.hstack((np.log(o_vars), np.log(d_vars), np.log(dij)))\n", 90 | " params = fit_maxlike(x, inputs, mu_guess=0.0, o_guess=1.0, d_guess=1.0)\n", 91 | " print(params)\n", 92 | " \n", 93 | " prime = lambda p: multigrad(poiss_loglike, argnums=[0,1,2])(p[0], p[1], p[2], x, inputs)\n", 94 | " print(prime(params))" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": null, 100 | "metadata": { 101 | "collapsed": true 102 | }, 103 | "outputs": [], 104 | "source": [] 105 | } 106 | ], 107 | "metadata": { 108 | "kernelspec": { 109 | "display_name": "Python 2", 110 | "language": "python", 111 | "name": "python2" 112 | }, 113 | "language_info": { 114 | "codemirror_mode": { 115 | "name": "ipython", 116 | "version": 2 117 | }, 118 | "file_extension": ".py", 119 | "mimetype": "text/x-python", 120 | "name": "python", 121 | "nbconvert_exporter": "python", 122 | "pygments_lexer": "ipython2", 123 | "version": "2.7.9" 124 | } 125 | }, 126 | "nbformat": 4, 127 | "nbformat_minor": 0 128 | } 129 | -------------------------------------------------------------------------------- /notebooks/dispersion_test.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 8, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import os\n", 12 | "os.chdir('/Users/toshan/dev/pysal/pysal/contrib/spint')\n", 13 | "from count_model import CountModel\n", 14 | "import numpy as np\n", 15 | "import pandas as pd\n", 16 | "from gravity import Gravity, Production, Attraction, Doubly, BaseGravity\n", 17 | "import statsmodels.formula.api as smf\n", 18 | "from statsmodels.api import families\n", 19 | "os.chdir('/Users/toshan/dev/pysal/pysal/contrib/glm')\n", 20 | "from glm import GLM\n", 21 | "from family import Poisson, QuasiPoisson\n", 22 | "\n", 23 | "import pysal\n", 24 | "import os\n", 25 | "os.chdir('/Users/toshan/dev/pysal/pysal/contrib/spint')\n", 26 | "from dispersion import alpha_disp, phi_disp\n", 27 | "\n" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 2, 33 | "metadata": { 34 | "collapsed": false 35 | }, 36 | "outputs": [], 37 | "source": [ 38 | "rec = pd.read_csv('/Users/toshan/Documents/RecreationDemand.csv')" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 3, 44 | "metadata": { 45 | "collapsed": false 46 | }, 47 | "outputs": [ 48 | { 49 | "data": { 50 | "text/html": [ 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 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | "
Unnamed: 0tripsqualityskiincomeuserfeecostCcostScostH
0 1 0 0 yes 4 no 67.59 68.620 76.800
1 2 0 0 no 9 no 68.86 70.936 84.780
2 3 0 0 yes 5 no 58.12 59.465 72.110
3 4 0 0 no 2 no 15.79 13.750 23.680
4 5 0 0 yes 3 no 24.02 34.033 34.547
\n", 130 | "
" 131 | ], 132 | "text/plain": [ 133 | " Unnamed: 0 trips quality ski income userfee costC costS costH\n", 134 | "0 1 0 0 yes 4 no 67.59 68.620 76.800\n", 135 | "1 2 0 0 no 9 no 68.86 70.936 84.780\n", 136 | "2 3 0 0 yes 5 no 58.12 59.465 72.110\n", 137 | "3 4 0 0 no 2 no 15.79 13.750 23.680\n", 138 | "4 5 0 0 yes 3 no 24.02 34.033 34.547" 139 | ] 140 | }, 141 | "execution_count": 3, 142 | "metadata": {}, 143 | "output_type": "execute_result" 144 | } 145 | ], 146 | "source": [ 147 | "rec.head()" 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": 4, 153 | "metadata": { 154 | "collapsed": true 155 | }, 156 | "outputs": [], 157 | "source": [ 158 | "y = rec['trips'].values.reshape((-1,1))" 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": 5, 164 | "metadata": { 165 | "collapsed": false 166 | }, 167 | "outputs": [], 168 | "source": [ 169 | "X = rec[['quality', 'income', 'costC', 'costS', 'costH']].values" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 22, 175 | "metadata": { 176 | "collapsed": false 177 | }, 178 | "outputs": [], 179 | "source": [ 180 | "test = CountModel(y, X, constant=False)" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 23, 186 | "metadata": { 187 | "collapsed": false 188 | }, 189 | "outputs": [], 190 | "source": [ 191 | "glm_results = test.fit(framework='glm')" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": 24, 197 | "metadata": { 198 | "collapsed": false 199 | }, 200 | "outputs": [ 201 | { 202 | "data": { 203 | "text/plain": [ 204 | "array([ 7.30811593e+00, 2.71035909e+00, 3.36051997e-03])" 205 | ] 206 | }, 207 | "execution_count": 24, 208 | "metadata": {}, 209 | "output_type": "execute_result" 210 | } 211 | ], 212 | "source": [ 213 | "phi_disp(glm_results)" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": 26, 219 | "metadata": { 220 | "collapsed": false 221 | }, 222 | "outputs": [ 223 | { 224 | "data": { 225 | "text/plain": [ 226 | "array([ 6.30811593e+00, 2.71035909e+00, 3.36051997e-03])" 227 | ] 228 | }, 229 | "execution_count": 26, 230 | "metadata": {}, 231 | "output_type": "execute_result" 232 | } 233 | ], 234 | "source": [ 235 | "alpha_disp(glm_results)" 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": 27, 241 | "metadata": { 242 | "collapsed": false 243 | }, 244 | "outputs": [ 245 | { 246 | "data": { 247 | "text/plain": [ 248 | "array([ 1.55402055e+00, 3.38253708e+00, 3.59097912e-04])" 249 | ] 250 | }, 251 | "execution_count": 27, 252 | "metadata": {}, 253 | "output_type": "execute_result" 254 | } 255 | ], 256 | "source": [ 257 | "alpha_disp(glm_results, lambda x: x**2)" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": 28, 263 | "metadata": { 264 | "collapsed": false 265 | }, 266 | "outputs": [], 267 | "source": [ 268 | "#Prepare some test data - columbus example\n", 269 | "db = pysal.open(pysal.examples.get_path('columbus.dbf'),'r')\n", 270 | "y = np.array(db.by_col(\"HOVAL\"))\n", 271 | "y = np.reshape(y, (49,1))\n", 272 | "X = []\n", 273 | "#X.append(np.ones(len(y)))\n", 274 | "X.append(db.by_col(\"INC\"))\n", 275 | "X.append(db.by_col(\"CRIME\"))\n", 276 | "X = np.array(X).T\n", 277 | "\n", 278 | "poisson_y = np.round(y).astype(int)" 279 | ] 280 | }, 281 | { 282 | "cell_type": "code", 283 | "execution_count": 29, 284 | "metadata": { 285 | "collapsed": false 286 | }, 287 | "outputs": [], 288 | "source": [ 289 | "test = CountModel(poisson_y, X)" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": 30, 295 | "metadata": { 296 | "collapsed": true 297 | }, 298 | "outputs": [], 299 | "source": [ 300 | "glm_results = test.fit(framework='glm')" 301 | ] 302 | }, 303 | { 304 | "cell_type": "code", 305 | "execution_count": 31, 306 | "metadata": { 307 | "collapsed": false 308 | }, 309 | "outputs": [ 310 | { 311 | "data": { 312 | "text/plain": [ 313 | "array([ 5.39968689, 2.3230411 , 0.01008847])" 314 | ] 315 | }, 316 | "execution_count": 31, 317 | "metadata": {}, 318 | "output_type": "execute_result" 319 | } 320 | ], 321 | "source": [ 322 | "phi_disp(glm_results)" 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": 32, 328 | "metadata": { 329 | "collapsed": false 330 | }, 331 | "outputs": [ 332 | { 333 | "data": { 334 | "text/plain": [ 335 | "array([ 4.39968689, 2.3230411 , 0.01008847])" 336 | ] 337 | }, 338 | "execution_count": 32, 339 | "metadata": {}, 340 | "output_type": "execute_result" 341 | } 342 | ], 343 | "source": [ 344 | "alpha_disp(glm_results)" 345 | ] 346 | }, 347 | { 348 | "cell_type": "code", 349 | "execution_count": 33, 350 | "metadata": { 351 | "collapsed": false 352 | }, 353 | "outputs": [ 354 | { 355 | "data": { 356 | "text/plain": [ 357 | "array([ 0.10690133, 2.24709978, 0.01231683])" 358 | ] 359 | }, 360 | "execution_count": 33, 361 | "metadata": {}, 362 | "output_type": "execute_result" 363 | } 364 | ], 365 | "source": [ 366 | "alpha_disp(glm_results, lambda x:x**2)" 367 | ] 368 | }, 369 | { 370 | "cell_type": "code", 371 | "execution_count": 10, 372 | "metadata": { 373 | "collapsed": false 374 | }, 375 | "outputs": [ 376 | { 377 | "name": "stdout", 378 | "output_type": "stream", 379 | "text": [ 380 | "\n", 381 | "\n", 382 | "\n" 383 | ] 384 | } 385 | ], 386 | "source": [ 387 | "model1 = GLM(y, X, constant=False, family=Poisson()).fit()" 388 | ] 389 | }, 390 | { 391 | "cell_type": "code", 392 | "execution_count": 11, 393 | "metadata": { 394 | "collapsed": false 395 | }, 396 | "outputs": [ 397 | { 398 | "name": "stdout", 399 | "output_type": "stream", 400 | "text": [ 401 | "\n", 402 | "\n", 403 | "\n" 404 | ] 405 | } 406 | ], 407 | "source": [ 408 | "model2 = GLM(y, X, constant=False, family=QuasiPoisson()).fit()" 409 | ] 410 | }, 411 | { 412 | "cell_type": "code", 413 | "execution_count": 13, 414 | "metadata": { 415 | "collapsed": false 416 | }, 417 | "outputs": [ 418 | { 419 | "name": "stdout", 420 | "output_type": "stream", 421 | "text": [ 422 | "1.0\n", 423 | "\n", 424 | "7.02573401193\n" 425 | ] 426 | } 427 | ], 428 | "source": [ 429 | "print model1.scale\n", 430 | "print model2.scale" 431 | ] 432 | } 433 | ], 434 | "metadata": { 435 | "kernelspec": { 436 | "display_name": "Python 2", 437 | "language": "python", 438 | "name": "python2" 439 | }, 440 | "language_info": { 441 | "codemirror_mode": { 442 | "name": "ipython", 443 | "version": 2 444 | }, 445 | "file_extension": ".py", 446 | "mimetype": "text/x-python", 447 | "name": "python", 448 | "nbconvert_exporter": "python", 449 | "pygments_lexer": "ipython2", 450 | "version": "2.7.9" 451 | } 452 | }, 453 | "nbformat": 4, 454 | "nbformat_minor": 0 455 | } 456 | -------------------------------------------------------------------------------- /notebooks/glm_speed.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "ExecuteTime": { 8 | "end_time": "2019-01-05T17:49:08.791636Z", 9 | "start_time": "2019-01-05T17:49:07.648966Z" 10 | } 11 | }, 12 | "outputs": [], 13 | "source": [ 14 | "import numpy as np\n", 15 | "import pandas as pd\n", 16 | "from spint.gravity import Gravity, Production, Attraction, Doubly, BaseGravity\n", 17 | "#from entropy import Unconstrained, ProductionConstrained, AttractionConstrained, DoublyConstrained\n", 18 | "import statsmodels.formula.api as smf\n", 19 | "from statsmodels.api import families\n", 20 | "import matplotlib.pyplot as plt\n", 21 | "%pylab inline\n", 22 | "\n", 23 | "import time \n", 24 | "\n", 25 | "def timeit(method):\n", 26 | "\n", 27 | " def timed(*args, **kw):\n", 28 | " ts = time.time()\n", 29 | " result = method(*args, **kw)\n", 30 | " te = time.time()\n", 31 | " elapsed = te-ts\n", 32 | " \n", 33 | " return result, elapsed\n", 34 | "\n", 35 | " return timed" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": null, 41 | "metadata": { 42 | "ExecuteTime": { 43 | "end_time": "2019-01-05T17:49:11.621267Z", 44 | "start_time": "2019-01-05T17:49:11.612565Z" 45 | } 46 | }, 47 | "outputs": [], 48 | "source": [ 49 | "@timeit\n", 50 | "def gravity(f ,o, d, o_vars, d_vars, dij, cost='exp', framework='glm'):\n", 51 | " results = Gravity(f, o_vars, d_vars, dij, cost, framework=framework)\n", 52 | " return results\n", 53 | " \n", 54 | "@timeit \n", 55 | "def production(f ,o, d, o_vars, d_vars, dij, cost='exp', framework='glm'):\n", 56 | " results = Production(f, o, d_vars, dij, 'exp', framework=framework)\n", 57 | " return results\n", 58 | "\n", 59 | "@timeit \n", 60 | "def attraction(f ,o, d, o_vars, d_vars, dij, cost='exp', framework='glm'):\n", 61 | " results = Attraction(f, d, o_vars, dij, 'exp', framework=framework)\n", 62 | " return results\n", 63 | "\n", 64 | "@timeit \n", 65 | "def doubly(f ,o, d, o_vars, d_vars, dij, cost='exp', framework='glm'):\n", 66 | " results = Doubly(f, o, d, dij, 'exp', framework=framework)\n", 67 | " return results\n", 68 | "\n" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": null, 74 | "metadata": { 75 | "ExecuteTime": { 76 | "end_time": "2019-01-05T17:49:13.051717Z", 77 | "start_time": "2019-01-05T17:49:13.043400Z" 78 | } 79 | }, 80 | "outputs": [], 81 | "source": [ 82 | "def sim_data(n):\n", 83 | " o = np.tile(np.arange(n),n)\n", 84 | " d = np.repeat(np.arange(n),n)\n", 85 | " loc_size = np.random.randint(25000,500000, n)\n", 86 | " o_vars = np.tile(loc_size, n)\n", 87 | " d_vars = np.repeat(loc_size, n)\n", 88 | " dij = np.random.exponential(2500, n**2)\n", 89 | " f = o_vars**.3*d_vars**.4*np.exp(dij*-.00005)\n", 90 | " o = np.reshape(o, (-1,1))\n", 91 | " d = np.reshape(d, (-1,1))\n", 92 | " o_vars = np.reshape(o_vars, (-1,1))\n", 93 | " d_vars = np.reshape(d_vars, (-1,1))\n", 94 | " dij = np.reshape(dij, (-1,1))\n", 95 | " f = np.reshape(f, (-1,1))\n", 96 | " f = f.astype(np.int64)\n", 97 | " return f, o, d, o_vars, d_vars, dij\n" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "metadata": { 104 | "ExecuteTime": { 105 | "end_time": "2019-01-05T17:49:28.057547Z", 106 | "start_time": "2019-01-05T17:49:28.052351Z" 107 | } 108 | }, 109 | "outputs": [], 110 | "source": [ 111 | "def loop(func, start, stop, step, framework='glm'):\n", 112 | " results = []\n", 113 | " for n in np.arange(start, stop, step):\n", 114 | " f, o, d, o_vars, d_vars, dij = sim_data(n)\n", 115 | " out, elapsed = func(f, o, d, o_vars, d_vars, dij, 'exp', framework=framework)\n", 116 | " print(out.params[-2:])\n", 117 | " results.append(elapsed)\n", 118 | " return results" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": { 125 | "ExecuteTime": { 126 | "end_time": "2019-01-05T17:49:33.184949Z", 127 | "start_time": "2019-01-05T17:49:30.182637Z" 128 | } 129 | }, 130 | "outputs": [], 131 | "source": [ 132 | "glm_grav = loop(gravity, 50, 250, 50)\n", 133 | "glm_prod = loop(production, 50, 250, 50)\n", 134 | "glm_att = loop(attraction, 50, 250, 50)\n", 135 | "glm_doub = loop(doubly, 50, 250, 50)" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "metadata": { 142 | "ExecuteTime": { 143 | "end_time": "2019-01-05T17:49:36.298895Z", 144 | "start_time": "2019-01-05T17:49:36.193100Z" 145 | } 146 | }, 147 | "outputs": [], 148 | "source": [ 149 | "smglm_grav = loop(gravity, 50, 250, 50, framework='sm_glm')\n", 150 | "smglm_prod = loop(production, 50, 250, 50, framework='sm_glm')\n", 151 | "smglm_att = loop(attraction, 50, 250, 50, framework='sm_glm')\n", 152 | "smglm_doub = loop(doubly, 50, 250, 50, framework='sm_glm')" 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": null, 158 | "metadata": { 159 | "ExecuteTime": { 160 | "end_time": "2019-01-05T17:49:51.262028Z", 161 | "start_time": "2019-01-05T17:49:51.258592Z" 162 | } 163 | }, 164 | "outputs": [], 165 | "source": [ 166 | "x = np.arange(50, 250, 50)" 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": null, 172 | "metadata": { 173 | "ExecuteTime": { 174 | "end_time": "2019-01-05T17:49:51.934219Z", 175 | "start_time": "2019-01-05T17:49:51.642595Z" 176 | }, 177 | "scrolled": true 178 | }, 179 | "outputs": [], 180 | "source": [ 181 | "plt.plot(x, glm_grav, x, glm_prod, x, glm_att, x, glm_doub)\n", 182 | "plt.legend(('unconstrained', 'production', 'attraction', 'doubly'))\n", 183 | "plt.title('Custom GLM Framework')\n", 184 | "plt.xlabel('Sample Size')\n", 185 | "plt.ylabel('Seconds')" 186 | ] 187 | }, 188 | { 189 | "cell_type": "code", 190 | "execution_count": null, 191 | "metadata": { 192 | "ExecuteTime": { 193 | "end_time": "2019-01-05T17:49:53.767784Z", 194 | "start_time": "2019-01-05T17:49:53.751473Z" 195 | } 196 | }, 197 | "outputs": [], 198 | "source": [ 199 | "plt.plot(x, smglm_grav, x, smglm_prod, x, smglm_att, x, smglm_doub)\n", 200 | "plt.legend(('unconstrained', 'production', 'attraction', 'doubly'))\n", 201 | "plt.legend(('unconstrained', 'production', 'attraction', 'doubly'))\n", 202 | "plt.title('Statsmodels GLM Framework')\n", 203 | "plt.xlabel('Sample Size')\n", 204 | "plt.ylabel('Seconds')" 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": null, 210 | "metadata": {}, 211 | "outputs": [], 212 | "source": [] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": null, 217 | "metadata": { 218 | "ExecuteTime": { 219 | "end_time": "2019-01-05T17:50:02.265965Z", 220 | "start_time": "2019-01-05T17:50:02.181539Z" 221 | } 222 | }, 223 | "outputs": [], 224 | "source": [ 225 | "f, o, d, o_vars, d_vars, dij = sim_data(100)\n", 226 | "test = Production(f, o, d_vars, dij, 'exp')" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": null, 232 | "metadata": { 233 | "ExecuteTime": { 234 | "end_time": "2019-01-05T17:50:03.122726Z", 235 | "start_time": "2019-01-05T17:50:03.117604Z" 236 | } 237 | }, 238 | "outputs": [], 239 | "source": [ 240 | "test." 241 | ] 242 | } 243 | ], 244 | "metadata": { 245 | "kernelspec": { 246 | "display_name": "Python [conda env:py3_spgh_dev]", 247 | "language": "python", 248 | "name": "conda-env-py3_spgh_dev-py" 249 | }, 250 | "language_info": { 251 | "codemirror_mode": { 252 | "name": "ipython", 253 | "version": 3 254 | }, 255 | "file_extension": ".py", 256 | "mimetype": "text/x-python", 257 | "name": "python", 258 | "nbconvert_exporter": "python", 259 | "pygments_lexer": "ipython3", 260 | "version": "3.6.6" 261 | } 262 | }, 263 | "nbformat": 4, 264 | "nbformat_minor": 1 265 | } 266 | -------------------------------------------------------------------------------- /notebooks/local_SI.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [ 10 | { 11 | "name": "stdout", 12 | "output_type": "stream", 13 | "text": [ 14 | "Populating the interactive namespace from numpy and matplotlib\n" 15 | ] 16 | } 17 | ], 18 | "source": [ 19 | "import numpy as np\n", 20 | "import pandas as pd\n", 21 | "import os\n", 22 | "os.chdir('../')\n", 23 | "from gravity import Gravity, Production, Attraction, Doubly, BaseGravity\n", 24 | "import statsmodels.formula.api as smf\n", 25 | "from statsmodels.api import families\n", 26 | "import matplotlib.pyplot as plt\n", 27 | "%pylab inline" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 2, 33 | "metadata": { 34 | "collapsed": true 35 | }, 36 | "outputs": [], 37 | "source": [ 38 | "austria = pd.read_csv('http://dl.dropbox.com/u/8649795/AT_Austria.csv')\n", 39 | "austria = austria[austria['Origin'] != austria['Destination']]\n", 40 | "f = austria['Data'].values\n", 41 | "o = austria['Origin'].values\n", 42 | "d = austria['Destination'].values\n", 43 | "dij = austria['Dij'].values\n", 44 | "o_vars = austria['Oi2007'].values\n", 45 | "d_vars = austria['Dj2007'].values" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": 37, 51 | "metadata": { 52 | "collapsed": false 53 | }, 54 | "outputs": [ 55 | { 56 | "name": "stdout", 57 | "output_type": "stream", 58 | "text": [ 59 | "-0.00976746026969\n" 60 | ] 61 | } 62 | ], 63 | "source": [ 64 | "model = Gravity(f, o_vars, d_vars, dij, 'exp')\n", 65 | "print model.params[-1]" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": 39, 71 | "metadata": { 72 | "collapsed": false 73 | }, 74 | "outputs": [ 75 | { 76 | "data": { 77 | "text/plain": [ 78 | "[-0.01699776161094757,\n", 79 | " -0.0053210259160796358,\n", 80 | " -0.0028594272276957211,\n", 81 | " -0.006533037784217155,\n", 82 | " -0.0024666647861060209,\n", 83 | " -0.0058258251130860472,\n", 84 | " -0.010739622617965516,\n", 85 | " -0.0046867791898773659,\n", 86 | " -0.0065940756391066335]" 87 | ] 88 | }, 89 | "execution_count": 39, 90 | "metadata": {}, 91 | "output_type": "execute_result" 92 | } 93 | ], 94 | "source": [ 95 | "local = model.local(loc_index=o, locs=np.unique(o))\n", 96 | "local['param2']" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 41, 102 | "metadata": { 103 | "collapsed": false 104 | }, 105 | "outputs": [ 106 | { 107 | "name": "stdout", 108 | "output_type": "stream", 109 | "text": [ 110 | "-0.00727113391179\n" 111 | ] 112 | } 113 | ], 114 | "source": [ 115 | "model = Production(f, o, d_vars, dij, 'exp')\n", 116 | "print model.params[-1]" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 42, 122 | "metadata": { 123 | "collapsed": false 124 | }, 125 | "outputs": [ 126 | { 127 | "data": { 128 | "text/plain": [ 129 | "[-0.016997761610949791,\n", 130 | " -0.005321025916080413,\n", 131 | " -0.0028594272276953325,\n", 132 | " -0.0065330377842177101,\n", 133 | " -0.0024666647861060209,\n", 134 | " -0.0058258251130863803,\n", 135 | " -0.010739622617965183,\n", 136 | " -0.0046867791898770328,\n", 137 | " -0.0065940756391070776]" 138 | ] 139 | }, 140 | "execution_count": 42, 141 | "metadata": {}, 142 | "output_type": "execute_result" 143 | } 144 | ], 145 | "source": [ 146 | "local = model.local()\n", 147 | "local['param2']" 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": 43, 153 | "metadata": { 154 | "collapsed": false 155 | }, 156 | "outputs": [ 157 | { 158 | "name": "stdout", 159 | "output_type": "stream", 160 | "text": [ 161 | "-0.00693754909526\n" 162 | ] 163 | } 164 | ], 165 | "source": [ 166 | "model = Attraction(f, d, o_vars, dij, 'exp')\n", 167 | "print model.params[-1]" 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": 44, 173 | "metadata": { 174 | "collapsed": false 175 | }, 176 | "outputs": [ 177 | { 178 | "data": { 179 | "text/plain": [ 180 | "[-0.010872636479707154,\n", 181 | " -0.0054690202130680543,\n", 182 | " -0.0025567421332022833,\n", 183 | " -0.0051439340488994012,\n", 184 | " -0.0036020461535491433,\n", 185 | " -0.010088935906795271,\n", 186 | " -0.012926843651020203,\n", 187 | " -0.0075750287063747201,\n", 188 | " -0.0081576735088411123]" 189 | ] 190 | }, 191 | "execution_count": 44, 192 | "metadata": {}, 193 | "output_type": "execute_result" 194 | } 195 | ], 196 | "source": [ 197 | "local = model.local()\n", 198 | "local['param2']" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": null, 204 | "metadata": { 205 | "collapsed": true 206 | }, 207 | "outputs": [], 208 | "source": [] 209 | } 210 | ], 211 | "metadata": { 212 | "kernelspec": { 213 | "display_name": "Python 2", 214 | "language": "python", 215 | "name": "python2" 216 | }, 217 | "language_info": { 218 | "codemirror_mode": { 219 | "name": "ipython", 220 | "version": 2 221 | }, 222 | "file_extension": ".py", 223 | "mimetype": "text/x-python", 224 | "name": "python", 225 | "nbconvert_exporter": "python", 226 | "pygments_lexer": "ipython2", 227 | "version": "2.7.9" 228 | } 229 | }, 230 | "nbformat": 4, 231 | "nbformat_minor": 0 232 | } 233 | -------------------------------------------------------------------------------- /notebooks/netW.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import numpy as np\n", 12 | "import os\n", 13 | "os.chdir('/Users/toshan/dev/pysal/pysal/weights')\n", 14 | "from spintW import netW, mat2L" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "metadata": { 21 | "collapsed": true 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "link_list = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'a'), ('b', 'c'), ('b', 'd'), ('c', 'a'), ('c', 'b'), ('c', 'd'), ('d', 'a'), ('d', 'b'), ('d', 'c')]" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 3, 31 | "metadata": { 32 | "collapsed": false 33 | }, 34 | "outputs": [ 35 | { 36 | "data": { 37 | "text/plain": [ 38 | "array([[ 0., 1., 1., 1., 1., 1., 1., 1., 0., 1., 1., 0.],\n", 39 | " [ 1., 0., 1., 1., 1., 0., 1., 1., 1., 1., 0., 1.],\n", 40 | " [ 1., 1., 0., 1., 0., 1., 1., 0., 1., 1., 1., 1.],\n", 41 | " [ 1., 1., 1., 0., 1., 1., 1., 1., 0., 1., 1., 0.],\n", 42 | " [ 1., 1., 0., 1., 0., 1., 1., 1., 1., 0., 1., 1.],\n", 43 | " [ 1., 0., 1., 1., 1., 0., 0., 1., 1., 1., 1., 1.],\n", 44 | " [ 1., 1., 1., 1., 1., 0., 0., 1., 1., 1., 0., 1.],\n", 45 | " [ 1., 1., 0., 1., 1., 1., 1., 0., 1., 0., 1., 1.],\n", 46 | " [ 0., 1., 1., 0., 1., 1., 1., 1., 0., 1., 1., 1.],\n", 47 | " [ 1., 1., 1., 1., 0., 1., 1., 0., 1., 0., 1., 1.],\n", 48 | " [ 1., 0., 1., 1., 1., 1., 0., 1., 1., 1., 0., 1.],\n", 49 | " [ 0., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1., 0.]])" 50 | ] 51 | }, 52 | "execution_count": 3, 53 | "metadata": {}, 54 | "output_type": "execute_result" 55 | } 56 | ], 57 | "source": [ 58 | "w = netW(link_list)\n", 59 | "w.full()[0]" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 4, 65 | "metadata": { 66 | "collapsed": false 67 | }, 68 | "outputs": [ 69 | { 70 | "data": { 71 | "text/plain": [ 72 | "array([[ 0., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", 73 | " [ 1., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", 74 | " [ 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", 75 | " [ 0., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0.],\n", 76 | " [ 0., 0., 0., 1., 0., 1., 0., 0., 0., 0., 0., 0.],\n", 77 | " [ 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 0.],\n", 78 | " [ 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0.],\n", 79 | " [ 0., 0., 0., 0., 0., 0., 1., 0., 1., 0., 0., 0.],\n", 80 | " [ 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0.],\n", 81 | " [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1.],\n", 82 | " [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 1.],\n", 83 | " [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0.]])" 84 | ] 85 | }, 86 | "execution_count": 4, 87 | "metadata": {}, 88 | "output_type": "execute_result" 89 | } 90 | ], 91 | "source": [ 92 | "w = netW(link_list, share='O')\n", 93 | "w.full()[0]" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 5, 99 | "metadata": { 100 | "collapsed": false 101 | }, 102 | "outputs": [ 103 | { 104 | "data": { 105 | "text/plain": [ 106 | "array([[ 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 1., 0.],\n", 107 | " [ 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 1.],\n", 108 | " [ 0., 0., 0., 0., 0., 1., 0., 0., 1., 0., 0., 0.],\n", 109 | " [ 0., 0., 0., 0., 0., 0., 1., 0., 0., 1., 0., 0.],\n", 110 | " [ 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],\n", 111 | " [ 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0.],\n", 112 | " [ 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., 0.],\n", 113 | " [ 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],\n", 114 | " [ 0., 0., 1., 0., 0., 1., 0., 0., 0., 0., 0., 0.],\n", 115 | " [ 0., 0., 0., 1., 0., 0., 1., 0., 0., 0., 0., 0.],\n", 116 | " [ 1., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],\n", 117 | " [ 0., 1., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.]])" 118 | ] 119 | }, 120 | "execution_count": 5, 121 | "metadata": {}, 122 | "output_type": "execute_result" 123 | } 124 | ], 125 | "source": [ 126 | "w = netW(link_list, share='D')\n", 127 | "w.full()[0]" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": 6, 133 | "metadata": { 134 | "collapsed": false 135 | }, 136 | "outputs": [ 137 | { 138 | "data": { 139 | "text/plain": [ 140 | "array([[ 0., 1., 1., 0., 0., 0., 0., 1., 0., 0., 1., 0.],\n", 141 | " [ 1., 0., 1., 0., 1., 0., 0., 0., 0., 0., 0., 1.],\n", 142 | " [ 1., 1., 0., 0., 0., 1., 0., 0., 1., 0., 0., 0.],\n", 143 | " [ 0., 0., 0., 0., 1., 1., 1., 0., 0., 1., 0., 0.],\n", 144 | " [ 0., 1., 0., 1., 0., 1., 0., 0., 0., 0., 0., 1.],\n", 145 | " [ 0., 0., 1., 1., 1., 0., 0., 0., 1., 0., 0., 0.],\n", 146 | " [ 0., 0., 0., 1., 0., 0., 0., 1., 1., 1., 0., 0.],\n", 147 | " [ 1., 0., 0., 0., 0., 0., 1., 0., 1., 0., 1., 0.],\n", 148 | " [ 0., 0., 1., 0., 0., 1., 1., 1., 0., 0., 0., 0.],\n", 149 | " [ 0., 0., 0., 1., 0., 0., 1., 0., 0., 0., 1., 1.],\n", 150 | " [ 1., 0., 0., 0., 0., 0., 0., 1., 0., 1., 0., 1.],\n", 151 | " [ 0., 1., 0., 0., 1., 0., 0., 0., 0., 1., 1., 0.]])" 152 | ] 153 | }, 154 | "execution_count": 6, 155 | "metadata": {}, 156 | "output_type": "execute_result" 157 | } 158 | ], 159 | "source": [ 160 | "w = netW(link_list, share='OD')\n", 161 | "w.full()[0]" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 7, 167 | "metadata": { 168 | "collapsed": false 169 | }, 170 | "outputs": [ 171 | { 172 | "data": { 173 | "text/plain": [ 174 | "array([[ 0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0.],\n", 175 | " [ 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0.],\n", 176 | " [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1.],\n", 177 | " [ 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", 178 | " [ 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0.],\n", 179 | " [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1.],\n", 180 | " [ 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", 181 | " [ 0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0.],\n", 182 | " [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1.],\n", 183 | " [ 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", 184 | " [ 0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0.],\n", 185 | " [ 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0.]])" 186 | ] 187 | }, 188 | "execution_count": 7, 189 | "metadata": {}, 190 | "output_type": "execute_result" 191 | } 192 | ], 193 | "source": [ 194 | "w = netW(link_list, share='C')\n", 195 | "w.full()[0]" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 8, 201 | "metadata": { 202 | "collapsed": false 203 | }, 204 | "outputs": [ 205 | { 206 | "data": { 207 | "text/plain": [ 208 | "array([[0, 1, 1],\n", 209 | " [1, 0, 1],\n", 210 | " [1, 1, 0]])" 211 | ] 212 | }, 213 | "execution_count": 8, 214 | "metadata": {}, 215 | "output_type": "execute_result" 216 | } 217 | ], 218 | "source": [ 219 | "mat = np.array([[0,1,1],[1,0,1],[1,1,0]])\n", 220 | "mat" 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": 11, 226 | "metadata": { 227 | "collapsed": false 228 | }, 229 | "outputs": [ 230 | { 231 | "data": { 232 | "text/plain": [ 233 | "[(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]" 234 | ] 235 | }, 236 | "execution_count": 11, 237 | "metadata": {}, 238 | "output_type": "execute_result" 239 | } 240 | ], 241 | "source": [ 242 | "adjL = mat2L(mat)\n", 243 | "adjL" 244 | ] 245 | }, 246 | { 247 | "cell_type": "code", 248 | "execution_count": 10, 249 | "metadata": { 250 | "collapsed": false 251 | }, 252 | "outputs": [ 253 | { 254 | "data": { 255 | "text/plain": [ 256 | "array([[ 0., 0., 1., 1., 0., 0.],\n", 257 | " [ 0., 0., 0., 0., 1., 1.],\n", 258 | " [ 1., 1., 0., 0., 0., 0.],\n", 259 | " [ 0., 0., 0., 0., 1., 1.],\n", 260 | " [ 1., 1., 0., 0., 0., 0.],\n", 261 | " [ 0., 0., 1., 1., 0., 0.]])" 262 | ] 263 | }, 264 | "execution_count": 10, 265 | "metadata": {}, 266 | "output_type": "execute_result" 267 | } 268 | ], 269 | "source": [ 270 | "w = netW(adjL, share='C')\n", 271 | "w.full()[0]" 272 | ] 273 | }, 274 | { 275 | "cell_type": "code", 276 | "execution_count": null, 277 | "metadata": { 278 | "collapsed": true 279 | }, 280 | "outputs": [], 281 | "source": [] 282 | } 283 | ], 284 | "metadata": { 285 | "kernelspec": { 286 | "display_name": "Python 2", 287 | "language": "python", 288 | "name": "python2" 289 | }, 290 | "language_info": { 291 | "codemirror_mode": { 292 | "name": "ipython", 293 | "version": 2 294 | }, 295 | "file_extension": ".py", 296 | "mimetype": "text/x-python", 297 | "name": "python", 298 | "nbconvert_exporter": "python", 299 | "pygments_lexer": "ipython2", 300 | "version": "2.7.9" 301 | } 302 | }, 303 | "nbformat": 4, 304 | "nbformat_minor": 0 305 | } 306 | -------------------------------------------------------------------------------- /notebooks/sparse_categorical.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import numpy as np\n", 12 | "from scipy import sparse as sp\n", 13 | "from statsmodels.tools.tools import categorical\n", 14 | "from datetime import datetime as dt\n" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "metadata": { 21 | "collapsed": true 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "def spcategorical(data):\n", 26 | " '''\n", 27 | " Returns a dummy matrix given an array of categorical variables.\n", 28 | " Parameters\n", 29 | " ----------\n", 30 | " data : array\n", 31 | " A 1d vector of the categorical variable.\n", 32 | "\n", 33 | " Returns\n", 34 | " --------\n", 35 | " dummy_matrix\n", 36 | " A sparse matrix of dummy (indicator/binary) float variables for the\n", 37 | " categorical data. \n", 38 | "\n", 39 | " '''\n", 40 | " if np.squeeze(data).ndim == 1:\n", 41 | " tmp_arr = np.unique(data)\n", 42 | " tmp_dummy = sp.csr_matrix((0, len(data)))\n", 43 | " for each in tmp_arr[:, None]:\n", 44 | " row = sp.csr_matrix((each == data).astype(float))\n", 45 | " tmp_dummy = sp.vstack([tmp_dummy, row])\n", 46 | " tmp_dummy = tmp_dummy.T\n", 47 | " return tmp_dummy\n", 48 | " else:\n", 49 | " raise IndexError(\"The index %s is not understood\" % col)\n" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 3, 55 | "metadata": { 56 | "collapsed": false 57 | }, 58 | "outputs": [ 59 | { 60 | "data": { 61 | "text/plain": [ 62 | "True" 63 | ] 64 | }, 65 | "execution_count": 3, 66 | "metadata": {}, 67 | "output_type": "execute_result" 68 | } 69 | ], 70 | "source": [ 71 | "data = np.random.randint(1,100, 10000)\n", 72 | "np.allclose(spcategorical(np.array(data)).toarray(), categorical(np.array(data), drop=True))" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 4, 78 | "metadata": { 79 | "collapsed": false 80 | }, 81 | "outputs": [ 82 | { 83 | "ename": "KeyboardInterrupt", 84 | "evalue": "", 85 | "output_type": "error", 86 | "traceback": [ 87 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 88 | "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", 89 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m3000\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mo\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mo_dums\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mspcategorical\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mo\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0mn\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m3000\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0md\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrepeat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 90 | "\u001b[0;32m\u001b[0m in \u001b[0;36mspcategorical\u001b[0;34m(data)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0mtmp_dummy\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcsr_matrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0meach\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtmp_arr\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mNone\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0mrow\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcsr_matrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0meach\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mastype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfloat\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 21\u001b[0m \u001b[0mtmp_dummy\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvstack\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mtmp_dummy\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrow\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0mtmp_dummy\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtmp_dummy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mT\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 91 | "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scipy/sparse/compressed.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, arg1, shape, dtype, copy)\u001b[0m\n\u001b[1;32m 67\u001b[0m self.format)\n\u001b[1;32m 68\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m\u001b[0mcoo\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mcoo_matrix\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 69\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_set_self\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__class__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcoo_matrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0marg1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdtype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 70\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 71\u001b[0m \u001b[0;31m# Read matrix dimensions given, if any\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 92 | "\u001b[0;32m/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scipy/sparse/coo.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, arg1, shape, dtype, copy)\u001b[0m\n\u001b[1;32m 197\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mM\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 198\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 199\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrow\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcol\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mM\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnonzero\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 200\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mM\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrow\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcol\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 201\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhas_canonical_format\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 93 | "\u001b[0;31mKeyboardInterrupt\u001b[0m: " 94 | ] 95 | } 96 | ], 97 | "source": [ 98 | "s = dt.now()\n", 99 | "n = 3000\n", 100 | "o = np.tile(np.arange(n),n)\n", 101 | "o_dums = spcategorical(np.array(o))\n", 102 | "n = 3000\n", 103 | "d = np.repeat(np.arange(n),n)\n", 104 | "d_dums = spcategorical(np.array(d))\n", 105 | "sp.hstack((o_dums, d_dums))\n", 106 | "e = dt.now()\n", 107 | "print e-s" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 59, 113 | "metadata": { 114 | "collapsed": false 115 | }, 116 | "outputs": [ 117 | { 118 | "data": { 119 | "text/plain": [ 120 | "<9000000x6000 sparse matrix of type ''\n", 121 | "\twith 18000000 stored elements in Compressed Sparse Column format>" 122 | ] 123 | }, 124 | "execution_count": 59, 125 | "metadata": {}, 126 | "output_type": "execute_result" 127 | } 128 | ], 129 | "source": [ 130 | "all_dums = sp.hstack((o_dums, d_dums))\n", 131 | "all_dums" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 7, 137 | "metadata": { 138 | "collapsed": false 139 | }, 140 | "outputs": [ 141 | { 142 | "name": "stdout", 143 | "output_type": "stream", 144 | "text": [ 145 | "(10000, 99)\n" 146 | ] 147 | } 148 | ], 149 | "source": [ 150 | "print spcategorical(np.array(data)).toarray().shape" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": null, 156 | "metadata": { 157 | "collapsed": true 158 | }, 159 | "outputs": [], 160 | "source": [] 161 | } 162 | ], 163 | "metadata": { 164 | "kernelspec": { 165 | "display_name": "Python 2", 166 | "language": "python", 167 | "name": "python2" 168 | }, 169 | "language_info": { 170 | "codemirror_mode": { 171 | "name": "ipython", 172 | "version": 2 173 | }, 174 | "file_extension": ".py", 175 | "mimetype": "text/x-python", 176 | "name": "python", 177 | "nbconvert_exporter": "python", 178 | "pygments_lexer": "ipython2", 179 | "version": "2.7.9" 180 | } 181 | }, 182 | "nbformat": 4, 183 | "nbformat_minor": 0 184 | } 185 | -------------------------------------------------------------------------------- /notebooks/sparse_categorical_bottleneck.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "from scipy import sparse as sp\n", 12 | "import numpy as np\n", 13 | "\n", 14 | "def spcategorical(n_cat_ids):\n", 15 | " '''\n", 16 | " Returns a dummy matrix given an array of categorical variables.\n", 17 | " Parameters\n", 18 | " ----------\n", 19 | " n_cat_ids : array\n", 20 | " A 1d vector of the categorical labels for n observations.\n", 21 | "\n", 22 | " Returns\n", 23 | " --------\n", 24 | " dummy : array\n", 25 | " A sparse matrix of dummy (indicator/binary) variables for the\n", 26 | " categorical data. \n", 27 | "\n", 28 | " '''\n", 29 | " if np.squeeze(n_cat_ids).ndim == 1:\n", 30 | " cat_set = np.unique(n_cat_ids)\n", 31 | " n = len(n_cat_ids)\n", 32 | " index = [np.where(cat_set == id)[0].tolist()[0] for id in n_cat_ids] #This list comprehension is likely \n", 33 | " print index #the most intense part of the algorithm\n", 34 | " indptr = np.arange(n+1, dtype=int) \n", 35 | " return sp.csr_matrix((np.ones(n), index, indptr))\n", 36 | " else:\n", 37 | " raise IndexError(\"The index %s is not understood\" % col)\n", 38 | "\n", 39 | "#If the variable, n_cat_ids, is already composed of integers and the integers are the n x 1 vector of\n", 40 | "#origins or destinations in OD pairs for which w ewant to build fixed effects then there is no need to \n", 41 | "#create the index variable, which probably takes the most time within this function. Instead n_cat_ids can\n", 42 | "#passed directly to the csr matrix constructor and some speed-ups can be achieved. In the case where the\n", 43 | "#origin/destination ids are not integers but are strings a speed-up may be possible by alterign the algorithm\n", 44 | "#so that the index is build in chunks (say each origin/destination) rather than for each row of of the n x 1\n", 45 | "#n_cat_ids array as is done in creating the index variable." 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": { 52 | "collapsed": true 53 | }, 54 | "outputs": [], 55 | "source": [] 56 | } 57 | ], 58 | "metadata": { 59 | "kernelspec": { 60 | "display_name": "Python 2", 61 | "language": "python", 62 | "name": "python2" 63 | }, 64 | "language_info": { 65 | "codemirror_mode": { 66 | "name": "ipython", 67 | "version": 2 68 | }, 69 | "file_extension": ".py", 70 | "mimetype": "text/x-python", 71 | "name": "python", 72 | "nbconvert_exporter": "python", 73 | "pygments_lexer": "ipython2", 74 | "version": "2.7.9" 75 | } 76 | }, 77 | "nbformat": 4, 78 | "nbformat_minor": 0 79 | } 80 | -------------------------------------------------------------------------------- /notebooks/sparse_scipy_optim.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 114, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import pandas as pd\n", 12 | "import scipy.optimize as sc\n", 13 | "import scipy.sparse as sp" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 115, 19 | "metadata": { 20 | "collapsed": true 21 | }, 22 | "outputs": [], 23 | "source": [ 24 | "data = np.random.poisson(100, (10000,1))" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 116, 30 | "metadata": { 31 | "collapsed": true 32 | }, 33 | "outputs": [], 34 | "source": [ 35 | "data = sp.csr_matrix(data)" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 117, 41 | "metadata": { 42 | "collapsed": false 43 | }, 44 | "outputs": [ 45 | { 46 | "name": "stdout", 47 | "output_type": "stream", 48 | "text": [ 49 | "[ 0.]\n", 50 | "[ 0.00025]\n", 51 | "[ 0.0005]\n", 52 | "[ 0.00075]\n", 53 | "[ 0.00125]\n", 54 | "[ 0.00175]\n", 55 | "[ 0.00275]\n", 56 | "[ 0.00375]\n", 57 | "[ 0.00575]\n", 58 | "[ 0.00775]\n", 59 | "[ 0.01175]\n", 60 | "[ 0.01575]\n", 61 | "[ 0.02375]\n", 62 | "[ 0.03175]\n", 63 | "[ 0.04775]\n", 64 | "[ 0.06375]\n", 65 | "[ 0.09575]\n", 66 | "[ 0.12775]\n", 67 | "[ 0.19175]\n", 68 | "[ 0.25575]\n", 69 | "[ 0.38375]\n", 70 | "[ 0.51175]\n", 71 | "[ 0.76775]\n", 72 | "[ 1.02375]\n", 73 | "[ 1.53575]\n", 74 | "[ 2.04775]\n", 75 | "[ 3.07175]\n", 76 | "[ 4.09575]\n", 77 | "[ 6.14375]\n", 78 | "[ 8.19175]\n", 79 | "[ 12.28775]\n", 80 | "[ 16.38375]\n", 81 | "[ 24.57575]\n", 82 | "[ 32.76775]\n", 83 | "[ 49.15175]\n", 84 | "[ 65.53575]\n", 85 | "[ 98.30375]\n", 86 | "[ 131.07175]\n", 87 | "[ 131.07175]\n", 88 | "[ 114.68775]\n", 89 | "[ 81.91975]\n", 90 | "[ 106.49575]\n", 91 | "[ 90.11175]\n", 92 | "[ 102.39975]\n", 93 | "[ 94.20775]\n", 94 | "[ 100.35175]\n", 95 | "[ 102.39975]\n", 96 | "[ 99.32775]\n", 97 | "[ 98.30375]\n", 98 | "[ 99.83975]\n", 99 | "[ 100.35175]\n", 100 | "[ 99.58375]\n", 101 | "[ 100.09575]\n", 102 | "[ 99.71175]\n", 103 | "[ 99.58375]\n", 104 | "[ 99.77575]\n", 105 | "[ 99.83975]\n", 106 | "[ 99.74375]\n", 107 | "[ 99.80775]\n", 108 | "[ 99.75975]\n", 109 | "[ 99.74375]\n", 110 | "[ 99.76775]\n", 111 | "[ 99.77575]\n", 112 | "[ 99.76375]\n", 113 | "[ 99.77175]\n", 114 | "[ 99.76575]\n", 115 | "[ 99.76975]\n", 116 | "[ 99.76675]\n", 117 | "[ 99.76875]\n", 118 | "[ 99.76725]\n", 119 | "[ 99.76825]\n", 120 | "[ 99.7675]\n", 121 | "[ 99.76725]\n", 122 | "[ 99.767625]\n", 123 | "[ 99.76775]\n", 124 | "[ 99.7675625]\n", 125 | "Optimization terminated successfully.\n", 126 | " Current function value: -3594470.473058\n", 127 | " Iterations: 38\n", 128 | " Function evaluations: 76\n", 129 | "[ 99.767625]\n" 130 | ] 131 | } 132 | ], 133 | "source": [ 134 | "def poiss_loglike(x, data, a):\n", 135 | " print x\n", 136 | " return -np.sum(data*np.log(x)-x)*a\n", 137 | "\n", 138 | "\n", 139 | "params = sc.fmin(poiss_loglike, 0, args=(data ,1))\n", 140 | "print params" 141 | ] 142 | } 143 | ], 144 | "metadata": { 145 | "kernelspec": { 146 | "display_name": "Python 2", 147 | "language": "python", 148 | "name": "python2" 149 | }, 150 | "language_info": { 151 | "codemirror_mode": { 152 | "name": "ipython", 153 | "version": 2 154 | }, 155 | "file_extension": ".py", 156 | "mimetype": "text/x-python", 157 | "name": "python", 158 | "nbconvert_exporter": "python", 159 | "pygments_lexer": "ipython2", 160 | "version": "2.7.9" 161 | } 162 | }, 163 | "nbformat": 4, 164 | "nbformat_minor": 0 165 | } 166 | -------------------------------------------------------------------------------- /notebooks/test_grav.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [ 10 | { 11 | "name": "stderr", 12 | "output_type": "stream", 13 | "text": [ 14 | "//anaconda/lib/python2.7/site-packages/matplotlib/font_manager.py:273: UserWarning: Matplotlib is building the font cache using fc-list. This may take a moment.\n", 15 | " warnings.warn('Matplotlib is building the font cache using fc-list. This may take a moment.')\n" 16 | ] 17 | }, 18 | { 19 | "name": "stdout", 20 | "output_type": "stream", 21 | "text": [ 22 | "Populating the interactive namespace from numpy and matplotlib\n" 23 | ] 24 | } 25 | ], 26 | "source": [ 27 | "import numpy as np\n", 28 | "import pandas as pd\n", 29 | "import os\n", 30 | "os.chdir('../')\n", 31 | "from gravity import Gravity, Production, Attraction, Doubly, BaseGravity\n", 32 | "import statsmodels.formula.api as smf\n", 33 | "from statsmodels.api import families\n", 34 | "import matplotlib.pyplot as plt\n", 35 | "%pylab inline" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 2, 41 | "metadata": { 42 | "collapsed": false 43 | }, 44 | "outputs": [], 45 | "source": [ 46 | "\n", 47 | "n = 3000\n", 48 | "o = np.tile(np.arange(n),n)\n", 49 | "d = np.repeat(np.arange(n),n)\n", 50 | "loc_size = np.random.randint(25000,500000, n)\n", 51 | "o_vars = np.tile(loc_size, n)\n", 52 | "d_vars = np.repeat(loc_size, n)\n", 53 | "dij = np.random.exponential(2500, n**2)\n", 54 | "f = o_vars**.3*d_vars**.4*np.exp(dij*-.00005)\n", 55 | "o = np.reshape(o, (-1,1))\n", 56 | "d = np.reshape(d, (-1,1))\n", 57 | "o_vars = np.reshape(o_vars, (-1,1))\n", 58 | "d_vars = np.reshape(d_vars, (-1,1))\n", 59 | "dij = np.reshape(dij, (-1,1))\n", 60 | "f = np.reshape(f, (-1,1))\n", 61 | "f = f.astype(np.int64)" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 3, 67 | "metadata": { 68 | "collapsed": false 69 | }, 70 | "outputs": [ 71 | { 72 | "name": "stdout", 73 | "output_type": "stream", 74 | "text": [ 75 | "CPU times: user 14.3 s, sys: 1.46 s, total: 15.8 s\n", 76 | "Wall time: 7.41 s\n" 77 | ] 78 | }, 79 | { 80 | "data": { 81 | "text/plain": [ 82 | "" 83 | ] 84 | }, 85 | "execution_count": 3, 86 | "metadata": {}, 87 | "output_type": "execute_result" 88 | } 89 | ], 90 | "source": [ 91 | "%time Gravity(f, o_vars, d_vars, dij, 'exp')" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 4, 97 | "metadata": { 98 | "collapsed": false 99 | }, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | "CPU times: user 38.3 s, sys: 4 s, total: 42.3 s\n", 106 | "Wall time: 24.6 s\n" 107 | ] 108 | }, 109 | { 110 | "data": { 111 | "text/plain": [ 112 | "" 113 | ] 114 | }, 115 | "execution_count": 4, 116 | "metadata": {}, 117 | "output_type": "execute_result" 118 | } 119 | ], 120 | "source": [ 121 | "%time Production(f, o, d_vars, dij, 'exp')" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": 5, 127 | "metadata": { 128 | "collapsed": false 129 | }, 130 | "outputs": [ 131 | { 132 | "name": "stdout", 133 | "output_type": "stream", 134 | "text": [ 135 | "CPU times: user 36 s, sys: 4.25 s, total: 40.2 s\n", 136 | "Wall time: 21.4 s\n" 137 | ] 138 | }, 139 | { 140 | "data": { 141 | "text/plain": [ 142 | "" 143 | ] 144 | }, 145 | "execution_count": 5, 146 | "metadata": {}, 147 | "output_type": "execute_result" 148 | } 149 | ], 150 | "source": [ 151 | "%time Attraction(f, d, o_vars, dij, 'exp')" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 6, 157 | "metadata": { 158 | "collapsed": false 159 | }, 160 | "outputs": [ 161 | { 162 | "name": "stdout", 163 | "output_type": "stream", 164 | "text": [ 165 | "CPU times: user 1min 19s, sys: 6.3 s, total: 1min 25s\n", 166 | "Wall time: 37.4 s\n" 167 | ] 168 | }, 169 | { 170 | "data": { 171 | "text/plain": [ 172 | "" 173 | ] 174 | }, 175 | "execution_count": 6, 176 | "metadata": {}, 177 | "output_type": "execute_result" 178 | } 179 | ], 180 | "source": [ 181 | "%time Doubly(f, o, d, dij, 'exp')" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": null, 187 | "metadata": { 188 | "collapsed": true 189 | }, 190 | "outputs": [], 191 | "source": [] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": null, 196 | "metadata": { 197 | "collapsed": true 198 | }, 199 | "outputs": [], 200 | "source": [] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": 3, 205 | "metadata": { 206 | "collapsed": false 207 | }, 208 | "outputs": [], 209 | "source": [ 210 | "from glm import GLM\n", 211 | "from iwls import iwls\n", 212 | "import line_profiler\n", 213 | "import IPython\n", 214 | "ip = IPython.get_ipython()\n", 215 | "ip.define_magic('lprun', line_profiler.magic_lprun)\n", 216 | "instance = Production(f, o, d_vars, dij, 'exp')\n" 217 | ] 218 | }, 219 | { 220 | "cell_type": "code", 221 | "execution_count": 9, 222 | "metadata": { 223 | "collapsed": false 224 | }, 225 | "outputs": [ 226 | { 227 | "name": "stdout", 228 | "output_type": "stream", 229 | "text": [ 230 | "correct sparse\n" 231 | ] 232 | } 233 | ], 234 | "source": [ 235 | "%lprun -f BaseGravity.__init__ instance.__init__(f, o, d_vars, dij, 'exp')" 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": 8, 241 | "metadata": { 242 | "collapsed": true 243 | }, 244 | "outputs": [], 245 | "source": [ 246 | "glm_inst = GLM(instance.y, instance.X, family=families.Poisson())\n", 247 | "%lprun -f GLM.__init__ glm_inst.__init__(instance.y, instance.X, family=families.Poisson())" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": 7, 253 | "metadata": { 254 | "collapsed": true 255 | }, 256 | "outputs": [], 257 | "source": [ 258 | "%lprun -f iwls iwls(instance.y, instance.X, family=families.Poisson(), offset=None, y_fix=None)" 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": null, 264 | "metadata": { 265 | "collapsed": true 266 | }, 267 | "outputs": [], 268 | "source": [] 269 | } 270 | ], 271 | "metadata": { 272 | "anaconda-cloud": {}, 273 | "kernelspec": { 274 | "display_name": "Python [Root]", 275 | "language": "python", 276 | "name": "Python [Root]" 277 | }, 278 | "language_info": { 279 | "codemirror_mode": { 280 | "name": "ipython", 281 | "version": 2 282 | }, 283 | "file_extension": ".py", 284 | "mimetype": "text/x-python", 285 | "name": "python", 286 | "nbconvert_exporter": "python", 287 | "pygments_lexer": "ipython2", 288 | "version": "2.7.12" 289 | } 290 | }, 291 | "nbformat": 4, 292 | "nbformat_minor": 0 293 | } 294 | -------------------------------------------------------------------------------- /notebooks/validate_gravity.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 75, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "#import sys\n", 12 | "#sys.path.append('/Users/toshan/dev/pysal/pysal/contrib/glm')\n", 13 | "#from utils import \n", 14 | "import numpy as np\n", 15 | "import pandas as pd\n", 16 | "import sys\n", 17 | "sys.path.append('/Users/toshan/dev/pysal/pysal/contrib/spint')\n", 18 | "from gravity import Gravity, Production, Attraction, Doubly, BaseGravity\n", 19 | "import gravity\n", 20 | "from utils import sorensen\n", 21 | "import statsmodels.formula.api as smf\n", 22 | "from statsmodels.api import families as families" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 32, 28 | "metadata": { 29 | "collapsed": false 30 | }, 31 | "outputs": [], 32 | "source": [ 33 | "austria = pd.read_csv('http://dl.dropbox.com/u/8649795/AT_Austria.csv')\n", 34 | "austria = austria[austria['Origin'] != austria['Destination']]\n", 35 | "f = austria['Data'].values\n", 36 | "o = austria['Origin'].values\n", 37 | "d = austria['Destination'].values\n", 38 | "dij = austria['Dij'].values\n", 39 | "o_vars = austria['Oi2007'].values\n", 40 | "d_vars = austria['Dj2007'].values\n" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 33, 46 | "metadata": { 47 | "collapsed": false 48 | }, 49 | "outputs": [ 50 | { 51 | "name": "stdout", 52 | "output_type": "stream", 53 | "text": [ 54 | "[ -7.95447436e+00 8.63867812e-01 8.80474585e-01 -6.20544765e-03]\n", 55 | "[ -7.95447436e+00 8.63867812e-01 8.80474585e-01 -6.20544766e-03]\n" 56 | ] 57 | } 58 | ], 59 | "source": [ 60 | "grav = Gravity(f, o_vars, d_vars, dij, 'exp', framework='glm', constant=True)\n", 61 | "print grav.params\n", 62 | "\n", 63 | "gravity = smf.glm('Data~np.log(Oi2007)+np.log(Dj2007)+Dij', family=families.Poisson(), data=austria).fit()\n", 64 | "print gravity.params.values" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 35, 70 | "metadata": { 71 | "collapsed": false, 72 | "scrolled": false 73 | }, 74 | "outputs": [ 75 | { 76 | "name": "stdout", 77 | "output_type": "stream", 78 | "text": [ 79 | "[-1.11700938 1.68662317 2.15188689 0.60300297 0.88380784 1.20926104\n", 80 | " 0.68938983 1.15472804 1.02479968 0.89278717 -0.00727113]\n", 81 | "[-1.11700938 1.68662317 2.15188689 0.60300297 0.88380784 1.20926105\n", 82 | " 0.68938983 1.15472805 1.02479968 0.89278717 -0.00727113]\n" 83 | ] 84 | } 85 | ], 86 | "source": [ 87 | "production = Production(f, o, d_vars, dij, 'exp', framework='glm')\n", 88 | "print production.params\n", 89 | "\n", 90 | "gravity = smf.glm('Data~Origin+np.log(Dj2007)+Dij', family=families.Poisson(), data=austria).fit()\n", 91 | "print gravity.params.values" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 5, 97 | "metadata": { 98 | "collapsed": false 99 | }, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | "[-0.88439723 1.62180605 1.92772078 0.12462001 0.62378812 0.69646073\n", 106 | " 0.20909411 0.6856777 0.48539625 0.89235874 -0.00693755]\n", 107 | "[-0.88439723 1.62180605 1.92772078 0.12462002 0.62378812 0.69646073\n", 108 | " 0.20909411 0.6856777 0.48539625 0.89235874 -0.00693755]\n" 109 | ] 110 | } 111 | ], 112 | "source": [ 113 | "attraction = Attraction(f, d, o_vars, dij, 'exp', framework='glm', constant=True)\n", 114 | "print attraction.params\n", 115 | "\n", 116 | "gravity = smf.glm('Data~np.log(Oi2007)+Destination + Dij', family=families.Poisson(), data=austria).fit()\n", 117 | "print gravity.params.values" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 6, 123 | "metadata": { 124 | "collapsed": false, 125 | "scrolled": true 126 | }, 127 | "outputs": [ 128 | { 129 | "name": "stdout", 130 | "output_type": "stream", 131 | "text": [ 132 | "[ 6.20471518 1.5449095 2.4414292 0.69924374 0.94869185 1.28967637\n", 133 | " 0.74270015 1.19468573 0.98874193 1.49709841 2.18492741 0.18784818\n", 134 | " 0.66434515 0.74264938 0.21334535 0.66765781 0.39986094 -0.00791533]\n", 135 | "[ 6.20471518 1.5449095 2.4414292 0.69924374 0.94869185 1.28967637\n", 136 | " 0.74270016 1.19468574 0.98874192 1.49709841 2.18492741 0.18784818\n", 137 | " 0.66434515 0.74264938 0.21334535 0.66765782 0.39986087 -0.00791533]\n" 138 | ] 139 | } 140 | ], 141 | "source": [ 142 | "doubly = Doubly(f, o, d, dij, 'exp', framework='glm', constant=True)\n", 143 | "print doubly.params\n", 144 | "\n", 145 | "gravity = smf.glm('Data~Origin+Destination+Dij', family=families.Poisson(), data=austria).fit()\n", 146 | "print gravity.params.values" 147 | ] 148 | } 149 | ], 150 | "metadata": { 151 | "anaconda-cloud": {}, 152 | "kernelspec": { 153 | "display_name": "Python [Root]", 154 | "language": "python", 155 | "name": "Python [Root]" 156 | }, 157 | "language_info": { 158 | "codemirror_mode": { 159 | "name": "ipython", 160 | "version": 2 161 | }, 162 | "file_extension": ".py", 163 | "mimetype": "text/x-python", 164 | "name": "python", 165 | "nbconvert_exporter": "python", 166 | "pygments_lexer": "ipython2", 167 | "version": "2.7.12" 168 | } 169 | }, 170 | "nbformat": 4, 171 | "nbformat_minor": 0 172 | } 173 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | # Required 2 | version: 2 3 | 4 | # Build documentation in the docs/ directory with Sphinx 5 | sphinx: 6 | configuration: doc/conf.py 7 | 8 | # Optionally build your docs in additional formats such as PDF and ePub 9 | formats: all 10 | 11 | python: 12 | version: 3.7 13 | install: 14 | - requirements: requirements.txt 15 | - method: pip 16 | path: . 17 | extra_requirements: 18 | - tests 19 | - docs 20 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | scipy>=0.11 2 | numpy>=1.3 3 | libpysal>=4.0.0 4 | spglm>=1.0.6 5 | spreg 6 | -------------------------------------------------------------------------------- /requirements_docs.txt: -------------------------------------------------------------------------------- 1 | sphinx>=1.4.3 2 | sphinxcontrib-napoleon 3 | sphinx_gallery 4 | sphinxcontrib-bibtex 5 | sphinx_bootstrap_theme 6 | numpydoc 7 | -------------------------------------------------------------------------------- /requirements_tests.txt: -------------------------------------------------------------------------------- 1 | nose 2 | nose-progressive 3 | nose-exclude 4 | coverage 5 | coveralls 6 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from distutils.command.build_py import build_py 3 | 4 | # Get __version__ from PACKAGE_NAME/__init__.py without importing the package 5 | # __version__ has to be defined in the first line 6 | with open('spint/__init__.py', 'r') as f: 7 | exec(f.readline()) 8 | 9 | 10 | def _get_requirements_from_files(groups_files): 11 | groups_reqlist = {} 12 | 13 | for k, v in groups_files.items(): 14 | with open(v, 'r') as f: 15 | pkg_list = f.read().splitlines() 16 | groups_reqlist[k] = pkg_list 17 | 18 | return groups_reqlist 19 | 20 | 21 | def setup_package(): 22 | _groups_files = { 23 | 'base': 'requirements.txt', 24 | 'tests': 'requirements_tests.txt', 25 | 'docs': 'requirements_docs.txt' 26 | } 27 | 28 | reqs = _get_requirements_from_files(_groups_files) 29 | install_reqs = reqs.pop('base') 30 | extras_reqs = reqs 31 | 32 | setup(name='spint', # name of package 33 | version=__version__, 34 | description='SPatial INTeraction models', # short <80chr description 35 | url='https://github.com/pysal/spint', # github repo 36 | maintainer='Taylor M. Oshan', 37 | maintainer_email='tayoshan@gmail.com', 38 | python_requires='>3.5', 39 | test_suite='nose.collector', 40 | tests_require=['nose'], 41 | keywords='spatial statistics', 42 | classifiers=[ 43 | 'Development Status :: 5 - Production/Stable', 44 | 'Intended Audience :: Science/Research', 45 | 'Intended Audience :: Developers', 46 | 'Intended Audience :: Education', 47 | 'Topic :: Scientific/Engineering', 48 | 'Topic :: Scientific/Engineering :: GIS', 49 | 'License :: OSI Approved :: BSD License', 50 | 'Programming Language :: Python', 51 | 'Programming Language :: Python :: 3.6', 52 | 'Programming Language :: Python :: 3.7' 53 | ], 54 | license='3-Clause BSD', 55 | packages=find_packages(), 56 | install_requires=install_reqs, 57 | extras_require=extras_reqs, 58 | zip_safe=False, 59 | cmdclass={'build.py': build_py}) 60 | 61 | 62 | if __name__ == '__main__': 63 | setup_package() 64 | -------------------------------------------------------------------------------- /spint/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '1.0.7' 2 | 3 | from .gravity import Gravity, Production, Attraction, Doubly 4 | from .utils import CPC, sorensen, srmse 5 | from .vec_SA import VecMoran as Moran_Vector 6 | from .dispersion import phi_disp, alpha_disp 7 | from .flow_accessibility import Accessibility 8 | -------------------------------------------------------------------------------- /spint/count_model.py: -------------------------------------------------------------------------------- 1 | """ 2 | CountModel class for dispatching different types of count models and different 3 | types of estimation technqiues. 4 | """ 5 | 6 | __author__ = "Taylor Oshan tayoshan@gmail.com" 7 | 8 | import numpy as np 9 | from spglm.glm import GLM 10 | from spglm.family import Poisson, QuasiPoisson 11 | 12 | 13 | class CountModel(object): 14 | """ 15 | Base class for variety of count-based models such as Poisson, negative binomial, 16 | etc. of the exponetial family. 17 | 18 | Parameters 19 | ---------- 20 | y : array 21 | n x 1; n observations of the depedent variable 22 | X : array 23 | n x k; design matrix of k explanatory variables 24 | family : instance of class 'family' 25 | default is Poisson() 26 | constant : boolean 27 | True if intercept should be estimated and false otherwise. 28 | Default is True. 29 | 30 | 31 | Attributes 32 | ---------- 33 | y : array 34 | n x 1; n observations of the depedent variable 35 | X : array 36 | n x k; design matrix of k explanatory variables 37 | fitted : boolean 38 | False is model has not been fitted and True if it has been 39 | successfully fitted. Deault is False. 40 | constant : boolean 41 | True if intercept should be estimated and false otherwise. 42 | Default is True. 43 | 44 | Example 45 | ------- 46 | >>> from spint.count_model import CountModel 47 | >>> import libpysal 48 | >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') 49 | >>> y = np.array(db.by_col("HOVAL")) 50 | >>> y = np.reshape(y, (49,1)) 51 | >>> y = np.round(y).astype(int) 52 | >>> X = [] 53 | >>> X.append(db.by_col("INC")) 54 | >>> X.append(db.by_col("CRIME")) 55 | >>> X = np.array(X).T 56 | >>> model = CountModel(y, X, family=Poisson()) 57 | >>> results = model.fit('GLM') 58 | >>> results.params 59 | array([ 3.92159085, 0.01183491, -0.01371397]) 60 | 61 | """ 62 | 63 | def __init__(self, y, X, family=Poisson(), constant=True): 64 | self.y = self._check_counts(y) 65 | self.X = X 66 | self.constant = constant 67 | 68 | def _check_counts(self, y): 69 | if (y.dtype == 'int64') | (y.dtype == 'int32'): 70 | return y 71 | else: 72 | raise TypeError( 73 | 'Dependent variable (y) must be composed of integers') 74 | 75 | def fit(self, framework='GLM', Quasi=False): 76 | """ 77 | Method that fits a particular count model usign the appropriate 78 | estimation technique. Models include Poisson GLM, Negative Binomial GLM, 79 | Quasi-Poisson - at the moment Poisson GLM is the only option. 80 | 81 | TODO: add zero inflated variants and hurdle variants. 82 | 83 | Parameters 84 | ---------- 85 | framework : string 86 | estimation framework; default is GLM 87 | "GLM" | "QUASI" | 88 | """ 89 | if (framework.lower() == 'glm'): 90 | if not Quasi: 91 | results = GLM( 92 | self.y, 93 | self.X, 94 | family=Poisson(), 95 | constant=self.constant).fit() 96 | else: 97 | results = GLM( 98 | self.y, 99 | self.X, 100 | family=QuasiPoisson(), 101 | constant=self.constant).fit() 102 | return CountModelResults(results) 103 | 104 | else: 105 | raise NotImplemented( 106 | 'Poisson GLM is the only count model currently implemented') 107 | 108 | 109 | class CountModelResults(object): 110 | """ 111 | Results of estimated GLM and diagnostics. 112 | 113 | Parameters 114 | ---------- 115 | results : GLM object 116 | Pointer to GLMResults object with estimated parameters 117 | and diagnostics. 118 | 119 | Attributes 120 | ---------- 121 | model : GLM Object 122 | Points to model object for which parameters have been 123 | estimated. May contain additional diagnostics. 124 | y : array 125 | n*1, dependent variable. 126 | X : array 127 | n*k, independent variable, including constant. 128 | family : string 129 | Model type: 'Gaussian', 'Poisson', 'Logistic' 130 | n : integer 131 | Number of observations 132 | k : integer 133 | Number of independent variables 134 | df_model : float 135 | k-1, where k is the number of variables (including 136 | intercept) 137 | df_residual : float 138 | observations minus variables (n-k) 139 | routine. 140 | params : array 141 | n*k, estimared beta coefficients 142 | yhat : array 143 | n*1, predicted value of y (i.e., fittedvalues) 144 | cov_params : array 145 | Variance covariance matrix (kxk) of betas 146 | std_err : array 147 | k*1, standard errors of betas 148 | pvalues : array 149 | k*1, two-tailed pvalues of parameters 150 | tvalues : array 151 | k*1, the tvalues of the standard errors 152 | deviance : float 153 | value of the deviance function evalued at params; 154 | see family.py for distribution-specific deviance 155 | llf : float 156 | value of the loglikelihood function evalued at params; 157 | see family.py for distribution-specific loglikelihoods 158 | llnull : float 159 | value of the loglikelihood function evaluated with only an 160 | intercept; see family.py for distribution-specific 161 | loglikelihoods 162 | AIC : float 163 | Akaike information criterion 164 | resid : array 165 | response residuals; defined as y-mu 166 | 167 | resid_dev : array 168 | k x 1, residual deviance of model 169 | D2 : float 170 | percentage of explained deviance 171 | adj_D2 : float 172 | 173 | pseudo_R2 : float 174 | McFadden's pseudo R2 (coefficient of determination) 175 | adj_pseudoR2 : float 176 | adjusted McFadden's pseudo R2 177 | 178 | """ 179 | 180 | def __init__(self, results): 181 | self.y = results.y 182 | self.X = results.X 183 | self.family = results.family 184 | self.params = results.params 185 | self.AIC = results.aic 186 | self.df_model = results.df_model 187 | self.df_resid = results.df_resid 188 | self.llf = results.llf 189 | self.llnull = results.llnull 190 | self.yhat = results.mu 191 | self.deviance = results.deviance 192 | self.n = results.n 193 | self.k = results.k 194 | self.resid = results.resid_response 195 | self.resid_dev = results.resid_deviance 196 | self.cov_params = results.cov_params() 197 | self.std_err = results.bse 198 | self.pvalues = results.pvalues 199 | self.tvalues = results.tvalues 200 | self.D2 = results.D2 201 | self.adj_D2 = results.adj_D2 202 | self.pseudoR2 = results.pseudoR2 203 | self.adj_pseudoR2 = results.adj_pseudoR2 204 | self.model = results 205 | -------------------------------------------------------------------------------- /spint/dispersion.py: -------------------------------------------------------------------------------- 1 | """ 2 | Various functions to test hypotheses regarding the dispersion of the variance of 3 | a variable. 4 | 5 | """ 6 | 7 | __author__ = "Taylor Oshan tayoshan@gmail.com" 8 | 9 | from spglm.glm import GLM 10 | from spglm.family import Poisson 11 | import numpy as np 12 | import scipy.stats as stats 13 | from types import FunctionType 14 | 15 | 16 | def phi_disp(model): 17 | """ 18 | Test the hypothesis that var[y] = mu (equidispersion) against the 19 | alternative hypothesis (quasi-Poisson) that var[y] = phi * mu where mu 20 | is the expected value of y and phi is an estimated overdispersion 21 | coefficient which is equivalent to 1+alpha in the alternative alpha 22 | dispersion test. 23 | 24 | phi > 0: overdispersion 25 | phi = 1: equidispersion 26 | phi < 0: underdispersion 27 | 28 | Parameters 29 | ---------- 30 | model : Model results class 31 | function can only be called on a sucessfully fitted model 32 | which has a valid response variable, y, and a valid 33 | predicted response variable, yhat. 34 | alt_var : function 35 | specifies an alternative varaince as a function of mu. 36 | Function must take a single scalar as input and return a 37 | single scalar as output 38 | Returns 39 | ------- 40 | array : [alpha coefficient, tvalue of alpha, pvalue of alpha] 41 | 42 | """ 43 | try: 44 | y = model.y.reshape((-1, 1)) 45 | yhat = model.yhat.reshape((-1, 1)) 46 | ytest = (((y - yhat)**2 - y) / yhat).reshape((-1, 1)) 47 | except BaseException: 48 | raise AttributeError( 49 | "Check that fitted model has valid 'y' and 'yhat' attributes") 50 | 51 | phi = 1 + np.mean(ytest) 52 | zval = np.sqrt(len(ytest)) * np.mean(ytest) / np.std(ytest, ddof=1) 53 | pval = stats.norm.sf(zval) 54 | 55 | return np.array([phi, zval, pval]) 56 | 57 | 58 | def alpha_disp(model, alt_var=lambda x: x): 59 | """ 60 | Test the hypothesis that var[y] = mu (equidispersion) against the 61 | alternative hypothesis that var[y] = mu + alpha * alt_var(mu) where mu 62 | is the expected value of y, alpha is an estimated coefficient, and 63 | alt_var() specifies an alternative variance as a function of mu. 64 | alt_var=lambda x:x corresponds to an alternative hypothesis of a negative 65 | binomimal model with a linear variance function and alt_var=lambda 66 | x:x**2 correspinds to an alternative hypothesis of a negative binomial 67 | model with a quadratic varaince function. 68 | 69 | alpha > 0: overdispersion 70 | alpha = 1: equidispersion 71 | alpha < 0: underdispersion 72 | 73 | Parameters 74 | ---------- 75 | model : Model results class 76 | function can only be called on a sucessfully fitted model 77 | which has a valid response variable, y, and a valid 78 | predicted response variable, yhat. 79 | alt_var : function 80 | specifies an alternative varaince as a function of mu. 81 | Function must take a single scalar as input and return a 82 | single scalar as output 83 | Returns 84 | ------- 85 | array : [alpha coefficient, tvalue of alpha, pvalue of alpha] 86 | 87 | """ 88 | try: 89 | y = model.y.reshape((-1, 1)) 90 | yhat = model.yhat.reshape((-1, 1)) 91 | ytest = (((y - yhat)**2 - y) / yhat).reshape((-1, 1)) 92 | except BaseException: 93 | raise AttributeError( 94 | "Make sure model passed has been estimated and has a valid 'y' and 'yhat' attribute") 95 | 96 | if isinstance(alt_var, FunctionType): 97 | X = (alt_var(yhat) / yhat).reshape((-1, 1)) 98 | test_results = GLM(ytest, X, constant=False).fit() 99 | alpha = test_results.params[0] 100 | zval = test_results.tvalues[0] 101 | pval = stats.norm.sf(zval) 102 | else: 103 | raise TypeError( 104 | "The alternative variance function, 'alt_var', must be a valid function'") 105 | 106 | return np.array([alpha, zval, pval]) 107 | -------------------------------------------------------------------------------- /spint/flow_accessibility.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | # 3. FlowAccessibility = Accessibility of flow taking existing destinations 3 | import numpy as np 4 | import pandas as pd 5 | import itertools 6 | 7 | #------------------------------------------------------------------------------------------------------------- 8 | 9 | def _generate_dummy_flows(): 10 | nodes = ['A','B','C','D','E'] 11 | destination_masses = [60,10,10,30,50] 12 | 13 | all_flow = pd.DataFrame( list(itertools.product(nodes,nodes 14 | ) 15 | ) 16 | ).rename(columns = {0:'origin_ID', 1:'destination_ID' 17 | } 18 | ) 19 | 20 | masses = {'nodes': nodes,'dest_masses': destination_masses 21 | } 22 | 23 | masses = pd.DataFrame({'nodes': nodes,'dest_masses': destination_masses 24 | }, columns = ['nodes','dest_masses' 25 | ] 26 | ) 27 | 28 | all_flow['volume_in_unipartite'] = [10,10,10,10,10, 29 | 10,0,0,10,10, 30 | 10,0,0,10,0, 31 | 10,10,10,0,10, 32 | 10,10,0,10,10] 33 | 34 | all_flow['volume_in_bipartite'] = [0,0,10,10,10, 35 | 0,0,0,10,10, 36 | 0,0,0,0,0, 37 | 0,0,0,0,0, 38 | 0,0,0,0,0] 39 | 40 | all_flow['distances'] = [0,8,2,5,5, 41 | 8,0,10,7,4, 42 | 2,10,0,6,9, 43 | 5,7,6,0,2, 44 | 5,4,9,2,0] 45 | 46 | all_flow = all_flow.merge(masses, how = 'left', left_on = 'destination_ID', right_on = 'nodes') 47 | 48 | all_flow['results_all=False'] = [500, 510, 730, 230, 190, 49 | 400, 890, 750, 400, 360, 50 | 150, 690, 300, 300, 360, 51 | 350, 780, 670, 530, 430, 52 | 230, 690, 400, 370, 400] 53 | 54 | return all_flow 55 | 56 | 57 | #------------------------------------------------------------------------------------------------------------- 58 | 59 | 60 | 61 | def Accessibility(dest_nodes, distances, weights, masses, all_destinations=False, is_bipartite = False): 62 | 63 | """ 64 | Function to calculate Accessibility for Competing Destination model, given a COMPLETE origin-destination edgelist. 65 | See an example notebook to see how to construct the COMPLETE origin-destination edgelist from your data. 66 | 67 | Parameters 68 | ---------- 69 | dest_nodes : array of strings or numeric codes 70 | n x 1; the DESTINATION column in the origin-destination edgelist 71 | 72 | distances : array of numbers 73 | n x 1; the distance column in the origin-destination edgelist 74 | 75 | weights : array of numbers 76 | n x 1; the flow volume column in the origin-destination edgelist 77 | 78 | masses : array of numbers 79 | n x 1; the DESTINATION masses column in the origin-destination edgelist 80 | 81 | all_destinations: bolean, Deafult is False 82 | True to consider all the existing destinations as a competing destinations, 83 | even those where flows does not exist in the data. 84 | False to consider only those destinations as a competing destinations, which exists in the data. 85 | This option is only available for flow data that can be represented as unipartite graph. 86 | is_bipartite : bolean, Deafult is False 87 | True to predefine the flow graph as bipartite: one where origins and destinations are separate 88 | entities and where interaction can happen only in one direction, from origin to destination. 89 | False to keep assumption for regular unipartite graph. 90 | """ 91 | 92 | # convert numbers to integers 93 | distances = np.array(distances.astype(int)) 94 | weights = np.array(weights.astype(int)) 95 | masses = np.array(masses.astype(int)) 96 | dest_nodes = np.array(dest_nodes.astype(str)) 97 | 98 | # define error 99 | if len(distances) != len(weights) != len(masses) != len(dest_nodes): 100 | raise ValueError("One of the input array is different length then the others, but they should all be the same length. See notebook example if you are unsure what the input should look like ") 101 | if all_destinations & is_bipartite: 102 | raise ValueError("This option has not been implemented yet") 103 | 104 | # define number of rows 105 | nrows= len(dest_nodes) 106 | uniques = len(np.unique(np.array(dest_nodes))) 107 | 108 | # create binary for weight 109 | v_bin = np.ones(nrows) 110 | weights[np.isnan(weights)] = 0 111 | v_bin[weights <= 0] = 0 112 | 113 | # define the base matrices 114 | distance = distances.reshape(uniques,uniques) 115 | mass =masses.reshape(uniques,uniques).T 116 | 117 | # define the identity array 118 | idn = np.identity(uniques) 119 | idn = np.where((idn==1), 0, 1) 120 | idn = np.concatenate(uniques * [idn.ravel()], axis = 0 121 | ).reshape(uniques,uniques,uniques 122 | ).T 123 | 124 | # multiply the distance by mass 125 | dm = distance * mass 126 | 127 | # combine all matrices for either all or existing destinations 128 | if is_bipartite: 129 | exists = v_bin.reshape(uniques,uniques).T 130 | output = (np.concatenate(uniques * [exists], axis = 0 131 | ).reshape(uniques,uniques,uniques 132 | ).T 133 | ) * idn * (uniques * [dm] 134 | ) 135 | elif all_destinations: 136 | exists = v_bin.reshape(uniques,uniques) 137 | output = idn * (nrows * [dm]) 138 | else: 139 | exists = v_bin.reshape(uniques,uniques) 140 | output = (np.concatenate(uniques * [exists], axis = 0 141 | ).reshape(uniques,uniques,uniques 142 | ).T 143 | ) * idn * (uniques * [dm] 144 | ) 145 | 146 | # get the sum and covert to series 147 | output = (np.sum(output,axis = 1 148 | ) 149 | ).reshape(nrows 150 | ).T 151 | 152 | 153 | return output 154 | -------------------------------------------------------------------------------- /spint/primer/SpIntPrimer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pysal/spint/050865acae4054b8ac30b12e6d38ca884e7a43cc/spint/primer/SpIntPrimer.pdf -------------------------------------------------------------------------------- /spint/primer/austria.csv: -------------------------------------------------------------------------------- 1 | ,Origin,Destination,Data,Oi,Dj,Dij 2 | 0,AT11,AT11,0,4016,5146,1e-300 3 | 1,AT11,AT12,1131,4016,25741,103.001845 4 | 2,AT11,AT13,1887,4016,26980,84.204666 5 | 3,AT11,AT21,69,4016,4117,220.811933 6 | 4,AT11,AT22,738,4016,8634,132.00748 7 | 5,AT11,AT31,98,4016,8193,214.511814 8 | 6,AT11,AT32,31,4016,4902,246.933305 9 | 7,AT11,AT33,43,4016,3952,390.85611 10 | 8,AT11,AT34,19,4016,1910,505.089539 11 | 9,AT12,AT11,1633,20080,5146,103.001845 12 | 10,AT12,AT12,0,20080,25741,1e-300 13 | 11,AT12,AT13,14055,20080,26980,45.796272 14 | 12,AT12,AT21,416,20080,4117,216.994739 15 | 13,AT12,AT22,1276,20080,8634,129.878172 16 | 14,AT12,AT31,1850,20080,8193,140.706671 17 | 15,AT12,AT32,388,20080,4902,201.232355 18 | 16,AT12,AT33,303,20080,3952,343.50075 19 | 17,AT12,AT34,159,20080,1910,453.515594 20 | 18,AT13,AT11,2301,29142,5146,84.204666 21 | 19,AT13,AT12,20164,29142,25741,45.796272 22 | 20,AT13,AT13,0,29142,26980,1e-300 23 | 21,AT13,AT21,1080,29142,4117,249.932874 24 | 22,AT13,AT22,1831,29142,8634,158.630661 25 | 23,AT13,AT31,1943,29142,8193,186.420738 26 | 24,AT13,AT32,742,29142,4902,244.108305 27 | 25,AT13,AT33,674,29142,3952,387.61776 28 | 26,AT13,AT34,407,29142,1910,498.407152 29 | 27,AT21,AT11,85,4897,5146,220.811933 30 | 28,AT21,AT12,379,4897,25741,216.994739 31 | 29,AT21,AT13,1597,4897,26980,249.932874 32 | 30,AT21,AT21,0,4897,4117,1e-300 33 | 31,AT21,AT22,1608,4897,8634,92.407958 34 | 32,AT21,AT31,328,4897,8193,151.777157 35 | 33,AT21,AT32,317,4897,4902,92.894408 36 | 34,AT21,AT33,469,4897,3952,194.851669 37 | 35,AT21,AT34,114,4897,1910,306.105825 38 | 36,AT22,AT11,762,8487,5146,132.00748 39 | 37,AT22,AT12,1110,8487,25741,129.878172 40 | 38,AT22,AT13,2973,8487,26980,158.630661 41 | 39,AT22,AT21,1252,8487,4117,92.407958 42 | 40,AT22,AT22,0,8487,8634,1e-300 43 | 41,AT22,AT31,1081,8487,8193,124.563096 44 | 42,AT22,AT32,622,8487,4902,122.433524 45 | 43,AT22,AT33,425,8487,3952,261.893783 46 | 44,AT22,AT34,262,8487,1910,376.34667 47 | 45,AT31,AT11,196,10638,5146,214.511814 48 | 46,AT31,AT12,2027,10638,25741,140.706671 49 | 47,AT31,AT13,3498,10638,26980,186.420738 50 | 48,AT31,AT21,346,10638,4117,151.777157 51 | 49,AT31,AT22,1332,10638,8634,124.563096 52 | 50,AT31,AT31,0,10638,8193,1e-300 53 | 51,AT31,AT32,2144,10638,4902,81.753652 54 | 52,AT31,AT33,821,10638,3952,208.456383 55 | 53,AT31,AT34,274,10638,1910,314.793199 56 | 54,AT32,AT11,49,5790,5146,246.933305 57 | 55,AT32,AT12,378,5790,25741,201.232355 58 | 56,AT32,AT13,1349,5790,26980,244.108305 59 | 57,AT32,AT21,310,5790,4117,92.894408 60 | 58,AT32,AT22,851,5790,8634,122.433524 61 | 59,AT32,AT31,2117,5790,8193,81.753652 62 | 60,AT32,AT32,0,5790,4902,1e-300 63 | 61,AT32,AT33,630,5790,3952,145.076472 64 | 62,AT32,AT34,106,5790,1910,258.591197 65 | 63,AT33,AT11,87,4341,5146,390.85611 66 | 64,AT33,AT12,424,4341,25741,343.50075 67 | 65,AT33,AT13,978,4341,26980,387.61776 68 | 66,AT33,AT21,490,4341,4117,194.851669 69 | 67,AT33,AT22,670,4341,8634,261.893783 70 | 68,AT33,AT31,577,4341,8193,208.456383 71 | 69,AT33,AT32,546,4341,4902,145.076472 72 | 70,AT33,AT33,0,4341,3952,1e-300 73 | 71,AT33,AT34,569,4341,1910,114.46325 74 | 72,AT34,AT11,33,2184,5146,505.089539 75 | 73,AT34,AT12,128,2184,25741,453.515594 76 | 74,AT34,AT13,643,2184,26980,498.407152 77 | 75,AT34,AT21,154,2184,4117,306.105825 78 | 76,AT34,AT22,328,2184,8634,376.34667 79 | 77,AT34,AT31,199,2184,8193,314.793199 80 | 78,AT34,AT32,112,2184,4902,258.591197 81 | 79,AT34,AT33,587,2184,3952,114.46325 82 | 80,AT34,AT34,0,2184,1910,1e-300 83 | -------------------------------------------------------------------------------- /spint/primer/austria.dbf: -------------------------------------------------------------------------------- 1 | _ fOBJECTIDN NUTS_IDCSTAT_LEVL_N AREAN LENN Shape_LengN Shape_AreaN 299AT33 2 0.00000000000 0.00000000000 11.11589824150 1.50022172697 312AT34 2 0.00000000000 0.00000000000 3.43932445938 0.30882099234 316AT11 2 0.00000000000 0.00000000000 7.25018235459 0.47491040095 326AT13 2 0.00000000000 0.00000000000 1.42907805863 0.05005857427 333AT31 2 0.00000000000 0.00000000000 9.13947499030 1.44833936577 334AT21 2 0.00000000000 0.00000000000 7.26685835453 1.12271501139 336AT32 2 0.00000000000 0.00000000000 8.17138727933 0.85287668505 337AT12 2 0.00000000000 0.00000000000 12.10618028170 2.32668356970 350AT22 2 0.00000000000 0.00000000000 9.32843862672 1.95118722812 -------------------------------------------------------------------------------- /spint/primer/austria.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["ETRS89",DATUM["D_ETRS_1989",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] -------------------------------------------------------------------------------- /spint/primer/austria.qpj: -------------------------------------------------------------------------------- 1 | GEOGCS["ETRS89",DATUM["European_Terrestrial_Reference_System_1989",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6258"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4258"]] 2 | -------------------------------------------------------------------------------- /spint/primer/austria.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pysal/spint/050865acae4054b8ac30b12e6d38ca884e7a43cc/spint/primer/austria.shp -------------------------------------------------------------------------------- /spint/primer/austria.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pysal/spint/050865acae4054b8ac30b12e6d38ca884e7a43cc/spint/primer/austria.shx -------------------------------------------------------------------------------- /spint/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pysal/spint/050865acae4054b8ac30b12e6d38ca884e7a43cc/spint/tests/__init__.py -------------------------------------------------------------------------------- /spint/tests/test_accessibility.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for Accessibility function. 3 | 4 | The correctness of the function is veryfied by matching the output to manually calculated values, using very simple dummy dataset. 5 | 6 | """ 7 | 8 | __author__ = 'Lenka Hasova haska.lenka@gmail.com' 9 | 10 | import unittest 11 | import numpy as np 12 | from ..flow_accessibility import _generate_dummy_flows 13 | from ..flow_accessibility import Accessibility 14 | 15 | 16 | 17 | class AccessibilityTest(unittest.TestCase): 18 | 19 | def test_accessibility(self): 20 | flow = _generate_dummy_flows() 21 | flow = flow.loc[:,['origin_ID', 'destination_ID','distances', 'volume_in_unipartite','dest_masses','results_all=False']] 22 | flow['acc_uni'] = Accessibility(nodes = flow['origin_ID'], distances = flow['distances'], weights = flow['volume_in_unipartite'], masses = flow['dest_masses'], all_destinations=False) 23 | 24 | np.testing.testing.assert_array_equal(flow['results_all=False'], flow['acc_uni']) 25 | 26 | if __name__ == '__main__': 27 | unittest.main() -------------------------------------------------------------------------------- /spint/tests/test_count_model.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for CountModel class, which includes various linear models designed for 3 | count data 4 | 5 | Test data is the Columbus dataset after it has been rounded to integers to act 6 | as count data. Results are verified using corresponding functions in R. 7 | 8 | """ 9 | 10 | __author__ = 'Taylor Oshan tayoshan@gmail.com' 11 | 12 | import unittest 13 | import numpy as np 14 | import libpysal 15 | from spglm.family import Poisson 16 | from ..count_model import CountModel 17 | 18 | 19 | class TestCountModel(unittest.TestCase): 20 | """Tests CountModel class""" 21 | 22 | def setUp(self): 23 | db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'), 'r') 24 | y = np.array(db.by_col("HOVAL")) 25 | y = np.reshape(y, (49, 1)) 26 | self.y = np.round(y).astype(int) 27 | X = [] 28 | X.append(db.by_col("INC")) 29 | X.append(db.by_col("CRIME")) 30 | self.X = np.array(X).T 31 | 32 | def test_PoissonGLM(self): 33 | model = CountModel(self.y, self.X, family=Poisson()) 34 | results = model.fit('GLM') 35 | np.testing.assert_allclose(results.params, [3.92159085, 0.01183491, 36 | -0.01371397], atol=1.0e-8) 37 | self.assertIsInstance(results.family, Poisson) 38 | self.assertEqual(results.n, 49) 39 | self.assertEqual(results.k, 3) 40 | self.assertEqual(results.df_model, 2) 41 | self.assertEqual(results.df_resid, 46) 42 | np.testing.assert_allclose(results.yhat, 43 | [51.26831574, 44 | 50.15022766, 45 | 40.06142973, 46 | 34.13799739, 47 | 28.76119226, 48 | 42.6836241, 49 | 55.64593703, 50 | 34.08277997, 51 | 40.90389582, 52 | 37.19727958, 53 | 23.47459217, 54 | 26.12384057, 55 | 29.78303507, 56 | 25.96888223, 57 | 29.14073823, 58 | 26.04369592, 59 | 34.18996367, 60 | 32.28924005, 61 | 27.42284396, 62 | 72.69207879, 63 | 33.05316347, 64 | 36.52276972, 65 | 49.2551479, 66 | 35.33439632, 67 | 24.07252457, 68 | 31.67153709, 69 | 27.81699478, 70 | 25.38021219, 71 | 24.31759259, 72 | 23.13586161, 73 | 48.40724678, 74 | 48.57969818, 75 | 31.92596006, 76 | 43.3679231, 77 | 34.32925819, 78 | 51.78908089, 79 | 34.49778584, 80 | 27.56236198, 81 | 48.34273194, 82 | 57.50829097, 83 | 50.66038226, 84 | 54.68701352, 85 | 35.77103116, 86 | 43.21886784, 87 | 40.07615759, 88 | 49.98658004, 89 | 43.13352883, 90 | 40.28520774, 91 | 46.28910294]) 92 | np.testing.assert_allclose(results.cov_params, 93 | [[1.70280610e-02, -6.18628383e-04, -2.21386966e-04], 94 | [-6.18628383e-04, 2.61733917e-05, 6.77496445e-06], 95 | [-2.21386966e-04, 6.77496445e-06, 3.75463502e-06]]) 96 | np.testing.assert_allclose(results.std_err, [0.13049161, 0.00511599, 97 | 0.00193769], atol=1.0e-8) 98 | np.testing.assert_allclose( 99 | results.pvalues, [ 100 | 2.02901657e-198, 2.07052532e-002, 1.46788805e-012]) 101 | np.testing.assert_allclose(results.tvalues, [30.0524361, 2.31331634, 102 | -7.07748998]) 103 | np.testing.assert_allclose(results.resid, [28.73168426, - 104 | 5.15022766, - 105 | 14.06142973, - 106 | 1.13799739, - 107 | 5.76119226, - 108 | 13.6836241, 19.35406297, 2.91722003, 12.09610418, 58.80272042, - 109 | 3.47459217, - 110 | 6.12384057, 12.21696493, 17.03111777, - 111 | 11.14073823, - 112 | 7.04369592, 7.81003633, 27.71075995, 3.57715604, 8.30792121, - 113 | 13.05316347, - 114 | 6.52276972, - 115 | 1.2551479, 17.66560368, - 116 | 6.07252457, - 117 | 11.67153709, 6.18300522, - 118 | 2.38021219, 7.68240741, - 119 | 1.13586161, - 120 | 16.40724678, - 121 | 8.57969818, - 122 | 7.92596006, - 123 | 15.3679231, - 124 | 7.32925819, - 125 | 15.78908089, 8.50221416, - 126 | 4.56236198, - 127 | 8.34273194, 4.49170903, - 128 | 8.66038226, - 129 | 10.68701352, - 130 | 9.77103116, - 131 | 9.21886784, - 132 | 12.07615759, 26.01341996, - 133 | 1.13352883, - 134 | 13.28520774, - 135 | 10.28910294]) 136 | self.assertAlmostEqual(results.deviance, 230.46013824817649) 137 | self.assertAlmostEqual(results.llf, -247.42592089969378) 138 | self.assertAlmostEqual(results.AIC, 500.85184179938756) 139 | self.assertAlmostEqual(results.D2, 0.388656011675) 140 | self.assertAlmostEqual(results.adj_D2, 0.36207583826952761) 141 | 142 | 143 | if __name__ == '__main__': 144 | unittest.main() 145 | -------------------------------------------------------------------------------- /spint/tests/test_dispersion.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Tests for regressiom based dispersion tests (Cameron & Trivedi, 2013) 4 | 5 | Cameron, Colin A. & Trivedi, Pravin K. (2013) Regression Analysis of Count Data. 6 | Camridge University Press: New York, New York. 7 | 8 | """ 9 | 10 | __author__ = 'Taylor Oshan tayoshan@gmail.com' 11 | 12 | import unittest 13 | import numpy as np 14 | import libpysal 15 | from spglm.family import Poisson 16 | from ..count_model import CountModel 17 | from ..dispersion import phi_disp, alpha_disp 18 | 19 | 20 | class TestDispersion(unittest.TestCase): 21 | 22 | def setUp(self): 23 | db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'), 'r') 24 | y = np.array(db.by_col("HOVAL")) 25 | y = np.reshape(y, (49, 1)) 26 | self.y = np.round(y).astype(int) 27 | X = [] 28 | X.append(db.by_col("INC")) 29 | X.append(db.by_col("CRIME")) 30 | self.X = np.array(X).T 31 | 32 | def test_Dispersion(self): 33 | model = CountModel(self.y, self.X, family=Poisson()) 34 | results = model.fit('GLM') 35 | phi = phi_disp(results) 36 | alpha1 = alpha_disp(results) 37 | alpha2 = alpha_disp(results, lambda x: x**2) 38 | np.testing.assert_allclose(phi, [5.39968689, 2.3230411, 0.01008847], 39 | atol=1.0e-8) 40 | np.testing.assert_allclose(alpha1, [4.39968689, 2.3230411, 41 | 0.01008847], atol=1.0e-8) 42 | np.testing.assert_allclose(alpha2, [0.10690133, 2.24709978, 43 | 0.01231683], atol=1.0e-8) 44 | 45 | 46 | if __name__ == '__main__': 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /spint/tests/test_universal.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for universal spatial interaction models. 3 | 4 | Test data is the Austria migration dataset used in Dennet's (2012) practical 5 | primer on spatial interaction modeling. The data was made avialable through the 6 | following dropbox link: http://dl.dropbox.com/u/8649795/AT_Austria.csv. 7 | The data has been pre-filtered so that there are no intra-zonal flows. 8 | 9 | Dennett, A. (2012). Estimating flows between geographical locations: get me 10 | started in spatial interaction modelling (Working Paper No. 184). 11 | UCL: Citeseer. 12 | """ 13 | 14 | __author__ = 'Tyler Hoffman tylerhoff1@gmail.com' 15 | 16 | import unittest 17 | import numpy as np 18 | from scipy.stats import pearsonr 19 | from ..universal import Lenormand, Radiation, PWO 20 | np.random.seed(123456) 21 | 22 | 23 | class TestUniversal(unittest.TestCase): 24 | """ Tests for universal models """ 25 | 26 | def setUp(self): 27 | self.f = np.array([0, 1131, 1887, 69, 738, 98, 28 | 31, 43, 19, 1633, 0, 14055, 416, 29 | 1276, 1850, 388, 303, 159, 2301, 20164, 30 | 0, 1080, 1831, 1943, 742, 674, 407, 31 | 85, 379, 1597, 0, 1608, 328, 317, 32 | 469, 114, 762, 1110, 2973, 1252, 0, 33 | 1081, 622, 425, 262, 196, 2027, 3498, 346, 34 | 1332, 0, 2144, 821, 274, 49, 378, 1349, 35 | 310, 851, 2117, 0, 630, 106, 87, 424, 36 | 978, 490, 670, 577, 546, 0, 569, 37 | 33, 128, 643, 154, 328, 199, 112, 587, 0]) 38 | 39 | self.o = np.array(['AT11', 'AT11', 'AT11', 'AT11', 'AT11', 'AT11', 40 | 'AT11', 'AT11', 'AT11', 'AT12', 'AT12', 'AT12', 41 | 'AT12', 'AT12', 'AT12', 'AT12', 'AT12', 'AT12', 42 | 'AT13', 'AT13', 'AT13', 'AT13', 'AT13', 'AT13', 43 | 'AT13', 'AT13', 'AT13', 'AT21', 'AT21', 'AT21', 44 | 'AT21', 'AT21', 'AT21', 'AT21', 'AT21', 'AT21', 45 | 'AT22', 'AT22', 'AT22', 'AT22', 'AT22', 'AT22', 46 | 'AT22', 'AT22', 'AT22', 'AT31', 'AT31', 'AT31', 47 | 'AT31', 'AT31', 'AT31', 'AT31', 'AT31', 'AT31', 48 | 'AT32', 'AT32', 'AT32', 'AT32', 'AT32', 'AT32', 49 | 'AT32', 'AT32', 'AT32', 'AT33', 'AT33', 'AT33', 50 | 'AT33', 'AT33', 'AT33', 'AT33', 'AT33', 'AT33', 51 | 'AT34', 'AT34', 'AT34', 'AT34', 'AT34', 'AT34', 52 | 'AT34', 'AT34', 'AT34']) 53 | 54 | self.d = np.array(['AT11', 'AT12', 'AT13', 'AT21', 'AT22', 'AT31', 55 | 'AT32', 'AT33', 'AT34', 'AT11', 'AT12', 'AT13', 56 | 'AT21', 'AT22', 'AT31', 'AT32', 'AT33', 'AT34', 57 | 'AT11', 'AT12', 'AT13', 'AT21', 'AT22', 'AT31', 58 | 'AT32', 'AT33', 'AT34', 'AT11', 'AT12', 'AT13', 59 | 'AT21', 'AT22', 'AT31', 'AT32', 'AT33', 'AT34', 60 | 'AT11', 'AT12', 'AT13', 'AT21', 'AT22', 'AT31', 61 | 'AT32', 'AT33', 'AT34', 'AT11', 'AT12', 'AT13', 62 | 'AT21', 'AT22', 'AT31', 'AT32', 'AT33', 'AT34', 63 | 'AT11', 'AT12', 'AT13', 'AT21', 'AT22', 'AT31', 64 | 'AT32', 'AT33', 'AT34', 'AT11', 'AT12', 'AT13', 65 | 'AT21', 'AT22', 'AT31', 'AT32', 'AT33', 'AT34', 66 | 'AT11', 'AT12', 'AT13', 'AT21', 'AT22', 'AT31', 67 | 'AT32', 'AT33', 'AT34']) 68 | 69 | self.dij = np.array([0, 103, 84, 221, 132, 215, 247, 391, 505, 70 | 103, 0, 46, 217, 130, 141, 201, 344, 454, 71 | 84, 46, 0, 250, 159, 186, 244, 288, 498, 72 | 221, 217, 250, 0, 92, 152, 93, 195, 306, 73 | 132, 130, 159, 92, 0, 125, 122, 262, 376, 74 | 215, 141, 186, 152, 125, 0, 82, 208, 315, 75 | 247, 201, 244, 93, 122, 82, 0, 145, 259, 76 | 391, 344, 388, 195, 262, 208, 145, 0, 114, 77 | 505, 454, 498, 306, 376, 315, 259, 114, 0]) 78 | 79 | self.o_var = np.array([4016, 4016, 4016, 4016, 4016, 4016, 80 | 4016, 4016, 4016, 20080, 20080, 20080, 81 | 20080, 20080, 20080, 20080, 20080, 20080, 82 | 29142, 29142, 29142, 29142, 29142, 29142, 83 | 29142, 29142, 29142, 4897, 4897, 4897, 84 | 4897, 4897, 4897, 4897, 4897, 4897, 85 | 8487, 8487, 8487, 8487, 8487, 8487, 86 | 8487, 8487, 8487, 10638, 10638, 10638, 87 | 10638, 10638, 10638, 10638, 10638, 10638, 88 | 5790, 5790, 5790, 5790, 5790, 5790, 89 | 5790, 5790, 5790, 4341, 4341, 4341, 90 | 4341, 4341, 4341, 4341, 4341, 4341, 91 | 2184, 2184, 2184, 2184, 2184, 2184, 92 | 2184, 2184, 2184]) 93 | 94 | self.d_var = np.array([5146, 25741, 26980, 4117, 8634, 8193, 95 | 4902, 3952, 1910, 5146, 25741, 26980, 4117, 96 | 8634, 8193, 4902, 3952, 1910, 5146, 25741, 97 | 26980, 4117, 8634, 8193, 4902, 3952, 1910, 98 | 5146, 25741, 26980, 4117, 8634, 8193, 4902, 99 | 3952, 1910, 5146, 25741, 26980, 4117, 8634, 100 | 8193, 4902, 3952, 1910, 5146, 25741, 26980, 101 | 4117, 8634, 8193, 4902, 3952, 1910, 102 | 5146, 25741, 26980, 4117, 8634, 8193, 103 | 4902, 3952, 1910, 5146, 25741, 26980, 4117, 104 | 8634, 8193, 4902, 3952, 1910, 5146, 25741, 105 | 26980, 4117, 8634, 8193, 4902, 3952, 1910]) 106 | 107 | self.xlocs = np.array([47.1537, 48.1081, 48.2082, 46.7222, 47.3593, 108 | 48.0259, 47.8095, 47.2537, 47.2497]) 109 | 110 | self.ylocs = np.array([16.2689, 15.805, 16.3738, 14.1806, 14.47, 111 | 13.9724, 13.055, 11.6015, 9.9797]) 112 | 113 | def ready(self): 114 | N = 9 115 | outflows = self.o_var[0::N] 116 | inflows = self.d_var[0:N] 117 | locs = np.zeros((N, 2)) 118 | locs[:, 0] = self.xlocs 119 | locs[:, 1] = self.ylocs 120 | dists = np.reshape(self.dij, (N, N), order='C') 121 | T_obs = np.reshape(self.f, (N, N), order='C') 122 | 123 | return outflows, inflows, locs, dists, T_obs 124 | 125 | def test_Lenormand(self): 126 | outflows, inflows, locs, dists, T_obs = self.ready() 127 | 128 | # Lenormand paper's model 129 | model = Lenormand(inflows, outflows, dists) 130 | T_L = model.flowmat() 131 | np.testing.assert_almost_equal( 132 | pearsonr(T_L.flatten(), T_obs.flatten()), 133 | (-0.0728415, 0.5181216) 134 | ) 135 | 136 | def test_Radiation(self): 137 | outflows, inflows, locs, dists, T_obs = self.ready() 138 | 139 | # Radiation model -- requires locations of each node 140 | model = Radiation(inflows, outflows, dists, locs, locs) 141 | T_R = model.flowmat() 142 | np.testing.assert_almost_equal( 143 | pearsonr(T_R.flatten(), T_obs.flatten()), 144 | (0.05384603805950201, 0.6330568989373918) 145 | ) 146 | 147 | def test_PWO(self): 148 | outflows, inflows, locs, dists, T_obs = self.ready() 149 | 150 | # PWO model 151 | model = PWO(inflows, outflows, dists, locs, locs) 152 | T_P = model.flowmat() 153 | np.testing.assert_almost_equal( 154 | pearsonr(T_P.flatten(), T_obs.flatten()), 155 | (0.23623562773229048, 0.033734908271368574) 156 | ) 157 | 158 | 159 | if __name__ == '__main__': 160 | unittest.main() 161 | -------------------------------------------------------------------------------- /spint/tests/test_vec_SA.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests for analysis of spatial autocorrelation within vectors 3 | 4 | """ 5 | 6 | __author__ = 'Taylor Oshan tayoshan@gmail.com' 7 | 8 | import unittest 9 | import numpy as np 10 | from libpysal.weights.distance import DistanceBand 11 | from ..vec_SA import VecMoran 12 | 13 | 14 | class TestVecMoran(unittest.TestCase): 15 | """Tests VecMoran class""" 16 | 17 | def setUp(self): 18 | self.vecs = np.array([[1, 55, 60, 100, 500], 19 | [2, 60, 55, 105, 501], 20 | [3, 500, 55, 155, 500], 21 | [4, 505, 60, 160, 500], 22 | [5, 105, 950, 105, 500], 23 | [6, 155, 950, 155, 499]]) 24 | self.origins = self.vecs[:, 1:3] 25 | self.dests = self.vecs[:, 3:5] 26 | 27 | def test_origin_focused_A(self): 28 | wo = DistanceBand( 29 | self.origins, 30 | threshold=9999, 31 | alpha=-1.5, 32 | binary=False) 33 | np.random.seed(1) 34 | vmo = VecMoran(self.vecs, wo, focus='origin', rand='A') 35 | self.assertAlmostEquals(vmo.I, 0.645944594367) 36 | self.assertAlmostEquals(vmo.p_z_sim, 0.03898650733809228) 37 | 38 | def test_dest_focused_A(self): 39 | wd = DistanceBand(self.dests, threshold=9999, alpha=-1.5, binary=False) 40 | np.random.seed(1) 41 | vmd = VecMoran(self.vecs, wd, focus='destination', rand='A') 42 | self.assertAlmostEquals(vmd.I, -0.764603695022) 43 | self.assertAlmostEquals(vmd.p_z_sim, 0.149472673677) 44 | 45 | def test_origin_focused_B(self): 46 | wo = DistanceBand( 47 | self.origins, 48 | threshold=9999, 49 | alpha=-1.5, 50 | binary=False) 51 | np.random.seed(1) 52 | vmo = VecMoran(self.vecs, wo, focus='origin', rand='B') 53 | self.assertAlmostEquals(vmo.I, 0.645944594367) 54 | self.assertAlmostEquals(vmo.p_z_sim, 0.02944612633233532) 55 | 56 | def test_dest_focused_B(self): 57 | wd = DistanceBand(self.dests, threshold=9999, alpha=-1.5, binary=False) 58 | np.random.seed(1) 59 | vmd = VecMoran(self.vecs, wd, focus='destination', rand='B') 60 | self.assertAlmostEquals(vmd.I, -0.764603695022) 61 | self.assertAlmostEquals(vmd.p_z_sim, 0.12411761124197379) 62 | 63 | 64 | if __name__ == '__main__': 65 | unittest.main() 66 | -------------------------------------------------------------------------------- /spint/universal.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementations of universal spatial interaction models: Lenormand's 3 | model, radiation model, and population-weighted opportunities. 4 | 5 | References 6 | ---------- 7 | Lenormand, M., Huet, S., Gargiulo, F., and Deffuant, G. (2012). "A Universal 8 | Model of Commuting Networks." PLOS One, 7, 10. 9 | 10 | Simini, F., Gonzalez, M. C., Maritan, A., Barabasi, A.-L. (2012). "A universal 11 | model for mobility and migration patterns." Nature, 484, 96-100. 12 | 13 | Yan, X.-Y., Zhao, C., Fan, Y., Di, Z., and Wang, W.-X. (2014). "Universal 14 | predictability of mobility patterns in cities." Journal of the Royal 15 | Society Interface, 11, 100. 16 | """ 17 | 18 | __author__ = 'Tyler Hoffman tylerhoff1@gmail.com' 19 | 20 | from abc import ABC, abstractmethod 21 | import numpy as np 22 | import pandas as pd 23 | from scipy.stats import pearsonr 24 | 25 | 26 | class Universal(ABC): 27 | """ 28 | Base class for all the universal models as they all have similar 29 | underlying structures. For backend design purposes, not practical use. 30 | 31 | Parameters 32 | ---------- 33 | inflows : array of reals 34 | N x 1, observed flows into each location 35 | outflows : array of reals 36 | M x 1, observed flows out of each location 37 | dists : matrix of reals 38 | N x M, pairwise distances between each location 39 | 40 | Attributes 41 | ---------- 42 | N : integer 43 | number of origins 44 | M : integer 45 | number of destinations 46 | flowmat : abstract method 47 | estimates flows, implemented by children 48 | """ 49 | def __init__(self, inflows, outflows, dists): 50 | self.N = len(outflows) # number of origins 51 | self.M = len(inflows) # number of destinations 52 | self.outflows = outflows.copy() # list of origin outflows 53 | self.inflows = inflows.copy() # list of destination inflows 54 | self.dists = dists.copy() # list of distances 55 | 56 | @abstractmethod 57 | def flowmat(self): pass 58 | 59 | 60 | class Lenormand(Universal): 61 | """ 62 | Universal model based off of Lenormand et al. 2012, 63 | "A Universal Model of Commuting Networks". 64 | 65 | Parameters 66 | ---------- 67 | inflows : array of reals 68 | N x 1, observed flows into each location 69 | outflows : array of reals 70 | M x 1, observed flows out of each location 71 | dists : matrix of reals 72 | N x M, pairwise distances between each location 73 | beta : scalar 74 | real, universal parameter for the model 75 | avg_sa : scalar 76 | real, average surface area of units 77 | 78 | Attributes 79 | ---------- 80 | N : integer 81 | number of origins 82 | M : integer 83 | number of destinations 84 | calibrate : method 85 | calibrates beta using constants from the paper 86 | flowmat : method 87 | estimates flows via the Lenormand model 88 | """ 89 | 90 | def __init__(self, inflows, outflows, dists, beta=1, avg_sa=None): 91 | super().__init__(inflows, outflows, dists) 92 | self.beta = self.calibrate(avg_sa) if avg_sa is not None else beta 93 | 94 | def calibrate(self, avg_sa): 95 | # Constants from the paper 96 | nu = 0.177 97 | alpha = 3.15 * 10**(-4) 98 | self.beta = alpha*avg_sa**(-nu) 99 | 100 | def flowmat(self): 101 | # Builds the matrix T from the parameter beta and a matrix of distances 102 | T = np.zeros((self.N, self.M)) 103 | 104 | # Copy class variables so as not to modify 105 | sIN = self.inflows.copy() 106 | sOUT = self.outflows.copy() 107 | 108 | # Assembly loop 109 | while sum(sOUT) > 0: 110 | # Pick random nonzero sOUT 111 | idxs, = np.where(sOUT > 0) 112 | i = np.random.choice(idxs) 113 | 114 | # Compute Pij's (not memoized b/c it changes on iteration) 115 | Pi = np.multiply(sIN, np.exp(-self.beta*self.dists[i, :])) / \ 116 | np.dot(sIN, np.exp(-self.beta*self.dists[i, :])) 117 | 118 | # Pick random j according to Pij 119 | j = np.random.choice(range(self.N), p=Pi) 120 | 121 | # Adjust values 122 | T[i, j] += 1 123 | sIN[j] -= 1 124 | sOUT[i] -= 1 125 | 126 | return T 127 | 128 | 129 | class Radiation(Universal): 130 | """ 131 | Universal model based off of Simini et al. 2012, 132 | "A universal model for mobility and migration patterns". 133 | Requires slightly more data than Lenormand. 134 | 135 | Parameters 136 | ---------- 137 | inflows : array of reals 138 | N x 1, observed flows into each location 139 | outflows : array of reals 140 | M x 1, observed flows out of each location 141 | dists : matrix of reals 142 | N x M, pairwise distances between each location 143 | ilocs : array of reals 144 | N x 2, inflow node locations 145 | olocs : array of reals 146 | M x 2, outflow node locations 147 | 148 | Attributes 149 | ---------- 150 | N : integer 151 | number of origins 152 | M : integer 153 | number of destinations 154 | flowmat : method 155 | estimates flows via the Radiation model 156 | """ 157 | 158 | def __init__(self, inflows, outflows, dists, ilocs, olocs): 159 | super().__init__(inflows, outflows, dists) 160 | self.ilocs = ilocs.copy() 161 | self.olocs = olocs.copy() 162 | 163 | def _from_origin(self, idx, total_origins): 164 | # Sort destinations by distance from origin 165 | didxs = np.argsort(self.dists[idx, :]) 166 | inflows = self.inflows[didxs] 167 | 168 | # Normalization 169 | F = 1.0/(1.0 - self.outflows[idx]/total_origins) 170 | 171 | pop_in_radius = 0 172 | flows = np.zeros((self.M,)) 173 | for j in range(self.M): 174 | # Use formula from the paper 175 | flows[j] = F*(self.outflows[idx]*inflows[j]) / \ 176 | ((self.outflows[idx] + pop_in_radius) * 177 | (self.outflows[idx] + inflows[j] + pop_in_radius)) 178 | 179 | pop_in_radius += inflows[j] 180 | 181 | # Unsort list 182 | return flows[didxs.argsort()] 183 | 184 | def flowmat(self): 185 | # Builds the OD matrix T from the inputted data 186 | T = np.zeros((self.N, self.M)) 187 | total_origins = sum(self.outflows) 188 | 189 | for i in range(self.N): 190 | T[i, :] = self._from_origin(i, total_origins) 191 | 192 | return T 193 | 194 | 195 | class PWO(Universal): 196 | """ 197 | Population-weighted opportunies (PWO) implements a 198 | universal model based off of Yan et al. 2014, 199 | "Universal predictability of mobility patterns in cities". 200 | Requires slightly more data than Lenormand. 201 | 202 | Parameters 203 | ---------- 204 | inflows : array of reals 205 | N x 1, observed flows into each location 206 | outflows : array of reals 207 | M x 1, observed flows out of each location 208 | dists : matrix of reals 209 | N x M, pairwise distances between each location 210 | ilocs : array of reals 211 | N x 2, inflow node locations 212 | olocs : array of reals 213 | M x 2, outflow node locations 214 | 215 | Attributes 216 | ---------- 217 | N : integer 218 | number of origins 219 | M : integer 220 | number of destinations 221 | flowmat : method 222 | estimates flows via the Radiation model 223 | """ 224 | 225 | def __init__(self, inflows, outflows, dists, ilocs, olocs): 226 | super().__init__(inflows, outflows, dists) 227 | self.ilocs = ilocs.copy() 228 | self.olocs = olocs.copy() 229 | self.total = sum(inflows) # total population of the system 230 | 231 | def _from_destination(self, jdx): 232 | # Sort origins by distance from destination 233 | didxs = np.argsort(self.dists[jdx, :]) 234 | outflows = self.outflows[didxs] 235 | pop_in_radius = self.inflows[jdx] # here pop_in_radius includes endpts 236 | flows = np.zeros((self.N,)) 237 | 238 | # Loop over origins 239 | for i in range(self.N): 240 | pop_in_radius += outflows[i] # add other endpt 241 | 242 | # Compute denominator 243 | denom = 0 244 | denom_pop_in_radius = outflows[i] 245 | for k in range(self.M): # loop over destinations 246 | denom_pop_in_radius += self.inflows[k] 247 | if k != i: 248 | denom += self.inflows[k] * (1/denom_pop_in_radius - 249 | 1/self.total) 250 | 251 | # Use formula from the paper 252 | flows[i] = self.inflows[jdx]*(1/pop_in_radius - 1/self.total)/denom 253 | 254 | # Unsort list 255 | return flows[didxs.argsort()] 256 | 257 | def flowmat(self): 258 | # Builds the OD matrix T from the inputted data 259 | T = np.zeros((self.N, self.M)) 260 | 261 | for j in range(self.M): 262 | T[:, j] = self._from_destination(j) 263 | 264 | return T 265 | 266 | 267 | def test(): 268 | # Read data from Austria file 269 | N = 9 270 | austria = pd.read_csv('austria.csv') 271 | modN = austria[austria.index % N == 0] 272 | outflows = modN['Oi'].values 273 | inflows = austria['Dj'].head(n=N).values 274 | locs = np.zeros((N, 2)) 275 | locs[:, 0] = modN['X'].values 276 | locs[:, 1] = modN['Y'].values 277 | dists = np.reshape(austria['Dij'].values, (N, N), order='C') 278 | T_obs = np.reshape(austria['Data'].values, (N, N), order='C') 279 | 280 | # Lenormand paper's model 281 | model = Lenormand(inflows, outflows, dists) 282 | T_L = model.flowmat() 283 | print(pearsonr(T_L.flatten(), T_obs.flatten())) 284 | 285 | # Radiation model -- requires locations of each node 286 | model = Radiation(inflows, outflows, dists, locs, locs) 287 | T_R = model.flowmat() 288 | print(pearsonr(T_R.flatten(), T_obs.flatten())) 289 | 290 | # PWO model 291 | model = PWO(inflows, outflows, dists, locs, locs) 292 | T_P = model.flowmat() 293 | print(pearsonr(T_P.flatten(), T_obs.flatten())) 294 | 295 | 296 | if __name__ == '__main__': 297 | test() 298 | -------------------------------------------------------------------------------- /spint/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Useful functions for analyzing spatial interaction data. 3 | """ 4 | 5 | __author__ = "Taylor Oshan tayoshan@gmail.com" 6 | 7 | from scipy import sparse as sp 8 | import numpy as np 9 | from collections import defaultdict 10 | from functools import partial 11 | from itertools import count 12 | 13 | 14 | def CPC(model): 15 | """ 16 | Common part of commuters based on Sorensen index 17 | Lenormand et al. 2012 18 | """ 19 | y = model.y 20 | try: 21 | yhat = model.yhat.resahpe((-1, 1)) 22 | except BaseException: 23 | yhat = model.mu((-1, 1)) 24 | N = model.n 25 | YYhat = np.hstack([y, yhat]) 26 | NCC = np.sum(np.min(YYhat, axis=1)) 27 | NCY = np.sum(Y) 28 | NCYhat = np.sum(yhat) 29 | return (N * NCC) / (NCY + NCYhat) 30 | 31 | 32 | def sorensen(model): 33 | """ 34 | Sorensen similarity index 35 | 36 | For use on spatial interaction models; N = sample size 37 | rather than N = number of locations and normalized by N instead of N**2 38 | """ 39 | try: 40 | y = model.y.reshape((-1, 1)) 41 | except BaseException: 42 | y = model.f.reshape((-1, 1)) 43 | try: 44 | yhat = model.yhat.reshape((-1, 1)) 45 | except BaseException: 46 | yhat = model.mu.reshape((-1, 1)) 47 | N = model.n 48 | YYhat = np.hstack([y, yhat]) 49 | num = 2.0 * np.min(YYhat, axis=1) 50 | den = yhat + y 51 | return (1.0 / N) * (np.sum(num.reshape((-1, 1)) / den.reshape((-1, 1)))) 52 | 53 | 54 | def srmse(model): 55 | """ 56 | Standardized root mean square error 57 | """ 58 | n = float(model.n) 59 | try: 60 | y = model.y.reshape((-1, 1)).astype(float) 61 | except BaseException: 62 | y = model.f.reshape((-1, 1)).astype(float) 63 | try: 64 | yhat = model.yhat.reshape((-1, 1)).astype(float) 65 | except BaseException: 66 | yhat = model.mu.reshape((-1, 1)).astype(float) 67 | srmse = ((np.sum((y - yhat)**2) / n)**.5) / (np.sum(y) / n) 68 | return srmse 69 | 70 | 71 | def spcategorical(index): 72 | ''' 73 | Returns a dummy matrix given an array of categorical variables. 74 | Parameters 75 | ---------- 76 | n_cat_ids : array 77 | A 1d vector of the categorical labels for n observations. 78 | 79 | Returns 80 | -------- 81 | dummy : array 82 | A sparse matrix of dummy (indicator/binary) variables for the 83 | categorical data. 84 | 85 | ''' 86 | if np.squeeze(index).ndim == 1: 87 | id_set = np.unique(index) 88 | n = len(index) 89 | # if index.dtype.type is not np.int_: 90 | mapper = defaultdict(partial(next, count())) 91 | [mapper[each] for each in id_set] 92 | index = [mapper[each] for each in index] 93 | indptr = np.arange(n + 1, dtype=int) 94 | return sp.csr_matrix((np.ones(n), index, indptr)) 95 | else: 96 | raise IndexError("The index %s is not understood" % index) 97 | 98 | 99 | #old and slow 100 | """ 101 | def spcategorical(n_cat_ids): 102 | ''' 103 | Returns a dummy matrix given an array of categorical variables. 104 | Parameters 105 | ---------- 106 | n_cat_ids : array 107 | A 1d vector of the categorical labels for n observations. 108 | 109 | Returns 110 | -------- 111 | dummy : array 112 | A sparse matrix of dummy (indicator/binary) variables for the 113 | categorical data. 114 | 115 | ''' 116 | if np.squeeze(n_cat_ids).ndim == 1: 117 | cat_set = np.unique(n_cat_ids) 118 | n = len(n_cat_ids) 119 | index = [np.where(cat_set == id)[0].tolist()[0] for id in n_cat_ids] 120 | indptr = np.arange(n+1, dtype=int) 121 | return sp.csr_matrix((np.ones(n), index, indptr)) 122 | else: 123 | raise IndexError("The index %s is not understood" % col) 124 | """ 125 | -------------------------------------------------------------------------------- /spint/vec_SA.py: -------------------------------------------------------------------------------- 1 | """ 2 | Classes for statistics for testing hypotheses of spatial autocorrelation amongst 3 | vectors. 4 | """ 5 | 6 | _author_ = "Taylor Oshan tayoshan@gmail.com, Levi Wolf levi.john.wolf@gmail.com" 7 | 8 | import numpy as np 9 | import scipy.stats as stats 10 | from libpysal.weights.distance import DistanceBand 11 | 12 | PERMUTATIONS = 99 13 | 14 | 15 | class VecMoran: 16 | """Moran's I Global Autocorrelation Statistic For Vectors 17 | 18 | Parameters 19 | ---------- 20 | y : array 21 | variable measured across n origin-destination vectors 22 | w : W 23 | spatial weights instance 24 | focus : string 25 | denotes whether to calculate the statistic with a focus on 26 | spatial proximity between origins or destinations; default 27 | is 'origin' but option include: 28 | 29 | 'origin' | 'destination' 30 | 31 | rand : string 32 | denote which randomization technqiue to use for 33 | significance testing; default is 'A' but options are: 34 | 35 | 'A': transate entire vector 36 | 'B': shuffle points and redraw vectors 37 | 38 | permutations : int 39 | number of random permutations for calculation of 40 | pseudo-p_values 41 | two_tailed : boolean 42 | If True (default) analytical p-values for Moran are two 43 | tailed, otherwise if False, they are one-tailed. 44 | Attributes 45 | ---------- 46 | y : array 47 | original variable 48 | w : W obejct 49 | original w object 50 | n : integer 51 | number of vectors 52 | o : array 53 | n x 2; 2D coordinates of vector origins 54 | d : array 55 | n x 2: 2D coordinates of vector destinations 56 | alpha : scalar 57 | distance decay parameter harvested from W object 58 | binary : boolean 59 | True is all entries in W > 0 are set to 1; False if if they 60 | are inverse distance weighted; default is False; attribute is 61 | harvested from W object 62 | build_sp : boolean 63 | True if W object is build using sparse distance matrix and 64 | False if it is built using a dense distance matrix; attribute 65 | is harvested from W object 66 | threshold : scalar 67 | all values larger than threshold are set 0 in W object; 68 | attribute is harvested from W object 69 | silent : boolean 70 | True if island warnings are silent and False if they are not; 71 | default is False; attribute is harvested from W object 72 | focus : string 73 | denotes whether to calculate the statistic with a focus on 74 | spatial proximity between origins or destinations; default 75 | is 'origin' but option include: 76 | 77 | 'origin' | 'destination' 78 | 79 | rand : string 80 | denote which randomization technqiue to use for 81 | significance testing; default is 'A' but options are: 82 | 83 | 'A': transate entire vector 84 | 'B': shuffle points and redraw vectors 85 | 86 | permutations : int 87 | number of permutations 88 | I : float 89 | value of vector-based Moran's I 90 | EI : float 91 | expected value under randomization assumption 92 | VI_rand : float 93 | variance of I under randomization assumption 94 | seI_rand : float 95 | standard deviation of I under randomization assumption 96 | z_rand : float 97 | z-value of I under randomization assumption 98 | p_rand : float 99 | p-value of I under randomization assumption 100 | two_tailed : boolean 101 | If True p_norm and p_rand are two-tailed, otherwise they 102 | are one-tailed. 103 | sim : array 104 | (if permutations>0) 105 | vector of I values for permuted samples 106 | p_sim : array 107 | (if permutations>0) 108 | p-value based on permutations (one-tailed) 109 | null: spatial randomness 110 | alternative: the observed I is extreme if 111 | it is either extremely greater or extremely lower 112 | than the values obtained based on permutations 113 | EI_sim : float 114 | (if permutations>0) 115 | average value of I from permutations 116 | VI_sim : float 117 | (if permutations>0) 118 | variance of I from permutations 119 | seI_sim : float 120 | (if permutations>0) 121 | standard deviation of I under permutations. 122 | z_sim : float 123 | (if permutations>0) 124 | standardized I based on permutations 125 | p_z_sim : float 126 | (if permutations>0) 127 | p-value based on standard normal approximation from 128 | permutations 129 | 130 | Examples 131 | -------- 132 | >>> import numpy as np 133 | >>> np.random.seed(1) 134 | >>> from libpysal.weights import DistanceBand 135 | >>> from spint.vec_SA import VecMoran 136 | >>> vecs = np.array([[1, 55, 60, 100, 500], 137 | ... [2, 60, 55, 105, 501], 138 | ... [3, 500, 55, 155, 500], 139 | ... [4, 505, 60, 160, 500], 140 | ... [5, 105, 950, 105, 500], 141 | ... [6, 155, 950, 155, 499]]) 142 | >>> origins = vecs[:, 1:3] 143 | >>> dests = vecs[:, 3:5] 144 | >>> wo = DistanceBand(origins, threshold=9999, alpha=-1.5, binary=False) 145 | >>> wd = DistanceBand(dests, threshold=9999, alpha=-1.5, binary=False) 146 | 147 | #randomization technique A 148 | >>> vmo = VecMoran(vecs, wo, focus='origin', rand='A') 149 | >>> vmd = VecMoran(vecs, wd, focus='destination', rand='A') 150 | >>> vmo.I 151 | 0.6459445943670211 152 | >>> vmo.p_z_sim 153 | 0.03898650733809228 154 | >>> vmd.I 155 | -0.7646036950223406 156 | >>> vmd.p_z_sim 157 | 0.11275129553163704 158 | 159 | #randomization technique B 160 | >>> vmo = VecMoran(vecs, wo, focus='origin', rand='B') 161 | >>> vmd = VecMoran(vecs, wd, focus='destination', rand='B') 162 | >>> vmo.I 163 | 0.6459445943670211 164 | >>> vmo.p_z_sim 165 | 0.05087923006558356 166 | >>> vmd.I 167 | -0.7646036950223406 168 | >>> vmd.p_z_sim 169 | 0.1468368983650693 170 | 171 | """ 172 | 173 | def __init__( 174 | self, 175 | y, 176 | w, 177 | focus='origin', 178 | rand='A', 179 | permutations=PERMUTATIONS, 180 | two_tailed=True): 181 | self.y = y 182 | self.o = y[:, 1:3] 183 | self.d = y[:, 3:5] 184 | self.focus = focus 185 | self.rand = rand 186 | self.permutations = permutations 187 | self.two_tailed = two_tailed 188 | if isinstance(w, DistanceBand): 189 | self.w = w 190 | else: 191 | raise TypeError('Spatial weight, W, must be of type DistanceBand') 192 | try: 193 | self.threshold = w.threshold 194 | self.alpha = w.alpha 195 | self.build_sp = w.build_sp 196 | self.binary = w.binary 197 | self.silence_warnings = w.silence_warnings 198 | except BaseException: 199 | raise AttributeError('W object missing necessary attributes: ' 200 | 'threshold, alpha, binary, build_sp, silent') 201 | 202 | self.__moments() 203 | self.I = self.__calc(self.z) 204 | self.z_rand = (self.I - self.EI) / self.seI_rand 205 | 206 | if self.z_rand > 0: 207 | self.p_rand = 1 - stats.norm.cdf(self.z_rand) 208 | else: 209 | self.p_rand = stats.norm.cdf(self.z_rand) 210 | 211 | if self.two_tailed: 212 | self.p_rand *= 2. 213 | 214 | if permutations: 215 | if self.rand.upper() == 'A': 216 | sim = self.__rand_vecs_A(self.focus) 217 | elif self.rand.upper() == 'B': 218 | sim = self.__rand_vecs_B(self.focus) 219 | else: 220 | raise ValueError( 221 | "Parameter 'rand' must take a value of either 'A' or 'B'") 222 | 223 | self.sim = sim = np.array(sim) 224 | above = sim >= self.I 225 | larger = above.sum() 226 | if (self.permutations - larger) < larger: 227 | larger = self.permutations - larger 228 | self.p_sim = (larger + 1.) / (permutations + 1.) 229 | self.EI_sim = sim.sum() / permutations 230 | self.seI_sim = np.array(sim).std() 231 | self.VI_sim = self.seI_sim ** 2 232 | self.z_sim = (self.I - self.EI_sim) / self.seI_sim 233 | if self.z_sim > 0: 234 | self.p_z_sim = 1 - stats.norm.cdf(self.z_sim) 235 | else: 236 | self.p_z_sim = stats.norm.cdf(self.z_sim) 237 | 238 | def __moments(self): 239 | self.n = len(self.y) 240 | xObar = self.o[:, 0].mean() 241 | yObar = self.o[:, 1].mean() 242 | xDbar = self.d[:, 0].mean() 243 | yDbar = self.d[:, 1].mean() 244 | u = (self.y[:, 3] - self.y[:, 1]) - (xDbar - xObar) 245 | v = (self.y[:, 4] - self.y[:, 2]) - (yDbar - yObar) 246 | z = np.outer(u, u) + np.outer(v, v) 247 | self.z = z 248 | self.uv2ss = np.sum(np.dot(u, u) + np.dot(v, v)) 249 | self.EI = -1. / (self.n - 1) 250 | n = self.n 251 | s1 = self.w.s1 252 | W = self.w.s0 253 | s2 = self.w.s2 254 | 255 | v_num = n * n * s1 - n * s2 + 3 * W * W 256 | v_den = (n - 1) * (n + 1) * W * W 257 | 258 | a2 = np.sum(np.dot(u, u)) / n 259 | b2 = np.sum(np.dot(v, v)) / n 260 | m2 = a2 + b2 261 | a4 = np.sum(np.dot(np.dot(u, u), np.dot(u, u))) / n 262 | b4 = np.sum(np.dot(np.dot(v, u), np.dot(v, v))) / n 263 | n1 = a2**2 * ((n**2 - 3 * n + 3) * s1 - n * s2 + 3 * W**2) 264 | n2 = a4 * ((n**2 - n) * s1 - 2 * n * s2 + 6 * W**2) 265 | n3 = b2**2 * ((n**2 - 3 * n + 3) * s1 - n * s2 + 3 * W**2) 266 | n4 = b4 * ((n**2 - n) * s1 - 2 * n * s2 + 6 * W**2) 267 | d = (n - 1) * (n - 2) * (n - 3) 268 | self.VI_rand = 1 / (W**2 * m2**2) * \ 269 | ((n1 - n2) / d + (n3 - n4) / d) + \ 270 | ((a2 * b2) - m2**2) / (m2**2 * (n - 1)**2) 271 | self.seI_rand = self.VI_rand ** (1 / 2.) 272 | 273 | def __calc(self, z): 274 | zl = self._slag(self.w, z) 275 | inum = np.sum(zl) 276 | return self.n / self.w.s0 * inum / self.uv2ss 277 | 278 | def _newD(self, oldO, oldD, newO): 279 | oldOX, oldOY = oldO[:, 0], oldO[:, 1] 280 | oldDX, oldDY = oldD[:, 0], oldD[:, 1] 281 | newOX, newOY = newO[:, 0], newO[:, 1] 282 | deltaX = newOX - oldOX 283 | deltaY = newOY - oldOY 284 | newDX = oldDX + deltaX 285 | newDY = oldDY + deltaY 286 | return np.hstack([newDX.reshape((-1, 1)), newDY.reshape((-1, 1))]) 287 | 288 | def _newO(self, oldO, oldD, newD): 289 | oldOX, oldOY = oldO[:, 0], oldO[:, 1] 290 | oldDX, oldDY = oldD[:, 0], oldD[:, 1] 291 | newDX, newDY = newD[:, 0], newD[:, 1] 292 | deltaX = newDX - oldDX 293 | deltaY = newDY - oldDY 294 | newOX = oldOX + deltaX 295 | newOY = oldOY + deltaY 296 | return np.hstack([newOX.reshape((-1, 1)), newOY.reshape((-1, 1))]) 297 | 298 | def __rand_vecs_A(self, focus): 299 | if focus.lower() == 'origin': 300 | newOs = [ 301 | np.random.permutation( 302 | self.o) for i in range( 303 | self.permutations)] 304 | sims = [np.hstack([np.arange(self.n).reshape((-1, 1)), newO, 305 | self._newD(self.o, self.d, newO)]) for newO in newOs] 306 | Ws = [ 307 | DistanceBand( 308 | newO, 309 | threshold=self.threshold, 310 | alpha=self.alpha, 311 | binary=self.binary, 312 | build_sp=self.build_sp, 313 | silence_warnings=self.silence_warnings) for newO in newOs] 314 | elif focus.lower() == 'destination': 315 | newDs = [ 316 | np.random.permutation( 317 | self.d) for i in range( 318 | self.permutations)] 319 | sims = [np.hstack([np.arange(self.n).reshape( 320 | (-1, 1)), self._newO(self.o, self.d, newD), newD]) for newD in newDs] 321 | Ws = [ 322 | DistanceBand( 323 | newD, 324 | threshold=self.threshold, 325 | alpha=self.alpha, 326 | binary=self.binary, 327 | build_sp=self.build_sp, 328 | silence_warnings=self.silence_warnings) for newD in newDs] 329 | else: 330 | raise ValueError( 331 | "Parameter 'focus' must take value of either 'origin' or 'destination.'") 332 | 333 | VMs = [VecMoran(y, Ws[i], permutations=None) 334 | for i, y in enumerate(sims)] 335 | sim = [VM.__calc(VM.z) for VM in VMs] 336 | return sim 337 | 338 | def __rand_vecs_B(self, focus): 339 | if focus.lower() == 'origin': 340 | sims = [ 341 | np.hstack( 342 | [ 343 | np.arange( 344 | self.n).reshape( 345 | (-1, 346 | 1)), 347 | self.o, 348 | np.random.permutation( 349 | self.d)]) for i in range( 350 | self.permutations)] 351 | elif focus.lower() == 'destination': 352 | sims = [ 353 | np.hstack( 354 | [ 355 | np.arange( 356 | self.n).reshape( 357 | (-1, 358 | 1)), 359 | np.random.permutation( 360 | self.o), 361 | self.d]) for i in range( 362 | self.permutations)] 363 | else: 364 | raise ValueError( 365 | "Parameter 'focus' must take value of either 'origin' or 'destination.'") 366 | sims = [VecMoran(y, self.w, permutations=None) for y in sims] 367 | sim = [VM.__calc(VM.z) for VM in sims] 368 | return sim 369 | 370 | def _slag(self, w, y): 371 | """ 372 | Dense spatial lag operator for. 373 | If w is row standardized, returns the average of each observation's neighbors; 374 | if not, returns the weighted sum of each observation's neighbors. 375 | Parameters 376 | ---------- 377 | w : W 378 | object 379 | y : array 380 | numpy array with dimensionality conforming to w (see examples) 381 | Returns 382 | ------- 383 | wy : array 384 | array of numeric values for the spatial lag 385 | """ 386 | return np.array(w.sparse.todense()) * y 387 | --------------------------------------------------------------------------------