From 60210c4ccee6600372009f4e8410956c299c4014 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 1 Feb 2024 14:35:01 +0000 Subject: [PATCH] Update documentation --- _images/notebooks_skater_reg_11_1.png | Bin 0 -> 94753 bytes _images/notebooks_skater_reg_9_0.png | Bin 0 -> 28472 bytes _modules/index.html | 175 + _modules/spreg/diagnostics.html | 1533 +++ _modules/spreg/diagnostics_panel.html | 367 + _modules/spreg/diagnostics_sp.html | 917 ++ _modules/spreg/diagnostics_sur.html | 496 + _modules/spreg/diagnostics_tsls.html | 487 + _modules/spreg/error_sp.html | 1476 +++ _modules/spreg/error_sp_het.html | 1787 +++ _modules/spreg/error_sp_het_regimes.html | 2092 +++ _modules/spreg/error_sp_hom.html | 1751 +++ _modules/spreg/error_sp_hom_regimes.html | 2081 +++ _modules/spreg/error_sp_regimes.html | 2222 ++++ _modules/spreg/ml_error.html | 761 ++ _modules/spreg/ml_error_regimes.html | 731 ++ _modules/spreg/ml_lag.html | 847 ++ _modules/spreg/ml_lag_regimes.html | 793 ++ _modules/spreg/ols.html | 686 + _modules/spreg/ols_regimes.html | 899 ++ _modules/spreg/panel_fe.html | 825 ++ _modules/spreg/panel_re.html | 974 ++ _modules/spreg/probit.html | 1152 ++ _modules/spreg/skater_reg.html | 813 ++ _modules/spreg/sp_panels.html | 676 + _modules/spreg/sur.html | 1182 ++ _modules/spreg/sur_error.html | 1281 ++ _modules/spreg/sur_lag.html | 679 + _modules/spreg/twosls.html | 696 + _modules/spreg/twosls_regimes.html | 957 ++ _modules/spreg/twosls_sp.html | 768 ++ _modules/spreg/twosls_sp_regimes.html | 1134 ++ _sources/api.rst.txt | 130 + _sources/generated/spreg.AKtest.rst.txt | 22 + _sources/generated/spreg.GM_Combo.rst.txt | 29 + _sources/generated/spreg.GM_Combo_Het.rst.txt | 29 + .../spreg.GM_Combo_Het_Regimes.rst.txt | 29 + _sources/generated/spreg.GM_Combo_Hom.rst.txt | 29 + .../spreg.GM_Combo_Hom_Regimes.rst.txt | 29 + .../generated/spreg.GM_Combo_Regimes.rst.txt | 29 + .../generated/spreg.GM_Endog_Error.rst.txt | 29 + .../spreg.GM_Endog_Error_Het.rst.txt | 29 + .../spreg.GM_Endog_Error_Het_Regimes.rst.txt | 29 + .../spreg.GM_Endog_Error_Hom.rst.txt | 29 + .../spreg.GM_Endog_Error_Hom_Regimes.rst.txt | 29 + .../spreg.GM_Endog_Error_Regimes.rst.txt | 29 + _sources/generated/spreg.GM_Error.rst.txt | 29 + _sources/generated/spreg.GM_Error_Het.rst.txt | 29 + .../spreg.GM_Error_Het_Regimes.rst.txt | 29 + _sources/generated/spreg.GM_Error_Hom.rst.txt | 29 + .../spreg.GM_Error_Hom_Regimes.rst.txt | 29 + .../generated/spreg.GM_Error_Regimes.rst.txt | 29 + _sources/generated/spreg.GM_KKP.rst.txt | 29 + _sources/generated/spreg.GM_Lag.rst.txt | 34 + .../generated/spreg.GM_Lag_Regimes.rst.txt | 36 + _sources/generated/spreg.LMtests.rst.txt | 22 + _sources/generated/spreg.ML_Error.rst.txt | 34 + .../generated/spreg.ML_Error_Regimes.rst.txt | 34 + _sources/generated/spreg.ML_Lag.rst.txt | 33 + .../generated/spreg.ML_Lag_Regimes.rst.txt | 34 + _sources/generated/spreg.MoranRes.rst.txt | 22 + _sources/generated/spreg.OLS.rst.txt | 33 + _sources/generated/spreg.OLS_Regimes.rst.txt | 33 + .../generated/spreg.Panel_FE_Error.rst.txt | 33 + _sources/generated/spreg.Panel_FE_Lag.rst.txt | 33 + .../generated/spreg.Panel_RE_Error.rst.txt | 33 + _sources/generated/spreg.Panel_RE_Lag.rst.txt | 33 + _sources/generated/spreg.Probit.rst.txt | 49 + _sources/generated/spreg.SUR.rst.txt | 22 + _sources/generated/spreg.SURerrorGM.rst.txt | 22 + _sources/generated/spreg.SURerrorML.rst.txt | 22 + _sources/generated/spreg.SURlagIV.rst.txt | 22 + _sources/generated/spreg.Skater_reg.rst.txt | 26 + _sources/generated/spreg.TSLS.rst.txt | 34 + _sources/generated/spreg.TSLS_Regimes.rst.txt | 34 + _sources/generated/spreg.ThreeSLS.rst.txt | 22 + _sources/generated/spreg.akaike.rst.txt | 6 + _sources/generated/spreg.ar2.rst.txt | 6 + .../generated/spreg.breusch_pagan.rst.txt | 6 + .../generated/spreg.condition_index.rst.txt | 6 + .../generated/spreg.constant_check.rst.txt | 6 + _sources/generated/spreg.f_stat.rst.txt | 6 + _sources/generated/spreg.jarque_bera.rst.txt | 6 + .../generated/spreg.koenker_bassett.rst.txt | 6 + _sources/generated/spreg.lam_setp.rst.txt | 6 + _sources/generated/spreg.likratiotest.rst.txt | 6 + .../generated/spreg.log_likelihood.rst.txt | 6 + .../generated/spreg.panel_Hausman.rst.txt | 6 + .../generated/spreg.panel_LMerror.rst.txt | 6 + _sources/generated/spreg.panel_LMlag.rst.txt | 6 + .../generated/spreg.panel_rLMerror.rst.txt | 6 + _sources/generated/spreg.panel_rLMlag.rst.txt | 6 + _sources/generated/spreg.r2.rst.txt | 6 + _sources/generated/spreg.schwarz.rst.txt | 6 + _sources/generated/spreg.se_betas.rst.txt | 6 + _sources/generated/spreg.surLMe.rst.txt | 6 + _sources/generated/spreg.surLMlag.rst.txt | 6 + _sources/generated/spreg.sur_lmtest.rst.txt | 6 + _sources/generated/spreg.sur_lrtest.rst.txt | 6 + _sources/generated/spreg.sur_setp.rst.txt | 6 + _sources/generated/spreg.t_stat.rst.txt | 6 + _sources/generated/spreg.vif.rst.txt | 6 + _sources/generated/spreg.white.rst.txt | 6 + _sources/index.rst.txt | 35 +- _sources/installation.rst.txt | 14 + _sources/notebooks/GM_Lag_example.ipynb.txt | 511 + _sources/notebooks/Panel_FE_example.ipynb.txt | 367 + _sources/notebooks/skater_reg.ipynb.txt | 716 + _sources/references.rst.txt | 7 + _sources/tutorials.rst.txt | 23 + .../_sphinx_javascript_frameworks_compat.js | 134 + _static/basic.css | 306 +- .../css/bootstrap-responsive.css | 1109 ++ .../css/bootstrap-responsive.min.css | 9 + _static/bootstrap-2.3.2/css/bootstrap.css | 6167 +++++++++ _static/bootstrap-2.3.2/css/bootstrap.min.css | 9 + .../img/glyphicons-halflings-white.png | Bin 0 -> 8777 bytes .../img/glyphicons-halflings.png | Bin 0 -> 12799 bytes _static/bootstrap-2.3.2/js/bootstrap.js | 2287 ++++ _static/bootstrap-2.3.2/js/bootstrap.min.js | 6 + .../bootstrap-3.4.1/css/bootstrap-theme.css | 587 + .../css/bootstrap-theme.css.map | 1 + .../css/bootstrap-theme.min.css | 6 + .../css/bootstrap-theme.min.css.map | 1 + _static/bootstrap-3.4.1/css/bootstrap.css | 6834 ++++++++++ _static/bootstrap-3.4.1/css/bootstrap.css.map | 1 + _static/bootstrap-3.4.1/css/bootstrap.min.css | 6 + .../bootstrap-3.4.1/css/bootstrap.min.css.map | 1 + .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes _static/bootstrap-3.4.1/js/bootstrap.js | 2580 ++++ _static/bootstrap-3.4.1/js/bootstrap.min.js | 6 + _static/bootstrap-3.4.1/js/npm.js | 13 + _static/bootstrap-sphinx.css | 223 + _static/bootstrap-sphinx.js | 175 + .../bootswatch-2.3.2/amelia/bootstrap.min.css | 9 + .../cerulean/bootstrap.min.css | 9 + .../bootswatch-2.3.2/cosmo/bootstrap.min.css | 9 + .../bootswatch-2.3.2/cyborg/bootstrap.min.css | 9 + .../bootswatch-2.3.2/flatly/bootstrap.min.css | 9 + .../img/glyphicons-halflings-white.png | Bin 0 -> 8777 bytes .../img/glyphicons-halflings.png | Bin 0 -> 12799 bytes .../journal/bootstrap.min.css | 9 + .../readable/bootstrap.min.css | 9 + .../simplex/bootstrap.min.css | 9 + .../bootswatch-2.3.2/slate/bootstrap.min.css | 9 + .../spacelab/bootstrap.min.css | 9 + .../bootswatch-2.3.2/spruce/bootstrap.min.css | 9 + .../superhero/bootstrap.min.css | 9 + .../bootswatch-2.3.2/united/bootstrap.min.css | 9 + .../cerulean/bootstrap.min.css | 11 + .../bootswatch-3.4.1/cosmo/bootstrap.min.css | 11 + .../bootswatch-3.4.1/cyborg/bootstrap.min.css | 11 + .../bootswatch-3.4.1/darkly/bootstrap.min.css | 11 + .../bootswatch-3.4.1/flatly/bootstrap.min.css | 11 + .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../journal/bootstrap.min.css | 11 + .../bootswatch-3.4.1/lumen/bootstrap.min.css | 11 + .../bootswatch-3.4.1/paper/bootstrap.min.css | 11 + .../readable/bootstrap.min.css | 11 + .../sandstone/bootstrap.min.css | 11 + .../simplex/bootstrap.min.css | 11 + .../bootswatch-3.4.1/slate/bootstrap.min.css | 11 + .../spacelab/bootstrap.min.css | 11 + .../superhero/bootstrap.min.css | 11 + .../bootswatch-3.4.1/united/bootstrap.min.css | 11 + .../bootswatch-3.4.1/yeti/bootstrap.min.css | 11 + _static/doctools.js | 377 +- _static/documentation_options.js | 9 +- _static/images/pysal_favicon.ico | Bin 0 -> 32038 bytes _static/jquery-3.6.0.js | 10881 ++++++++++++++++ _static/jquery.js | 4 +- _static/js/jquery-1.12.4.min.js | 5 + _static/js/jquery-fix.js | 2 + _static/language_data.js | 106 +- _static/plot_directive.css | 16 + _static/pygments.css | 143 +- _static/pysal-styles.css | 82 + _static/pysal_favicon.ico | Bin 0 -> 32038 bytes _static/references.bib | 277 + _static/searchtools.js | 810 +- _static/sphinx_highlight.js | 144 + _static/underscore-1.13.1.js | 2042 +++ _static/underscore.js | 37 +- api.html | 426 + generated/spreg.AKtest.html | 316 + generated/spreg.GM_Combo.html | 445 + generated/spreg.GM_Combo_Het.html | 461 + generated/spreg.GM_Combo_Het_Regimes.html | 567 + generated/spreg.GM_Combo_Hom.html | 451 + generated/spreg.GM_Combo_Hom_Regimes.html | 573 + generated/spreg.GM_Combo_Regimes.html | 541 + generated/spreg.GM_Endog_Error.html | 407 + generated/spreg.GM_Endog_Error_Het.html | 434 + .../spreg.GM_Endog_Error_Het_Regimes.html | 529 + generated/spreg.GM_Endog_Error_Hom.html | 433 + .../spreg.GM_Endog_Error_Hom_Regimes.html | 537 + generated/spreg.GM_Endog_Error_Regimes.html | 497 + generated/spreg.GM_Error.html | 373 + generated/spreg.GM_Error_Het.html | 389 + generated/spreg.GM_Error_Het_Regimes.html | 473 + generated/spreg.GM_Error_Hom.html | 385 + generated/spreg.GM_Error_Hom_Regimes.html | 487 + generated/spreg.GM_Error_Regimes.html | 453 + generated/spreg.GM_KKP.html | 384 + generated/spreg.GM_Lag.html | 539 + generated/spreg.GM_Lag_Regimes.html | 685 + generated/spreg.LMtests.html | 289 + generated/spreg.ML_Error.html | 417 + generated/spreg.ML_Error_Regimes.html | 506 + generated/spreg.ML_Lag.html | 500 + generated/spreg.ML_Lag_Regimes.html | 525 + generated/spreg.MoranRes.html | 273 + generated/spreg.OLS.html | 548 + generated/spreg.OLS_Regimes.html | 616 + generated/spreg.Panel_FE_Error.html | 355 + generated/spreg.Panel_FE_Lag.html | 360 + generated/spreg.Panel_RE_Error.html | 369 + generated/spreg.Panel_RE_Lag.html | 371 + generated/spreg.Probit.html | 577 + generated/spreg.SUR.html | 407 + generated/spreg.SURerrorGM.html | 333 + generated/spreg.SURerrorML.html | 371 + generated/spreg.SURlagIV.html | 379 + generated/spreg.Skater_reg.html | 436 + generated/spreg.TSLS.html | 465 + generated/spreg.TSLS_Regimes.html | 574 + generated/spreg.ThreeSLS.html | 344 + generated/spreg.akaike.html | 219 + generated/spreg.ar2.html | 217 + generated/spreg.breusch_pagan.html | 248 + generated/spreg.condition_index.html | 220 + generated/spreg.constant_check.html | 181 + generated/spreg.f_stat.html | 220 + generated/spreg.jarque_bera.html | 236 + generated/spreg.koenker_bassett.html | 248 + generated/spreg.lam_setp.html | 187 + generated/spreg.likratiotest.html | 227 + generated/spreg.log_likelihood.html | 218 + generated/spreg.panel_Hausman.html | 185 + generated/spreg.panel_LMerror.html | 187 + generated/spreg.panel_LMlag.html | 187 + generated/spreg.panel_rLMerror.html | 187 + generated/spreg.panel_rLMlag.html | 187 + generated/spreg.r2.html | 219 + generated/spreg.schwarz.html | 219 + generated/spreg.se_betas.html | 218 + generated/spreg.surLMe.html | 188 + generated/spreg.surLMlag.html | 195 + generated/spreg.sur_lmtest.html | 187 + generated/spreg.sur_lrtest.html | 189 + generated/spreg.sur_setp.html | 185 + generated/spreg.t_stat.html | 264 + generated/spreg.vif.html | 238 + generated/spreg.white.html | 240 + genindex.html | 893 +- index.html | 219 +- installation.html | 168 + notebooks/GM_Lag_example.html | 812 ++ notebooks/GM_Lag_example.ipynb | 511 + notebooks/Panel_FE_example.html | 680 + notebooks/Panel_FE_example.ipynb | 367 + notebooks/skater_reg.html | 1039 ++ notebooks/skater_reg.ipynb | 716 + objects.inv | Bin 273 -> 8727 bytes references.html | 259 + search.html | 200 +- searchindex.js | 2 +- tutorials.html | 178 + 276 files changed, 101113 insertions(+), 1168 deletions(-) create mode 100644 _images/notebooks_skater_reg_11_1.png create mode 100644 _images/notebooks_skater_reg_9_0.png create mode 100644 _modules/index.html create mode 100644 _modules/spreg/diagnostics.html create mode 100644 _modules/spreg/diagnostics_panel.html create mode 100644 _modules/spreg/diagnostics_sp.html create mode 100644 _modules/spreg/diagnostics_sur.html create mode 100644 _modules/spreg/diagnostics_tsls.html create mode 100644 _modules/spreg/error_sp.html create mode 100644 _modules/spreg/error_sp_het.html create mode 100644 _modules/spreg/error_sp_het_regimes.html create mode 100644 _modules/spreg/error_sp_hom.html create mode 100644 _modules/spreg/error_sp_hom_regimes.html create mode 100644 _modules/spreg/error_sp_regimes.html create mode 100644 _modules/spreg/ml_error.html create mode 100644 _modules/spreg/ml_error_regimes.html create mode 100644 _modules/spreg/ml_lag.html create mode 100644 _modules/spreg/ml_lag_regimes.html create mode 100644 _modules/spreg/ols.html create mode 100644 _modules/spreg/ols_regimes.html create mode 100644 _modules/spreg/panel_fe.html create mode 100644 _modules/spreg/panel_re.html create mode 100644 _modules/spreg/probit.html create mode 100644 _modules/spreg/skater_reg.html create mode 100644 _modules/spreg/sp_panels.html create mode 100644 _modules/spreg/sur.html create mode 100644 _modules/spreg/sur_error.html create mode 100644 _modules/spreg/sur_lag.html create mode 100644 _modules/spreg/twosls.html create mode 100644 _modules/spreg/twosls_regimes.html create mode 100644 _modules/spreg/twosls_sp.html create mode 100644 _modules/spreg/twosls_sp_regimes.html create mode 100644 _sources/api.rst.txt create mode 100644 _sources/generated/spreg.AKtest.rst.txt create mode 100644 _sources/generated/spreg.GM_Combo.rst.txt create mode 100644 _sources/generated/spreg.GM_Combo_Het.rst.txt create mode 100644 _sources/generated/spreg.GM_Combo_Het_Regimes.rst.txt create mode 100644 _sources/generated/spreg.GM_Combo_Hom.rst.txt create mode 100644 _sources/generated/spreg.GM_Combo_Hom_Regimes.rst.txt create mode 100644 _sources/generated/spreg.GM_Combo_Regimes.rst.txt create mode 100644 _sources/generated/spreg.GM_Endog_Error.rst.txt create mode 100644 _sources/generated/spreg.GM_Endog_Error_Het.rst.txt create mode 100644 _sources/generated/spreg.GM_Endog_Error_Het_Regimes.rst.txt create mode 100644 _sources/generated/spreg.GM_Endog_Error_Hom.rst.txt create mode 100644 _sources/generated/spreg.GM_Endog_Error_Hom_Regimes.rst.txt create mode 100644 _sources/generated/spreg.GM_Endog_Error_Regimes.rst.txt create mode 100644 _sources/generated/spreg.GM_Error.rst.txt create mode 100644 _sources/generated/spreg.GM_Error_Het.rst.txt create mode 100644 _sources/generated/spreg.GM_Error_Het_Regimes.rst.txt create mode 100644 _sources/generated/spreg.GM_Error_Hom.rst.txt create mode 100644 _sources/generated/spreg.GM_Error_Hom_Regimes.rst.txt create mode 100644 _sources/generated/spreg.GM_Error_Regimes.rst.txt create mode 100644 _sources/generated/spreg.GM_KKP.rst.txt create mode 100644 _sources/generated/spreg.GM_Lag.rst.txt create mode 100644 _sources/generated/spreg.GM_Lag_Regimes.rst.txt create mode 100644 _sources/generated/spreg.LMtests.rst.txt create mode 100644 _sources/generated/spreg.ML_Error.rst.txt create mode 100644 _sources/generated/spreg.ML_Error_Regimes.rst.txt create mode 100644 _sources/generated/spreg.ML_Lag.rst.txt create mode 100644 _sources/generated/spreg.ML_Lag_Regimes.rst.txt create mode 100644 _sources/generated/spreg.MoranRes.rst.txt create mode 100644 _sources/generated/spreg.OLS.rst.txt create mode 100644 _sources/generated/spreg.OLS_Regimes.rst.txt create mode 100644 _sources/generated/spreg.Panel_FE_Error.rst.txt create mode 100644 _sources/generated/spreg.Panel_FE_Lag.rst.txt create mode 100644 _sources/generated/spreg.Panel_RE_Error.rst.txt create mode 100644 _sources/generated/spreg.Panel_RE_Lag.rst.txt create mode 100644 _sources/generated/spreg.Probit.rst.txt create mode 100644 _sources/generated/spreg.SUR.rst.txt create mode 100644 _sources/generated/spreg.SURerrorGM.rst.txt create mode 100644 _sources/generated/spreg.SURerrorML.rst.txt create mode 100644 _sources/generated/spreg.SURlagIV.rst.txt create mode 100644 _sources/generated/spreg.Skater_reg.rst.txt create mode 100644 _sources/generated/spreg.TSLS.rst.txt create mode 100644 _sources/generated/spreg.TSLS_Regimes.rst.txt create mode 100644 _sources/generated/spreg.ThreeSLS.rst.txt create mode 100644 _sources/generated/spreg.akaike.rst.txt create mode 100644 _sources/generated/spreg.ar2.rst.txt create mode 100644 _sources/generated/spreg.breusch_pagan.rst.txt create mode 100644 _sources/generated/spreg.condition_index.rst.txt create mode 100644 _sources/generated/spreg.constant_check.rst.txt create mode 100644 _sources/generated/spreg.f_stat.rst.txt create mode 100644 _sources/generated/spreg.jarque_bera.rst.txt create mode 100644 _sources/generated/spreg.koenker_bassett.rst.txt create mode 100644 _sources/generated/spreg.lam_setp.rst.txt create mode 100644 _sources/generated/spreg.likratiotest.rst.txt create mode 100644 _sources/generated/spreg.log_likelihood.rst.txt create mode 100644 _sources/generated/spreg.panel_Hausman.rst.txt create mode 100644 _sources/generated/spreg.panel_LMerror.rst.txt create mode 100644 _sources/generated/spreg.panel_LMlag.rst.txt create mode 100644 _sources/generated/spreg.panel_rLMerror.rst.txt create mode 100644 _sources/generated/spreg.panel_rLMlag.rst.txt create mode 100644 _sources/generated/spreg.r2.rst.txt create mode 100644 _sources/generated/spreg.schwarz.rst.txt create mode 100644 _sources/generated/spreg.se_betas.rst.txt create mode 100644 _sources/generated/spreg.surLMe.rst.txt create mode 100644 _sources/generated/spreg.surLMlag.rst.txt create mode 100644 _sources/generated/spreg.sur_lmtest.rst.txt create mode 100644 _sources/generated/spreg.sur_lrtest.rst.txt create mode 100644 _sources/generated/spreg.sur_setp.rst.txt create mode 100644 _sources/generated/spreg.t_stat.rst.txt create mode 100644 _sources/generated/spreg.vif.rst.txt create mode 100644 _sources/generated/spreg.white.rst.txt create mode 100644 _sources/installation.rst.txt create mode 100644 _sources/notebooks/GM_Lag_example.ipynb.txt create mode 100644 _sources/notebooks/Panel_FE_example.ipynb.txt create mode 100644 _sources/notebooks/skater_reg.ipynb.txt create mode 100644 _sources/references.rst.txt create mode 100644 _sources/tutorials.rst.txt create mode 100644 _static/_sphinx_javascript_frameworks_compat.js create mode 100644 _static/bootstrap-2.3.2/css/bootstrap-responsive.css create mode 100644 _static/bootstrap-2.3.2/css/bootstrap-responsive.min.css create mode 100644 _static/bootstrap-2.3.2/css/bootstrap.css create mode 100644 _static/bootstrap-2.3.2/css/bootstrap.min.css create mode 100644 _static/bootstrap-2.3.2/img/glyphicons-halflings-white.png create mode 100644 _static/bootstrap-2.3.2/img/glyphicons-halflings.png create mode 100644 _static/bootstrap-2.3.2/js/bootstrap.js create mode 100644 _static/bootstrap-2.3.2/js/bootstrap.min.js create mode 100644 _static/bootstrap-3.4.1/css/bootstrap-theme.css create mode 100644 _static/bootstrap-3.4.1/css/bootstrap-theme.css.map create mode 100644 _static/bootstrap-3.4.1/css/bootstrap-theme.min.css create mode 100644 _static/bootstrap-3.4.1/css/bootstrap-theme.min.css.map create mode 100644 _static/bootstrap-3.4.1/css/bootstrap.css create mode 100644 _static/bootstrap-3.4.1/css/bootstrap.css.map create mode 100644 _static/bootstrap-3.4.1/css/bootstrap.min.css create mode 100644 _static/bootstrap-3.4.1/css/bootstrap.min.css.map create mode 100644 _static/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.eot create mode 100644 _static/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.svg create mode 100644 _static/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.ttf create mode 100644 _static/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.woff create mode 100644 _static/bootstrap-3.4.1/fonts/glyphicons-halflings-regular.woff2 create mode 100644 _static/bootstrap-3.4.1/js/bootstrap.js create mode 100644 _static/bootstrap-3.4.1/js/bootstrap.min.js create mode 100644 _static/bootstrap-3.4.1/js/npm.js create mode 100644 _static/bootstrap-sphinx.css create mode 100644 _static/bootstrap-sphinx.js create mode 100644 _static/bootswatch-2.3.2/amelia/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/cerulean/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/cosmo/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/cyborg/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/flatly/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/img/glyphicons-halflings-white.png create mode 100644 _static/bootswatch-2.3.2/img/glyphicons-halflings.png create mode 100644 _static/bootswatch-2.3.2/journal/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/readable/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/simplex/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/slate/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/spacelab/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/spruce/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/superhero/bootstrap.min.css create mode 100644 _static/bootswatch-2.3.2/united/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/cerulean/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/cosmo/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/cyborg/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/darkly/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/flatly/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/fonts/glyphicons-halflings-regular.eot create mode 100644 _static/bootswatch-3.4.1/fonts/glyphicons-halflings-regular.svg create mode 100644 _static/bootswatch-3.4.1/fonts/glyphicons-halflings-regular.ttf create mode 100644 _static/bootswatch-3.4.1/fonts/glyphicons-halflings-regular.woff create mode 100644 _static/bootswatch-3.4.1/fonts/glyphicons-halflings-regular.woff2 create mode 100644 _static/bootswatch-3.4.1/journal/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/lumen/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/paper/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/readable/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/sandstone/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/simplex/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/slate/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/spacelab/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/superhero/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/united/bootstrap.min.css create mode 100644 _static/bootswatch-3.4.1/yeti/bootstrap.min.css create mode 100644 _static/images/pysal_favicon.ico create mode 100644 _static/jquery-3.6.0.js create mode 100644 _static/js/jquery-1.12.4.min.js create mode 100644 _static/js/jquery-fix.js create mode 100644 _static/plot_directive.css create mode 100644 _static/pysal-styles.css create mode 100644 _static/pysal_favicon.ico create mode 100644 _static/references.bib create mode 100644 _static/sphinx_highlight.js create mode 100644 _static/underscore-1.13.1.js create mode 100644 api.html create mode 100644 generated/spreg.AKtest.html create mode 100644 generated/spreg.GM_Combo.html create mode 100644 generated/spreg.GM_Combo_Het.html create mode 100644 generated/spreg.GM_Combo_Het_Regimes.html create mode 100644 generated/spreg.GM_Combo_Hom.html create mode 100644 generated/spreg.GM_Combo_Hom_Regimes.html create mode 100644 generated/spreg.GM_Combo_Regimes.html create mode 100644 generated/spreg.GM_Endog_Error.html create mode 100644 generated/spreg.GM_Endog_Error_Het.html create mode 100644 generated/spreg.GM_Endog_Error_Het_Regimes.html create mode 100644 generated/spreg.GM_Endog_Error_Hom.html create mode 100644 generated/spreg.GM_Endog_Error_Hom_Regimes.html create mode 100644 generated/spreg.GM_Endog_Error_Regimes.html create mode 100644 generated/spreg.GM_Error.html create mode 100644 generated/spreg.GM_Error_Het.html create mode 100644 generated/spreg.GM_Error_Het_Regimes.html create mode 100644 generated/spreg.GM_Error_Hom.html create mode 100644 generated/spreg.GM_Error_Hom_Regimes.html create mode 100644 generated/spreg.GM_Error_Regimes.html create mode 100644 generated/spreg.GM_KKP.html create mode 100644 generated/spreg.GM_Lag.html create mode 100644 generated/spreg.GM_Lag_Regimes.html create mode 100644 generated/spreg.LMtests.html create mode 100644 generated/spreg.ML_Error.html create mode 100644 generated/spreg.ML_Error_Regimes.html create mode 100644 generated/spreg.ML_Lag.html create mode 100644 generated/spreg.ML_Lag_Regimes.html create mode 100644 generated/spreg.MoranRes.html create mode 100644 generated/spreg.OLS.html create mode 100644 generated/spreg.OLS_Regimes.html create mode 100644 generated/spreg.Panel_FE_Error.html create mode 100644 generated/spreg.Panel_FE_Lag.html create mode 100644 generated/spreg.Panel_RE_Error.html create mode 100644 generated/spreg.Panel_RE_Lag.html create mode 100644 generated/spreg.Probit.html create mode 100644 generated/spreg.SUR.html create mode 100644 generated/spreg.SURerrorGM.html create mode 100644 generated/spreg.SURerrorML.html create mode 100644 generated/spreg.SURlagIV.html create mode 100644 generated/spreg.Skater_reg.html create mode 100644 generated/spreg.TSLS.html create mode 100644 generated/spreg.TSLS_Regimes.html create mode 100644 generated/spreg.ThreeSLS.html create mode 100644 generated/spreg.akaike.html create mode 100644 generated/spreg.ar2.html create mode 100644 generated/spreg.breusch_pagan.html create mode 100644 generated/spreg.condition_index.html create mode 100644 generated/spreg.constant_check.html create mode 100644 generated/spreg.f_stat.html create mode 100644 generated/spreg.jarque_bera.html create mode 100644 generated/spreg.koenker_bassett.html create mode 100644 generated/spreg.lam_setp.html create mode 100644 generated/spreg.likratiotest.html create mode 100644 generated/spreg.log_likelihood.html create mode 100644 generated/spreg.panel_Hausman.html create mode 100644 generated/spreg.panel_LMerror.html create mode 100644 generated/spreg.panel_LMlag.html create mode 100644 generated/spreg.panel_rLMerror.html create mode 100644 generated/spreg.panel_rLMlag.html create mode 100644 generated/spreg.r2.html create mode 100644 generated/spreg.schwarz.html create mode 100644 generated/spreg.se_betas.html create mode 100644 generated/spreg.surLMe.html create mode 100644 generated/spreg.surLMlag.html create mode 100644 generated/spreg.sur_lmtest.html create mode 100644 generated/spreg.sur_lrtest.html create mode 100644 generated/spreg.sur_setp.html create mode 100644 generated/spreg.t_stat.html create mode 100644 generated/spreg.vif.html create mode 100644 generated/spreg.white.html create mode 100644 installation.html create mode 100644 notebooks/GM_Lag_example.html create mode 100644 notebooks/GM_Lag_example.ipynb create mode 100644 notebooks/Panel_FE_example.html create mode 100644 notebooks/Panel_FE_example.ipynb create mode 100644 notebooks/skater_reg.html create mode 100644 notebooks/skater_reg.ipynb create mode 100644 references.html create mode 100644 tutorials.html diff --git a/_images/notebooks_skater_reg_11_1.png b/_images/notebooks_skater_reg_11_1.png new file mode 100644 index 0000000000000000000000000000000000000000..fa439b378743d79a874d591d702dee2501745bf4 GIT binary patch literal 94753 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≫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 V-UZT%R2bk;l>I1EBV`iu{{Zqr`qlsd literal 0 HcmV?d00001 diff --git a/_images/notebooks_skater_reg_9_0.png b/_images/notebooks_skater_reg_9_0.png new file mode 100644 index 0000000000000000000000000000000000000000..843e518ca4f0228aef6240fdb50b7f97d8d8d33b GIT binary patch literal 28472 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 Z@exzsKB5dt{twJ_HNXG> literal 0 HcmV?d00001 diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 00000000..c54a7f4b --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,175 @@ + + + + + + + Overview: module code — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/diagnostics.html b/_modules/spreg/diagnostics.html new file mode 100644 index 00000000..91718699 --- /dev/null +++ b/_modules/spreg/diagnostics.html @@ -0,0 +1,1533 @@ + + + + + + + spreg.diagnostics — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.diagnostics

+"""
+Diagnostics for regression estimations. 
+        
+"""
+__author__ = (
+    "Luc Anselin luc.anselin@asu.edu, Nicholas Malizia nicholas.malizia@asu.edu "
+)
+
+from math import sqrt, pi
+
+from libpysal.common import MISSINGVALUE
+import numpy as np
+import numpy.linalg as la
+import scipy.sparse as SP
+from scipy import stats
+
+from .utils import spmultiply, sphstack, spmin, spmax
+
+
+__all__ = [
+    "f_stat",
+    "t_stat",
+    "r2",
+    "ar2",
+    "se_betas",
+    "log_likelihood",
+    "akaike",
+    "schwarz",
+    "condition_index",
+    "jarque_bera",
+    "breusch_pagan",
+    "white",
+    "koenker_bassett",
+    "vif",
+    "likratiotest",
+    "constant_check",
+]
+
+
+
[docs]def f_stat(reg): + """ + Calculates the f-statistic and associated p-value of the + regression. :cite:`Greene2003`. + (For two stage least squares see f_stat_tsls) + + Parameters + ---------- + reg : regression object + output instance from a regression model + + Returns + ---------- + fs_result : tuple + includes value of F statistic and associated p-value + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the F-statistic for the regression. + + >>> testresult = spreg.f_stat(reg) + + Print the results tuple, including the statistic and its significance. + + >>> print("%12.12f"%testresult[0],"%12.12f"%testresult[1]) + 28.385629224695 0.000000009341 + + """ + k = reg.k # (scalar) number of ind. vars (includes constant) + n = reg.n # (scalar) number of observations + utu = reg.utu # (scalar) residual sum of squares + predy = reg.predy # (array) vector of predicted values (n x 1) + mean_y = reg.mean_y # (scalar) mean of dependent observations + Q = utu + U = np.sum((predy - mean_y) ** 2) + fStat = (U / (k - 1)) / (Q / (n - k)) + pValue = stats.f.sf(fStat, k - 1, n - k) + fs_result = (fStat, pValue) + return fs_result
+ + +def t_stat(reg, z_stat=False): + """ + Calculates the t-statistics (or z-statistics) and associated + p-values. :cite:`Greene2003` + + Parameters + ---------- + reg : regression object + output instance from a regression model + z_stat : boolean + If True run z-stat instead of t-stat + + Returns + ------- + ts_result : list of tuples + each tuple includes value of t statistic (or z + statistic) and associated p-value + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate t-statistics for the regression coefficients. + + >>> testresult = spreg.t_stat(reg) + + Print the tuples that contain the t-statistics and their significances. + + >>> print("%12.12f"%testresult[0][0], "%12.12f"%testresult[0][1], "%12.12f"%testresult[1][0], "%12.12f"%testresult[1][1], "%12.12f"%testresult[2][0], "%12.12f"%testresult[2][1]) + 14.490373143689 0.000000000000 -4.780496191297 0.000018289595 -2.654408642718 0.010874504910 + """ + + k = reg.k # (scalar) number of ind. vars (includes constant) + n = reg.n # (scalar) number of observations + vm = reg.vm # (array) coefficients of variance matrix (k x k) + betas = reg.betas # (array) coefficients of the regressors (1 x k) + variance = vm.diagonal() + tStat = betas[list(range(0, len(vm)))].reshape( + len(vm), + ) / np.sqrt(variance) + ts_result = [] + for t in tStat: + if z_stat: + ts_result.append((t, stats.norm.sf(abs(t)) * 2)) + else: + ts_result.append((t, stats.t.sf(abs(t), n - k) * 2)) + return ts_result + + +
[docs]def r2(reg): + """ + Calculates the R^2 value for the regression. :cite:`Greene2003` + + Parameters + ---------- + reg : regression object + output instance from a regression model + + Returns + ---------- + r2_result : float + value of the coefficient of determination for the + regression + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the R^2 value for the regression. + + >>> testresult = spreg.r2(reg) + + Print the result. + + >>> print("%1.8f"%testresult) + 0.55240404 + + """ + y = reg.y # (array) vector of dep observations (n x 1) + mean_y = reg.mean_y # (scalar) mean of dep observations + utu = reg.utu # (scalar) residual sum of squares + ss_tot = ((y - mean_y) ** 2).sum(0) + r2 = 1 - utu / ss_tot + r2_result = r2[0] + return r2_result
+ + +
[docs]def ar2(reg): + """ + Calculates the adjusted R^2 value for the regression. :cite:`Greene2003` + + Parameters + ---------- + reg : regression object + output instance from a regression model + + Returns + ---------- + ar2_result : float + value of R^2 adjusted for the number of explanatory + variables. + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the adjusted R^2 value for the regression. + >>> testresult = spreg.ar2(reg) + + Print the result. + + >>> print("%1.8f"%testresult) + 0.53294335 + + """ + k = reg.k # (scalar) number of ind. variables (includes constant) + n = reg.n # (scalar) number of observations + ar2_result = 1 - (1 - r2(reg)) * (n - 1) / (n - k) + return ar2_result
+ + +
[docs]def se_betas(reg): + """ + Calculates the standard error of the regression coefficients. :cite:`Greene2003` + + Parameters + ---------- + reg : regression object + output instance from a regression model + + Returns + ---------- + se_result : array + includes standard errors of each coefficient (1 x k) + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the standard errors of the regression coefficients. + + >>> testresult = spreg.se_betas(reg) + + Print the vector of standard errors. + + >>> testresult + array([4.73548613, 0.33413076, 0.10319868]) + + """ + vm = reg.vm # (array) coefficients of variance matrix (k x k) + variance = vm.diagonal() + se_result = np.sqrt(variance) + return se_result
+ + +
[docs]def log_likelihood(reg): + """ + Calculates the log-likelihood value for the regression. :cite:`Greene2003` + + Parameters + ---------- + reg : regression object + output instance from a regression model + + Returns + ------- + ll_result : float + value for the log-likelihood of the regression. + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the log-likelihood for the regression. + + >>> testresult = spreg.log_likelihood(reg) + + Print the result. + + >>> testresult + -187.3772388121491 + + """ + n = reg.n # (scalar) number of observations + utu = reg.utu # (scalar) residual sum of squares + ll_result = -0.5 * (n * (np.log(2 * pi)) + n * np.log(utu / n) + (utu / (utu / n))) + return ll_result
+ + +
[docs]def akaike(reg): + """ + Calculates the Akaike Information Criterion. :cite:`Akaike1974` + + Parameters + ---------- + reg : regression object + output instance from a regression model + + Returns + ------- + aic_result : scalar + value for Akaike Information Criterion of the + regression. + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the Akaike Information Criterion (AIC). + + >>> testresult = spreg.akaike(reg) + + Print the result. + + >>> testresult + 380.7544776242982 + + """ + k = reg.k # (scalar) number of explanatory vars (including constant) + try: # ML estimation, logll already exists + # spatial coefficient included in k + aic_result = 2.0 * k - 2.0 * reg.logll + except AttributeError: # OLS case + n = reg.n # (scalar) number of observations + utu = reg.utu # (scalar) residual sum of squares + aic_result = 2 * k + n * (np.log((2 * np.pi * utu) / n) + 1) + return aic_result
+ + +
[docs]def schwarz(reg): + """ + Calculates the Schwarz Information Criterion. :cite:`Schwarz1978` + + Parameters + ---------- + reg : regression object + output instance from a regression model + + Returns + ------- + bic_result : scalar + value for Schwarz (Bayesian) Information Criterion of + the regression. + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the Schwarz Information Criterion. + + >>> testresult = spreg.schwarz(reg) + + Print the results. + + >>> np.round(testresult, 5) + 386.42994 + + """ + n = reg.n # (scalar) number of observations + k = reg.k # (scalar) number of ind. variables (including constant) + try: # ML case logll already computed + # spatial coeff included in k + sc_result = k * np.log(n) - 2.0 * reg.logll + except AttributeError: # OLS case + utu = reg.utu # (scalar) residual sum of squares + sc_result = k * np.log(n) + n * (np.log((2 * np.pi * utu) / n) + 1) + return sc_result
+ + +
[docs]def condition_index(reg): + """ + Calculates the multicollinearity condition index according to Belsey, + Kuh and Welsh (1980) :cite:`Belsley1980`. + + Parameters + ---------- + reg : regression object + output instance from a regression model + + Returns + ------- + ci_result : float + scalar value for the multicollinearity condition + index. + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the condition index to check for multicollinearity. + + >>> testresult = spreg.condition_index(reg) + + Print the result. + + >>> print("%1.3f"%testresult) + 6.542 + + """ + if hasattr(reg, "xtx"): + xtx = reg.xtx # (array) k x k projection matrix (includes constant) + elif hasattr(reg, "hth"): + xtx = reg.hth # (array) k x k projection matrix (includes constant) + diag = np.diagonal(xtx) + scale = xtx / diag + eigval = np.linalg.eigvals(scale) + max_eigval = max(eigval) + min_eigval = min(eigval) + ci_result = sqrt(max_eigval / min_eigval) + return ci_result
+ + +
[docs]def jarque_bera(reg): + """ + Jarque-Bera test for normality in the residuals. :cite:`Jarque1980` + + Parameters + ---------- + reg : regression object + output instance from a regression model + + Returns + ------- + jb_result : dictionary + contains the statistic (jb) for the Jarque-Bera test + and the associated p-value (p-value) + df : integer + degrees of freedom for the test (always 2) + jb : float + value of the test statistic + pvalue : float + p-value associated with the statistic (chi^2 + distributed with 2 df) + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"), "r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the Jarque-Bera test for normality of residuals. + + >>> testresult = spreg.jarque_bera(reg) + + Print the degrees of freedom for the test. + + >>> testresult['df'] + 2 + + Print the test statistic. + + >>> print("%1.3f"%testresult['jb']) + 1.836 + + Print the associated p-value. + + >>> print("%1.4f"%testresult['pvalue']) + 0.3994 + + """ + n = reg.n # (scalar) number of observations + u = reg.u # (array) residuals from regression + u2 = u**2 + u3 = u**3 + u4 = u**4 + mu2 = np.mean(u2) + mu3 = np.mean(u3) + mu4 = np.mean(u4) + S = mu3 / (mu2 ** (1.5)) # skewness measure + K = mu4 / (mu2**2) # kurtosis measure + jb = n * (((S**2) / 6) + ((K - 3) ** 2) / 24) + pvalue = stats.chisqprob(jb, 2) + jb_result = {"df": 2, "jb": jb, "pvalue": pvalue} + return jb_result
+ + +
[docs]def breusch_pagan(reg, z=None): + """ + Calculates the Breusch-Pagan test statistic to check for + heteroscedasticity. :cite:`Breusch1979` + + Parameters + ---------- + reg : regression object + output instance from a regression model + z : array + optional input for specifying an alternative set of + variables (Z) to explain the observed variance. By + default this is a matrix of the squared explanatory + variables (X**2) with a constant added to the first + column if not already present. In the default case, + the explanatory variables are squared to eliminate + negative values. + + Returns + ------- + bp_result : dictionary + contains the statistic (bp) for the test and the + associated p-value (p-value) + bp : float + scalar value for the Breusch-Pagan test statistic + df : integer + degrees of freedom associated with the test (k) + pvalue : float + p-value associated with the statistic (chi^2 + distributed with k df) + + Notes + ----- + x attribute in the reg object must have a constant term included. This is + standard for spreg.OLS so no testing done to confirm constant. + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"), "r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the Breusch-Pagan test for heteroscedasticity. + + >>> testresult = spreg.breusch_pagan(reg) + + Print the degrees of freedom for the test. + + >>> testresult['df'] + 2 + + Print the test statistic. + + >>> print("%1.3f"%testresult['bp']) + 7.900 + + Print the associated p-value. + + >>> print("%1.4f"%testresult['pvalue']) + 0.0193 + + """ + e2 = reg.u**2 + e = reg.u + n = reg.n + k = reg.k + ete = reg.utu + + den = ete / n + g = e2 / den - 1.0 + + if z == None: + x = reg.x + # constant = constant_check(x) + # if constant == False: + # z = np.hstack((np.ones((n,1)),x))**2 + # else: + # z = x**2 + z = spmultiply(x, x) + else: + # constant = constant_check(z) + # if constant == False: + # z = np.hstack((np.ones((n,1)),z)) + pass + + n, p = z.shape + + # Check to identify any duplicate columns in Z + omitcolumn = [] + for i in range(p): + current = z[:, i] + for j in range(p): + check = z[:, j] + if i < j: + test = abs(current - check).sum() + if test == 0: + omitcolumn.append(j) + + uniqueomit = set(omitcolumn) + omitcolumn = list(uniqueomit) + + # Now the identified columns must be removed (done in reverse to + # prevent renumbering) + omitcolumn.sort() + omitcolumn.reverse() + for c in omitcolumn: + z = np.delete(z, c, 1) + n, p = z.shape + + df = p - 1 + + # Now that the variables are prepared, we calculate the statistic + zt = np.transpose(z) + gt = np.transpose(g) + gtz = np.dot(gt, z) + ztg = np.dot(zt, g) + ztz = np.dot(zt, z) + ztzi = la.inv(ztz) + + part1 = np.dot(gtz, ztzi) + part2 = np.dot(part1, ztg) + bp_array = 0.5 * part2 + bp = bp_array[0, 0] + + pvalue = stats.chisqprob(bp, df) + bp_result = {"df": df, "bp": bp, "pvalue": pvalue} + return bp_result
+ + +
[docs]def white(reg): + """ + Calculates the White test to check for heteroscedasticity. :cite:`White1980` + + Parameters + ---------- + reg : regression object + output instance from a regression model + + Returns + ------- + white_result : dictionary + contains the statistic (white), degrees of freedom + (df) and the associated p-value (pvalue) for the + White test. + white : float + scalar value for the White test statistic. + df : integer + degrees of freedom associated with the test + pvalue : float + p-value associated with the statistic (chi^2 + distributed with k df) + + Notes + ----- + x attribute in the reg object must have a constant term included. This is + standard for spreg.OLS so no testing done to confirm constant. + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the White test for heteroscedasticity. + + >>> testresult = spreg.white(reg) + + Print the degrees of freedom for the test. + + >>> print(testresult['df']) + 5 + + Print the test statistic. + + >>> print("%1.3f"%testresult['wh']) + 19.946 + + Print the associated p-value. + + >>> print("%1.4f"%testresult['pvalue']) + 0.0013 + + """ + e = reg.u**2 + k = int(reg.k) + n = int(reg.n) + y = reg.y + X = reg.x + # constant = constant_check(X) + + # Check for constant, if none add one, see Greene 2003, pg. 222 + # if constant == False: + # X = np.hstack((np.ones((n,1)),X)) + + # Check for multicollinearity in the X matrix + ci = condition_index(reg) + if ci > 30: + white_result = "Not computed due to multicollinearity." + return white_result + + # Compute cross-products and squares of the regression variables + if type(X).__name__ == "ndarray": + A = np.zeros((n, (k * (k + 1)) // 2)) + elif type(X).__name__ == "csc_matrix" or type(X).__name__ == "csr_matrix": + # this is probably inefficient + A = SP.lil_matrix((n, (k * (k + 1)) // 2)) + else: + raise Exception("unknown X type, %s" % type(X).__name__) + counter = 0 + for i in range(k): + for j in range(i, k): + v = spmultiply(X[:, i], X[:, j], False) + A[:, counter] = v + counter += 1 + + # Append the original variables + A = sphstack(X, A) # note: this also converts a LIL to CSR + n, k = A.shape + + # Check to identify any duplicate or constant columns in A + omitcolumn = [] + for i in range(k): + current = A[:, i] + # remove all constant terms (will add a constant back later) + if spmax(current) == spmin(current): + omitcolumn.append(i) + pass + # do not allow duplicates + for j in range(k): + check = A[:, j] + if i < j: + test = abs(current - check).sum() + if test == 0: + omitcolumn.append(j) + uniqueomit = set(omitcolumn) + omitcolumn = list(uniqueomit) + + # Now the identified columns must be removed + if type(A).__name__ == "ndarray": + A = np.delete(A, omitcolumn, 1) + elif type(A).__name__ == "csc_matrix" or type(A).__name__ == "csr_matrix": + # this is probably inefficient + keepcolumn = list(range(k)) + for i in omitcolumn: + keepcolumn.remove(i) + A = A[:, keepcolumn] + else: + raise Exception("unknown A type, %s" % type(X).__name__) + A = sphstack(np.ones((A.shape[0], 1)), A) # add a constant back in + n, k = A.shape + + # Conduct the auxiliary regression and calculate the statistic + from . import ols as OLS + + aux_reg = OLS.BaseOLS(e, A) + aux_r2 = r2(aux_reg) + wh = aux_r2 * n + df = k - 1 + pvalue = stats.chisqprob(wh, df) + white_result = {"df": df, "wh": wh, "pvalue": pvalue} + return white_result
+ + +
[docs]def koenker_bassett(reg, z=None): + """ + Calculates the Koenker-Bassett test statistic to check for + heteroscedasticity. :cite:`Koenker1982,Greene2003` + + Parameters + ---------- + reg : regression output + output from an instance of a regression class + z : array + optional input for specifying an alternative set of + variables (Z) to explain the observed variance. By + default this is a matrix of the squared explanatory + variables (X**2) with a constant added to the first + column if not already present. In the default case, + the explanatory variables are squared to eliminate + negative values. + + Returns + ------- + kb_result : dictionary + contains the statistic (kb), degrees of freedom (df) + and the associated p-value (pvalue) for the test. + kb : float + scalar value for the Koenker-Bassett test statistic. + df : integer + degrees of freedom associated with the test + pvalue : float + p-value associated with the statistic (chi^2 + distributed) + + Notes + ----- + x attribute in the reg object must have a constant term included. This is + standard for spreg.OLS so no testing done to confirm constant. + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the Koenker-Bassett test for heteroscedasticity. + + >>> testresult = spreg.koenker_bassett(reg) + + Print the degrees of freedom for the test. + + >>> testresult['df'] + 2 + + Print the test statistic. + + >>> print("%1.3f"%testresult['kb']) + 5.694 + + Print the associated p-value. + + >>> print("%1.4f"%testresult['pvalue']) + 0.0580 + + """ + # The notation here matches that of Greene (2003). + u = reg.u**2 + e = reg.u + n = reg.n + k = reg.k + x = reg.x + ete = reg.utu + # constant = constant_check(x) + + ubar = ete / n + ubari = ubar * np.ones((n, 1)) + g = u - ubari + v = (1.0 / n) * np.sum((u - ubar) ** 2) + + if z == None: + x = reg.x + # constant = constant_check(x) + # if constant == False: + # z = np.hstack((np.ones((n,1)),x))**2 + # else: + # z = x**2 + z = spmultiply(x, x) + else: + # constant = constant_check(z) + # if constant == False: + # z = np.hstack((np.ones((n,1)),z)) + pass + + n, p = z.shape + + # Check to identify any duplicate columns in Z + omitcolumn = [] + for i in range(p): + current = z[:, i] + for j in range(p): + check = z[:, j] + if i < j: + test = abs(current - check).sum() + if test == 0: + omitcolumn.append(j) + + uniqueomit = set(omitcolumn) + omitcolumn = list(uniqueomit) + + # Now the identified columns must be removed (done in reverse to + # prevent renumbering) + omitcolumn.sort() + omitcolumn.reverse() + for c in omitcolumn: + z = np.delete(z, c, 1) + n, p = z.shape + + df = p - 1 + + # Conduct the auxiliary regression. + zt = np.transpose(z) + gt = np.transpose(g) + gtz = np.dot(gt, z) + ztg = np.dot(zt, g) + ztz = np.dot(zt, z) + ztzi = la.inv(ztz) + + part1 = np.dot(gtz, ztzi) + part2 = np.dot(part1, ztg) + kb_array = (1.0 / v) * part2 + kb = kb_array[0, 0] + + pvalue = stats.chisqprob(kb, df) + kb_result = {"kb": kb, "df": df, "pvalue": pvalue} + return kb_result
+ + +
[docs]def vif(reg): + """ + Calculates the variance inflation factor for each independent variable. + For the ease of indexing the results, the constant is currently + included. This should be omitted when reporting the results to the + output text. :cite:`Greene2003` + + Parameters + ---------- + reg : regression object + output instance from a regression model + + Returns + ------- + vif_result : list of tuples + each tuple includes the vif and the tolerance, the + order of the variables corresponds to their order in + the reg.x matrix + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Read the DBF associated with the Columbus data. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),"r") + + Create the dependent variable vector. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Create the matrix of independent variables. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. + + >>> reg = OLS(y,X) + + Calculate the variance inflation factor (VIF). + >>> testresult = spreg.vif(reg) + + Select the tuple for the income variable. + + >>> incvif = testresult[1] + + Print the VIF for income. + + >>> print("%12.12f"%incvif[0]) + 1.333117497189 + + Print the tolerance for income. + + >>> print("%12.12f"%incvif[1]) + 0.750121427487 + + Repeat for the home value variable. + + >>> hovalvif = testresult[2] + >>> print("%12.12f"%hovalvif[0]) + 1.333117497189 + >>> print("%12.12f"%hovalvif[1]) + 0.750121427487 + + """ + X = reg.x + n, k = X.shape + vif_result = [] + + for j in range(k): + Z = X.copy() + Z = np.delete(Z, j, 1) + y = X[:, j] + from . import ols as OLS + + aux = OLS.BaseOLS(y, Z) + mean_y = aux.mean_y + utu = aux.utu + ss_tot = sum((y - mean_y) ** 2) + if ss_tot == 0: + resj = MISSINGVALUE + else: + r2aux = 1 - utu / ss_tot + tolj = 1 - r2aux + vifj = 1 / tolj + resj = (vifj, tolj) + vif_result.append(resj) + return vif_result
+ + +
[docs]def constant_check(array): + """ + Checks to see numpy array includes a constant. + + Parameters + ---------- + array : array + an array of variables to be inspected + + Returns + ------- + constant : boolean + true signifies the presence of a constant + + Example + ------- + + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),"r") + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + >>> reg = OLS(y,X) + >>> spreg.constant_check(reg.x) + True + + """ + + n, k = array.shape + constant = False + for j in range(k): + variable = array[:, j] + varmin = variable.min() + varmax = variable.max() + if varmin == varmax: + constant = True + break + return constant
+ + +
[docs]def likratiotest(reg0, reg1): + """ + Likelihood ratio test statistic :cite:`Greene2003` + + Parameters + ---------- + reg0 : regression object + for constrained model (H0) + reg1 : regression object + for unconstrained model (H1) + + Returns + ------- + + likratio : dictionary + contains the statistic (likr), the degrees of + freedom (df) and the p-value (pvalue) + likr : float + likelihood ratio statistic + df : integer + degrees of freedom + p-value : float + p-value + + Examples + -------- + + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import scipy.stats as stats + >>> from spreg import ML_Lag, OLS + >>> from spreg import likratiotest + + Use the baltim sample data set + + >>> db = libpysal.io.open(examples.get_path("baltim.dbf"),'r') + >>> y_name = "PRICE" + >>> y = np.array(db.by_col(y_name)).T + >>> y.shape = (len(y),1) + >>> x_names = ["NROOM","NBATH","PATIO","FIREPL","AC","GAR","AGE","LOTSZ","SQFT"] + >>> x = np.array([db.by_col(var) for var in x_names]).T + >>> ww = libpysal.io.open(examples.get_path("baltim_q.gal")) + >>> w = ww.read() + >>> ww.close() + >>> w.transform = 'r' + + OLS regression + + >>> ols1 = OLS(y,x) + + ML Lag regression + + >>> mllag1 = ML_Lag(y,x,w) + + >>> lr = likratiotest(ols1,mllag1) + + >>> print("Likelihood Ratio Test: {0:.4f} df: {1} p-value: {2:.4f}".format(lr["likr"],lr["df"],lr["p-value"])) + Likelihood Ratio Test: 44.5721 df: 1 p-value: 0.0000 + + """ + + likratio = {} + + try: + likr = 2.0 * (reg1.logll - reg0.logll) + except AttributeError: + raise Exception("Missing or improper log-likelihoods in regression objects") + if likr < 0.0: # always enforces positive likelihood ratio + likr = -likr + pvalue = stats.chisqprob(likr, 1) + likratio = {"likr": likr, "df": 1, "p-value": pvalue} + return likratio
+ + +def _test(): + import doctest + + doctest.testmod() + + +if __name__ == "__main__": + _test() +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/diagnostics_panel.html b/_modules/spreg/diagnostics_panel.html new file mode 100644 index 00000000..33f023f1 --- /dev/null +++ b/_modules/spreg/diagnostics_panel.html @@ -0,0 +1,367 @@ + + + + + + + spreg.diagnostics_panel — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.diagnostics_panel

+"""
+Diagnostics for panel data estimation
+"""
+
+__author__ = "Wei Kang weikang9009@gmail.com, \
+              Pedro Amaral pedroamaral@cedeplar.ufmg.br, \
+              Pablo Estrada pabloestradace@gmail.com"
+
+import numpy as np
+import numpy.linalg as la
+from scipy import sparse as sp
+from . import user_output as USER
+from .ols import OLS
+from .utils import spdot
+from scipy import stats
+from .panel_utils import check_panel
+
+chisqprob = lambda chisq, df: stats.chi2.sf(chisq, df)
+
+__all__ = [
+    "panel_LMlag",
+    "panel_LMerror",
+    "panel_rLMlag",
+    "panel_rLMerror",
+    "panel_Hausman",
+]
+
+
+
[docs]def panel_LMlag(y, x, w): + """ + Lagrange Multiplier test on lag spatial autocorrelation in panel data. + :cite:`Anselin2008`. + + Parameters + ---------- + y : array + nxt or (nxt)x1 array for dependent variable + x : array + nx(txk) or (nxt)xk array for independent (exogenous) + variables, excluding the constant + w : pysal W object + Spatial weights object + + Returns + ------- + lme : tuple + Pair of statistic and p-value for the LM lag test. + """ + y, x, name_y, name_x, warn = check_panel(y, x, w, None, None) + x, name_x, warn = USER.check_constant(x, name_x) + ols = OLS(y, x) + n = w.n + t = y.shape[0] // n + W = w.full()[0] + Wsp_nt = sp.kron(sp.identity(t), w.sparse, format="csr") + wxb = spdot(Wsp_nt, ols.predy) + ww = spdot(W, W) + wTw = spdot(W.T, W) + trw = ww.diagonal().sum() + wTw.diagonal().sum() + num1 = np.asarray(sp.identity(t * n) - spdot(x, spdot(ols.xtxi, x.T))) + num2 = spdot(wxb.T, spdot(num1, wxb)) + num = num2 + (trw * trw * ols.sig2) + J = num / ols.sig2 + utwy = spdot(ols.u.T, spdot(Wsp_nt, y)) + lm = utwy ** 2 / (ols.sig2 ** 2 * J) + pval = chisqprob(lm, 1) + return (lm[0][0], pval[0][0])
+ + +
[docs]def panel_LMerror(y, x, w): + """ + Lagrange Multiplier test on error spatial autocorrelation in panel data. + :cite:`Anselin2008`. + + Parameters + ---------- + y : array + nxt or (nxt)x1 array for dependent variable + x : array + nx(txk) or (nxt)xk array for independent (exogenous) + variables, excluding the constant + w : pysal W object + Spatial weights object + + Returns + ------- + lme : tuple + Pair of statistic and p-value for the LM error test. + """ + y, x, name_y, name_x, warn = check_panel(y, x, w, None, None) + x, name_x, warn = USER.check_constant(x, name_x) + ols = OLS(y, x) + n = w.n + t = y.shape[0] // n + W = w.full()[0] + Wsp_nt = sp.kron(sp.identity(t), w.sparse, format="csr") + ww = spdot(W, W) + wTw = spdot(W.T, W) + trw = ww.diagonal().sum() + wTw.diagonal().sum() + utwu = spdot(ols.u.T, spdot(Wsp_nt, ols.u)) + lm = utwu ** 2 / (ols.sig2 ** 2 * t * trw) + pval = chisqprob(lm, 1) + return (lm[0][0], pval[0][0])
+ + +
[docs]def panel_rLMlag(y, x, w): + """ + Robust Lagrange Multiplier test on lag spatial autocorrelation in + panel data. :cite:`Elhorst2014`. + + Parameters + ---------- + y : array + nxt or (nxt)x1 array for dependent variable + x : array + nx(txk) or (nxt)xk array for independent (exogenous) + variables, excluding the constant + w : pysal W object + Spatial weights object + + Returns + ------- + lme : tuple + Pair of statistic and p-value for the Robust LM lag test. + """ + y, x, name_y, name_x, warn = check_panel(y, x, w, None, None) + x, name_x, warn = USER.check_constant(x, name_x) + ols = OLS(y, x) + n = w.n + t = y.shape[0] // n + W = w.full()[0] + Wsp_nt = sp.kron(sp.identity(t), w.sparse, format="csr") + wxb = spdot(Wsp_nt, ols.predy) + ww = spdot(W, W) + wTw = spdot(W.T, W) + trw = ww.diagonal().sum() + wTw.diagonal().sum() + utwu = spdot(ols.u.T, spdot(Wsp_nt, ols.u)) + num1 = np.asarray(sp.identity(t * n) - spdot(x, spdot(ols.xtxi, x.T))) + num2 = spdot(wxb.T, spdot(num1, wxb)) + num = num2 + (t * trw * ols.sig2) + J = num / ols.sig2 + utwy = spdot(ols.u.T, spdot(Wsp_nt, y)) + lm = (utwy / ols.sig2 - utwu / ols.sig2) ** 2 / (J - t * trw) + pval = chisqprob(lm, 1) + return (lm[0][0], pval[0][0])
+ + +
[docs]def panel_rLMerror(y, x, w): + """ + Robust Lagrange Multiplier test on error spatial autocorrelation in + panel data. :cite:`Elhorst2014`. + + Parameters + ---------- + y : array + nxt or (nxt)x1 array for dependent variable + x : array + nx(txk) or (nxt)xk array for independent (exogenous) + variables, excluding the constant + w : pysal W object + Spatial weights object + + Returns + ------- + lme : tuple + Pair of statistic and p-value for the Robust LM error test. + """ + y, x, name_y, name_x, warn = check_panel(y, x, w, None, None) + x, name_x, warn = USER.check_constant(x, name_x) + ols = OLS(y, x) + n = w.n + t = y.shape[0] // n + W = w.full()[0] + Wsp_nt = sp.kron(sp.identity(t), w.sparse, format="csr") + wxb = spdot(Wsp_nt, ols.predy) + ww = spdot(W, W) + wTw = spdot(W.T, W) + trw = ww.diagonal().sum() + wTw.diagonal().sum() + utwu = spdot(ols.u.T, spdot(Wsp_nt, ols.u)) + num1 = np.asarray(sp.identity(t * n) - spdot(x, spdot(ols.xtxi, x.T))) + num2 = spdot(wxb.T, spdot(num1, wxb)) + num = num2 + (t * trw * ols.sig2) + J = num / ols.sig2 + utwy = spdot(ols.u.T, spdot(Wsp_nt, y)) + lm = (utwu / ols.sig2 - t * trw / J * utwy / ols.sig2) ** 2 / ( + t * trw * (1 - t * trw / J) + ) + pval = chisqprob(lm, 1) + return (lm[0][0], pval[0][0])
+ + +
[docs]def panel_Hausman(panel_fe, panel_re, sp_lag=True): + """ + Hausman test on panel data with spatial interactions. :cite:`Elhorst2014`. + + Parameters + ---------- + panel_fe : panel_fe + Instance from a fixed effects panel spatial regression + panel_re : panel_re + Instance from a random effects panel spatial regression + sp_lag : boolean + if True, calculate Hausman test for spatial lag model. + + Returns + ------- + h : tuple + Pair of statistic and p-value for the Hausman test. + """ + if hasattr(panel_fe, "rho") & hasattr(panel_re, "rho"): + d = panel_fe.betas - panel_re.betas[1:-1] + elif hasattr(panel_fe, "lam") & hasattr(panel_re, "lam"): + d = panel_fe.betas[0:-1] - panel_re.betas[1:-2] + else: + raise Exception("Only same spatial interaction allowed") + + vard = panel_re.varb[1:, 1:] - panel_fe.varb + vardi = la.inv(vard) + h = spdot(d.T, spdot(vardi, d)) + pval = chisqprob(h, panel_re.k) + return (h[0][0], pval[0][0])
+
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/diagnostics_sp.html b/_modules/spreg/diagnostics_sp.html new file mode 100644 index 00000000..5c323043 --- /dev/null +++ b/_modules/spreg/diagnostics_sp.html @@ -0,0 +1,917 @@ + + + + + + + spreg.diagnostics_sp — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.diagnostics_sp

+"""
+Spatial diagnostics module
+"""
+__author__ = "Luc Anselin luc.anselin@asu.edu, Daniel Arribas-Bel darribas@asu.edu"
+
+from .utils import spdot
+
+# from scipy.stats.stats import chisqprob
+from scipy import stats
+
+# stats.chisqprob = lambda chisq, df: stats.chi2.sf(chisq, df)
+chisqprob = lambda chisq, df: stats.chi2.sf(chisq, df)
+from scipy.stats import norm
+import numpy as np
+import numpy.linalg as la
+
+__all__ = ["LMtests", "MoranRes", "AKtest"]
+
+
+
[docs]class LMtests: + """ + Lagrange Multiplier tests. Implemented as presented in :cite:`Anselin1996a` + + Attributes + ---------- + + ols : OLS + OLS regression object + w : W + Spatial weights instance + tests : list + Lists of strings with the tests desired to be performed. + Values may be: + + * 'all': runs all the options (default) + * 'lme': LM error test + * 'rlme': Robust LM error test + * 'lml' : LM lag test + * 'rlml': Robust LM lag test + + Parameters + ---------- + + lme : tuple + (Only if 'lme' or 'all' was in tests). Pair of statistic and + p-value for the LM error test. + lml : tuple + (Only if 'lml' or 'all' was in tests). Pair of statistic and + p-value for the LM lag test. + rlme : tuple + (Only if 'rlme' or 'all' was in tests). Pair of statistic + and p-value for the Robust LM error test. + rlml : tuple + (Only if 'rlml' or 'all' was in tests). Pair of statistic + and p-value for the Robust LM lag test. + sarma : tuple + (Only if 'rlml' or 'all' was in tests). Pair of statistic + and p-value for the SARMA test. + + Examples + -------- + + >>> import numpy as np + >>> import libpysal + >>> from spreg import OLS + >>> import spreg + + Open the csv file to access the data for analysis + + >>> csv = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + + Pull out from the csv the files we need ('HOVAL' as dependent as well as + 'INC' and 'CRIME' as independent) and directly transform them into nx1 and + nx2 arrays, respectively + + >>> y = np.array([csv.by_col('HOVAL')]).T + >>> x = np.array([csv.by_col('INC'), csv.by_col('CRIME')]).T + + Create the weights object from existing .gal file + + >>> w = libpysal.io.open(libpysal.examples.get_path('columbus.gal'), 'r').read() + + Row-standardize the weight object (not required although desirable in some + cases) + + >>> w.transform='r' + + Run an OLS regression + + >>> ols = OLS(y, x) + + Run all the LM tests in the residuals. These diagnostics test for the + presence of remaining spatial autocorrelation in the residuals of an OLS + model and give indication about the type of spatial model. There are five + types: presence of a spatial lag model (simple and robust version), + presence of a spatial error model (simple and robust version) and joint presence + of both a spatial lag as well as a spatial error model. + + >>> lms = spreg.LMtests(ols, w) + + LM error test: + + >>> print(round(lms.lme[0],4), round(lms.lme[1],4)) + 3.0971 0.0784 + + LM lag test: + + >>> print(round(lms.lml[0],4), round(lms.lml[1],4)) + 0.9816 0.3218 + + Robust LM error test: + + >>> print(round(lms.rlme[0],4), round(lms.rlme[1],4)) + 3.2092 0.0732 + + Robust LM lag test: + + >>> print(round(lms.rlml[0],4), round(lms.rlml[1],4)) + 1.0936 0.2957 + + LM SARMA test: + + >>> print(round(lms.sarma[0],4), round(lms.sarma[1],4)) + 4.1907 0.123 + """ + +
[docs] def __init__(self, ols, w, tests=["all"]): + cache = spDcache(ols, w) + if tests == ["all"]: + tests = ["lme", "lml", "rlme", "rlml", "sarma"] + if "lme" in tests: + self.lme = lmErr(ols, w, cache) + if "lml" in tests: + self.lml = lmLag(ols, w, cache) + if "rlme" in tests: + self.rlme = rlmErr(ols, w, cache) + if "rlml" in tests: + self.rlml = rlmLag(ols, w, cache) + if "sarma" in tests: + self.sarma = lmSarma(ols, w, cache)
+ + +
[docs]class MoranRes: + """ + Moran's I for spatial autocorrelation in residuals from OLS regression + + + Parameters + ---------- + ols : OLS + OLS regression object + w : W + Spatial weights instance + z : boolean + If set to True computes attributes eI, vI and zI. Due to computational burden of vI, defaults to False. + + Attributes + ---------- + I : float + Moran's I statistic + eI : float + Moran's I expectation + vI : float + Moran's I variance + zI : float + Moran's I standardized value + + Examples + -------- + + >>> import numpy as np + >>> import libpysal + >>> from spreg import OLS + >>> import spreg + + Open the csv file to access the data for analysis + + >>> csv = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + + Pull out from the csv the files we need ('HOVAL' as dependent as well as + 'INC' and 'CRIME' as independent) and directly transform them into nx1 and + nx2 arrays, respectively + + >>> y = np.array([csv.by_col('HOVAL')]).T + >>> x = np.array([csv.by_col('INC'), csv.by_col('CRIME')]).T + + Create the weights object from existing .gal file + + >>> w = libpysal.io.open(libpysal.examples.get_path('columbus.gal'), 'r').read() + + Row-standardize the weight object (not required although desirable in some + cases) + + >>> w.transform='r' + + Run an OLS regression + + >>> ols = OLS(y, x) + + Run Moran's I test for residual spatial autocorrelation in an OLS model. + This computes the traditional statistic applying a correction in the + expectation and variance to account for the fact it comes from residuals + instead of an independent variable + + >>> m = spreg.MoranRes(ols, w, z=True) + + Value of the Moran's I statistic: + + >>> print(round(m.I,4)) + 0.1713 + + Value of the Moran's I expectation: + + >>> print(round(m.eI,4)) + -0.0345 + + Value of the Moran's I variance: + + >>> print(round(m.vI,4)) + 0.0081 + + Value of the Moran's I standardized value. This is + distributed as a standard Normal(0, 1) + + >>> print(round(m.zI,4)) + 2.2827 + + P-value of the standardized Moran's I value (z): + + >>> print(round(m.p_norm,4)) + 0.0224 + """ + +
[docs] def __init__(self, ols, w, z=False): + cache = spDcache(ols, w) + self.I = get_mI(ols, w, cache) + if z: + self.eI = get_eI(ols, w, cache) + self.vI = get_vI(ols, w, self.eI, cache) + self.zI, self.p_norm = get_zI(self.I, self.eI, self.vI)
+ + +
[docs]class AKtest: + """ + Moran's I test of spatial autocorrelation for IV estimation. + Implemented following the original reference :cite:`Anselin1997` + + + Parameters + ---------- + + iv : TSLS + Regression object from TSLS class + w : W + Spatial weights instance + case : string + Flag for special cases (default to 'nosp'): + + * 'nosp': Only NO spatial end. reg. + * 'gen': General case (spatial lag + end. reg.) + + Attributes + ---------- + + mi : float + Moran's I statistic for IV residuals + ak : float + Square of corrected Moran's I for residuals + :math:`ak = \dfrac{N \times I^*}{\phi^2}`. + Note: if case='nosp' then it simplifies to the LMerror + p : float + P-value of the test + + Examples + -------- + + We first need to import the needed modules. Numpy is needed to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. The TSLS is required to run the model on + which we will perform the tests. + + >>> import numpy as np + >>> import libpysal + >>> from spreg import TSLS, GM_Lag, AKtest + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"),'r') + + Before being able to apply the diagnostics, we have to run a model and, + for that, we need the input variables. Extract the CRIME column (crime + rates) from the DBF file and make it the dependent variable for the + regression. Note that PySAL requires this to be an numpy array of shape + (n, 1) as opposed to the also common shape of (n, ) that other packages + accept. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) vector from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this model adds a vector of ones to the + independent variables passed in, but this can be overridden by passing + constant=False. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + + In this case, we consider HOVAL (home value) as an endogenous regressor, + so we acknowledge that by reading it in a different category. + + >>> yd = [] + >>> yd.append(db.by_col("HOVAL")) + >>> yd = np.array(yd).T + + In order to properly account for the endogeneity, we have to pass in the + instruments. Let us consider DISCBD (distance to the CBD) is a good one: + + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + + Now we are good to run the model. It is an easy one line task. + + >>> reg = TSLS(y, X, yd, q=q) + + Now we are concerned with whether our non-spatial model presents spatial + autocorrelation in the residuals. To assess this possibility, we can run + the Anselin-Kelejian test, which is a version of the classical LM error + test adapted for the case of residuals from an instrumental variables (IV) + regression. First we need an extra object, the weights matrix, which + includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``columbus.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are good to run the test. It is a very simple task: + + >>> ak = AKtest(reg, w) + + And explore the information obtained: + + >>> print('AK test: %f\tP-value: %f'%(ak.ak, ak.p)) + AK test: 4.642895 P-value: 0.031182 + + The test also accomodates the case when the residuals come from an IV + regression that includes a spatial lag of the dependent variable. The only + requirement needed is to modify the ``case`` parameter when we call + ``AKtest``. First, let us run a spatial lag model: + + >>> reg_lag = GM_Lag(y, X, yd, q=q, w=w) + + And now we can run the AK test and obtain similar information as in the + non-spatial model. + + >>> ak_sp = AKtest(reg, w, case='gen') + >>> print('AK test: %f\tP-value: %f'%(ak_sp.ak, ak_sp.p)) + AK test: 1.157593 P-value: 0.281965 + + """ + +
[docs] def __init__(self, iv, w, case="nosp"): + if case == "gen": + cache = spDcache(iv, w) + self.mi, self.ak, self.p = akTest(iv, w, cache) + elif case == "nosp": + cache = spDcache(iv, w) + self.mi = get_mI(iv, w, cache) + self.ak, self.p = lmErr(iv, w, cache) + else: + print( + """\n + Fix the optional argument 'case' to match the requirements: + * 'gen': General case (spatial lag + end. reg.) + * 'nosp': No spatial end. reg. + \n""" + )
+ + +class spDcache: + """ + Helper class to compute reusable pieces in the spatial diagnostics module + ... + + Parameters + ---------- + + reg : OLS_dev, TSLS_dev, STSLS_dev + Instance from a regression class + w : W + Spatial weights instance + + Attributes + ---------- + + j : array + 1x1 array with the result from: + :math:`J = \dfrac{1}{[(WX\beta)' M (WX\beta) + T \sigma^2]}` + wu : array + nx1 array with spatial lag of the residuals + utwuDs : array + 1x1 array with the result from: + :math:`utwuDs = \dfrac{u' W u}{\tilde{\sigma^2}}` + utwyDs : array + 1x1 array with the result from: + :math:`utwyDs = \dfrac{u' W y}{\tilde{\sigma^2}}` + t : array + 1x1 array with the result from : + :math:` T = tr[(W' + W) W]` + trA : float + Trace of A as in Cliff & Ord (1981) + + """ + + def __init__(self, reg, w): + self.reg = reg + self.w = w + self._cache = {} + + @property + def j(self): + if "j" not in self._cache: + wxb = self.w.sparse * self.reg.predy + wxb2 = np.dot(wxb.T, wxb) + xwxb = spdot(self.reg.x.T, wxb) + num1 = wxb2 - np.dot(xwxb.T, np.dot(self.reg.xtxi, xwxb)) + num = num1 + (self.t * self.reg.sig2n) + den = self.reg.n * self.reg.sig2n + self._cache["j"] = num / den + return self._cache["j"] + + @property + def wu(self): + if "wu" not in self._cache: + self._cache["wu"] = self.w.sparse * self.reg.u + return self._cache["wu"] + + @property + def utwuDs(self): + if "utwuDs" not in self._cache: + res = np.dot(self.reg.u.T, self.wu) / self.reg.sig2n + self._cache["utwuDs"] = res + return self._cache["utwuDs"] + + @property + def utwyDs(self): + if "utwyDs" not in self._cache: + res = np.dot(self.reg.u.T, self.w.sparse * self.reg.y) + self._cache["utwyDs"] = res / self.reg.sig2n + return self._cache["utwyDs"] + + @property + def t(self): + if "t" not in self._cache: + prod = (self.w.sparse.T + self.w.sparse) * self.w.sparse + self._cache["t"] = np.sum(prod.diagonal()) + return self._cache["t"] + + @property + def trA(self): + if "trA" not in self._cache: + xtwx = spdot(self.reg.x.T, spdot(self.w.sparse, self.reg.x)) + mw = np.dot(self.reg.xtxi, xtwx) + self._cache["trA"] = np.sum(mw.diagonal()) + return self._cache["trA"] + + @property + def AB(self): + """ + Computes A and B matrices as in Cliff-Ord 1981, p. 203 + """ + if "AB" not in self._cache: + U = (self.w.sparse + self.w.sparse.T) / 2.0 + z = spdot(U, self.reg.x, array_out=False) + c1 = spdot(self.reg.x.T, z, array_out=False) + c2 = spdot(z.T, z, array_out=False) + G = self.reg.xtxi + A = spdot(G, c1) + B = spdot(G, c2) + self._cache["AB"] = [A, B] + return self._cache["AB"] + + +def lmErr(reg, w, spDcache): + """ + LM error test. Implemented as presented in eq. (9) of Anselin et al. + (1996) :cite:`Anselin1996a`. + + Attributes + ---------- + reg : OLS_dev, TSLS_dev, STSLS_dev + Instance from a regression class + w : W + Spatial weights instance + spDcache : spDcache + Instance of spDcache class + + Returns + ------- + lme : tuple + Pair of statistic and p-value for the LM error test. + + """ + lm = spDcache.utwuDs ** 2 / spDcache.t + pval = chisqprob(lm, 1) + return (lm[0][0], pval[0][0]) + + +def lmLag(ols, w, spDcache): + """ + LM lag test. Implemented as presented in eq. (13) of Anselin et al. + (1996) :cite:`Anselin1996a`. + + Attributes + ---------- + ols : OLS_dev + Instance from an OLS_dev regression + w : W + Spatial weights instance + spDcache : spDcache + Instance of spDcache class + + Returns + ------- + lml : tuple + Pair of statistic and p-value for the LM lag test. + + """ + lm = spDcache.utwyDs ** 2 / (ols.n * spDcache.j) + pval = chisqprob(lm, 1) + return (lm[0][0], pval[0][0]) + + +def rlmErr(ols, w, spDcache): + """ + Robust LM error test. Implemented as presented in eq. (8) of Anselin et + al. (1996) :cite:`Anselin1996a`. + + NOTE: eq. (8) has an errata, the power -1 in the denominator + should be inside the square bracket. + + Attributes + ---------- + ols : OLS_dev + Instance from an OLS_dev regression + w : W + Spatial weights instance + spDcache : spDcache + Instance of spDcache class + + Returns + ------- + rlme : tuple + Pair of statistic and p-value for the Robust LM error test. + + """ + nj = ols.n * spDcache.j + num = (spDcache.utwuDs - (spDcache.t * spDcache.utwyDs) / nj) ** 2 + den = spDcache.t * (1.0 - (spDcache.t / nj)) + lm = num / den + pval = chisqprob(lm, 1) + return (lm[0][0], pval[0][0]) + + +def rlmLag(ols, w, spDcache): + """ + Robust LM lag test. Implemented as presented in eq. (12) of Anselin et al. + (1996) :cite:`Anselin1996a`. + + Attributes + ---------- + ols : OLS_dev + Instance from an OLS_dev regression + w : W + Spatial weights instance + spDcache : spDcache + Instance of spDcache class + + Returns + ------- + rlml : tuple + Pair of statistic and p-value for the Robust LM lag test. + + """ + lm = (spDcache.utwyDs - spDcache.utwuDs) ** 2 / ((ols.n * spDcache.j) - spDcache.t) + pval = chisqprob(lm, 1) + return (lm[0][0], pval[0][0]) + + +def lmSarma(ols, w, spDcache): + """ + LM error test. Implemented as presented in eq. (15) of Anselin et al. + (1996) :cite:`Anselin1996a`. + + Attributes + ---------- + ols : OLS_dev + Instance from an OLS_dev regression + w : W + Spatial weights instance + spDcache : spDcache + Instance of spDcache class + + Returns + ------- + sarma : tuple + Pair of statistic and p-value for the LM sarma test. + + """ + + first = (spDcache.utwyDs - spDcache.utwuDs) ** 2 / (w.n * spDcache.j - spDcache.t) + secnd = spDcache.utwuDs ** 2 / spDcache.t + lm = first + secnd + pval = chisqprob(lm, 2) + return (lm[0][0], pval[0][0]) + + +def get_mI(reg, w, spDcache): + """ + Moran's I statistic of spatial autocorrelation as showed in Cliff & Ord + (1981) :cite:`clifford1981`, p. 201-203 + + Attributes + ---------- + reg : OLS_dev, TSLS_dev, STSLS_dev + Instance from a regression class + w : W + Spatial weights instance + spDcache : spDcache + Instance of spDcache class + + Returns + ------- + moran : float + Statistic Moran's I test. + + """ + mi = (w.n * np.dot(reg.u.T, spDcache.wu)) / (w.s0 * reg.utu) + return mi[0][0] + + +def get_vI(ols, w, ei, spDcache): + """ + Moran's I variance coded as in :cite:`clifford1981` (p. 201-203) and R's spdep + """ + A = spDcache.AB[0] + trA2 = np.dot(A, A) + trA2 = np.sum(trA2.diagonal()) + + B = spDcache.AB[1] + trB = np.sum(B.diagonal()) * 4.0 + vi = (w.n ** 2 / (w.s0 ** 2 * (w.n - ols.k) * (w.n - ols.k + 2.0))) * ( + w.s1 + 2.0 * trA2 - trB - ((2.0 * (spDcache.trA ** 2)) / (w.n - ols.k)) + ) + return vi + + +def get_eI(ols, w, spDcache): + """ + Moran's I expectation using matrix M + """ + return -(w.n * spDcache.trA) / (w.s0 * (w.n - ols.k)) + + +def get_zI(I, ei, vi): + """ + Standardized I + + Returns two-sided p-values as provided in the GeoDa family + """ + z = abs((I - ei) / np.sqrt(vi)) + pval = norm.sf(z) * 2.0 + return (z, pval) + + +def akTest(iv, w, spDcache): + """ + Computes AK-test for the general case (end. reg. + sp. lag) + + Parameters + ---------- + + iv : STSLS_dev + Instance from spatial 2SLS regression + w : W + Spatial weights instance + spDcache : spDcache + Instance of spDcache class + + Attributes + ---------- + mi : float + Moran's I statistic for IV residuals + ak : float + Square of corrected Moran's I for residuals: + :math:`ak = \dfrac{N \times I^*}{\phi^2}` + p : float + P-value of the test + + """ + mi = get_mI(iv, w, spDcache) + # Phi2 + etwz = spdot(iv.u.T, spdot(w.sparse, iv.z)) + a = np.dot(etwz, np.dot(iv.varb, etwz.T)) + s12 = (w.s0 / w.n) ** 2 + phi2 = (spDcache.t + (4.0 / iv.sig2n) * a) / (s12 * w.n) + ak = w.n * mi ** 2 / phi2 + pval = chisqprob(ak, 1) + return (mi, ak[0][0], pval[0][0]) + + +def comfac_test(lambd, beta, gamma, vm): + """ + Computes the Spatial Common Factor Hypothesis test as shown in Anselin (1988, p. 226-229) + + Parameters + ---------- + + lambd : float + Spatial autoregressive coefficient (as in lambd*Wy) + beta : array + Coefficients of the exogenous (not spatially lagged) variables, without the constant (as in X*beta) + gamma : array + coefficients of the spatially lagged exogenous variables (as in WX*gamma) + vm : array + Variance-covariance matrix of the coefficients + Obs. Needs to match the order of theta' = [beta', gamma', lambda] + + Returns + ------- + W : float + Wald statistic + pvalue : float + P value for Wald statistic calculated as a Chi sq. distribution + with k-1 degrees of freedom + + """ + g = lambd * beta + gamma + G = np.vstack((lambd * np.eye(beta.shape[0]), np.eye(beta.shape[0]), beta.T)) + + GVGi = la.inv(np.dot(G.T, np.dot(vm, G))) + W = np.dot(g.T, np.dot(GVGi, g))[0][0] + df = G.shape[1] + pvalue = chisqprob(W, df) + return W, pvalue + + +def _test(): + import doctest + + doctest.testmod() + + +if __name__ == "__main__": + _test() +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/diagnostics_sur.html b/_modules/spreg/diagnostics_sur.html new file mode 100644 index 00000000..bb9cd043 --- /dev/null +++ b/_modules/spreg/diagnostics_sur.html @@ -0,0 +1,496 @@ + + + + + + + spreg.diagnostics_sur — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.diagnostics_sur

+"""
+Diagnostics for SUR and 3SLS estimation
+"""
+
+__author__ = "Luc Anselin lanselin@gmail.com,    \
+             Pedro V. Amaral pedrovma@gmail.com  \
+             Tony Aburaad taburaad@uchicago.edu"
+
+
+import numpy as np
+import scipy.stats as stats
+import numpy.linalg as la
+from .sur_utils import sur_dict2mat, sur_mat2dict, sur_corr, spdot
+from .regimes import buildR1var, wald_test
+
+
+__all__ = ["sur_setp", "sur_lrtest", "sur_lmtest", "lam_setp", "surLMe", "surLMlag"]
+
+
+
[docs]def sur_setp(bigB, varb): + """ + Utility to compute standard error, t and p-value + + Parameters + ---------- + bigB : dictionary + of regression coefficient estimates, + one vector by equation + varb : array + variance-covariance matrix of coefficients + + Returns + ------- + surinfdict : dictionary + with standard error, t-value, and + p-value array, one for each equation + + """ + vvb = varb.diagonal() + n_eq = len(bigB.keys()) + bigK = np.zeros((n_eq, 1), dtype=np.int_) + for r in range(n_eq): + bigK[r] = bigB[r].shape[0] + b = sur_dict2mat(bigB) + se = np.sqrt(vvb) + se.resize(len(se), 1) + t = np.divide(b, se) + tp = stats.norm.sf(abs(t)) * 2 + surinf = np.hstack((se, t, tp)) + surinfdict = sur_mat2dict(surinf, bigK) + return surinfdict
+ + +
[docs]def lam_setp(lam, vm): + """ + Standard errors, t-test and p-value for lambda in SUR Error ML + + Parameters + ---------- + lam : array + n_eq x 1 array with ML estimates for spatial error + autoregressive coefficient + vm : array + n_eq x n_eq subset of variance-covariance matrix for + lambda and Sigma in SUR Error ML + (needs to be subset from full vm) + + Returns + ------- + : tuple + with arrays for standard error, t-value and p-value + (each element in the tuple is an n_eq x 1 array) + + """ + vvb = vm.diagonal() + se = np.sqrt(vvb) + se.resize(len(se), 1) + t = np.divide(lam, se) + tp = stats.norm.sf(abs(t)) * 2 + return (se, t, tp)
+ + +
[docs]def sur_lrtest(n, n_eq, ldetS0, ldetS1): + """ + Likelihood Ratio test on off-diagonal elements of Sigma + + Parameters + ---------- + n : int + cross-sectional dimension (number of observations for an equation) + n_eq : int + number of equations + ldetS0 : float + log determinant of Sigma for OLS case + ldetS1 : float + log determinant of Sigma for SUR case (should be iterated) + + Returns + ------- + (lrtest,M,pvalue) : tuple + with value of test statistic (lrtest), + degrees of freedom (M, as an integer) + p-value + + """ + M = n_eq * (n_eq - 1) / 2.0 + lrtest = n * (ldetS0 - ldetS1) + pvalue = stats.chi2.sf(lrtest, M) + return (lrtest, int(M), pvalue)
+ + +
[docs]def sur_lmtest(n, n_eq, sig): + """ + Lagrange Multiplier test on off-diagonal elements of Sigma + + Parameters + ---------- + n : int + cross-sectional dimension (number of observations for an equation) + n_eq : int + number of equations + sig : array + inter-equation covariance matrix for null model (OLS) + + Returns + ------- + (lmtest,M,pvalue) : tuple + with value of test statistic (lmtest), + degrees of freedom (M, as an integer) + p-value + """ + R = sur_corr(sig) + tr = np.trace(np.dot(R.T, R)) + M = n_eq * (n_eq - 1) / 2.0 + lmtest = (n / 2.0) * (tr - n_eq) + pvalue = stats.chi2.sf(lmtest, M) + return (lmtest, int(M), pvalue)
+ + +
[docs]def surLMe(n_eq, WS, bigE, sig): + """ + Lagrange Multiplier test on error spatial autocorrelation in SUR + + Parameters + ---------- + n_eq : int + number of equations + WS : array + spatial weights matrix in sparse form + bigE : array + n x n_eq matrix of residuals by equation + sig : array + cross-equation error covariance matrix + + Returns + ------- + (LMe,n_eq,pvalue) : tuple + with value of statistic (LMe), degrees + of freedom (n_eq) and p-value + + """ + # spatially lagged residuals + WbigE = WS * bigE + # score + EWE = np.dot(bigE.T, WbigE) + sigi = la.inv(sig) + SEWE = sigi * EWE + # score = SEWE.sum(axis=1) + # score.resize(n_eq,1) + # note score is column sum of Sig_i * E'WE, a 1 by n_eq row vector + # previously stored as column + score = SEWE.sum(axis=0) + score.resize(1, n_eq) + + # trace terms + WW = WS * WS + trWW = np.sum(WW.diagonal()) + WTW = WS.T * WS + trWtW = np.sum(WTW.diagonal()) + # denominator + SiS = sigi * sig + Tii = trWW * np.identity(n_eq) + tSiS = trWtW * SiS + denom = Tii + tSiS + idenom = la.inv(denom) + # test statistic + # LMe = np.dot(np.dot(score.T,idenom),score)[0][0] + # score is now row vector + LMe = np.dot(np.dot(score, idenom), score.T)[0][0] + pvalue = stats.chi2.sf(LMe, n_eq) + return (LMe, n_eq, pvalue)
+ + +
[docs]def surLMlag(n_eq, WS, bigy, bigX, bigE, bigYP, sig, varb): + """ + Lagrange Multiplier test on lag spatial autocorrelation in SUR + + Parameters + ---------- + n_eq : int + number of equations + WS : spatial weights matrix in sparse form + bigy : dictionary + with y values + bigX : dictionary + with X values + bigE : array + n x n_eq matrix of residuals by equation + bigYP : array + n x n_eq matrix of predicted values by equation + sig : array + cross-equation error covariance matrix + varb : array + variance-covariance matrix for b coefficients (inverse of Ibb) + + Returns + ------- + (LMlag,n_eq,pvalue) : tuple + with value of statistic (LMlag), degrees + of freedom (n_eq) and p-value + + """ + # Score + Y = np.hstack([bigy[r] for r in range(n_eq)]) + WY = WS * Y + EWY = np.dot(bigE.T, WY) + sigi = la.inv(sig) + SEWE = sigi * EWY + score = SEWE.sum(axis=0) # column sums + score.resize(1, n_eq) # score as a row vector + + # I(rho,rho) as partitioned inverse, eq 72 + # trace terms + WW = WS * WS + trWW = np.sum(WW.diagonal()) # T1 + WTW = WS.T * WS + trWtW = np.sum(WTW.diagonal()) # T2 + + # I(rho,rho) + SiS = sigi * sig + Tii = trWW * np.identity(n_eq) # T1It + tSiS = trWtW * SiS + firstHalf = Tii + tSiS + WbigYP = WS * bigYP + inner = np.dot(WbigYP.T, WbigYP) + secondHalf = sigi * inner + Ipp = firstHalf + secondHalf # eq. 75 + + # I(b,b) inverse is varb + + # I(b,rho) + bp = sigi[0,] * spdot( + bigX[0].T, WbigYP + ) # initialize + for r in range(1, n_eq): + bpwork = ( + sigi[ + r, + ] + * spdot(bigX[r].T, WbigYP) + ) + bp = np.vstack((bp, bpwork)) + # partitioned part + i_inner = Ipp - np.dot(np.dot(bp.T, varb), bp) + # partitioned inverse of information matrix + Ippi = la.inv(i_inner) + + # test statistic + LMlag = np.dot(np.dot(score, Ippi), score.T)[0][0] + # p-value + pvalue = stats.chi2.sf(LMlag, n_eq) + return (LMlag, n_eq, pvalue)
+ + +def sur_chow(n_eq, bigK, bSUR, varb): + """ + test on constancy of regression coefficients across equations in + a SUR specification + + Note: requires a previous check on constancy of number of coefficients + across equations; no other checks are carried out, so it is possible + that the results are meaningless if the variables are not listed in + the same order in each equation. + + Parameters + ---------- + n_eq : int + number of equations + bigK : array + with the number of variables by equation (includes constant) + bSUR : dictionary + with the SUR regression coefficients by equation + varb : array + the variance-covariance matrix for the SUR regression + coefficients + + Returns + ------- + test : array + a list with for each coefficient (in order) a tuple with the + value of the test statistic, the degrees of freedom, and the + p-value + + """ + kr = bigK[0][0] + test = [] + bb = sur_dict2mat(bSUR) + kf = 0 + nr = n_eq + df = n_eq - 1 + for i in range(kr): + Ri = buildR1var(i, kr, kf, 0, nr) + tt, p = wald_test(bb, Ri, np.zeros((df, 1)), varb) + test.append((tt, df, p)) + return test + + +def sur_joinrho(n_eq, bigK, bSUR, varb): + """ + Test on joint significance of spatial autoregressive coefficient in SUR + + Parameters + ---------- + n_eq : int + number of equations + bigK : array + n_eq x 1 array with number of variables by equation + (includes constant term, exogenous and endogeneous and + spatial lag) + bSUR : dictionary + with regression coefficients by equation, with + the spatial autoregressive term as last + varb : array + variance-covariance matrix for regression coefficients + + Returns + ------- + : tuple + with test statistic, degrees of freedom, p-value + + """ + bb = sur_dict2mat(bSUR) + R = np.zeros((n_eq, varb.shape[0])) + q = np.zeros((n_eq, 1)) + kc = -1 + for i in range(n_eq): + kc = kc + bigK[i] + R[i, kc] = 1 + w, p = wald_test(bb, R, q, varb) + return (w, n_eq, p) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/diagnostics_tsls.html b/_modules/spreg/diagnostics_tsls.html new file mode 100644 index 00000000..2b19c00c --- /dev/null +++ b/_modules/spreg/diagnostics_tsls.html @@ -0,0 +1,487 @@ + + + + + + + spreg.diagnostics_tsls — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.diagnostics_tsls

+"""
+Diagnostics for two stage least squares regression estimations. 
+        
+"""
+
+__author__ = (
+    "Luc Anselin luc.anselin@asu.edu, Nicholas Malizia nicholas.malizia@asu.edu "
+)
+
+import numpy as np
+from scipy import stats
+from scipy.stats import pearsonr
+
+__all__ = ["t_stat", "pr2_aspatial", "pr2_spatial"]
+
+
+
[docs]def t_stat(reg, z_stat=False): + """ + Calculates the t-statistics (or z-statistics) and associated p-values. + :cite:`Greene2003` + + Parameters + ---------- + reg : regression object + output instance from a regression model + z_stat : boolean + If True run z-stat instead of t-stat + + Returns + ------- + ts_result : list of tuples + each tuple includes value of t statistic (or z + statistic) and associated p-value + + Examples + -------- + + We first need to import the needed modules. Numpy is needed to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. The ``diagnostics`` module is used for the tests + we will show here and the OLS and TSLS are required to run the models on + which we will perform the tests. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg + >>> from spreg import OLS + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),'r') + + Before being able to apply the diagnostics, we have to run a model and, + for that, we need the input variables. Extract the CRIME column (crime + rates) from the DBF file and make it the dependent variable for the + regression. Note that PySAL requires this to be an numpy array of shape + (n, 1) as opposed to the also common shape of (n, ) that other packages + accept. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) and HOVAL (home value) vector from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this model adds a vector of ones to the + independent variables passed in, but this can be overridden by passing + constant=False. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("HOVAL")) + >>> X = np.array(X).T + + Run an OLS regression. Since it is a non-spatial model, all we need is the + dependent and the independent variable. + + >>> reg = OLS(y,X) + + Now we can perform a t-statistic on the model: + + >>> testresult = spreg.t_stat(reg) + >>> print("%12.12f"%testresult[0][0], "%12.12f"%testresult[0][1], "%12.12f"%testresult[1][0], "%12.12f"%testresult[1][1], "%12.12f"%testresult[2][0], "%12.12f"%testresult[2][1]) + 14.490373143689 0.000000000000 -4.780496191297 0.000018289595 -2.654408642718 0.010874504910 + + We can also use the z-stat. For that, we re-build the model so we consider + HOVAL as endogenous, instrument for it using DISCBD and carry out two + stage least squares (TSLS) estimation. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + >>> yd = [] + >>> yd.append(db.by_col("HOVAL")) + >>> yd = np.array(yd).T + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + + Once the variables are read as different objects, we are good to run the + model. + + >>> reg = spreg.TSLS(y, X, yd, q) + + With the output of the TSLS regression, we can perform a z-statistic: + + >>> testresult = spreg.t_stat(reg, z_stat=True) + >>> print("%12.10f"%testresult[0][0], "%12.10f"%testresult[0][1], "%12.10f"%testresult[1][0], "%12.10f"%testresult[1][1], "%12.10f"%testresult[2][0], "%12.10f"%testresult[2][1]) + 5.8452644705 0.0000000051 0.3676015668 0.7131703463 -1.9946891308 0.0460767956 + """ + + k = reg.k # (scalar) number of ind. vas (includes constant) + n = reg.n # (scalar) number of observations + vm = reg.vm # (array) coefficients of variance matrix (k x k) + betas = reg.betas # (array) coefficients of the regressors (1 x k) + variance = vm.diagonal() + tStat = betas.reshape( + len(betas), + ) / np.sqrt(variance) + ts_result = [] + for t in tStat: + if z_stat: + ts_result.append((t, stats.norm.sf(abs(t)) * 2)) + else: + ts_result.append((t, stats.t.sf(abs(t), n - k) * 2)) + return ts_result
+ + +def pr2_aspatial(tslsreg): + """ + Calculates the pseudo r^2 for the two stage least squares regression. + + Parameters + ---------- + tslsreg : two stage least squares regression object + output instance from a two stage least squares + regression model + + Returns + ------- + pr2_result : float + value of the squared pearson correlation between + the y and tsls-predicted y vectors + + Examples + -------- + + We first need to import the needed modules. Numpy is needed to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. The TSLS is required to run the model on + which we will perform the tests. + + >>> import numpy as np + >>> from spreg import TSLS, pr2_aspatial + >>> import libpysal + >>> from libpysal import examples + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),'r') + + Before being able to apply the diagnostics, we have to run a model and, + for that, we need the input variables. Extract the CRIME column (crime + rates) from the DBF file and make it the dependent variable for the + regression. Note that PySAL requires this to be an numpy array of shape + (n, 1) as opposed to the also common shape of (n, ) that other packages + accept. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) vector from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this model adds a vector of ones to the + independent variables passed in, but this can be overridden by passing + constant=False. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + + In this case, we consider HOVAL (home value) as an endogenous regressor, + so we acknowledge that by reading it in a different category. + + >>> yd = [] + >>> yd.append(db.by_col("HOVAL")) + >>> yd = np.array(yd).T + + In order to properly account for the endogeneity, we have to pass in the + instruments. Let us consider DISCBD (distance to the CBD) is a good one: + + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + + Now we are good to run the model. It is an easy one line task. + + >>> reg = TSLS(y, X, yd, q=q) + + In order to perform the pseudo R^2, we pass the regression object to the + function and we are done! + + >>> result = pr2_aspatial(reg) + >>> print("%1.6f"%result) + 0.279361 + + """ + + y = tslsreg.y + predy = tslsreg.predy + pr = pearsonr(y.flatten(), predy.flatten())[0] + pr2_result = float(pr**2) + return pr2_result + + +def pr2_spatial(tslsreg): + """ + Calculates the pseudo r^2 for the spatial two stage least squares + regression. + + Parameters + ---------- + stslsreg : spatial two stage least squares regression object + output instance from a spatial two stage least + squares regression model + + Returns + ------- + pr2_result : float + value of the squared pearson correlation between + the y and stsls-predicted y vectors + + Examples + -------- + + We first need to import the needed modules. Numpy is needed to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. The GM_Lag is required to run the model on + which we will perform the tests and the ``spreg.diagnostics`` module + contains the function with the test. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> import spreg as D + >>> from spreg import GM_Lag + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(examples.get_path("columbus.dbf"),'r') + + Extract the HOVAL column (home value) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) vectors from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this model adds a vector of ones to the + independent variables passed in, but this can be overridden by passing + constant=False. + + >>> X = np.array(db.by_col("INC")) + >>> X = np.reshape(X, (49,1)) + + In this case, we consider CRIME (crime rates) as an endogenous regressor, + so we acknowledge that by reading it in a different category. + + >>> yd = np.array(db.by_col("CRIME")) + >>> yd = np.reshape(yd, (49,1)) + + In order to properly account for the endogeneity, we have to pass in the + instruments. Let us consider DISCBD (distance to the CBD) is a good one: + + >>> q = np.array(db.by_col("DISCBD")) + >>> q = np.reshape(q, (49,1)) + + Since this test has a spatial component, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``columbus.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(examples.get_path("columbus.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + Now we are good to run the spatial lag model. Make sure you pass all the + parameters correctly and, if desired, pass the names of the variables as + well so when you print the summary (reg.summary) they are included: + + >>> reg = GM_Lag(y, X, w=w, yend=yd, q=q, w_lags=2, name_x=['inc'], name_y='hoval', name_yend=['crime'], name_q=['discbd'], name_ds='columbus') + + Once we have a regression object, we can perform the spatial version of + the pesudo R^2. It is as simple as one line! + + >>> result = pr2_spatial(reg) + >>> print("%1.6f"%result) + 0.299649 + + """ + + y = tslsreg.y + predy_e = tslsreg.predy_e + pr = pearsonr(y.flatten(), predy_e.flatten())[0] + pr2_result = float(pr**2) + return pr2_result + + +def _test(): + import doctest + + doctest.testmod() + + +if __name__ == "__main__": + _test() +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/error_sp.html b/_modules/spreg/error_sp.html new file mode 100644 index 00000000..88cec391 --- /dev/null +++ b/_modules/spreg/error_sp.html @@ -0,0 +1,1476 @@ + + + + + + + spreg.error_sp — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.error_sp

+"""
+Spatial Error Models module
+"""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu, \
+        Daniel Arribas-Bel darribas@asu.edu, \
+        Pedro V. Amaral pedro.amaral@asu.edu"
+
+import numpy as np
+from numpy import linalg as la
+from . import ols as OLS
+from .utils import set_endog, sp_att, optim_moments, get_spFilter, get_lags, spdot, RegressionPropsY, set_warn
+from . import twosls as TSLS
+from . import user_output as USER
+import pandas as pd
+from .output import output, _spat_pseudo_r2
+from .error_sp_het import GM_Error_Het, GM_Endog_Error_Het, GM_Combo_Het
+from .error_sp_hom import GM_Error_Hom, GM_Endog_Error_Hom, GM_Combo_Hom
+
+
+__all__ = ["GMM_Error", "GM_Error", "GM_Endog_Error", "GM_Combo"]
+
+
+class BaseGM_Error(RegressionPropsY):
+
+    """
+    GMM method for a spatial error model (note: no consistency checks
+    diagnostics or constant added); based on Kelejian and Prucha
+    (1998, 1999) :cite:`Kelejian1998` :cite:`Kelejian1999`.
+
+    Parameters
+    ----------
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, excluding the constant
+    w            : Sparse matrix
+                   Spatial weights sparse matrix
+
+    Attributes
+    ----------
+    betas        : array
+                   kx1 array of estimated coefficients
+    u            : array
+                   nx1 array of residuals
+    e_filtered   : array
+                   nx1 array of spatially filtered residuals
+    predy        : array
+                   nx1 array of predicted y values
+    n            : integer
+                   Number of observations
+    k            : integer
+                   Number of variables for which coefficients are estimated
+                   (including the constant)
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, including the constant
+    mean_y       : float
+                   Mean of dependent variable
+    std_y        : float
+                   Standard deviation of dependent variable
+    vm           : array
+                   Variance covariance matrix (kxk)
+    sig2         : float
+                   Sigma squared used in computations
+
+    Examples
+    --------
+
+    >>> import libpysal
+    >>> import numpy as np
+    >>> import spreg
+    >>> dbf = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r')
+    >>> y = np.array([dbf.by_col('HOVAL')]).T
+    >>> x = np.array([dbf.by_col('INC'), dbf.by_col('CRIME')]).T
+    >>> x = np.hstack((np.ones(y.shape),x))
+    >>> w = libpysal.io.open(libpysal.examples.get_path("columbus.gal"), 'r').read()
+    >>> w.transform='r'
+    >>> model = spreg.error_sp.BaseGM_Error(y, x, w=w.sparse)
+    >>> np.around(model.betas, decimals=4)
+    array([[47.6946],
+           [ 0.7105],
+           [-0.5505],
+           [ 0.3257]])
+    """
+
+    def __init__(self, y, x, w):
+
+        # 1a. OLS --> \tilde{betas}
+        ols = OLS.BaseOLS(y=y, x=x)
+        self.n, self.k = ols.x.shape
+        self.x = ols.x
+        self.y = ols.y
+
+        # 1b. GMM --> \tilde{\lambda1}
+        moments = _momentsGM_Error(w, ols.u)
+        lambda1 = optim_moments(moments)
+
+        # 2a. OLS -->\hat{betas}
+        xs = get_spFilter(w, lambda1, self.x)
+        ys = get_spFilter(w, lambda1, self.y)
+        ols2 = OLS.BaseOLS(y=ys, x=xs)
+
+        # Output
+        self.predy = spdot(self.x, ols2.betas)
+        self.u = y - self.predy
+        self.betas = np.vstack((ols2.betas, np.array([[lambda1]])))
+        self.sig2 = ols2.sig2n
+        self.e_filtered = self.u - lambda1 * w * self.u
+
+        self.vm = self.sig2 * ols2.xtxi
+        se_betas = np.sqrt(self.vm.diagonal())
+        self._cache = {}
+
+
+
[docs]class GM_Error(BaseGM_Error): + + """ + GMM method for a spatial error model, with results and diagnostics; based + on Kelejian and Prucha (1998, 1999) :cite:`Kelejian1998` :cite:`Kelejian1999`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + w : pysal W object + Spatial weights object (always needed) + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + vm : array + Variance covariance matrix (kxk) + sig2 : float + Sigma squared used in computations + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import libpysal + >>> import numpy as np + >>> from spreg import GM_Error + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> dbf = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + + Extract the HOVAL column (home values) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array([dbf.by_col('HOVAL')]).T + + Extract CRIME (crime) and INC (income) vectors from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this class adds a vector of ones to the + independent variables passed in. + + >>> names_to_extract = ['INC', 'CRIME'] + >>> x = np.array([dbf.by_col(name) for name in names_to_extract]).T + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will use + ``columbus.gal``, which contains contiguity relationships between the + observations in the Columbus dataset we are using throughout this example. + Note that, in order to read the file, not only to open it, we need to + append '.read()' at the end of the command. + + >>> w = libpysal.io.open(libpysal.examples.get_path("columbus.gal"), 'r').read() + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, his allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform='r' + + We are all set with the preliminars, we are good to run the model. In this + case, we will need the variables and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> model = GM_Error(y, x, w=w, name_y='hoval', name_x=['income', 'crime'], name_ds='columbus') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. Note that because we are running the classical GMM error + model from 1998/99, the spatial parameter is obtained as a point estimate, so + although you get a value for it (there are for coefficients under + model.betas), you cannot perform inference on it (there are only three + values in model.se_betas). + + >>> print(model.name_x) + ['CONSTANT', 'income', 'crime', 'lambda'] + >>> np.around(model.betas, decimals=4) + array([[47.6946], + [ 0.7105], + [-0.5505], + [ 0.3257]]) + >>> np.around(model.std_err, decimals=4) + array([12.412 , 0.5044, 0.1785]) + >>> np.around(model.z_stat, decimals=6) #doctest: +SKIP + array([[ 3.84261100e+00, 1.22000000e-04], + [ 1.40839200e+00, 1.59015000e-01], + [ -3.08424700e+00, 2.04100000e-03]]) + >>> round(model.sig2,4) + 198.5596 + + """ + +
[docs] def __init__( + self, y, x, w, slx_lags=0, vm=False, name_y=None, name_x=None, name_w=None, name_ds=None, latex=False + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + + self.title = "GM SPATIALLY WEIGHTED LEAST SQUARES" + if slx_lags >0: + lag_x = get_lags(w, x_constant[:, 1:], slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + self.title += " WITH SLX (SDEM)" + + BaseGM_Error.__init__(self, y=y, x=x_constant, w=w.sparse) + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x_constant) + self.name_x.append("lambda") + self.name_w = USER.set_name_w(name_w, w) + self.output = pd.DataFrame(self.name_x, columns=['var_names']) + self.output['var_type'] = ['x'] * (len(self.name_x) - 1) + ['lambda'] + self.output['regime'], self.output['equation'] = (0, 0) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +class BaseGM_Endog_Error(RegressionPropsY): + + """ + GMM method for a spatial error model with endogenous variables (note: no + consistency checks, diagnostics or constant added); based on Kelejian and + Prucha (1998, 1999) :cite:`Kelejian1998` :cite:`Kelejian1999`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : Sparse matrix + Spatial weights sparse matrix + + Attributes + ---------- + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + z : array + nxk array of variables (combination of x and yend) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + sig2 : float + Sigma squared used in computations + + Examples + -------- + + >>> import libpysal + >>> import numpy as np + >>> import spreg + >>> dbf = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + >>> y = np.array([dbf.by_col('CRIME')]).T + >>> x = np.array([dbf.by_col('INC')]).T + >>> x = np.hstack((np.ones(y.shape),x)) + >>> yend = np.array([dbf.by_col('HOVAL')]).T + >>> q = np.array([dbf.by_col('DISCBD')]).T + >>> w = libpysal.io.open(libpysal.examples.get_path("columbus.gal"), 'r').read() + >>> w.transform='r' + >>> model = spreg.error_sp.BaseGM_Endog_Error(y, x, yend, q, w=w.sparse) + >>> np.around(model.betas, decimals=4) + array([[82.5723], + [ 0.581 ], + [-1.4481], + [ 0.3499]]) + + """ + + def __init__(self, y, x, yend, q, w): + + # 1a. TSLS --> \tilde{betas} + tsls = TSLS.BaseTSLS(y=y, x=x, yend=yend, q=q) + self.n, self.k = tsls.z.shape + self.x = tsls.x + self.y = tsls.y + self.yend, self.z = tsls.yend, tsls.z + + # 1b. GMM --> \tilde{\lambda1} + moments = _momentsGM_Error(w, tsls.u) + lambda1 = optim_moments(moments) + + # 2a. 2SLS -->\hat{betas} + xs = get_spFilter(w, lambda1, self.x) + ys = get_spFilter(w, lambda1, self.y) + yend_s = get_spFilter(w, lambda1, self.yend) + tsls2 = TSLS.BaseTSLS(ys, xs, yend_s, h=tsls.h) + + # Output + self.betas = np.vstack((tsls2.betas, np.array([[lambda1]]))) + self.predy = spdot(tsls.z, tsls2.betas) + self.u = y - self.predy + self.sig2 = float(np.dot(tsls2.u.T, tsls2.u)) / self.n + self.e_filtered = self.u - lambda1 * w * self.u + self.vm = self.sig2 * tsls2.varb + self._cache = {} + + +
[docs]class GM_Endog_Error(BaseGM_Endog_Error): + + """ + GMM method for a spatial error model with endogenous variables, with + results and diagnostics; based on Kelejian and Prucha (1998, + 1999) :cite:`Kelejian1998` :cite:`Kelejian1999`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : pysal W object + Spatial weights object (always needed) + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + z : array + nxk array of variables (combination of x and yend) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + sig2 : float + Sigma squared used in computations + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import libpysal + >>> import numpy as np + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> dbf = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"),'r') + + Extract the CRIME column (crime rates) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array([dbf.by_col('CRIME')]).T + + Extract INC (income) vector from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this model adds a vector of ones to the + independent variables passed in. + + >>> x = np.array([dbf.by_col('INC')]).T + + In this case we consider HOVAL (home value) is an endogenous regressor. + We tell the model that this is so by passing it in a different parameter + from the exogenous variables (x). + + >>> yend = np.array([dbf.by_col('HOVAL')]).T + + Because we have endogenous variables, to obtain a correct estimate of the + model, we need to instrument for HOVAL. We use DISCBD (distance to the + CBD) for this and hence put it in the instruments parameter, 'q'. + + >>> q = np.array([dbf.by_col('DISCBD')]).T + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will use + ``columbus.gal``, which contains contiguity relationships between the + observations in the Columbus dataset we are using throughout this example. + Note that, in order to read the file, not only to open it, we need to + append '.read()' at the end of the command. + + >>> w = libpysal.io.open(libpysal.examples.get_path("columbus.gal"), 'r').read() + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform='r' + + We are all set with the preliminars, we are good to run the model. In this + case, we will need the variables (exogenous and endogenous), the + instruments and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import GM_Endog_Error + >>> model = GM_Endog_Error(y, x, yend, q, w=w, name_x=['inc'], name_y='crime', name_yend=['hoval'], name_q=['discbd'], name_ds='columbus') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. Note that because we are running the classical GMM error + model from 1998/99, the spatial parameter is obtained as a point estimate, so + although you get a value for it (there are for coefficients under + model.betas), you cannot perform inference on it (there are only three + values in model.se_betas). Also, this regression uses a two stage least + squares estimation method that accounts for the endogeneity created by the + endogenous variables included. + + >>> print(model.name_z) + ['CONSTANT', 'inc', 'hoval', 'lambda'] + >>> np.around(model.betas, decimals=4) + array([[82.5723], + [ 0.581 ], + [-1.4481], + [ 0.3499]]) + >>> np.around(model.std_err, decimals=4) + array([16.1382, 1.3545, 0.7862]) + + """ + +
[docs] def __init__( + self, + y, + x, + yend, + q, + w, + slx_lags=0, + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(y, x, yend, q) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + self.title = "GM SPATIALLY WEIGHTED TWO STAGE LEAST SQUARES" + if slx_lags >0: + lag_x = get_lags(w, x_constant[:, 1:], slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + self.title += " WITH SLX (SDEM)" + BaseGM_Endog_Error.__init__(self, y=y, x=x_constant, w=w.sparse, yend=yend, q=q) + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x_constant) + self.name_yend = USER.set_name_yend(name_yend, yend) + self.name_z = self.name_x + self.name_yend + self.name_z.append("lambda") + self.name_q = USER.set_name_q(name_q, q) + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.name_w = USER.set_name_w(name_w, w) + self.output = pd.DataFrame(self.name_z, + columns=['var_names']) + self.output['var_type'] = ['x'] * len(self.name_x) + ['yend'] * len(self.name_yend) + ['lambda'] + self.output['regime'], self.output['equation'] = (0, 0) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +
[docs]class GM_Combo(BaseGM_Endog_Error): + + """ + GMM method for a spatial lag and error model with endogenous variables, + with results and diagnostics; based on Kelejian and Prucha (1998, + 1999) :cite:`Kelejian1998` :cite:`Kelejian1999`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : pysal W object + Spatial weights object (always needed) + w_lags : integer + Orders of W to include as instruments for the spatially + lagged dependent variable. For example, w_lags=1, then + instruments are WX; if w_lags=2, then WX, WWX; and so on. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the General Nesting + Spatial Model (GNSM) type. + lag_q : boolean + If True, then include spatial lags of the additional + instruments (q) + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + e_pred : array + nx1 array of residuals (using reduced form) + predy : array + nx1 array of predicted y values + predy_e : array + nx1 array of predicted y values (using reduced form) + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + z : array + nxk array of variables (combination of x and yend) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + sig2 : float + Sigma squared used in computations (based on filtered + residuals) + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> from spreg import GM_Combo + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"),'r') + + Extract the CRIME column (crime rates) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) vector from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this model adds a vector of ones to the + independent variables passed in. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``columbus.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + The Combo class runs an SARAR model, that is a spatial lag+error model. + In this case we will run a simple version of that, where we have the + spatial effects as well as exogenous variables. Since it is a spatial + model, we have to pass in the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> reg = GM_Combo(y, X, w=w, name_y='crime', name_x=['income'], name_ds='columbus') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. Note that because we are running the classical GMM error + model from 1998/99, the spatial parameter is obtained as a point estimate, so + although you get a value for it (there are for coefficients under + model.betas), you cannot perform inference on it (there are only three + values in model.se_betas). Also, this regression uses a two stage least + squares estimation method that accounts for the endogeneity created by the + spatial lag of the dependent variable. We can check the betas: + + >>> print(reg.name_z) + ['CONSTANT', 'income', 'W_crime', 'lambda'] + >>> print(np.around(np.hstack((reg.betas[:-1],np.sqrt(reg.vm.diagonal()).reshape(3,1))),3)) + [[39.059 11.86 ] + [-1.404 0.391] + [ 0.467 0.2 ]] + + And lambda: + + >>> print('lambda: ', np.around(reg.betas[-1], 3)) + lambda: [-0.048] + + This class also allows the user to run a spatial lag+error model with the + extra feature of including non-spatial endogenous regressors. This means + that, in addition to the spatial lag and error, we consider some of the + variables on the right-hand side of the equation as endogenous and we + instrument for this. As an example, we will include HOVAL (home value) as + endogenous and will instrument with DISCBD (distance to the CSB). We first + need to read in the variables: + + >>> yd = [] + >>> yd.append(db.by_col("HOVAL")) + >>> yd = np.array(yd).T + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + + And then we can run and explore the model analogously to the previous combo: + + >>> reg = GM_Combo(y, X, yd, q, w=w, name_x=['inc'], name_y='crime', name_yend=['hoval'], name_q=['discbd'], name_ds='columbus') + >>> print(reg.name_z) + ['CONSTANT', 'inc', 'hoval', 'W_crime', 'lambda'] + >>> names = np.array(reg.name_z).reshape(5,1) + >>> print(np.hstack((names[0:4,:], np.around(np.hstack((reg.betas[:-1], np.sqrt(reg.vm.diagonal()).reshape(4,1))),4)))) + [['CONSTANT' '50.0944' '14.3593'] + ['inc' '-0.2552' '0.5667'] + ['hoval' '-0.6885' '0.3029'] + ['W_crime' '0.4375' '0.2314']] + + >>> print('lambda: ', np.around(reg.betas[-1], 3)) + lambda: [0.254] + + """ + +
[docs] def __init__( + self, + y, + x, + yend=None, + q=None, + w=None, + w_lags=1, + slx_lags=0, + lag_q=True, + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(y, x, yend, q) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + if slx_lags == 0: + yend2, q2 = set_endog(y, x_constant[:, 1:], w, yend, q, w_lags, lag_q) + else: + yend2, q2, wx = set_endog(y, x_constant[:, 1:], w, yend, q, w_lags, lag_q, slx_lags) + x_constant = np.hstack((x_constant, wx)) + + BaseGM_Endog_Error.__init__(self, y=y, x=x_constant, w=w.sparse, yend=yend2, q=q2) + + self.rho = self.betas[-2] + self.predy_e, self.e_pred, warn = sp_att( + w, self.y, self.predy, yend2[:, -1].reshape(self.n, 1), self.rho + ) + set_warn(self, warn) + self.title = "SPATIALLY WEIGHTED 2SLS - GM-COMBO MODEL" + if slx_lags > 0: + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + self.title += " WITH SLX (GNSM)" + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x_constant) + self.name_yend = USER.set_name_yend(name_yend, yend) + self.name_yend.append(USER.set_name_yend_sp(self.name_y)) + self.name_z = self.name_x + self.name_yend + self.name_z.append("lambda") + self.name_q = USER.set_name_q(name_q, q) + self.name_q.extend(USER.set_name_q_sp(self.name_x, w_lags, self.name_q, lag_q)) + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.name_w = USER.set_name_w(name_w, w) + self.output = pd.DataFrame(self.name_z, + columns=['var_names']) + self.output['var_type'] = ['x'] * len(self.name_x) + ['yend'] * (len(self.name_yend) - 1) + ['rho', 'lambda'] + self.output['regime'], self.output['equation'] = (0, 0) + self.other_top = _spat_pseudo_r2(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +class GMM_Error(GM_Error, GM_Endog_Error, GM_Combo, GM_Error_Het, GM_Endog_Error_Het, + GM_Combo_Het, GM_Error_Hom, GM_Endog_Error_Hom, GM_Combo_Hom): + + """ + Wrapper function to call any of the GMM methods for a spatial error model available in spreg + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + w : pysal W object + Spatial weights object (always needed) + yend : array + Two dimensional array with n rows and one column for each + endogenous variable (if any) + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (if any) + (note: this should not contain any variables from x) + estimator : string + Choice of estimator to be used. Options are: 'het', which + is robust to heteroskedasticity, 'hom', which assumes + homoskedasticity, and 'kp98', which does not provide + inference on the spatial parameter for the error term. + add_wy : boolean + If True, then a spatial lag of the dependent variable is included. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM or GNSM type. + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + **kwargs : keywords + Additional arguments to pass on to the estimators. + See the specific functions for details on what can be used. + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + vm : array + Variance covariance matrix (kxk) + sig2 : float + Sigma squared used in computations + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + name_yend : list of strings (optional) + Names of endogenous variables for use in output + name_z : list of strings (optional) + Names of exogenous and endogenous variables for use in + output + name_q : list of strings (optional) + Names of external instruments + name_h : list of strings (optional) + Names of all instruments used in ouput + + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``libpysal`` to + handle the weights and file management. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path("natregimes.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + Since we want to run a spatial error model, we need to specify + the spatial weights matrix that includes the spatial configuration of the + observations. To do that, we can open an already existing gal file or + create a new one. In this case, we will create one from ``NAT.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(nat.get_path("natregimes.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + The GMM_Error class can run error models and SARAR models, that is a spatial lag+error model. + In this example we will run a simple version of the latter, where we have the + spatial effects as well as exogenous variables. Since it is a spatial + model, we have to pass in the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import GMM_Error + >>> model = GMM_Error(y, x, w=w, add_wy=True, name_y=y_var, name_x=x_var, name_ds='NAT') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. + + >>> print(model.output) + var_names coefficients std_err zt_stat prob + 0 CONSTANT 2.176007 1.115807 1.950165 0.051156 + 1 PS90 1.108054 0.207964 5.328096 0.0 + 2 UE90 0.664362 0.061294 10.83893 0.0 + 3 W_HR90 -0.066539 0.154395 -0.430964 0.666494 + 4 lambda 0.765087 0.04268 17.926245 0.0 + + This class also allows the user to run a spatial lag+error model with the + extra feature of including non-spatial endogenous regressors. This means + that, in addition to the spatial lag and error, we consider some of the + variables on the right-hand side of the equation as endogenous and we + instrument for this. In this case we consider RD90 (resource deprivation) + as an endogenous regressor. We use FP89 (families below poverty) + for this and hence put it in the instruments parameter, 'q'. + + >>> yd_var = ['RD90'] + >>> yd = np.array([db.by_col(name) for name in yd_var]).T + >>> q_var = ['FP89'] + >>> q = np.array([db.by_col(name) for name in q_var]).T + + And then we can run and explore the model analogously to the previous combo: + + >>> model = GMM_Error(y, x, yend=yd, q=q, w=w, add_wy=True, name_y=y_var, name_x=x_var, name_yend=yd_var, name_q=q_var, name_ds='NAT') + >>> print(model.output) + var_names coefficients std_err zt_stat prob + 0 CONSTANT 5.44035 0.560476 9.706652 0.0 + 1 PS90 1.427042 0.1821 7.836572 0.0 + 2 UE90 -0.075224 0.050031 -1.503544 0.132699 + 3 RD90 3.316266 0.261269 12.692924 0.0 + 4 W_HR90 0.200314 0.057433 3.487777 0.000487 + 5 lambda 0.136933 0.070098 1.953457 0.050765 + + The class also allows for estimating a GNS model by adding spatial lags of the exogenous variables, using the argument slx_lags: + + >>> model = GMM_Error(y, x, w=w, add_wy=True, slx_lags=1, name_y=y_var, name_x=x_var, name_ds='NAT') + >>> print(model.output) + var_names coefficients std_err zt_stat prob + 0 CONSTANT -0.554756 0.551765 -1.00542 0.314695 + 1 PS90 1.09369 0.225895 4.841583 0.000001 + 2 UE90 0.697393 0.082744 8.428291 0.0 + 3 W_PS90 -1.533378 0.396651 -3.865811 0.000111 + 4 W_UE90 -1.107944 0.33523 -3.305028 0.00095 + 5 W_HR90 1.529277 0.389354 3.927728 0.000086 + 6 lambda -0.917928 0.079569 -11.53625 0.0 + + + """ + + def __init__( + self, y, x, w, yend=None, q=None, estimator='het', add_wy=False, slx_lags=0, vm=False, name_y=None, name_x=None, name_w=None, name_yend=None, + name_q=None, name_ds=None, latex=False, **kwargs): + + if estimator == 'het': + if yend is None and not add_wy: + GM_Error_Het.__init__(self, y=y, x=x, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_w=name_w, name_ds=name_ds, latex=latex, **kwargs) + elif yend is not None and not add_wy: + GM_Endog_Error_Het.__init__(self, y=y, x=x, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_ds=name_ds, latex=latex, **kwargs) + elif add_wy: + GM_Combo_Het.__init__(self, y=y, x=x, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_ds=name_ds, latex=latex, **kwargs) + else: + set_warn(self, 'Combination of arguments passed to GMM_Error not allowed. Using default arguments instead.') + GM_Error_Het.__init__(self, y=y, x=x, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_w=name_w, name_ds=name_ds, latex=latex) + elif estimator == 'hom': + if yend is None and not add_wy: + GM_Error_Hom.__init__(self, y=y, x=x, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_w=name_w, name_ds=name_ds, latex=latex, **kwargs) + elif yend is not None and not add_wy: + GM_Endog_Error_Hom.__init__(self, y=y, x=x, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_ds=name_ds, latex=latex, **kwargs) + elif add_wy: + GM_Combo_Hom.__init__(self, y=y, x=x, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_ds=name_ds, latex=latex, **kwargs) + else: + set_warn(self, 'Combination of arguments passed to GMM_Error not allowed. Using default arguments instead.') + GM_Error_Hom.__init__(self, y=y, x=x, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_w=name_w, name_ds=name_ds, latex=latex) + elif estimator == 'kp98': + if yend is None and not add_wy: + GM_Error.__init__(self, y=y, x=x, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_w=name_w, name_ds=name_ds, latex=latex, **kwargs) + elif yend is not None and not add_wy: + GM_Endog_Error.__init__(self, y=y, x=x, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_ds=name_ds, latex=latex, **kwargs) + elif add_wy: + GM_Combo.__init__(self, y=y, x=x, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_ds=name_ds, latex=latex, **kwargs) + else: + set_warn(self, 'Combination of arguments passed to GMM_Error not allowed. Using default arguments instead.') + GM_Error.__init__(self, y=y, x=x, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_w=name_w, name_ds=name_ds, latex=latex) + else: + set_warn(self, 'Combination of arguments passed to GMM_Error not allowed. Using default arguments instead.') + GM_Error_Het.__init__(self, y=y, x=x, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + name_w=name_w, name_ds=name_ds, latex=latex) + + +def _momentsGM_Error(w, u): + try: + wsparse = w.sparse + except: + wsparse = w + n = wsparse.shape[0] + u2 = np.dot(u.T, u) + wu = wsparse * u + uwu = np.dot(u.T, wu) + wu2 = np.dot(wu.T, wu) + wwu = wsparse * wu + uwwu = np.dot(u.T, wwu) + wwu2 = np.dot(wwu.T, wwu) + wuwwu = np.dot(wu.T, wwu) + wtw = wsparse.T * wsparse + trWtW = np.sum(wtw.diagonal()) + g = np.array([[u2[0][0], wu2[0][0], uwu[0][0]]]).T / n + G = ( + np.array( + [ + [2 * uwu[0][0], -wu2[0][0], n], + [2 * wuwwu[0][0], -wwu2[0][0], trWtW], + [uwwu[0][0] + wu2[0][0], -wuwwu[0][0], 0.0], + ] + ) + / n + ) + return [G, g] + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + + _test() + + import numpy as np + import libpysal + + db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + y = np.array(db.by_col("HOVAL")) + y = np.reshape(y, (49,1)) + X = [] + X.append(db.by_col("INC")) + X = np.array(X).T + yd = [] + yd.append(db.by_col("CRIME")) + yd = np.array(yd).T + q = [] + q.append(db.by_col("DISCBD")) + q = np.array(q).T + + w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + w.transform = 'r' + #reg = GM_Error(y, X, w=w, name_x=['inc'], name_y='hoval', name_ds='columbus', vm=True) + #reg = GM_Endog_Error(y, X, yd, q, w=w, name_x=['inc'], name_y='hoval', name_yend=['crime'], + # name_q=['discbd'], name_ds='columbus',vm=True) + reg = GM_Combo(y, X, yd, q, w=w, name_x=['inc'], name_y='hoval', name_yend=['crime'], name_q=['discbd'], + name_ds='columbus', vm=True) + + print(reg.output) + print(reg.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/error_sp_het.html b/_modules/spreg/error_sp_het.html new file mode 100644 index 00000000..9e0821d4 --- /dev/null +++ b/_modules/spreg/error_sp_het.html @@ -0,0 +1,1787 @@ + + + + + + + spreg.error_sp_het — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.error_sp_het

+"""
+Spatial Error with Heteroskedasticity family of models
+"""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu, \
+        Pedro V. Amaral pedro.amaral@asu.edu, \
+        Daniel Arribas-Bel darribas@asu.edu, \
+        David C. Folch david.folch@asu.edu \
+        Ran Wei rwei5@asu.edu"
+
+import numpy as np
+import numpy.linalg as la
+from . import ols as OLS
+from . import user_output as USER
+from . import twosls as TSLS
+from . import utils as UTILS
+from .utils import RegressionPropsY, spdot, set_endog, sphstack, set_warn, get_lags
+from scipy import sparse as SP
+from libpysal.weights.spatial_lag import lag_spatial
+import pandas as pd
+from .output import output, _summary_iteration, _spat_pseudo_r2
+
+__all__ = ["GM_Error_Het", "GM_Endog_Error_Het", "GM_Combo_Het"]
+
+
+class BaseGM_Error_Het(RegressionPropsY):
+
+    """
+    GMM method for a spatial error model with heteroskedasticity (note: no
+    consistency checks, diagnostics or constant added); based on
+    :cite:`Arraiz2010`, following :cite:`Anselin2011`.
+
+    Parameters
+    ----------
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, excluding the constant
+    w            : Sparse matrix
+                   Spatial weights sparse matrix
+    max_iter     : int
+                   Maximum number of iterations of steps 2a and 2b from
+                   :cite:`Arraiz2010`. Note: epsilon provides an additional
+                   stop condition.
+    epsilon      : float
+                   Minimum change in lambda required to stop iterations of
+                   steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides
+                   an additional stop condition.
+    step1c       : boolean
+                   If True, then include Step 1c from :cite:`Arraiz2010`.
+
+    Attributes
+    ----------
+    betas        : array
+                   kx1 array of estimated coefficients
+    u            : array
+                   nx1 array of residuals
+    e_filtered   : array
+                   nx1 array of spatially filtered residuals
+    predy        : array
+                   nx1 array of predicted y values
+    n            : integer
+                   Number of observations
+    k            : integer
+                   Number of variables for which coefficients are estimated
+                   (including the constant)
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, including the constant
+    iter_stop    : string
+                   Stop criterion reached during iteration of steps 2a and 2b
+                   from :cite:`Arraiz2010`.
+    iteration    : integer
+                   Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`.
+    mean_y       : float
+                   Mean of dependent variable
+    std_y        : float
+                   Standard deviation of dependent variable
+    vm           : array
+                   Variance covariance matrix (kxk)
+    xtx          : float
+                   X'X
+
+    Examples
+    --------
+    >>> import numpy as np
+    >>> import libpysal
+    >>> import spreg
+    >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r')
+    >>> y = np.array(db.by_col("HOVAL"))
+    >>> y = np.reshape(y, (49,1))
+    >>> X = []
+    >>> X.append(db.by_col("INC"))
+    >>> X.append(db.by_col("CRIME"))
+    >>> X = np.array(X).T
+    >>> X = np.hstack((np.ones(y.shape),X))
+    >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp"))
+    >>> w.transform = 'r'
+    >>> reg = spreg.error_sp_het.BaseGM_Error_Het(y, X, w.sparse, step1c=True)
+    >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4))
+    [[47.9963 11.479 ]
+     [ 0.7105  0.3681]
+     [-0.5588  0.1616]
+     [ 0.4118  0.168 ]]
+    """
+
+    def __init__(self, y, x, w, max_iter=1, epsilon=0.00001, step1c=False):
+
+        self.step1c = step1c
+        # 1a. OLS --> \tilde{betas}
+        ols = OLS.BaseOLS(y=y, x=x)
+        self.x, self.y, self.n, self.k, self.xtx = ols.x, ols.y, ols.n, ols.k, ols.xtx
+        wA1 = UTILS.get_A1_het(w)
+
+        # 1b. GMM --> \tilde{\lambda1}
+        moments = UTILS._moments2eqs(wA1, w, ols.u)
+        lambda1 = UTILS.optim_moments(moments)
+
+        if step1c:
+            # 1c. GMM --> \tilde{\lambda2}
+            sigma = get_psi_sigma(w, ols.u, lambda1)
+            vc1 = get_vc_het(w, wA1, sigma)
+            lambda2 = UTILS.optim_moments(moments, vc1)
+        else:
+            lambda2 = lambda1
+        lambda_old = lambda2
+
+        self.iteration, eps = 0, 1
+        while self.iteration < max_iter and eps > epsilon:
+            # 2a. reg -->\hat{betas}
+            xs = UTILS.get_spFilter(w, lambda_old, self.x)
+            ys = UTILS.get_spFilter(w, lambda_old, self.y)
+            ols_s = OLS.BaseOLS(y=ys, x=xs)
+            self.predy = spdot(self.x, ols_s.betas)
+            self.u = self.y - self.predy
+
+            # 2b. GMM --> \hat{\lambda}
+            sigma_i = get_psi_sigma(w, self.u, lambda_old)
+            vc_i = get_vc_het(w, wA1, sigma_i)
+            moments_i = UTILS._moments2eqs(wA1, w, self.u)
+            lambda3 = UTILS.optim_moments(moments_i, vc_i)
+            eps = abs(lambda3 - lambda_old)
+            lambda_old = lambda3
+            self.iteration += 1
+
+        self.iter_stop = UTILS.iter_msg(self.iteration, max_iter)
+
+        sigma = get_psi_sigma(w, self.u, lambda3)
+        vc3 = get_vc_het(w, wA1, sigma)
+        self.vm = get_vm_het(moments_i[0], lambda3, self, w, vc3)
+        self.betas = np.vstack((ols_s.betas, lambda3))
+        self.e_filtered = self.u - lambda3 * w * self.u
+        self._cache = {}
+
+
+
[docs]class GM_Error_Het(BaseGM_Error_Het): + """ + GMM method for a spatial error model with heteroskedasticity, with results + and diagnostics; based on :cite:`Arraiz2010`, following + :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + w : pysal W object + Spatial weights object + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + max_iter : int + Maximum number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + Note: epsilon provides an additional + stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + step1c : boolean + If True, then include Step 1c from :cite:`Arraiz2010`. + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + vm : array + Variance covariance matrix (kxk) + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + xtx : float + :math:`X'X` + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + + Extract the HOVAL column (home values) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) and CRIME (crime) vectors from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this class adds a vector of ones to the + independent variables passed in. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("CRIME")) + >>> X = np.array(X).T + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``columbus.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, his allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import GM_Error_Het + >>> reg = GM_Error_Het(y, X, w=w, step1c=True, name_y='home value', name_x=['income', 'crime'], name_ds='columbus') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. This class offers an error model that explicitly accounts + for heteroskedasticity and that unlike the models from + ``spreg.error_sp``, it allows for inference on the spatial + parameter. + + >>> print(reg.name_x) + ['CONSTANT', 'income', 'crime', 'lambda'] + + Hence, we find the same number of betas as of standard errors, + which we calculate taking the square root of the diagonal of the + variance-covariance matrix: + + >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4)) + [[47.9963 11.479 ] + [ 0.7105 0.3681] + [-0.5588 0.1616] + [ 0.4118 0.168 ]] + + Alternatively, we can have a summary of the output by typing: + print(reg.summary) + + """ + +
[docs] def __init__( + self, + y, + x, + w, + slx_lags=0, + max_iter=1, + epsilon=0.00001, + step1c=False, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + self.title = "GM SPATIALLY WEIGHTED LEAST SQUARES (HET)" + if slx_lags >0: + lag_x = get_lags(w, x_constant[:, 1:], slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + self.title += " WITH SLX (SDEM)" + BaseGM_Error_Het.__init__( + self, + y, + x_constant, + w.sparse, + max_iter=max_iter, + step1c=step1c, + epsilon=epsilon, + ) + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x_constant) + self.name_x.append("lambda") + self.name_w = USER.set_name_w(name_w, w) + self.output = pd.DataFrame(self.name_x, columns=['var_names']) + self.output['var_type'] = ['x'] * (len(self.name_x)-1) + ['lambda'] + self.output['regime'], self.output['equation'] = (0, 0) + self.other_top = _summary_iteration(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +class BaseGM_Endog_Error_Het(RegressionPropsY): + + """ + GMM method for a spatial error model with heteroskedasticity and + endogenous variables (note: no consistency checks, diagnostics or constant + added); based on :cite:`Arraiz2010`, following :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : Sparse matrix + Spatial weights sparse matrix + max_iter : int + Maximum number of iterations of steps 2a and 2b from + :cite:`Arraiz2010`. Note: epsilon provides an additional + stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + step1c : boolean + If True, then include Step 1c from :cite:`Arraiz2010`. + inv_method : string + If "power_exp", then compute inverse using the power + expansion. If "true_inv", then compute the true inverse. + Note that true_inv will fail for large n. + + + Attributes + ---------- + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + z : array + nxk array of variables (combination of x and yend) + h : array + nxl array of instruments (combination of x and q) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + hth : float + :math:`H'H` + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> import spreg + >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + >>> X = np.hstack((np.ones(y.shape),X)) + >>> yd = [] + >>> yd.append(db.by_col("CRIME")) + >>> yd = np.array(yd).T + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + >>> w.transform = 'r' + >>> reg = spreg.error_sp_het.BaseGM_Endog_Error_Het(y, X, yd, q, w=w.sparse, step1c=True) + >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4)) + [[55.3971 28.8901] + [ 0.4656 0.7731] + [-0.6704 0.468 ] + [ 0.4114 0.1777]] + """ + + def __init__( + self, + y, + x, + yend, + q, + w, + max_iter=1, + epsilon=0.00001, + step1c=False, + inv_method="power_exp", + ): + + self.step1c = step1c + # 1a. reg --> \tilde{betas} + tsls = TSLS.BaseTSLS(y=y, x=x, yend=yend, q=q) + self.x, self.z, self.h, self.y = tsls.x, tsls.z, tsls.h, tsls.y + self.yend, self.q, self.n, self.k, self.hth = ( + tsls.yend, + tsls.q, + tsls.n, + tsls.k, + tsls.hth, + ) + wA1 = UTILS.get_A1_het(w) + + # 1b. GMM --> \tilde{\lambda1} + moments = UTILS._moments2eqs(wA1, w, tsls.u) + lambda1 = UTILS.optim_moments(moments) + + if step1c: + # 1c. GMM --> \tilde{\lambda2} + self.u = tsls.u + zs = UTILS.get_spFilter(w, lambda1, self.z) + vc1 = get_vc_het_tsls( + w, wA1, self, lambda1, tsls.pfora1a2, zs, inv_method, filt=False + ) + lambda2 = UTILS.optim_moments(moments, vc1) + else: + lambda2 = lambda1 + lambda_old = lambda2 + + self.iteration, eps = 0, 1 + while self.iteration < max_iter and eps > epsilon: + # 2a. reg -->\hat{betas} + xs = UTILS.get_spFilter(w, lambda_old, self.x) + ys = UTILS.get_spFilter(w, lambda_old, self.y) + yend_s = UTILS.get_spFilter(w, lambda_old, self.yend) + tsls_s = TSLS.BaseTSLS(ys, xs, yend_s, h=self.h) + self.predy = spdot(self.z, tsls_s.betas) + self.u = self.y - self.predy + + # 2b. GMM --> \hat{\lambda} + vc2 = get_vc_het_tsls( + w, + wA1, + self, + lambda_old, + tsls_s.pfora1a2, + sphstack(xs, yend_s), + inv_method, + ) + moments_i = UTILS._moments2eqs(wA1, w, self.u) + lambda3 = UTILS.optim_moments(moments_i, vc2) + eps = abs(lambda3 - lambda_old) + lambda_old = lambda3 + self.iteration += 1 + + self.iter_stop = UTILS.iter_msg(self.iteration, max_iter) + + zs = UTILS.get_spFilter(w, lambda3, self.z) + P = get_P_hat(self, tsls.hthi, zs) + vc3 = get_vc_het_tsls(w, wA1, self, lambda3, P, zs, inv_method, save_a1a2=True) + self.vm = get_Omega_GS2SLS(w, lambda3, self, moments_i[0], vc3, P) + self.betas = np.vstack((tsls_s.betas, lambda3)) + self.e_filtered = self.u - lambda3 * w * self.u + self._cache = {} + + +
[docs]class GM_Endog_Error_Het(BaseGM_Endog_Error_Het): + + """ + GMM method for a spatial error model with heteroskedasticity and + endogenous variables, with results and diagnostics; based on + :cite:`Arraiz2010`, following :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : pysal W object + Spatial weights object + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + max_iter : int + Maximum number of iterations of steps 2a and 2b from + :cite:`Arraiz2010`. Note: epsilon provides an additional + stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + step1c : boolean + If True, then include Step 1c from :cite:`Arraiz2010`. + inv_method : string + If "power_exp", then compute inverse using the power + expansion. If "true_inv", then compute the true inverse. + Note that true_inv will fail for large n. + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + z : array + nxk array of variables (combination of x and yend) + h : array + nxl array of instruments (combination of x and q) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + hth : float + :math:`H'H` + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> from spreg import GM_Endog_Error_Het + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + + Extract the HOVAL column (home values) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) vector from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this class adds a vector of ones to the + independent variables passed in. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + + In this case we consider CRIME (crime rates) is an endogenous regressor. + We tell the model that this is so by passing it in a different parameter + from the exogenous variables (x). + + >>> yd = [] + >>> yd.append(db.by_col("CRIME")) + >>> yd = np.array(yd).T + + Because we have endogenous variables, to obtain a correct estimate of the + model, we need to instrument for CRIME. We use DISCBD (distance to the + CBD) for this and hence put it in the instruments parameter, 'q'. + + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``columbus.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, his allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables (exogenous and endogenous), the + instruments and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> reg = GM_Endog_Error_Het(y, X, yd, q, w=w, step1c=True, name_x=['inc'], name_y='hoval', name_yend=['crime'], name_q=['discbd'], name_ds='columbus') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. This class offers an error model that explicitly accounts + for heteroskedasticity and that unlike the models from + ``spreg.error_sp``, it allows for inference on the spatial + parameter. Hence, we find the same number of betas as of standard errors, + which we calculate taking the square root of the diagonal of the + variance-covariance matrix: + + >>> print(reg.name_z) + ['CONSTANT', 'inc', 'crime', 'lambda'] + >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4)) + [[55.3971 28.8901] + [ 0.4656 0.7731] + [-0.6704 0.468 ] + [ 0.4114 0.1777]] + + """ + +
[docs] def __init__( + self, + y, + x, + yend, + q, + w, + slx_lags=0, + max_iter=1, + epsilon=0.00001, + step1c=False, + inv_method="power_exp", + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(y, x, yend, q) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + self.title = "GM SPATIALLY WEIGHTED TWO STAGE LEAST SQUARES (HET)" + if slx_lags > 0: + lag_x = get_lags(w, x_constant[:, 1:], slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + self.title += " WITH SLX (SDEM)" + BaseGM_Endog_Error_Het.__init__( + self, + y=y, + x=x_constant, + yend=yend, + q=q, + w=w.sparse, + max_iter=max_iter, + step1c=step1c, + epsilon=epsilon, + inv_method=inv_method, + ) + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x_constant) + self.name_yend = USER.set_name_yend(name_yend, yend) + self.name_z = self.name_x + self.name_yend + self.name_z.append("lambda") # listing lambda last + self.name_q = USER.set_name_q(name_q, q) + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.name_w = USER.set_name_w(name_w, w) + self.output = pd.DataFrame(self.name_z, + columns=['var_names']) + self.output['var_type'] = ['x'] * len(self.name_x) + ['yend'] * len(self.name_yend) + ['lambda'] + self.output['regime'], self.output['equation'] = (0, 0) + self.other_top = _summary_iteration(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +class BaseGM_Combo_Het(BaseGM_Endog_Error_Het): + + """ + GMM method for a spatial lag and error model with heteroskedasticity and + endogenous variables (note: no consistency checks, diagnostics or constant + added); based on :cite:`Arraiz2010`, following :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : Sparse matrix + Spatial weights sparse matrix + w_lags : integer + Orders of W to include as instruments for the spatially + lagged dependent variable. For example, w_lags=1, then + instruments are WX; if w_lags=2, then WX, WWX; and so on. + lag_q : boolean + If True, then include spatial lags of the additional + instruments (q). + max_iter : int + Maximum number of iterations of steps 2a and 2b from + :cite:`Arraiz2010`. Note: epsilon provides an additional + stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + step1c : boolean + If True, then include Step 1c from :cite:`Arraiz2010`. + inv_method : string + If "power_exp", then compute inverse using the power + expansion. If "true_inv", then compute the true inverse. + Note that true_inv will fail for large n. + + + Attributes + ---------- + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + z : array + nxk array of variables (combination of x and yend) + h : array + nxl array of instruments (combination of x and q) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + hth : float + :math:`H'H` + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> import spreg + >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + >>> w.transform = 'r' + >>> w_lags = 1 + >>> yd2, q2 = spreg.set_endog(y, X, w, None, None, w_lags, True) + >>> X = np.hstack((np.ones(y.shape),X)) + + Example only with spatial lag + + >>> reg = spreg.error_sp_het.BaseGM_Combo_Het(y, X, yend=yd2, q=q2, w=w.sparse, step1c=True) + >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4)) + [[ 9.9753 14.1435] + [ 1.5742 0.374 ] + [ 0.1535 0.3978] + [ 0.2103 0.3924]] + + Example with both spatial lag and other endogenous variables + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + >>> yd = [] + >>> yd.append(db.by_col("CRIME")) + >>> yd = np.array(yd).T + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + >>> yd2, q2 = spreg.set_endog(y, X, w, yd, q, w_lags, True) + >>> X = np.hstack((np.ones(y.shape),X)) + >>> reg = spreg.error_sp_het.BaseGM_Combo_Het(y, X, yd2, q2, w=w.sparse, step1c=True) + >>> betas = np.array([['CONSTANT'],['inc'],['crime'],['lag_hoval'],['lambda']]) + >>> print(np.hstack((betas, np.around(np.hstack((reg.betas, np.sqrt(reg.vm.diagonal()).reshape(5,1))),5)))) + [['CONSTANT' '113.91292' '64.38815'] + ['inc' '-0.34822' '1.18219'] + ['crime' '-1.35656' '0.72482'] + ['lag_hoval' '-0.57657' '0.75856'] + ['lambda' '0.65608' '0.15719']] + """ + + def __init__( + self, + y, + x, + yend=None, + q=None, + w=None, + w_lags=1, + lag_q=True, + max_iter=1, + epsilon=0.00001, + step1c=False, + inv_method="power_exp", + ): + + BaseGM_Endog_Error_Het.__init__( + self, + y=y, + x=x, + w=w, + yend=yend, + q=q, + max_iter=max_iter, + step1c=step1c, + epsilon=epsilon, + inv_method=inv_method, + ) + + +
[docs]class GM_Combo_Het(BaseGM_Combo_Het): + + """ + GMM method for a spatial lag and error model with heteroskedasticity and + endogenous variables, with results and diagnostics; based on + :cite:`Arraiz2010`, following :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : pysal W object + Spatial weights object (always needed) + w_lags : integer + Orders of W to include as instruments for the spatially + lagged dependent variable. For example, w_lags=1, then + instruments are WX; if w_lags=2, then WX, WWX; and so on. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the General Nesting + Spatial Model (GNSM) type. + lag_q : boolean + If True, then include spatial lags of the additional + instruments (q). + max_iter : int + Maximum number of iterations of steps 2a and 2b from + :cite:`Arraiz2010`. Note: epsilon provides an additional + stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + step1c : boolean + If True, then include Step 1c from :cite:`Arraiz2010`. + inv_method : string + If "power_exp", then compute inverse using the power + expansion. If "true_inv", then compute the true inverse. + Note that true_inv will fail for large n. + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + e_pred : array + nx1 array of residuals (using reduced form) + predy : array + nx1 array of predicted y values + predy_e : array + nx1 array of predicted y values (using reduced form) + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + z : array + nxk array of variables (combination of x and yend) + h : array + nxl array of instruments (combination of x and q) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + hth : float + :math:`H'H` + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> from spreg import GM_Combo_Het + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + + Extract the HOVAL column (home values) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) vector from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this class adds a vector of ones to the + independent variables passed in. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``columbus.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, his allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + The Combo class runs an SARAR model, that is a spatial lag+error model. + In this case we will run a simple version of that, where we have the + spatial effects as well as exogenous variables. Since it is a spatial + model, we have to pass in the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> reg = GM_Combo_Het(y, X, w=w, step1c=True, name_y='hoval', name_x=['income'], name_ds='columbus') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. This class offers an error model that explicitly accounts + for heteroskedasticity and that unlike the models from + ``spreg.error_sp``, it allows for inference on the spatial + parameter. Hence, we find the same number of betas as of standard errors, + which we calculate taking the square root of the diagonal of the + variance-covariance matrix: + + >>> print(reg.name_z) + ['CONSTANT', 'income', 'W_hoval', 'lambda'] + >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4)) + [[ 9.9753 14.1435] + [ 1.5742 0.374 ] + [ 0.1535 0.3978] + [ 0.2103 0.3924]] + + This class also allows the user to run a spatial lag+error model with the + extra feature of including non-spatial endogenous regressors. This means + that, in addition to the spatial lag and error, we consider some of the + variables on the right-hand side of the equation as endogenous and we + instrument for this. As an example, we will include CRIME (crime rates) as + endogenous and will instrument with DISCBD (distance to the CSB). We first + need to read in the variables: + + >>> yd = [] + >>> yd.append(db.by_col("CRIME")) + >>> yd = np.array(yd).T + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + + And then we can run and explore the model analogously to the previous combo: + + >>> reg = GM_Combo_Het(y, X, yd, q, w=w, step1c=True, name_x=['inc'], name_y='hoval', name_yend=['crime'], name_q=['discbd'], name_ds='columbus') + >>> print(reg.name_z) + ['CONSTANT', 'inc', 'crime', 'W_hoval', 'lambda'] + >>> print(np.round(reg.betas,4)) + [[113.9129] + [ -0.3482] + [ -1.3566] + [ -0.5766] + [ 0.6561]] + + """ + +
[docs] def __init__( + self, + y, + x, + yend=None, + q=None, + w=None, + w_lags=1, + slx_lags=0, + lag_q=True, + max_iter=1, + epsilon=0.00001, + step1c=False, + inv_method="power_exp", + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(y, x, yend, q) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + + if slx_lags == 0: + yend2, q2 = set_endog(y, x_constant[:, 1:], w, yend, q, w_lags, lag_q) + else: + yend2, q2, wx = set_endog(y, x_constant[:, 1:], w, yend, q, w_lags, lag_q, slx_lags) + x_constant = np.hstack((x_constant, wx)) + + BaseGM_Combo_Het.__init__( + self, + y=y, + x=x_constant, + yend=yend2, + q=q2, + w=w.sparse, + w_lags=w_lags, + max_iter=max_iter, + step1c=step1c, + lag_q=lag_q, + epsilon=epsilon, + inv_method=inv_method, + ) + self.rho = self.betas[-2] + self.predy_e, self.e_pred, warn = UTILS.sp_att( + w, self.y, self.predy, yend2[:, -1].reshape(self.n, 1), self.rho + ) + UTILS.set_warn(self, warn) + self.title = "SPATIALLY WEIGHTED 2SLS- GM-COMBO MODEL (HET)" + if slx_lags > 0: + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + self.title += " WITH SLX (GNSM)" + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x_constant) + self.name_yend = USER.set_name_yend(name_yend, yend) + self.name_yend.append(USER.set_name_yend_sp(self.name_y)) + self.name_z = self.name_x + self.name_yend + self.name_z.append("lambda") # listing lambda last + self.name_q = USER.set_name_q(name_q, q) + self.name_q.extend(USER.set_name_q_sp(self.name_x, w_lags, self.name_q, lag_q)) + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.name_w = USER.set_name_w(name_w, w) + self.output = pd.DataFrame(self.name_z, + columns=['var_names']) + self.output['var_type'] = ['x'] * len(self.name_x) + ['yend'] * (len(self.name_yend)-1) + ['rho', 'lambda'] + self.output['regime'], self.output['equation'] = (0, 0) + self.other_top = _spat_pseudo_r2(self) + self.other_top += _summary_iteration(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +# Functions + + +def get_psi_sigma(w, u, lamb): + """ + Computes the Sigma matrix needed to compute Psi + + Parameters + ---------- + w : Sparse matrix + Spatial weights sparse matrix + u : array + nx1 vector of residuals + lamb : float + Lambda + + """ + + e = (u - lamb * (w * u)) ** 2 + E = SP.dia_matrix((e.flat, 0), shape=(w.shape[0], w.shape[0])) + return E.tocsr() + + +def get_vc_het(w, wA1, E): + """ + Computes the VC matrix Psi based on lambda as in Arraiz et al :cite:`Arraiz2010`: + + ..math:: + + \tilde{Psi} = \left(\begin{array}{c c} + \psi_{11} & \psi_{12} \\ + \psi_{21} & \psi_{22} \\ + \end{array} \right) + + NOTE: psi12=psi21 + + ... + + Parameters + ---------- + + w : Sparse matrix + Spatial weights sparse matrix + + E : sparse matrix + Sigma + + Returns + ------- + + Psi : array + 2x2 array with estimator of the variance-covariance matrix + + """ + aPatE = 2 * wA1 * E + wPwtE = (w + w.T) * E + + psi11 = aPatE * aPatE + psi12 = aPatE * wPwtE + psi22 = wPwtE * wPwtE + psi = list(map(np.sum, [psi11.diagonal(), psi12.diagonal(), psi22.diagonal()])) + return np.array([[psi[0], psi[1]], [psi[1], psi[2]]]) / (2.0 * w.shape[0]) + + +def get_vm_het(G, lamb, reg, w, psi): + """ + Computes the variance-covariance matrix Omega as in Arraiz et al + :cite:`Arraiz2010` + + Parameters + ---------- + + G : array + G from moments equations + + lamb : float + Final lambda from spHetErr estimation + + reg : regression object + output instance from a regression model + + u : array + nx1 vector of residuals + + w : Sparse matrix + Spatial weights sparse matrix + + psi : array + 2x2 array with the variance-covariance matrix of the moment equations + + Returns + ------- + + vm : array + (k+1)x(k+1) array with the variance-covariance matrix of the parameters + + """ + + J = np.dot(G, np.array([[1], [2 * lamb]])) + Zs = UTILS.get_spFilter(w, lamb, reg.x) + ZstEZs = spdot((Zs.T * get_psi_sigma(w, reg.u, lamb)), Zs) + ZsZsi = la.inv(spdot(Zs.T, Zs)) + omega11 = w.shape[0] * np.dot(np.dot(ZsZsi, ZstEZs), ZsZsi) + omega22 = la.inv(np.dot(np.dot(J.T, la.inv(psi)), J)) + zero = np.zeros((reg.k, 1), float) + vm = ( + np.vstack((np.hstack((omega11, zero)), np.hstack((zero.T, omega22)))) + / w.shape[0] + ) + return vm + + +def get_P_hat(reg, hthi, zf): + """ + P_hat from Appendix B, used for a1 a2, using filtered Z + """ + htzf = spdot(reg.h.T, zf) + P1 = spdot(hthi, htzf) + P2 = spdot(htzf.T, P1) + P2i = la.inv(P2) + return reg.n * np.dot(P1, P2i) + + +def get_a1a2(w, wA1, reg, lambdapar, P, zs, inv_method, filt): + """ + Computes the a1 in psi assuming residuals come from original regression. + :cite:`Anselin2011` + + Parameters + ---------- + w : Sparse matrix + Spatial weights sparse matrix + reg : TSLS + Two stage least quare regression instance + lambdapar : float + Spatial autoregressive parameter + + Returns + ------- + [a1, a2] : list + a1 and a2 are two nx1 array in psi equation + + """ + us = UTILS.get_spFilter(w, lambdapar, reg.u) + alpha1 = (-2.0 / w.shape[0]) * (np.dot(spdot(zs.T, wA1), us)) + alpha2 = (-1.0 / w.shape[0]) * (np.dot(spdot(zs.T, (w + w.T)), us)) + a1 = np.dot(spdot(reg.h, P), alpha1) + a2 = np.dot(spdot(reg.h, P), alpha2) + if not filt: + a1 = UTILS.inverse_prod( + w, a1, lambdapar, post_multiply=True, inv_method=inv_method + ).T + a2 = UTILS.inverse_prod( + w, a2, lambdapar, post_multiply=True, inv_method=inv_method + ).T + return [a1, a2] + + +def get_vc_het_tsls( + w, wA1, reg, lambdapar, P, zs, inv_method, filt=True, save_a1a2=False +): + + sigma = get_psi_sigma(w, reg.u, lambdapar) + vc1 = get_vc_het(w, wA1, sigma) + a1, a2 = get_a1a2(w, wA1, reg, lambdapar, P, zs, inv_method, filt) + a1s = a1.T * sigma + a2s = a2.T * sigma + psi11 = float(np.dot(a1s, a1)) + psi12 = float(np.dot(a1s, a2)) + psi21 = float(np.dot(a2s, a1)) + psi22 = float(np.dot(a2s, a2)) + psi0 = np.array([[psi11, psi12], [psi21, psi22]]) / w.shape[0] + if save_a1a2: + psi = (vc1 + psi0, a1, a2) + else: + psi = vc1 + psi0 + return psi + + +def get_Omega_GS2SLS(w, lamb, reg, G, psi, P): + """ + Computes the variance-covariance matrix for GS2SLS: + + Parameters + ---------- + w : Sparse matrix + Spatial weights sparse matrix + lamb : float + Spatial autoregressive parameter + reg : GSTSLS + Generalized Spatial two stage least quare regression instance + G : array + Moments + psi : array + Weighting matrix + + Returns + ------- + omega : array + (k+1)x(k+1) + """ + psi, a1, a2 = psi + sigma = get_psi_sigma(w, reg.u, lamb) + psi_dd_1 = (1.0 / w.shape[0]) * reg.h.T * sigma + psi_dd = spdot(psi_dd_1, reg.h) + psi_dl = spdot(psi_dd_1, np.hstack((a1, a2))) + psi_o = np.hstack((np.vstack((psi_dd, psi_dl.T)), np.vstack((psi_dl, psi)))) + psii = la.inv(psi) + + j = np.dot(G, np.array([[1.0], [2 * lamb]])) + jtpsii = np.dot(j.T, psii) + jtpsiij = np.dot(jtpsii, j) + jtpsiiji = la.inv(jtpsiij) + omega_1 = np.dot(jtpsiiji, jtpsii) + omega_2 = np.dot(np.dot(psii, j), jtpsiiji) + om_1_s = omega_1.shape + om_2_s = omega_2.shape + p_s = P.shape + omega_left = np.hstack( + ( + np.vstack((P.T, np.zeros((om_1_s[0], p_s[0])))), + np.vstack((np.zeros((p_s[1], om_1_s[1])), omega_1)), + ) + ) + omega_right = np.hstack( + ( + np.vstack((P, np.zeros((om_2_s[0], p_s[1])))), + np.vstack((np.zeros((p_s[0], om_2_s[1])), omega_2)), + ) + ) + omega = np.dot(np.dot(omega_left, psi_o), omega_right) + return omega / w.shape[0] + + +def _test(): + import doctest + + doctest.testmod() + + +if __name__ == "__main__": + _test() + import numpy as np + import libpysal + + db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + y = np.array(db.by_col("HOVAL")) + y = np.reshape(y, (49,1)) + X = [] + X.append(db.by_col("INC")) + X = np.array(X).T + yd = [] + yd.append(db.by_col("CRIME")) + yd = np.array(yd).T + q = [] + q.append(db.by_col("DISCBD")) + q = np.array(q).T + + w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + w.transform = 'r' + # reg = GM_Error_Het(y, X, w=w, name_x=['inc'], name_y='hoval', name_ds='columbus', vm=True) + # reg = GM_Endog_Error_Het(y, X, yd, q, w=w, name_x=['inc'], name_y='hoval', name_yend=['crime'], + # name_q=['discbd'], name_ds='columbus',vm=True) + reg = GM_Combo_Het(y, X, yd, q, w=w, step1c=True, name_x=['inc'], name_y='hoval', name_yend=['crime'], name_q=['discbd'], name_ds='columbus', + vm=True) + print(reg.output) + print(reg.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/error_sp_het_regimes.html b/_modules/spreg/error_sp_het_regimes.html new file mode 100644 index 00000000..5dd4de33 --- /dev/null +++ b/_modules/spreg/error_sp_het_regimes.html @@ -0,0 +1,2092 @@ + + + + + + + spreg.error_sp_het_regimes — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.error_sp_het_regimes

+"""
+Spatial Error with Heteroskedasticity and Regimes family of models
+"""
+__author__ = "Luc Anselin luc.anselin@asu.edu, Pedro V. Amaral pedro.amaral@asu.edu"
+
+import numpy as np
+import multiprocessing as mp
+from . import user_output as USER
+from . import utils as UTILS
+from . import regimes as REGI
+from .ols import BaseOLS
+from .twosls import BaseTSLS
+from .error_sp_het import (
+    BaseGM_Error_Het,
+    BaseGM_Endog_Error_Het,
+    get_psi_sigma,
+    get_vc_het,
+    get_vm_het,
+    get_P_hat,
+    get_a1a2,
+    get_vc_het_tsls,
+    get_Omega_GS2SLS,
+)
+from .utils import RegressionPropsY, spdot, set_endog, sphstack, set_warn, sp_att, get_lags
+from scipy import sparse as SP
+from libpysal.weights.spatial_lag import lag_spatial
+from platform import system
+import pandas as pd
+from .output import output, _summary_iteration, _spat_pseudo_r2
+
+
+
[docs]class GM_Error_Het_Regimes(RegressionPropsY, REGI.Regimes_Frame): + + """ + GMM method for a spatial error model with heteroskedasticity and regimes; + based on Arraiz et al :cite:`Arraiz2010`, following Anselin :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + w : pysal W object + Spatial weights object + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes + + * 'many': a vector of ones is appended to x and considered different per regime (default) + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + regime_lag_sep: boolean + Always False, kept for consistency, ignored. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + max_iter : int + Maximum number of iterations of steps 2a and 2b from Arraiz + et al. Note: epsilon provides an additional stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from Arraiz et al. Note: max_iter provides + an additional stop condition. + step1c : boolean + If True, then include Step 1c from Arraiz et al. + vm : boolean + If True, include variance-covariance matrix in summary + results + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + vm : array + Variance covariance matrix (kxk) + sig2 : float + Sigma squared used in computations + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi: string + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes + + * 'many': a vector of ones is appended to x and considered different per regime + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path('natregimes.dbf'),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to run a spatial error model, we need to specify + the spatial weights matrix that includes the spatial configuration of the + observations. To do that, we can open an already existing gal file or + create a new one. In this case, we will create one from ``NAT.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(nat.get_path("natregimes.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> reg = GM_Error_Het_Regimes(y, x, regimes, w=w, step1c=True, name_y=y_var, name_x=x_var, name_regimes=r_var, name_ds='NAT.dbf') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. This class offers an error model that explicitly accounts + for heteroskedasticity and that unlike the models from + ``spreg.error_sp``, it allows for inference on the spatial + parameter. Alternatively, we can have a summary of the + output by typing: model.summary + + >>> print(reg.name_x) + ['0_CONSTANT', '0_PS90', '0_UE90', '1_CONSTANT', '1_PS90', '1_UE90', 'lambda'] + >>> np.around(reg.betas, decimals=6) + array([[0.009121], + [0.812973], + [0.549355], + [5.00279 ], + [1.200929], + [0.614681], + [0.429277]]) + >>> np.around(reg.std_err, decimals=6) + array([0.355844, 0.221743, 0.059276, 0.686764, 0.35843 , 0.092788, + 0.02524 ]) + + """ + +
[docs] def __init__( + self, + y, + x, + regimes, + w, + max_iter=1, + epsilon=0.00001, + step1c=False, + constant_regi="many", + cols2regi="all", + regime_err_sep=False, + regime_lag_sep=False, + slx_lags=0, + cores=False, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + name_regimes=None, + latex=False, + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + self.constant_regi = constant_regi + self.cols2regi = cols2regi + self.regime_err_sep = regime_err_sep + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_w = USER.set_name_w(name_w, w) + self.name_regimes = USER.set_name_ds(name_regimes) + self.n, self.step1c = n, step1c + self.y = y + + x_constant, name_x, warn = USER.check_constant(x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + + if slx_lags >0: + lag_x = get_lags(w, x_constant, slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + + self.name_x_r = USER.set_name_x(name_x, x_constant) + + cols2regi = REGI.check_cols2regi(constant_regi, cols2regi, x_constant) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, self.n, x_constant.shape[1]) + self.regime_err_sep = regime_err_sep + + if regime_err_sep == True: + if set(cols2regi) == set([True]): + self._error_het_regimes_multi( + y, + x_constant, + regimes, + w, + slx_lags, + cores, + max_iter, + epsilon, + step1c, + cols2regi, + vm, + name_x, + latex, + ) + else: + raise Exception( + "All coefficients must vary across regimes if regime_err_sep = True." + ) + else: + x_constant = sphstack(np.ones((x_constant.shape[0], 1)), x_constant) + name_x = USER.set_name_x(name_x, x_constant) + self.x, self.name_x, x_rlist = REGI.Regimes_Frame.__init__( + self, + x_constant, + regimes, + constant_regi=None, + cols2regi=cols2regi, + names=name_x, + rlist=True, + ) + ols = BaseOLS(y=y, x=self.x) + self.k = ols.x.shape[1] + wA1 = UTILS.get_A1_het(w.sparse) + + # 1b. GMM --> \tilde{\lambda1} + moments = UTILS._moments2eqs(wA1, w.sparse, ols.u) + lambda1 = UTILS.optim_moments(moments) + + if step1c: + # 1c. GMM --> \tilde{\lambda2} + sigma = get_psi_sigma(w.sparse, ols.u, lambda1) + vc1 = get_vc_het(w.sparse, wA1, sigma) + lambda2 = UTILS.optim_moments(moments, vc1) + else: + lambda2 = lambda1 + lambda_old = lambda2 + + self.iteration, eps = 0, 1 + while self.iteration < max_iter and eps > epsilon: + # 2a. reg -->\hat{betas} + xs = UTILS.get_spFilter(w, lambda_old, x_constant) + ys = UTILS.get_spFilter(w, lambda_old, y) + xs = REGI.Regimes_Frame.__init__( + self, xs, regimes, constant_regi=None, cols2regi=cols2regi + )[0] + ols_s = BaseOLS(y=ys, x=xs) + self.predy = spdot(self.x, ols_s.betas) + self.u = self.y - self.predy + + # 2b. GMM --> \hat{\lambda} + sigma_i = get_psi_sigma(w.sparse, self.u, lambda_old) + vc_i = get_vc_het(w.sparse, wA1, sigma_i) + moments_i = UTILS._moments2eqs(wA1, w.sparse, self.u) + lambda3 = UTILS.optim_moments(moments_i, vc_i) + eps = abs(lambda3 - lambda_old) + lambda_old = lambda3 + self.iteration += 1 + + self.iter_stop = UTILS.iter_msg(self.iteration, max_iter) + + sigma = get_psi_sigma(w.sparse, self.u, lambda3) + vc3 = get_vc_het(w.sparse, wA1, sigma) + self.vm = get_vm_het(moments_i[0], lambda3, self, w.sparse, vc3) + self.betas = np.vstack((ols_s.betas, lambda3)) + self.e_filtered = self.u - lambda3 * lag_spatial(w, self.u) + if slx_lags == 0: + self.title = "GM SPATIALLY WEIGHTED MODEL (HET) - REGIMES" + else: + self.title = "GM SPATIALLY WEIGHTED MODEL + SLX (SDEM-HET) - REGIMES" + + self.name_x.append("lambda") + self.kf += 1 + self.chow = REGI.Chow(self) + self._cache = {} + self.output = pd.DataFrame(self.name_x, + columns=['var_names']) + self.output['var_type'] = ['x']*(len(self.name_x)-1)+['lambda'] + self.output['regime'] = x_rlist + ['_Global'] + self.output['equation'] = 0 + self.other_top = _summary_iteration(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + def _error_het_regimes_multi( + self, y, x, regimes, w, slx_lags, cores, max_iter, epsilon, step1c, cols2regi, vm, name_x, latex + ): + + regi_ids = dict( + (r, list(np.where(np.array(regimes) == r)[0])) for r in self.regimes_set + ) + results_p = {} + """ + for r in self.regimes_set: + if system() == 'Windows': + is_win = True + results_p[r] = _work_error(*(y,x,regi_ids,r,w,max_iter,epsilon,step1c,self.name_ds,self.name_y,name_x+['lambda'],self.name_w,self.name_regimes)) + else: + pool = mp.Pool(cores) + results_p[r] = pool.apply_async(_work_error,args=(y,x,regi_ids,r,w,max_iter,epsilon,step1c,self.name_ds,self.name_y,name_x+['lambda'],self.name_w,self.name_regimes, )) + is_win = False + """ + x_constant, name_x = REGI.check_const_regi(self, x, name_x, regi_ids) + self.name_x_r = name_x + for r in self.regimes_set: + if cores: + pool = mp.Pool(None) + results_p[r] = pool.apply_async( + _work_error, + args=( + y, + x_constant, + regi_ids, + r, + w, + max_iter, + epsilon, + step1c, + self.name_ds, + self.name_y, + name_x + ["lambda"], + self.name_w, + self.name_regimes, + slx_lags, + ), + ) + else: + results_p[r] = _work_error( + *( + y, + x_constant, + regi_ids, + r, + w, + max_iter, + epsilon, + step1c, + self.name_ds, + self.name_y, + name_x + ["lambda"], + self.name_w, + self.name_regimes, + slx_lags, + ) + ) + + self.kryd = 0 + self.kr = len(cols2regi) + 1 + self.kf = 0 + self.nr = len(self.regimes_set) + self.vm = np.zeros((self.nr * self.kr, self.nr * self.kr), float) + self.betas = np.zeros((self.nr * self.kr, 1), float) + self.u = np.zeros((self.n, 1), float) + self.predy = np.zeros((self.n, 1), float) + self.e_filtered = np.zeros((self.n, 1), float) + """ + if not is_win: + pool.close() + pool.join() + """ + if cores: + pool.close() + pool.join() + + results = {} + self.name_y, self.name_x = [], [] + counter = 0 + self.output = pd.DataFrame(columns=['var_names', 'var_type', 'regime', 'equation']) + for r in self.regimes_set: + """ + if is_win: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + """ + if not cores: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + + self.vm[ + (counter * self.kr) : ((counter + 1) * self.kr), + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].vm + self.betas[ + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].betas + self.u[ + regi_ids[r], + ] = results[r].u + self.predy[ + regi_ids[r], + ] = results[r].predy + self.e_filtered[ + regi_ids[r], + ] = results[r].e_filtered + self.name_y += results[r].name_y + results[r].name_x = [str(r) + '_lambda' if value == 'lambda' else value for value in results[r].name_x] + self.name_x += results[r].name_x + results[r].other_top = _summary_iteration(results[r]) + self.output = pd.concat([self.output, pd.DataFrame({'var_names': results[r].name_x, + 'var_type': ['x'] * (len(results[r].name_x)-1) + + ['lambda'], + 'regime': r, 'equation': r})], ignore_index=True) + counter += 1 + self.chow = REGI.Chow(self) + self.multi = results + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +
[docs]class GM_Endog_Error_Het_Regimes(RegressionPropsY, REGI.Regimes_Frame): + + """ + GMM method for a spatial error model with heteroskedasticity, regimes and + endogenous variables, with results and diagnostics; based on Arraiz et al + :cite:`Arraiz2010`, following Anselin :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + w : pysal W object + Spatial weights object + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep : boolean + If True, a separate regression is run for each regime. + regime_lag_sep : boolean + Always False, kept for consistency, ignored. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + max_iter : int + Maximum number of iterations of steps 2a and 2b from + :cite:`Arraiz2010`. Note: epsilon provides an additional stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + step1c : boolean + If True, then include Step 1c from :cite:`Arraiz2010`. + inv_method : string + If "power_exp", then compute inverse using the power + expansion. If "true_inv", then compute the true inverse. + Note that true_inv will fail for large n. + vm : boolean + If True, include variance-covariance matrix in summary + results + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant). + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z : array + nxk array of variables (combination of x and yend) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + h : array + nxl array of instruments (combination of x and q) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi : string + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep : boolean + If True, a separate regression is run for each regime. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path("natregimes.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + For the endogenous models, we add the endogenous variable RD90 (resource deprivation) + and we decide to instrument for it with FP89 (families below poverty): + + >>> yd_var = ['RD90'] + >>> yend = np.array([db.by_col(name) for name in yd_var]).T + >>> q_var = ['FP89'] + >>> q = np.array([db.by_col(name) for name in q_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``NAT.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(nat.get_path("natregimes.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables (exogenous and endogenous), the + instruments and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> reg = GM_Endog_Error_Het_Regimes(y, x, yend, q, regimes, w=w, step1c=True, name_y=y_var, name_x=x_var, name_yend=yd_var, name_q=q_var, name_regimes=r_var, name_ds='NAT.dbf') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. This class offers an error model that explicitly accounts + for heteroskedasticity and that unlike the models from + ``spreg.error_sp``, it allows for inference on the spatial + parameter. Hence, we find the same number of betas as of standard errors, + which we calculate taking the square root of the diagonal of the + variance-covariance matrix Alternatively, we can have a summary of the + output by typing: model.summary + + >>> print(reg.name_z) + ['0_CONSTANT', '0_PS90', '0_UE90', '1_CONSTANT', '1_PS90', '1_UE90', '0_RD90', '1_RD90', 'lambda'] + + >>> print(np.around(reg.betas,4)) + [[ 3.5944] + [ 1.065 ] + [ 0.1587] + [ 9.184 ] + [ 1.8784] + [-0.2466] + [ 2.4617] + [ 3.5756] + [ 0.2908]] + + >>> print(np.around(np.sqrt(reg.vm.diagonal()),4)) + [0.5043 0.2132 0.0581 0.6681 0.3504 0.0999 0.3686 0.3402 0.028 ] + + """ + +
[docs] def __init__( + self, + y, + x, + yend, + q, + regimes, + w, + max_iter=1, + epsilon=0.00001, + step1c=False, + constant_regi="many", + cols2regi="all", + regime_err_sep=False, + regime_lag_sep=False, + slx_lags=0, + inv_method="power_exp", + cores=False, + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + name_regimes=None, + summ=True, + add_lag=False, + latex=False, + ): + + n = USER.check_arrays(y, x, yend, q) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + self.constant_regi = constant_regi + self.cols2regi = cols2regi + self.name_ds = USER.set_name_ds(name_ds) + self.name_regimes = USER.set_name_ds(name_regimes) + self.name_w = USER.set_name_w(name_w, w) + self.n, self.step1c = n, step1c + self.y = y + + x_constant, name_x, warn = USER.check_constant(x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + + if slx_lags > 0: + lag_x = get_lags(w, x_constant, slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + + if summ: + name_yend = USER.set_name_yend(name_yend, yend) + self.name_y = USER.set_name_y(name_y) + name_q = USER.set_name_q(name_q, q) + self.name_x_r = USER.set_name_x(name_x, x_constant) + name_yend + cols2regi = REGI.check_cols2regi( + constant_regi, cols2regi, x_constant, yend=yend + ) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, self.n, x_constant.shape[1]) + self.regime_err_sep = regime_err_sep + + if regime_err_sep == True: + if set(cols2regi) == set([True]): + self._endog_error_het_regimes_multi( + y, + x_constant, + regimes, + w, + yend, + q, + slx_lags, + cores, + max_iter, + epsilon, + step1c, + inv_method, + cols2regi, + vm, + name_x, + name_yend, + name_q, + add_lag, + latex, + ) + else: + raise Exception( + "All coefficients must vary across regimes if regime_err_sep = True." + ) + else: + x_constant = sphstack(np.ones((x_constant.shape[0], 1)), x_constant) + name_x = USER.set_name_x(name_x, x_constant) + q, name_q = REGI.Regimes_Frame.__init__( + self, q, regimes, constant_regi=None, cols2regi="all", names=name_q + ) + x, name_x, x_rlist = REGI.Regimes_Frame.__init__( + self, + x_constant, + regimes, + constant_regi=None, + cols2regi=cols2regi, + names=name_x, + rlist=True, + ) + yend2, name_yend, yend_rlist = REGI.Regimes_Frame.__init__( + self, + yend, + regimes, + constant_regi=None, + cols2regi=cols2regi, + yend=True, + names=name_yend, + rlist=True, + ) + + # 1a. S2SLS --> \tilde{\delta} + tsls = BaseTSLS(y=y, x=x, yend=yend2, q=q) + self.k = tsls.z.shape[1] + self.x = tsls.x + self.yend, self.z, self.h = tsls.yend, tsls.z, tsls.h + wA1 = UTILS.get_A1_het(w.sparse) + + # 1b. GMM --> \tilde{\lambda1} + moments = UTILS._moments2eqs(wA1, w.sparse, tsls.u) + lambda1 = UTILS.optim_moments(moments) + + if step1c: + # 1c. GMM --> \tilde{\lambda2} + self.u = tsls.u + zs = UTILS.get_spFilter(w, lambda1, self.z) + vc1 = get_vc_het_tsls( + w.sparse, + wA1, + self, + lambda1, + tsls.pfora1a2, + zs, + inv_method, + filt=False, + ) + lambda2 = UTILS.optim_moments(moments, vc1) + else: + lambda2 = lambda1 + lambda_old = lambda2 + + self.iteration, eps = 0, 1 + while self.iteration < max_iter and eps > epsilon: + # 2a. reg -->\hat{betas} + xs = UTILS.get_spFilter(w, lambda1, x_constant) + xs = REGI.Regimes_Frame.__init__( + self, xs, regimes, constant_regi=None, cols2regi=cols2regi + )[0] + ys = UTILS.get_spFilter(w, lambda1, y) + yend_s = UTILS.get_spFilter(w, lambda1, yend) + yend_s = REGI.Regimes_Frame.__init__( + self, + yend_s, + regimes, + constant_regi=None, + cols2regi=cols2regi, + yend=True, + )[0] + tsls_s = BaseTSLS(ys, xs, yend_s, h=tsls.h) + self.predy = spdot(self.z, tsls_s.betas) + self.u = self.y - self.predy + + # 2b. GMM --> \hat{\lambda} + vc2 = get_vc_het_tsls( + w.sparse, + wA1, + self, + lambda_old, + tsls_s.pfora1a2, + sphstack(xs, yend_s), + inv_method, + ) + moments_i = UTILS._moments2eqs(wA1, w.sparse, self.u) + lambda3 = UTILS.optim_moments(moments_i, vc2) + eps = abs(lambda3 - lambda_old) + lambda_old = lambda3 + self.iteration += 1 + + self.iter_stop = UTILS.iter_msg(self.iteration, max_iter) + + zs = UTILS.get_spFilter(w, lambda3, self.z) + P = get_P_hat(self, tsls.hthi, zs) + vc3 = get_vc_het_tsls( + w.sparse, wA1, self, lambda3, P, zs, inv_method, save_a1a2=True + ) + self.vm = get_Omega_GS2SLS(w.sparse, lambda3, self, moments_i[0], vc3, P) + self.betas = np.vstack((tsls_s.betas, lambda3)) + self.e_filtered = self.u - lambda3 * lag_spatial(w, self.u) + self.name_x = USER.set_name_x(name_x, x, constant=True) + self.name_yend = USER.set_name_yend(name_yend, yend) + self.name_z = self.name_x + self.name_yend + self.name_z.append("lambda") # listing lambda last + self.name_q = USER.set_name_q(name_q, q) + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.kf += 1 + self.chow = REGI.Chow(self) + self._cache = {} + self.output = pd.DataFrame(self.name_z, + columns=['var_names']) + self.output['var_type'] = ['x']*len(self.name_x)+['yend']*len(self.name_yend)+['lambda'] + self.output['regime'] = x_rlist + yend_rlist + ['_Global'] + self.output['equation'] = 0 + if summ: + self.other_top = _summary_iteration(self) + if slx_lags == 0: + self.title = ("GM SPATIALLY WEIGHTED 2SLS (HET) - REGIMES") + else: + self.title = ("GM SPATIALLY WEIGHTED 2SLS + SLX (SDEM-HET) - REGIMES") + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + def _endog_error_het_regimes_multi( + self, + y, + x, + regimes, + w, + yend, + q, + slx_lags, + cores, + max_iter, + epsilon, + step1c, + inv_method, + cols2regi, + vm, + name_x, + name_yend, + name_q, + add_lag, + latex, + ): + + regi_ids = dict( + (r, list(np.where(np.array(regimes) == r)[0])) for r in self.regimes_set + ) + if add_lag != False: + self.cols2regi += [True] + cols2regi += [True] + self.predy_e = np.zeros((self.n, 1), float) + self.e_pred = np.zeros((self.n, 1), float) + results_p = {} + """ + for r in self.regimes_set: + if system() == 'Windows': + is_win = True + results_p[r] = _work_endog_error(*(y,x,yend,q,regi_ids,r,w,max_iter,epsilon,step1c,inv_method,self.name_ds,self.name_y,name_x,name_yend,name_q,self.name_w,self.name_regimes,add_lag)) + else: + pool = mp.Pool(cores) + results_p[r] = pool.apply_async(_work_endog_error,args=(y,x,yend,q,regi_ids,r,w,max_iter,epsilon,step1c,inv_method,self.name_ds,self.name_y,name_x,name_yend,name_q,self.name_w,self.name_regimes,add_lag, )) + is_win = False + """ + x_constant, name_x = REGI.check_const_regi(self, x, name_x, regi_ids) + self.name_x_r = name_x + name_yend + for r in self.regimes_set: + if cores: + pool = mp.Pool(None) + results_p[r] = pool.apply_async( + _work_endog_error, + args=( + y, + x_constant, + yend, + q, + regi_ids, + r, + w, + max_iter, + epsilon, + step1c, + inv_method, + self.name_ds, + self.name_y, + name_x, + name_yend, + name_q, + self.name_w, + self.name_regimes, + add_lag, + slx_lags, + ), + ) + else: + results_p[r] = _work_endog_error( + *( + y, + x_constant, + yend, + q, + regi_ids, + r, + w, + max_iter, + epsilon, + step1c, + inv_method, + self.name_ds, + self.name_y, + name_x, + name_yend, + name_q, + self.name_w, + self.name_regimes, + add_lag, + slx_lags, + ) + ) + + self.kryd, self.kf = 0, 0 + self.kr = len(cols2regi) + 1 + self.nr = len(self.regimes_set) + self.vm = np.zeros((self.nr * self.kr, self.nr * self.kr), float) + self.betas = np.zeros((self.nr * self.kr, 1), float) + self.u = np.zeros((self.n, 1), float) + self.predy = np.zeros((self.n, 1), float) + self.e_filtered = np.zeros((self.n, 1), float) + """ + if not is_win: + pool.close() + pool.join() + """ + if cores: + pool.close() + pool.join() + + results = {} + ( + self.name_y, + self.name_x, + self.name_yend, + self.name_q, + self.name_z, + self.name_h, + ) = ([], [], [], [], [], []) + counter = 0 + self.output = pd.DataFrame(columns=['var_names', 'var_type', 'regime', 'equation']) + for r in self.regimes_set: + """ + if is_win: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + """ + if not cores: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + + self.vm[ + (counter * self.kr) : ((counter + 1) * self.kr), + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].vm + self.betas[ + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].betas + self.u[ + regi_ids[r], + ] = results[r].u + self.predy[ + regi_ids[r], + ] = results[r].predy + self.e_filtered[ + regi_ids[r], + ] = results[r].e_filtered + self.name_y += results[r].name_y + self.name_x += results[r].name_x + self.name_yend += results[r].name_yend + self.name_q += results[r].name_q + self.name_z += results[r].name_z + self.name_h += results[r].name_h + if add_lag != False: + self.predy_e[ + regi_ids[r], + ] = results[r].predy_e + self.e_pred[ + regi_ids[r], + ] = results[r].e_pred + results[r].other_top = _spat_pseudo_r2(results[r]) + v_type = ['x'] * len(results[r].name_x) + ['yend'] * (len(results[r].name_yend)-1) + ['rho','lambda'] + else: + results[r].other_top = "" + v_type = ['x'] * len(results[r].name_x) + ['yend'] * len(results[r].name_yend) + ['lambda'] + results[r].other_top += _summary_iteration(results[r]) + self.output = pd.concat([self.output, pd.DataFrame({'var_names': results[r].name_z, + 'var_type': v_type, + 'regime': r, 'equation': r})], ignore_index=True) + counter += 1 + self.chow = REGI.Chow(self) + self.multi = results + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +
[docs]class GM_Combo_Het_Regimes(GM_Endog_Error_Het_Regimes): + + """ + GMM method for a spatial lag and error model with heteroskedasticity, + regimes and endogenous variables, with results and diagnostics; + based on Arraiz et al :cite:`Arraiz2010`, following Anselin :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + w : pysal W object + Spatial weights object (always needed) + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep : boolean + If True, a separate regression is run for each regime. + regime_lag_sep : boolean + If True, the spatial parameter for spatial lag is also + computed according to different regimes. If False (default), + the spatial parameter is fixed across regimes. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the GNSM type. + w_lags : integer + Orders of W to include as instruments for the spatially + lagged dependent variable. For example, w_lags=1, then + instruments are WX; if w_lags=2, then WX, WWX; and so on. + lag_q : boolean + If True, then include spatial lags of the additional + instruments (q). + max_iter : int + Maximum number of iterations of steps 2a and 2b from + :cite:`Arraiz2010`. Note: epsilon provides an additional stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + step1c : boolean + If True, then include Step 1c from :cite:`Arraiz2010`. + inv_method : string + If "power_exp", then compute inverse using the power + expansion. If "true_inv", then compute the true inverse. + Note that true_inv will fail for large n. + vm : boolean + If True, include variance-covariance matrix in summary + results + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + e_pred : array + nx1 array of residuals (using reduced form) + predy : array + nx1 array of predicted y values + predy_e : array + nx1 array of predicted y values (using reduced form) + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z : array + nxk array of variables (combination of x and yend) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + h : array + nxl array of instruments (combination of x and q) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi : string + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + regime_lag_sep: boolean + If True, the spatial parameter for spatial lag is also + computed according to different regimes. If False (default), + the spatial parameter is fixed across regimes. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path("natregimes.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to run a spatial combo model, we need to specify + the spatial weights matrix that includes the spatial configuration of the + observations. To do that, we can open an already existing gal file or + create a new one. In this case, we will create one from ``NAT.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(nat.get_path("natregimes.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + Example only with spatial lag + + The Combo class runs an SARAR model, that is a spatial lag+error model. + In this case we will run a simple version of that, where we have the + spatial effects as well as exogenous variables. Since it is a spatial + model, we have to pass in the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. We can have a + summary of the output by typing: model.summary + Alternatively, we can check the betas: + + >>> reg = GM_Combo_Het_Regimes(y, x, regimes, w=w, step1c=True, name_y=y_var, name_x=x_var, name_regimes=r_var, name_ds='NAT') + >>> print(reg.name_z) + ['0_CONSTANT', '0_PS90', '0_UE90', '1_CONSTANT', '1_PS90', '1_UE90', '_Global_W_HR90', 'lambda'] + >>> print(np.around(reg.betas,4)) + [[ 1.4613] + [ 0.9587] + [ 0.5658] + [ 9.1157] + [ 1.1324] + [ 0.6518] + [-0.4587] + [ 0.7174]] + + This class also allows the user to run a spatial lag+error model with the + extra feature of including non-spatial endogenous regressors. This means + that, in addition to the spatial lag and error, we consider some of the + variables on the right-hand side of the equation as endogenous and we + instrument for this. In this case we consider RD90 (resource deprivation) + as an endogenous regressor. We use FP89 (families below poverty) + for this and hence put it in the instruments parameter, 'q'. + + >>> yd_var = ['RD90'] + >>> yd = np.array([db.by_col(name) for name in yd_var]).T + >>> q_var = ['FP89'] + >>> q = np.array([db.by_col(name) for name in q_var]).T + + And then we can run and explore the model analogously to the previous combo: + + >>> reg = GM_Combo_Het_Regimes(y, x, regimes, yd, q, w=w, step1c=True, name_y=y_var, name_x=x_var, name_yend=yd_var, name_q=q_var, name_regimes=r_var, name_ds='NAT') + >>> print(reg.name_z) + ['0_CONSTANT', '0_PS90', '0_UE90', '1_CONSTANT', '1_PS90', '1_UE90', '0_RD90', '1_RD90', '_Global_W_HR90', 'lambda'] + >>> print(reg.betas) + [[ 3.41936197] + [ 1.04071048] + [ 0.16747219] + [ 8.85820215] + [ 1.847382 ] + [-0.24545394] + [ 2.43189808] + [ 3.61328423] + [ 0.03132164] + [ 0.29544224]] + >>> print(np.sqrt(reg.vm.diagonal())) + [0.53103804 0.20835827 0.05755679 1.00496234 0.34332131 0.10259525 + 0.3454436 0.37932794 0.07611667 0.07067059] + >>> print('lambda: ', np.around(reg.betas[-1], 4)) + lambda: [0.2954] + + """ + +
[docs] def __init__( + self, + y, + x, + regimes, + yend=None, + q=None, + w=None, + slx_lags=0, + w_lags=1, + lag_q=True, + max_iter=1, + epsilon=0.00001, + step1c=False, + cores=False, + inv_method="power_exp", + constant_regi="many", + cols2regi="all", + regime_err_sep=False, + regime_lag_sep=False, + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + name_regimes=None, + latex=False, + ): + if regime_lag_sep and not regime_err_sep: + set_warn(self, "regime_err_sep set to True when regime_lag_sep=True.") + regime_err_sep = True + if regime_err_sep and not regime_lag_sep: + set_warn(self, "regime_err_sep set to False when regime_lag_sep=False.") + regime_err_sep = False + n = USER.check_arrays(y, x) + self.step1c = step1c + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + + self.name_y = USER.set_name_y(name_y) + name_yend = USER.set_name_yend(name_yend, yend) + name_q = USER.set_name_q(name_q, q) + + if regime_err_sep and any(col != True for col in cols2regi): + set_warn(self, "All coefficients must vary across regimes if regime_err_sep = True, so setting cols2regi = 'all'.") + cols2regi = "all" + + if slx_lags > 0: + yend2, q2, wx = set_endog(y, x_constant, w, yend, q, w_lags, lag_q, slx_lags) + x_constant = np.hstack((x_constant, wx)) + name_slx = USER.set_name_spatial_lags(name_x, slx_lags) + name_q.extend(USER.set_name_q_sp(name_slx[-len(name_x):], w_lags, name_q, lag_q, force_all=True)) + name_x += name_slx + cols2regi = REGI.check_cols2regi(constant_regi, cols2regi, x_constant[:, :-1], yend=yend2, add_cons=False) + else: + name_q.extend(USER.set_name_q_sp(name_x, w_lags, name_q, lag_q, force_all=True)) + yend2, q2 = yend, q + cols2regi = REGI.check_cols2regi(constant_regi, cols2regi, x_constant, yend=yend2, add_cons=False) + + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, n, x_constant.shape[1]) + self.regime_err_sep = regime_err_sep + self.regime_lag_sep = regime_lag_sep + + if regime_lag_sep == True: + if slx_lags == 0: + add_lag = [w_lags, lag_q] + else: + cols2regi += [True] + add_lag = False + else: + add_lag = False + cols2regi += [False] + if slx_lags == 0: + yend2, q2 = set_endog(y, x_constant, w, yend2, q2, w_lags, lag_q) + + name_yend.append(USER.set_name_yend_sp(self.name_y)) + + GM_Endog_Error_Het_Regimes.__init__( + self, + y=y, + x=x_constant, + yend=yend2, + q=q2, + regimes=regimes, + w=w, + constant_regi=constant_regi, + cols2regi=cols2regi, + regime_err_sep=regime_err_sep, + max_iter=max_iter, + epsilon=epsilon, + step1c=step1c, + inv_method=inv_method, + cores=cores, + vm=vm, + name_y=name_y, + name_x=name_x, + name_yend=name_yend, + name_q=name_q, + name_w=name_w, + name_ds=name_ds, + name_regimes=name_regimes, + summ=False, + add_lag=add_lag, + latex=latex, + ) + + if regime_err_sep != True: + self.rho = self.betas[-2] + self.predy_e, self.e_pred, warn = UTILS.sp_att( + w, self.y, self.predy, yend2[:, -1].reshape(self.n, 1), self.rho + ) + UTILS.set_warn(self, warn) + self.regime_lag_sep = regime_lag_sep + if slx_lags == 0: + self.title = "GM SPATIALLY WEIGHTED 2SLS-COMBO MODEL (HET) - REGIMES" + else: + self.title = "GM SPATIALLY WEIGHTED 2SLS-COMBO + SLX (GNSM-HET) - REGIMES" + self.output.iat[-2, self.output.columns.get_loc('var_type')] = 'rho' + self.other_top = _spat_pseudo_r2(self) + self.other_top += _summary_iteration(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +def _work_error( + y, + x, + regi_ids, + r, + w, + max_iter, + epsilon, + step1c, + name_ds, + name_y, + name_x, + name_w, + name_regimes, + slx_lags, +): + w_r, warn = REGI.w_regime(w, regi_ids[r], r, transform=True) + y_r = y[regi_ids[r]] + x_r = x[regi_ids[r]] + model = BaseGM_Error_Het( + y_r, x_r, w_r.sparse, max_iter=max_iter, epsilon=epsilon, step1c=step1c + ) + set_warn(model, warn) + model.w = w_r + if slx_lags == 0: + model.title = "GM SPATIALLY WEIGHTED LS (HET) - REGIME %s" % r + else: + model.title = "GM SPATIALLY WEIGHTED LS + SLX (SDEM-HET) - REGIME %s" % r + model.name_ds = name_ds + model.name_y = "%s_%s" % (str(r), name_y) + model.name_x = ["%s_%s" % (str(r), i) for i in name_x] + model.name_w = name_w + model.name_regimes = name_regimes + return model + + +def _work_endog_error( + y, + x, + yend, + q, + regi_ids, + r, + w, + max_iter, + epsilon, + step1c, + inv_method, + name_ds, + name_y, + name_x, + name_yend, + name_q, + name_w, + name_regimes, + add_lag, + slx_lags, +): + w_r, warn = REGI.w_regime(w, regi_ids[r], r, transform=True) + y_r = y[regi_ids[r]] + x_r = x[regi_ids[r]] + if yend is not None: + yend_r = yend[regi_ids[r]] + q_r = q[regi_ids[r]] + else: + yend_r, q_r = None, None + if add_lag != False: + yend_r, q_r = set_endog( + y_r, x_r[:, 1:], w_r, yend_r, q_r, add_lag[0], add_lag[1] + ) + model = BaseGM_Endog_Error_Het( + y_r, + x_r, + yend_r, + q_r, + w_r.sparse, + max_iter=max_iter, + epsilon=epsilon, + step1c=step1c, + inv_method=inv_method, + ) + set_warn(model, warn) + if add_lag != False: + model.rho = model.betas[-2] + model.predy_e, model.e_pred, warn = sp_att( + w_r, model.y, model.predy, model.yend[:, -1].reshape(model.n, 1), model.rho + ) + set_warn(model, warn) + + if slx_lags == 0: + if add_lag != False: + model.title = "GM SPATIALLY WEIGHTED 2SLS-COMBO MODEL (HET)- REGIME %s" % r + else: + model.title = "GM SPATIALLY WEIGHTED 2SLS (HET) - REGIME %s" % r + else: + if add_lag != False: + model.title = "GM SPATIAL COMBO MODEL + SLX (GNSM-HET) - REGIME %s" % r + else: + model.title = "GM SPATIALLY WEIGHTED 2SLS + SLX (SDEM-HET) - REGIME %s" % r + model.name_ds = name_ds + model.name_y = "%s_%s" % (str(r), name_y) + model.name_x = ["%s_%s" % (str(r), i) for i in name_x] + model.name_yend = ["%s_%s" % (str(r), i) for i in name_yend] + model.name_z = model.name_x + model.name_yend + [str(r)+"lambda"] + model.name_q = ["%s_%s" % (str(r), i) for i in name_q] + model.name_h = model.name_x + model.name_q + model.name_w = name_w + model.name_regimes = name_regimes + return model + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + + import numpy as np + import libpysal + + db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + y = np.array(db.by_col("HOVAL")) + y = np.reshape(y, (49,1)) + X = [] + X.append(db.by_col("INC")) + X = np.array(X).T + yd = [] + yd.append(db.by_col("CRIME")) + yd = np.array(yd).T + q = [] + q.append(db.by_col("DISCBD")) + q = np.array(q).T + + r_var = 'NSA' + regimes = db.by_col(r_var) + + w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + w.transform = 'r' + #reg = GM_Error_Het_Regimes(y, X, regimes, w=w, name_x=['inc'], name_y='hoval', name_ds='columbus', vm=True, + # regime_err_sep=True) + #reg = GM_Endog_Error_Het_Regimes(y, X, yd, q, regimes, w=w, name_x=['inc'], name_y='hoval', name_yend=['crime'], + # name_q=['discbd'], name_ds='columbus',vm=True, regime_err_sep=True) + reg = GM_Combo_Het_Regimes(y, X, regimes, yd, q, w=w, step1c=True, name_x=['inc'], name_y='hoval', name_yend=['crime'], + name_q=['discbd'], name_ds='columbus', vm=True, regime_err_sep=False, regime_lag_sep=False) + print(reg.output) + print(reg.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/error_sp_hom.html b/_modules/spreg/error_sp_hom.html new file mode 100644 index 00000000..03dd3c2e --- /dev/null +++ b/_modules/spreg/error_sp_hom.html @@ -0,0 +1,1751 @@ + + + + + + + spreg.error_sp_hom — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.error_sp_hom

+"""
+Hom family of models based on: :cite:`Drukker2013` 
+Following: :cite:`Anselin2011`
+
+"""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu, Daniel Arribas-Bel darribas@asu.edu"
+
+from scipy import sparse as SP
+import numpy as np
+from numpy import linalg as la
+from . import ols as OLS
+from .utils import set_endog, iter_msg, sp_att
+from .utils import get_A1_hom, get_A2_hom, get_A1_het, optim_moments
+from .utils import get_spFilter, get_lags
+from .utils import spdot, RegressionPropsY, set_warn
+from . import twosls as TSLS
+from . import user_output as USER
+import pandas as pd
+from .output import output, _spat_pseudo_r2, _summary_iteration
+
+__all__ = ["GM_Error_Hom", "GM_Endog_Error_Hom", "GM_Combo_Hom"]
+
+
+class BaseGM_Error_Hom(RegressionPropsY):
+
+    """
+    GMM method for a spatial error model with homoskedasticity (note: no
+    consistency checks, diagnostics or constant added); based on
+    Drukker et al. (2013) :cite:`Drukker2013`, following Anselin (2011) :cite:`Anselin2011`.
+
+    Parameters
+    ----------
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, excluding the constant
+    w            : Sparse matrix
+                   Spatial weights sparse matrix
+    max_iter     : int
+                   Maximum number of iterations of steps 2a and 2b from :cite:`Arraiz2010`.
+                   Note: epsilon provides an additional stop condition.
+    epsilon      : float
+                   Minimum change in lambda required to stop iterations of
+                   steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides
+                   an additional stop condition.
+    A1           : string
+                   If A1='het', then the matrix A1 is defined as in :cite:`Arraiz2010`.
+                   If A1='hom', then as in :cite:`Anselin2011` (default).  If
+                   A1='hom_sc' (default), then as in :cite:`Drukker2013`
+                   and :cite:`Drukker:2013aa`.
+
+    Attributes
+    ----------
+    betas        : array
+                   kx1 array of estimated coefficients
+    u            : array
+                   nx1 array of residuals
+    e_filtered   : array
+                   nx1 array of spatially filtered residuals
+    predy        : array
+                   nx1 array of predicted y values
+    n            : integer
+                   Number of observations
+    k            : integer
+                   Number of variables for which coefficients are estimated
+                   (including the constant)
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, including the constant
+    iter_stop    : string
+                   Stop criterion reached during iteration of steps 2a and 2b
+                   from :cite:`Arraiz2010`.
+    iteration    : integer
+                   Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`.
+    mean_y       : float
+                   Mean of dependent variable
+    std_y        : float
+                   Standard deviation of dependent variable
+    vm           : array
+                   Variance covariance matrix (kxk)
+    sig2         : float
+                   Sigma squared used in computations
+    xtx          : float
+                   :math:`X'X`
+
+    Examples
+    --------
+    >>> import numpy as np
+    >>> import libpysal
+    >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r')
+    >>> y = np.array(db.by_col("HOVAL"))
+    >>> y = np.reshape(y, (49,1))
+    >>> X = []
+    >>> X.append(db.by_col("INC"))
+    >>> X.append(db.by_col("CRIME"))
+    >>> X = np.array(X).T
+    >>> X = np.hstack((np.ones(y.shape),X))
+    >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp"))
+    >>> w.transform = 'r'
+
+    Model commands
+
+    >>> reg = BaseGM_Error_Hom(y, X, w=w.sparse, A1='hom_sc')
+    >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4))
+    [[47.9479 12.3021]
+     [ 0.7063  0.4967]
+     [-0.556   0.179 ]
+     [ 0.4129  0.1835]]
+    >>> print(np.around(reg.vm, 4)) #doctest: +SKIP
+    [[  1.51340700e+02  -5.29060000e+00  -1.85650000e+00  -2.40000000e-03]
+     [ -5.29060000e+00   2.46700000e-01   5.14000000e-02   3.00000000e-04]
+     [ -1.85650000e+00   5.14000000e-02   3.21000000e-02  -1.00000000e-04]
+     [ -2.40000000e-03   3.00000000e-04  -1.00000000e-04   3.37000000e-02]]
+    """
+
+    def __init__(self, y, x, w, max_iter=1, epsilon=0.00001, A1="hom_sc"):
+        if A1 == "hom":
+            wA1 = get_A1_hom(w)
+        elif A1 == "hom_sc":
+            wA1 = get_A1_hom(w, scalarKP=True)
+        elif A1 == "het":
+            wA1 = get_A1_het(w)
+
+        wA2 = get_A2_hom(w)
+
+        # 1a. OLS --> \tilde{\delta}
+        ols = OLS.BaseOLS(y=y, x=x)
+        self.x, self.y, self.n, self.k, self.xtx = ols.x, ols.y, ols.n, ols.k, ols.xtx
+
+        # 1b. GM --> \tilde{\rho}
+        moments = moments_hom(w, wA1, wA2, ols.u)
+        lambda1 = optim_moments(moments)
+        lambda_old = lambda1
+
+        self.iteration, eps = 0, 1
+        while self.iteration < max_iter and eps > epsilon:
+            # 2a. SWLS --> \hat{\delta}
+            x_s = get_spFilter(w, lambda_old, self.x)
+            y_s = get_spFilter(w, lambda_old, self.y)
+            ols_s = OLS.BaseOLS(y=y_s, x=x_s)
+            self.predy = spdot(self.x, ols_s.betas)
+            self.u = self.y - self.predy
+
+            # 2b. GM 2nd iteration --> \hat{\rho}
+            moments = moments_hom(w, wA1, wA2, self.u)
+            psi = get_vc_hom(w, wA1, wA2, self, lambda_old)[0]
+            lambda2 = optim_moments(moments, psi)
+            eps = abs(lambda2 - lambda_old)
+            lambda_old = lambda2
+            self.iteration += 1
+
+        self.iter_stop = iter_msg(self.iteration, max_iter)
+
+        # Output
+        self.betas = np.vstack((ols_s.betas, lambda2))
+        self.vm, self.sig2 = get_omega_hom_ols(w, wA1, wA2, self, lambda2, moments[0])
+        self.e_filtered = self.u - lambda2 * w * self.u
+        self._cache = {}
+
+
+
[docs]class GM_Error_Hom(BaseGM_Error_Hom): + + """ + GMM method for a spatial error model with homoskedasticity, with results + and diagnostics; based on Drukker et al. (2013) :cite:`Drukker2013`, following Anselin + (2011) :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + w : pysal W object + Spatial weights object + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + max_iter : int + Maximum number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + Note: epsilon provides an additional stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + A1 : string + If A1='het', then the matrix A1 is defined as in Arraiz et + al. If A1='hom', then as in :cite:`Anselin2011`. If + A1='hom_sc' (default), then as in :cite:`Drukker2013` + and :cite:`Drukker:2013aa`. + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + iteration : integer + Number of iterations of steps 2a and 2b from Arraiz et al. + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + vm : array + Variance covariance matrix (kxk) + sig2 : float + Sigma squared used in computations + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + xtx : float + :math:`X'X` + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + + Extract the HOVAL column (home values) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) and CRIME (crime) vectors from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this class adds a vector of ones to the + independent variables passed in. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("CRIME")) + >>> X = np.array(X).T + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``columbus.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, his allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminars, we are good to run the model. In this + case, we will need the variables and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> reg = GM_Error_Hom(y, X, w=w, A1='hom_sc', name_y='home value', name_x=['income', 'crime'], name_ds='columbus') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. This class offers an error model that assumes + homoskedasticity but that unlike the models from + ``spreg.error_sp``, it allows for inference on the spatial + parameter. This is why you obtain as many coefficient estimates as + standard errors, which you calculate taking the square root of the + diagonal of the variance-covariance matrix of the parameters: + + >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4)) + [[47.9479 12.3021] + [ 0.7063 0.4967] + [-0.556 0.179 ] + [ 0.4129 0.1835]] + + """ + +
[docs] def __init__( + self, + y, + x, + w, + slx_lags=0, + max_iter=1, + epsilon=0.00001, + A1="hom_sc", + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + self.title = "GM SPATIALLY WEIGHTED LEAST SQUARES (HOM)" + if slx_lags >0: + lag_x = get_lags(w, x_constant[:, 1:], slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + self.title += " WITH SLX (SDEM)" + BaseGM_Error_Hom.__init__( + self, + y=y, + x=x_constant, + w=w.sparse, + A1=A1, + max_iter=max_iter, + epsilon=epsilon, + ) + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x_constant) + self.name_x.append("lambda") + self.name_w = USER.set_name_w(name_w, w) + self.A1 = A1 + self.output = pd.DataFrame(self.name_x, columns=['var_names']) + self.output['var_type'] = ['x'] * (len(self.name_x) - 1) + ['lambda'] + self.output['regime'], self.output['equation'] = (0, 0) + self.other_top = _summary_iteration(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +class BaseGM_Endog_Error_Hom(RegressionPropsY): + + """ + GMM method for a spatial error model with homoskedasticity and + endogenous variables (note: no consistency checks, diagnostics or constant + added); based on Drukker et al. (2013) :cite:`Drukker2013`, following Anselin (2011) + :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : Sparse matrix + Spatial weights sparse matrix + max_iter : int + Maximum number of iterations of steps 2a and 2b from + :cite:`Arraiz2010`. Note: epsilon provides an additional + stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + A1 : string + If A1='het', then the matrix A1 is defined as in Arraiz et + al. If A1='hom', then as in :cite:`Anselin2011`. If + A1='hom_sc' (default), then as in :cite:`Drukker2013` + and :cite:`Drukker:2013aa`. + + Attributes + ---------- + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + z : array + nxk array of variables (combination of x and yend) + h : array + nxl array of instruments (combination of x and q) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + sig2 : float + Sigma squared used in computations + hth : float + H'H + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + >>> X = np.hstack((np.ones(y.shape),X)) + >>> yd = [] + >>> yd.append(db.by_col("CRIME")) + >>> yd = np.array(yd).T + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + >>> w.transform = 'r' + >>> reg = BaseGM_Endog_Error_Hom(y, X, yd, q, w=w.sparse, A1='hom_sc') + >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4)) + [[55.3658 23.496 ] + [ 0.4643 0.7382] + [-0.669 0.3943] + [ 0.4321 0.1927]] + + + """ + + def __init__(self, y, x, yend, q, w, max_iter=1, epsilon=0.00001, A1="hom_sc"): + + if A1 == "hom": + wA1 = get_A1_hom(w) + elif A1 == "hom_sc": + wA1 = get_A1_hom(w, scalarKP=True) + elif A1 == "het": + wA1 = get_A1_het(w) + + wA2 = get_A2_hom(w) + + # 1a. S2SLS --> \tilde{\delta} + tsls = TSLS.BaseTSLS(y=y, x=x, yend=yend, q=q) + self.x, self.z, self.h, self.y, self.hth = ( + tsls.x, + tsls.z, + tsls.h, + tsls.y, + tsls.hth, + ) + self.yend, self.q, self.n, self.k = tsls.yend, tsls.q, tsls.n, tsls.k + + # 1b. GM --> \tilde{\rho} + moments = moments_hom(w, wA1, wA2, tsls.u) + lambda1 = optim_moments(moments) + lambda_old = lambda1 + + self.iteration, eps = 0, 1 + while self.iteration < max_iter and eps > epsilon: + # 2a. GS2SLS --> \hat{\delta} + x_s = get_spFilter(w, lambda_old, self.x) + y_s = get_spFilter(w, lambda_old, self.y) + yend_s = get_spFilter(w, lambda_old, self.yend) + tsls_s = TSLS.BaseTSLS(y=y_s, x=x_s, yend=yend_s, h=self.h) + self.predy = spdot(self.z, tsls_s.betas) + self.u = self.y - self.predy + + # 2b. GM 2nd iteration --> \hat{\rho} + moments = moments_hom(w, wA1, wA2, self.u) + psi = get_vc_hom(w, wA1, wA2, self, lambda_old, tsls_s.z)[0] + lambda2 = optim_moments(moments, psi) + eps = abs(lambda2 - lambda_old) + lambda_old = lambda2 + self.iteration += 1 + + self.iter_stop = iter_msg(self.iteration, max_iter) + + # Output + self.betas = np.vstack((tsls_s.betas, lambda2)) + self.vm, self.sig2 = get_omega_hom(w, wA1, wA2, self, lambda2, moments[0]) + self.e_filtered = self.u - lambda2 * w * self.u + self._cache = {} + + +
[docs]class GM_Endog_Error_Hom(BaseGM_Endog_Error_Hom): + + """ + GMM method for a spatial error model with homoskedasticity and endogenous + variables, with results and diagnostics; based on Drukker et al. (2013) + :cite:`Drukker2013`, following Anselin (2011) :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : pysal W object + Spatial weights object + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + max_iter : int + Maximum number of iterations of steps 2a and 2b from + :cite:`Arraiz2010`. Note: epsilon provides an additional stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + A1 : string + If A1='het', then the matrix A1 is defined as in :cite:`Arraiz2010`. + If A1='hom', then as in :cite:`Anselin2011`. If + A1='hom_sc' (default), then as in :cite:`Drukker2013` + and :cite:`Drukker:2013aa`. + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + z : array + nxk array of variables (combination of x and yend) + h : array + nxl array of instruments (combination of x and q) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + sig2 : float + Sigma squared used in computations + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + hth : float + :math:`H'H` + + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + + Extract the HOVAL column (home values) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) vector from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this class adds a vector of ones to the + independent variables passed in. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + + In this case we consider CRIME (crime rates) is an endogenous regressor. + We tell the model that this is so by passing it in a different parameter + from the exogenous variables (x). + + >>> yd = [] + >>> yd.append(db.by_col("CRIME")) + >>> yd = np.array(yd).T + + Because we have endogenous variables, to obtain a correct estimate of the + model, we need to instrument for CRIME. We use DISCBD (distance to the + CBD) for this and hence put it in the instruments parameter, 'q'. + + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``columbus.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, his allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminars, we are good to run the model. In this + case, we will need the variables (exogenous and endogenous), the + instruments and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> reg = GM_Endog_Error_Hom(y, X, yd, q, w=w, A1='hom_sc', name_x=['inc'], name_y='hoval', name_yend=['crime'], name_q=['discbd'], name_ds='columbus') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. This class offers an error model that assumes + homoskedasticity but that unlike the models from + ``spreg.error_sp``, it allows for inference on the spatial + parameter. Hence, we find the same number of betas as of standard errors, + which we calculate taking the square root of the diagonal of the + variance-covariance matrix: + + >>> print(reg.name_z) + ['CONSTANT', 'inc', 'crime', 'lambda'] + >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4)) + [[55.3658 23.496 ] + [ 0.4643 0.7382] + [-0.669 0.3943] + [ 0.4321 0.1927]] + """ + +
[docs] def __init__( + self, + y, + x, + yend, + q, + w, + slx_lags=0, + max_iter=1, + epsilon=0.00001, + A1="hom_sc", + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(y, x, yend, q) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + self.title = "GM SPATIALLY WEIGHTED TWO STAGE LEAST SQUARES (HOM)" + if slx_lags > 0: + lag_x = get_lags(w, x_constant[:, 1:], slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + self.title += " WITH SLX (SDEM)" + BaseGM_Endog_Error_Hom.__init__( + self, + y=y, + x=x_constant, + w=w.sparse, + yend=yend, + q=q, + A1=A1, + max_iter=max_iter, + epsilon=epsilon, + ) + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x_constant) + self.name_yend = USER.set_name_yend(name_yend, yend) + self.name_z = self.name_x + self.name_yend + self.name_z.append("lambda") # listing lambda last + self.name_q = USER.set_name_q(name_q, q) + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.name_w = USER.set_name_w(name_w, w) + self.A1 = A1 + self.output = pd.DataFrame(self.name_z, + columns=['var_names']) + self.output['var_type'] = ['x'] * len(self.name_x) + ['yend'] * len(self.name_yend) + ['lambda'] + self.output['regime'], self.output['equation'] = (0, 0) + self.other_top = _summary_iteration(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +class BaseGM_Combo_Hom(BaseGM_Endog_Error_Hom): + + """ + GMM method for a spatial lag and error model with homoskedasticity and + endogenous variables (note: no consistency checks, diagnostics or constant + added); based on Drukker et al. (2013) :cite:`Drukker2013`, following Anselin (2011) + :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : Sparse matrix + Spatial weights sparse matrix + w_lags : integer + Orders of W to include as instruments for the spatially + lagged dependent variable. For example, w_lags=1, then + instruments are WX; if w_lags=2, then WX, WWX; and so on. + lag_q : boolean + If True, then include spatial lags of the additional + instruments (q). + max_iter : int + Maximum number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + Note: epsilon provides an additional stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + A1 : string + If A1='het', then the matrix A1 is defined as in Arraiz et + al. If A1='hom', then as in :cite:`Anselin2011`. If + A1='hom_sc' (default), then as in :cite:`Drukker2013` + and :cite:`Drukker:2013aa`. + + + Attributes + ---------- + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + z : array + nxk array of variables (combination of x and yend) + h : array + nxl array of instruments (combination of x and q) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + sig2 : float + Sigma squared used in computations + hth : float + :math:`H'H` + + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> import spreg + >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + >>> w.transform = 'r' + >>> w_lags = 1 + >>> yd2, q2 = spreg.set_endog(y, X, w, None, None, w_lags, True) + >>> X = np.hstack((np.ones(y.shape),X)) + + Example only with spatial lag + + >>> reg = spreg.error_sp_hom.BaseGM_Combo_Hom(y, X, yend=yd2, q=q2, w=w.sparse, A1='hom_sc') + >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4)) + [[10.1254 15.2871] + [ 1.5683 0.4407] + [ 0.1513 0.4048] + [ 0.2103 0.4226]] + + + Example with both spatial lag and other endogenous variables + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + >>> yd = [] + >>> yd.append(db.by_col("CRIME")) + >>> yd = np.array(yd).T + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + >>> yd2, q2 = spreg.set_endog(y, X, w, yd, q, w_lags, True) + >>> X = np.hstack((np.ones(y.shape),X)) + >>> reg = spreg.error_sp_hom.BaseGM_Combo_Hom(y, X, yd2, q2, w=w.sparse, A1='hom_sc') + >>> betas = np.array([['CONSTANT'],['inc'],['crime'],['W_hoval'],['lambda']]) + >>> print(np.hstack((betas, np.around(np.hstack((reg.betas, np.sqrt(reg.vm.diagonal()).reshape(5,1))),5)))) + [['CONSTANT' '111.77057' '67.75191'] + ['inc' '-0.30974' '1.16656'] + ['crime' '-1.36043' '0.6841'] + ['W_hoval' '-0.52908' '0.84428'] + ['lambda' '0.60116' '0.18605']] + + """ + + def __init__( + self, + y, + x, + yend=None, + q=None, + w=None, + w_lags=1, + lag_q=True, + max_iter=1, + epsilon=0.00001, + A1="hom_sc", + ): + + BaseGM_Endog_Error_Hom.__init__( + self, + y=y, + x=x, + w=w, + yend=yend, + q=q, + A1=A1, + max_iter=max_iter, + epsilon=epsilon, + ) + + +
[docs]class GM_Combo_Hom(BaseGM_Combo_Hom): + + """ + GMM method for a spatial lag and error model with homoskedasticity and + endogenous variables, with results and diagnostics; based on Drukker et + al. (2013) :cite:`Drukker2013`, following Anselin (2011) :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : pysal W object + Spatial weights object (always necessary) + w_lags : integer + Orders of W to include as instruments for the spatially + lagged dependent variable. For example, w_lags=1, then + instruments are WX; if w_lags=2, then WX, WWX; and so on. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the General Nesting + Spatial Model (GNSM) type. + lag_q : boolean + If True, then include spatial lags of the additional + instruments (q). + max_iter : int + Maximum number of iterations of steps 2a and 2b from + :cite:`Arraiz2010`. Note: epsilon provides an additional + stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + A1 : string + If A1='het', then the matrix A1 is defined as in :cite:`Arraiz2010`. + If A1='hom', then as in :cite:`Anselin2011`. If + A1='hom_sc' (default), then as in :cite:`Drukker2013` + and :cite:`Drukker:2013aa`. + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + e_pred : array + nx1 array of residuals (using reduced form) + predy : array + nx1 array of predicted y values + predy_e : array + nx1 array of predicted y values (using reduced form) + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + z : array + nxk array of variables (combination of x and yend) + h : array + nxl array of instruments (combination of x and q) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + sig2 : float + Sigma squared used in computations (based on filtered + residuals) + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + hth : float + :math:`H'H` + + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + + Extract the HOVAL column (home values) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) vector from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this class adds a vector of ones to the + independent variables passed in. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``columbus.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, his allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + Example only with spatial lag + + The Combo class runs an SARAR model, that is a spatial lag+error model. + In this case we will run a simple version of that, where we have the + spatial effects as well as exogenous variables. Since it is a spatial + model, we have to pass in the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import GM_Combo_Hom + >>> reg = GM_Combo_Hom(y, X, w=w, A1='hom_sc', name_x=['inc'],\ + name_y='hoval', name_yend=['crime'], name_q=['discbd'],\ + name_ds='columbus') + >>> print(np.around(np.hstack((reg.betas,np.sqrt(reg.vm.diagonal()).reshape(4,1))),4)) + [[10.1254 15.2871] + [ 1.5683 0.4407] + [ 0.1513 0.4048] + [ 0.2103 0.4226]] + + This class also allows the user to run a spatial lag+error model with the + extra feature of including non-spatial endogenous regressors. This means + that, in addition to the spatial lag and error, we consider some of the + variables on the right-hand side of the equation as endogenous and we + instrument for this. As an example, we will include CRIME (crime rates) as + endogenous and will instrument with DISCBD (distance to the CSB). We first + need to read in the variables: + + + >>> yd = [] + >>> yd.append(db.by_col("CRIME")) + >>> yd = np.array(yd).T + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + + And then we can run and explore the model analogously to the previous combo: + + >>> reg = GM_Combo_Hom(y, X, yd, q, w=w, A1='hom_sc', \ + name_ds='columbus') + >>> betas = np.array([['CONSTANT'],['inc'],['crime'],['W_hoval'],['lambda']]) + >>> print(np.hstack((betas, np.around(np.hstack((reg.betas, np.sqrt(reg.vm.diagonal()).reshape(5,1))),5)))) + [['CONSTANT' '111.77057' '67.75191'] + ['inc' '-0.30974' '1.16656'] + ['crime' '-1.36043' '0.6841'] + ['W_hoval' '-0.52908' '0.84428'] + ['lambda' '0.60116' '0.18605']] + + """ + +
[docs] def __init__( + self, + y, + x, + yend=None, + q=None, + w=None, + w_lags=1, + slx_lags=0, + lag_q=True, + max_iter=1, + epsilon=0.00001, + A1="hom_sc", + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(y, x, yend, q) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + if slx_lags == 0: + yend2, q2 = set_endog(y, x_constant[:, 1:], w, yend, q, w_lags, lag_q) + else: + yend2, q2, wx = set_endog(y, x_constant[:, 1:], w, yend, q, w_lags, lag_q, slx_lags) + x_constant = np.hstack((x_constant, wx)) + BaseGM_Combo_Hom.__init__( + self, + y=y, + x=x_constant, + w=w.sparse, + yend=yend2, + q=q2, + w_lags=w_lags, + A1=A1, + lag_q=lag_q, + max_iter=max_iter, + epsilon=epsilon, + ) + self.rho = self.betas[-2] + self.predy_e, self.e_pred, warn = sp_att( + w, self.y, self.predy, yend2[:, -1].reshape(self.n, 1), self.rho + ) + set_warn(self, warn) + self.title = "SPATIALLY WEIGHTED 2SLS- GM-COMBO MODEL (HOM)" + if slx_lags > 0: + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + self.title += " WITH SLX (GNSM)" + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x_constant) + self.name_yend = USER.set_name_yend(name_yend, yend) + self.name_yend.append(USER.set_name_yend_sp(self.name_y)) + self.name_z = self.name_x + self.name_yend + self.name_z.append("lambda") # listing lambda last + self.name_q = USER.set_name_q(name_q, q) + self.name_q.extend(USER.set_name_q_sp(self.name_x, w_lags, self.name_q, lag_q)) + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.name_w = USER.set_name_w(name_w, w) + self.A1 = A1 + self.output = pd.DataFrame(self.name_z, + columns=['var_names']) + self.output['var_type'] = ['x'] * len(self.name_x) + ['yend'] * (len(self.name_yend) - 1) + ['rho', 'lambda'] + self.output['regime'], self.output['equation'] = (0, 0) + self.other_top = _spat_pseudo_r2(self) + self.other_top += _summary_iteration(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ +# Functions + + +def moments_hom(w, wA1, wA2, u): + """ + Compute G and g matrices for the spatial error model with homoscedasticity + as in Anselin :cite:`Anselin2011` (2011). + + Parameters + ---------- + + w : Sparse matrix + Spatial weights sparse matrix + + u : array + Residuals. nx1 array assumed to be aligned with w + + Attributes + ---------- + + moments : list + List of two arrays corresponding to the matrices 'G' and + 'g', respectively. + + + """ + n = w.shape[0] + A1u = wA1 * u + A2u = wA2 * u + wu = w * u + + g1 = np.dot(u.T, A1u) + g2 = np.dot(u.T, A2u) + g = np.array([[g1][0][0], [g2][0][0]]) / n + + G11 = 2 * np.dot(wu.T * wA1, u) + G12 = -np.dot(wu.T * wA1, wu) + G21 = 2 * np.dot(wu.T * wA2, u) + G22 = -np.dot(wu.T * wA2, wu) + G = np.array([[G11[0][0], G12[0][0]], [G21[0][0], G22[0][0]]]) / n + return [G, g] + + +def get_vc_hom(w, wA1, wA2, reg, lambdapar, z_s=None, for_omegaOLS=False): + """ + VC matrix \psi of Spatial error with homoscedasticity. As in + Anselin (2011) :cite:`Anselin2011` (p. 20) + ... + + Parameters + ---------- + w : Sparse matrix + Spatial weights sparse matrix + reg : reg + Regression object + lambdapar : float + Spatial parameter estimated in previous step of the + procedure + z_s : array + optional argument for spatially filtered Z (to be + passed only if endogenous variables are present) + for_omegaOLS : boolean + If True (default=False), it also returns P, needed + only in the computation of Omega + + Returns + ------- + psi : array + 2x2 VC matrix + a1 : array + nx1 vector a1. If z_s=None, a1 = 0. + a2 : array + nx1 vector a2. If z_s=None, a2 = 0. + p : array + P matrix. If z_s=None or for_omegaOLS=False, p=0. + + """ + u_s = get_spFilter(w, lambdapar, reg.u) + n = float(w.shape[0]) + sig2 = np.dot(u_s.T, u_s) / n + mu3 = np.sum(u_s ** 3) / n + mu4 = np.sum(u_s ** 4) / n + + tr11 = wA1 * wA1 + tr11 = np.sum(tr11.diagonal()) + tr12 = wA1 * (wA2 * 2) + tr12 = np.sum(tr12.diagonal()) + tr22 = wA2 * wA2 * 2 + tr22 = np.sum(tr22.diagonal()) + vecd1 = np.array([wA1.diagonal()]).T + + psi11 = 2 * sig2 ** 2 * tr11 + (mu4 - 3 * sig2 ** 2) * np.dot(vecd1.T, vecd1) + psi12 = sig2 ** 2 * tr12 + psi22 = sig2 ** 2 * tr22 + + a1, a2, p = 0.0, 0.0, 0.0 + + if for_omegaOLS: + x_s = get_spFilter(w, lambdapar, reg.x) + p = la.inv(spdot(x_s.T, x_s) / n) + + if ( + issubclass(type(z_s), np.ndarray) + or issubclass(type(z_s), SP.csr.csr_matrix) + or issubclass(type(z_s), SP.csc.csc_matrix) + ): + alpha1 = (-2 / n) * spdot(z_s.T, wA1 * u_s) + alpha2 = (-2 / n) * spdot(z_s.T, wA2 * u_s) + + hth = spdot(reg.h.T, reg.h) + hthni = la.inv(hth / n) + htzsn = spdot(reg.h.T, z_s) / n + p = spdot(hthni, htzsn) + p = spdot(p, la.inv(spdot(htzsn.T, p))) + hp = spdot(reg.h, p) + a1 = spdot(hp, alpha1) + a2 = spdot(hp, alpha2) + + psi11 = psi11 + sig2 * spdot(a1.T, a1) + 2 * mu3 * spdot(a1.T, vecd1) + psi12 = psi12 + sig2 * spdot(a1.T, a2) + mu3 * spdot(a2.T, vecd1) # 3rd term=0 + psi22 = psi22 + sig2 * spdot(a2.T, a2) # 3rd&4th terms=0 bc vecd2=0 + + psi = np.array([[psi11[0][0], psi12[0][0]], [psi12[0][0], psi22[0][0]]]) / n + return psi, a1, a2, p + + +def get_omega_hom(w, wA1, wA2, reg, lamb, G): + """ + Omega VC matrix for Hom models with endogenous variables computed as in + Anselin (2011) :cite:`Anselin2011` (p. 21). + ... + + Parameters + ---------- + w : Sparse matrix + Spatial weights sparse matrix + reg : reg + Regression object + lamb : float + Spatial parameter estimated in previous step of the + procedure + G : array + Matrix 'G' of the moment equation + + Returns + ------- + omega : array + Omega matrix of VC of the model + + """ + n = float(w.shape[0]) + z_s = get_spFilter(w, lamb, reg.z) + u_s = get_spFilter(w, lamb, reg.u) + sig2 = np.dot(u_s.T, u_s) / n + mu3 = np.sum(u_s ** 3) / n + vecdA1 = np.array([wA1.diagonal()]).T + psi, a1, a2, p = get_vc_hom(w, wA1, wA2, reg, lamb, z_s) + j = np.dot(G, np.array([[1.0], [2 * lamb]])) + psii = la.inv(psi) + t2 = spdot(reg.h.T, np.hstack((a1, a2))) + psiDL = ( + mu3 * spdot(reg.h.T, np.hstack((vecdA1, np.zeros((int(n), 1))))) + + sig2 * spdot(reg.h.T, np.hstack((a1, a2))) + ) / n + + oDD = spdot(la.inv(spdot(reg.h.T, reg.h)), spdot(reg.h.T, z_s)) + oDD = sig2 * la.inv(spdot(z_s.T, spdot(reg.h, oDD))) + oLL = la.inv(spdot(j.T, spdot(psii, j))) / n + oDL = spdot(spdot(spdot(p.T, psiDL), spdot(psii, j)), oLL) + + o_upper = np.hstack((oDD, oDL)) + o_lower = np.hstack((oDL.T, oLL)) + return np.vstack((o_upper, o_lower)), float(sig2) + + +def get_omega_hom_ols(w, wA1, wA2, reg, lamb, G): + """ + Omega VC matrix for Hom models without endogenous variables (OLS) computed + as in Anselin (2011) :cite:`Anselin2011`. + ... + + Parameters + ---------- + w : Sparse matrix + Spatial weights sparse matrix + reg : reg + Regression object + lamb : float + Spatial parameter estimated in previous step of the + procedure + G : array + Matrix 'G' of the moment equation + + Returns + ------- + omega : array + Omega matrix of VC of the model + + """ + n = float(w.shape[0]) + x_s = get_spFilter(w, lamb, reg.x) + u_s = get_spFilter(w, lamb, reg.u) + sig2 = np.dot(u_s.T, u_s) / n + vecdA1 = np.array([wA1.diagonal()]).T + psi, a1, a2, p = get_vc_hom(w, wA1, wA2, reg, lamb, for_omegaOLS=True) + j = np.dot(G, np.array([[1.0], [2 * lamb]])) + psii = la.inv(psi) + + oDD = sig2 * la.inv(spdot(x_s.T, x_s)) + oLL = la.inv(spdot(j.T, spdot(psii, j))) / n + # oDL = np.zeros((oDD.shape[0], oLL.shape[1])) + mu3 = np.sum(u_s ** 3) / n + psiDL = (mu3 * spdot(reg.x.T, np.hstack((vecdA1, np.zeros((int(n), 1)))))) / n + oDL = spdot(spdot(spdot(p.T, psiDL), spdot(psii, j)), oLL) + + o_upper = np.hstack((oDD, oDL)) + o_lower = np.hstack((oDL.T, oLL)) + return np.vstack((o_upper, o_lower)), float(sig2) + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + + import numpy as np + import libpysal + + db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + y = np.array(db.by_col("HOVAL")) + y = np.reshape(y, (49,1)) + X = [] + X.append(db.by_col("INC")) + X = np.array(X).T + yd = [] + yd.append(db.by_col("CRIME")) + yd = np.array(yd).T + q = [] + q.append(db.by_col("DISCBD")) + q = np.array(q).T + + w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + w.transform = 'r' + #reg = GM_Error_Hom(y, X, w=w, name_x=['inc'], name_y='hoval', name_ds='columbus', vm=True) + #reg = GM_Endog_Error_Hom(y, X, yd, q, w=w, name_x=['inc'], name_y='hoval', name_yend=['crime'], + # name_q=['discbd'], name_ds='columbus',vm=True) + reg = GM_Combo_Hom(y, X, yd, q, w=w, name_x=['inc'], name_y='hoval', name_yend=['crime'], name_q=['discbd'], + name_ds='columbus', vm=True) + + print(reg.output) + print(reg.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/error_sp_hom_regimes.html b/_modules/spreg/error_sp_hom_regimes.html new file mode 100644 index 00000000..1f93efbe --- /dev/null +++ b/_modules/spreg/error_sp_hom_regimes.html @@ -0,0 +1,2081 @@ + + + + + + + spreg.error_sp_hom_regimes — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.error_sp_hom_regimes

+"""
+Hom family of models with regimes. 
+"""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu, Pedro V. Amaral pedro.amaral@asu.edu, Daniel Arribas-Bel darribas@asu.edu"
+
+from scipy import sparse as SP
+import numpy as np
+import multiprocessing as mp
+from numpy import linalg as la
+from libpysal.weights.spatial_lag import lag_spatial
+from .utils import power_expansion, set_endog, iter_msg, sp_att
+from .utils import get_A1_hom, get_A2_hom, get_A1_het, optim_moments
+from .utils import get_spFilter, get_lags, _moments2eqs
+from .utils import spdot, RegressionPropsY, set_warn
+from .sputils import sphstack
+from .ols import BaseOLS
+from .twosls import BaseTSLS
+from .error_sp_hom import (
+    BaseGM_Error_Hom,
+    BaseGM_Endog_Error_Hom,
+    moments_hom,
+    get_vc_hom,
+    get_omega_hom,
+    get_omega_hom_ols,
+)
+from . import regimes as REGI
+from . import user_output as USER
+from platform import system
+import pandas as pd
+from .output import output, _summary_iteration, _spat_pseudo_r2
+
+
[docs]class GM_Error_Hom_Regimes(RegressionPropsY, REGI.Regimes_Frame): + + """ + GMM method for a spatial error model with homoskedasticity, with regimes, + results and diagnostics; based on Drukker et al. (2013) :cite:`Drukker2013`, following + Anselin (2011) :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + w : pysal W object + Spatial weights object + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + regime_lag_sep: boolean + Always False, kept for consistency, ignored. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + max_iter : int + Maximum number of iterations of steps 2a and 2b from + :cite:`Arraiz2010`. Note: epsilon provides an additional + stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + A1 : string + If A1='het', then the matrix A1 is defined as in + :cite:`Arraiz2010`. If A1='hom', then as in :cite:`Anselin2011`. If + A1='hom_sc', then as in :cite:`Drukker2013` + and :cite:`Drukker:2013aa`. + vm : boolean + If True, include variance-covariance matrix in summary + results + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + vm : array + Variance covariance matrix (kxk) + sig2 : float + Sigma squared used in computations + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + xtx : float + :math:`X'X`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi: string + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path("NAT.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to run a spatial lag model, we need to specify + the spatial weights matrix that includes the spatial configuration of the + observations. To do that, we can open an already existing gal file or + create a new one. In this case, we will create one from ``NAT.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("NAT.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import GM_Error_Hom_Regimes + >>> reg = GM_Error_Hom_Regimes(y, x, regimes, w=w, name_y=y_var, name_x=x_var, name_ds='NAT') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. This class offers an error model that assumes + homoskedasticity but that unlike the models from + ``spreg.error_sp``, it allows for inference on the spatial + parameter. This is why you obtain as many coefficient estimates as + standard errors, which you calculate taking the square root of the + diagonal of the variance-covariance matrix of the parameters. Alternatively, + we can have a summary of the output by typing: model.summary + >>> print(reg.name_x) + ['0_CONSTANT', '0_PS90', '0_UE90', '1_CONSTANT', '1_PS90', '1_UE90', 'lambda'] + + >>> print(np.around(reg.betas,4)) + [[0.069 ] + [0.7885] + [0.5398] + [5.0948] + [1.1965] + [0.6018] + [0.4104]] + + >>> print(np.sqrt(reg.vm.diagonal())) + [0.39105853 0.15664624 0.05254328 0.48379958 0.20018799 0.05834139 + 0.01882401] + """ + +
[docs] def __init__( + self, + y, + x, + regimes, + w, + max_iter=1, + epsilon=0.00001, + A1="het", + cores=False, + constant_regi="many", + cols2regi="all", + regime_err_sep=False, + regime_lag_sep=False, + slx_lags=0, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + name_regimes=None, + latex=False, + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + self.constant_regi = constant_regi + self.cols2regi = cols2regi + self.regime_err_sep = regime_err_sep + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_w = USER.set_name_w(name_w, w) + self.name_regimes = USER.set_name_ds(name_regimes) + self.n = n + self.y = y + + x_constant, name_x, warn = USER.check_constant(x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + + if slx_lags >0: + lag_x = get_lags(w, x_constant, slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + + self.name_x_r = USER.set_name_x(name_x, x_constant) + + cols2regi = REGI.check_cols2regi(constant_regi, cols2regi, x_constant) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, self.n, x_constant.shape[1]) + self.regime_err_sep = regime_err_sep + + if regime_err_sep == True: + if set(cols2regi) == set([True]): + self._error_hom_regimes_multi( + y, + x_constant, + regimes, + w, + slx_lags, + cores, + max_iter, + epsilon, + A1, + cols2regi, + vm, + name_x, + latex, + ) + else: + raise Exception( + "All coefficients must vary across regimes if regime_err_sep = True." + ) + else: + x_constant = sphstack(np.ones((x_constant.shape[0], 1)), x_constant) + name_x = USER.set_name_x(name_x, x_constant) + if A1 == "hom": + wA1 = get_A1_hom(w.sparse) + elif A1 == "hom_sc": + wA1 = get_A1_hom(w.sparse, scalarKP=True) + elif A1 == "het": + wA1 = get_A1_het(w.sparse) + + wA2 = get_A2_hom(w.sparse) + + # 1a. OLS --> \tilde{\delta} + self.x, self.name_x, x_rlist = REGI.Regimes_Frame.__init__( + self, + x_constant, + regimes, + constant_regi=None, + cols2regi=cols2regi, + names=name_x, + rlist=True, + ) + ols = BaseOLS(y=y, x=self.x) + self.k = ols.x.shape[1] + + # 1b. GM --> \tilde{\rho} + moments = moments_hom(w.sparse, wA1, wA2, ols.u) + lambda1 = optim_moments(moments) + lambda_old = lambda1 + + self.iteration, eps = 0, 1 + while self.iteration < max_iter and eps > epsilon: + # 2a. SWLS --> \hat{\delta} + xs = get_spFilter(w, lambda1, x_constant) + ys = get_spFilter(w, lambda1, y) + xs = REGI.Regimes_Frame.__init__( + self, xs, regimes, constant_regi=None, cols2regi=cols2regi + )[0] + ols_s = BaseOLS(y=ys, x=xs) + self.predy = spdot(self.x, ols_s.betas) + self.u = self.y - self.predy + + # 2b. GM 2nd iteration --> \hat{\rho} + moments = moments_hom(w.sparse, wA1, wA2, self.u) + psi = get_vc_hom(w.sparse, wA1, wA2, self, lambda_old)[0] + lambda2 = optim_moments(moments, psi) + eps = abs(lambda2 - lambda_old) + lambda_old = lambda2 + self.iteration += 1 + + self.iter_stop = iter_msg(self.iteration, max_iter) + + # Output + self.betas = np.vstack((ols_s.betas, lambda2)) + self.vm, self.sig2 = get_omega_hom_ols( + w.sparse, wA1, wA2, self, lambda2, moments[0] + ) + self.e_filtered = self.u - lambda2 * lag_spatial(w, self.u) + if slx_lags == 0: + self.title = "GM SPATIALLY WEIGHTED MODEL (HOM) - REGIMES" + else: + self.title = "GM SPATIALLY WEIGHTED MODEL + SLX (SDEM-HOM) - REGIMES" + self.name_x.append("lambda") + self.kf += 1 + self.chow = REGI.Chow(self) + self._cache = {} + self.A1 = A1 + self.output = pd.DataFrame(self.name_x, + columns=['var_names']) + self.output['var_type'] = ['x']*(len(self.name_x)-1)+['lambda'] + self.output['regime'] = x_rlist + ['_Global'] + self.output['equation'] = 0 + self.other_top = _summary_iteration(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + def _error_hom_regimes_multi( + self, y, x, regimes, w, slx_lags, cores, max_iter, epsilon, A1, cols2regi, vm, name_x, latex): + + regi_ids = dict( + (r, list(np.where(np.array(regimes) == r)[0])) for r in self.regimes_set + ) + results_p = {} + """ + for r in self.regimes_set: + if system() == 'Windows': + is_win = True + results_p[r] = _work_error(*(y,x,regi_ids,r,w,max_iter,epsilon,A1,self.name_ds,self.name_y,name_x+['lambda'],self.name_w,self.name_regimes)) + else: + pool = mp.Pool(cores) + results_p[r] = pool.apply_async(_work_error,args=(y,x,regi_ids,r,w,max_iter,epsilon,A1,self.name_ds,self.name_y,name_x+['lambda'],self.name_w,self.name_regimes, )) + is_win = False + """ + x_constant, name_x = REGI.check_const_regi(self, x, name_x, regi_ids) + self.name_x_r = name_x + for r in self.regimes_set: + if cores: + pool = mp.Pool(None) + results_p[r] = pool.apply_async( + _work_error, + args=( + y, + x_constant, + regi_ids, + r, + w, + max_iter, + epsilon, + A1, + self.name_ds, + self.name_y, + name_x + ["lambda"], + self.name_w, + self.name_regimes, + slx_lags, + ), + ) + else: + results_p[r] = _work_error( + *( + y, + x_constant, + regi_ids, + r, + w, + max_iter, + epsilon, + A1, + self.name_ds, + self.name_y, + name_x + ["lambda"], + self.name_w, + self.name_regimes, + slx_lags, + ) + ) + + self.kryd = 0 + self.kr = len(cols2regi) + 1 + self.kf = 0 + self.nr = len(self.regimes_set) + self.vm = np.zeros((self.nr * self.kr, self.nr * self.kr), float) + self.betas = np.zeros((self.nr * self.kr, 1), float) + self.u = np.zeros((self.n, 1), float) + self.predy = np.zeros((self.n, 1), float) + self.e_filtered = np.zeros((self.n, 1), float) + self.name_y, self.name_x = [], [] + """ + if not is_win: + pool.close() + pool.join() + """ + if cores: + pool.close() + pool.join() + + results = {} + counter = 0 + self.output = pd.DataFrame(columns=['var_names', 'var_type', 'regime', 'equation']) + for r in self.regimes_set: + """ + if is_win: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + """ + if not cores: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + + self.vm[ + (counter * self.kr) : ((counter + 1) * self.kr), + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].vm + self.betas[ + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].betas + self.u[ + regi_ids[r], + ] = results[r].u + self.predy[ + regi_ids[r], + ] = results[r].predy + self.e_filtered[ + regi_ids[r], + ] = results[r].e_filtered + self.name_y += results[r].name_y + self.name_x += results[r].name_x + results[r].A1 = A1 + results[r].other_top = _summary_iteration(results[r]) + self.output = pd.concat([self.output, pd.DataFrame({'var_names': results[r].name_x, + 'var_type': ['x'] * (len(results[r].name_x) - 1) + + ['lambda'], + 'regime': r, 'equation': r})], ignore_index=True) + counter += 1 + self.chow = REGI.Chow(self) + self.multi = results + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +
[docs]class GM_Endog_Error_Hom_Regimes(RegressionPropsY, REGI.Regimes_Frame): + + """ + GMM method for a spatial error model with homoskedasticity, regimes and + endogenous variables. + Based on Drukker et al. (2013) :cite:`Drukker2013`, following Anselin (2011) + :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + w : pysal W object + Spatial weights object + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep : boolean + If True, a separate regression is run for each regime. + regime_lag_sep : boolean + Always False, kept for consistency, ignored. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + max_iter : int + Maximum number of iterations of steps 2a and 2b from + :cite:`Arraiz2010`. Note: epsilon provides an additional stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + A1 : string + If A1='het', then the matrix A1 is defined as in + :cite:`Arraiz2010`. If A1='hom', then as in :cite:`Anselin2011`. If + A1='hom_sc', then as in :cite:`Drukker2013` + and :cite:`Drukker:2013aa`. + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z : array + nxk array of variables (combination of x and yend) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + h : array + nxl array of instruments (combination of x and q) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + sig2 : float + Sigma squared used in computations + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + hth : float + :math:`H'H`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi : ['one', 'many'] + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep : boolean + If True, a separate regression is run for each regime. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path("natregimes.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + For the endogenous models, we add the endogenous variable RD90 (resource deprivation) + and we decide to instrument for it with FP89 (families below poverty): + + >>> yd_var = ['RD90'] + >>> yend = np.array([db.by_col(name) for name in yd_var]).T + >>> q_var = ['FP89'] + >>> q = np.array([db.by_col(name) for name in q_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``NAT.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(nat.get_path("natregimes.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables (exogenous and endogenous), the + instruments and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import GM_Endog_Error_Hom_Regimes + >>> reg = GM_Endog_Error_Hom_Regimes(y, x, yend, q, regimes, w=w, A1='hom_sc', name_y=y_var, name_x=x_var, name_yend=yd_var, name_q=q_var, name_regimes=r_var, name_ds='NAT.dbf') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. This class offers an error model that assumes + homoskedasticity but that unlike the models from + ``spreg.error_sp``, it allows for inference on the spatial + parameter. Hence, we find the same number of betas as of standard errors, + which we calculate taking the square root of the diagonal of the + variance-covariance matrix. Alternatively, we can have a summary of the + output by typing: model.summary + + >>> print(reg.name_z) + ['0_CONSTANT', '0_PS90', '0_UE90', '1_CONSTANT', '1_PS90', '1_UE90', '0_RD90', '1_RD90', 'lambda'] + + >>> print(np.around(reg.betas,4)) + [[ 3.5973] + [ 1.0652] + [ 0.1582] + [ 9.198 ] + [ 1.8809] + [-0.2489] + [ 2.4616] + [ 3.5796] + [ 0.2541]] + + >>> print(np.around(np.sqrt(reg.vm.diagonal()),4)) + [0.5204 0.1371 0.0629 0.4721 0.1824 0.0725 0.2992 0.2395 0.024 ] + + """ + +
[docs] def __init__( + self, + y, + x, + yend, + q, + regimes, + w, + constant_regi="many", + cols2regi="all", + regime_err_sep=False, + regime_lag_sep=False, + slx_lags=0, + max_iter=1, + epsilon=0.00001, + A1="het", + cores=False, + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + name_regimes=None, + summ=True, + add_lag=False, + latex=False, + ): + + n = USER.check_arrays(y, x, yend, q) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + self.constant_regi = constant_regi + self.cols2regi = cols2regi + self.name_ds = USER.set_name_ds(name_ds) + self.name_regimes = USER.set_name_ds(name_regimes) + self.name_w = USER.set_name_w(name_w, w) + self.n = n + self.y = y + + x_constant, name_x, warn = USER.check_constant(x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + if slx_lags > 0: + lag_x = get_lags(w, x_constant, slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + + if summ: + name_yend = USER.set_name_yend(name_yend, yend) + self.name_y = USER.set_name_y(name_y) + name_q = USER.set_name_q(name_q, q) + self.name_x_r = USER.set_name_x(name_x, x_constant) + name_yend + + cols2regi = REGI.check_cols2regi( + constant_regi, cols2regi, x_constant, yend=yend + ) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, self.n, x_constant.shape[1]) + self.regime_err_sep = regime_err_sep + + if regime_err_sep == True: + if set(cols2regi) == set([True]): + self._endog_error_hom_regimes_multi( + y, + x_constant, + regimes, + w, + yend, + q, + slx_lags, + cores, + max_iter, + epsilon, + A1, + cols2regi, + vm, + name_x, + name_yend, + name_q, + add_lag, + latex, + ) + else: + raise Exception( + "All coefficients must vary across regimes if regime_err_sep = True." + ) + else: + x_constant = sphstack(np.ones((x_constant.shape[0], 1)), x_constant) + name_x = USER.set_name_x(name_x, x_constant) + q, name_q = REGI.Regimes_Frame.__init__( + self, q, regimes, constant_regi=None, cols2regi="all", names=name_q + ) + x, name_x, x_rlist = REGI.Regimes_Frame.__init__( + self, + x_constant, + regimes, + constant_regi=None, + cols2regi=cols2regi, + names=name_x, + rlist=True, + ) + yend2, name_yend, yend_rlist = REGI.Regimes_Frame.__init__( + self, + yend, + regimes, + constant_regi=None, + cols2regi=cols2regi, + yend=True, + names=name_yend, + rlist=True, + ) + if A1 == "hom": + wA1 = get_A1_hom(w.sparse) + elif A1 == "hom_sc": + wA1 = get_A1_hom(w.sparse, scalarKP=True) + elif A1 == "het": + wA1 = get_A1_het(w.sparse) + + wA2 = get_A2_hom(w.sparse) + + # 1a. S2SLS --> \tilde{\delta} + tsls = BaseTSLS(y=y, x=x, yend=yend2, q=q) + self.k = tsls.z.shape[1] + self.x = tsls.x + self.yend, self.z, self.h = tsls.yend, tsls.z, tsls.h + + # 1b. GM --> \tilde{\rho} + moments = moments_hom(w.sparse, wA1, wA2, tsls.u) + lambda1 = optim_moments(moments) + lambda_old = lambda1 + + self.iteration, eps = 0, 1 + while self.iteration < max_iter and eps > epsilon: + # 2a. GS2SLS --> \hat{\delta} + xs = get_spFilter(w, lambda1, x_constant) + xs = REGI.Regimes_Frame.__init__( + self, xs, regimes, constant_regi=None, cols2regi=cols2regi + )[0] + ys = get_spFilter(w, lambda1, y) + yend_s = get_spFilter(w, lambda1, yend) + yend_s = REGI.Regimes_Frame.__init__( + self, + yend_s, + regimes, + constant_regi=None, + cols2regi=cols2regi, + yend=True, + )[0] + tsls_s = BaseTSLS(ys, xs, yend_s, h=tsls.h) + self.predy = spdot(self.z, tsls_s.betas) + self.u = self.y - self.predy + + # 2b. GM 2nd iteration --> \hat{\rho} + moments = moments_hom(w.sparse, wA1, wA2, self.u) + psi = get_vc_hom(w.sparse, wA1, wA2, self, lambda_old, tsls_s.z)[0] + lambda2 = optim_moments(moments, psi) + eps = abs(lambda2 - lambda_old) + lambda_old = lambda2 + self.iteration += 1 + + self.iter_stop = iter_msg(self.iteration, max_iter) + + # Output + self.betas = np.vstack((tsls_s.betas, lambda2)) + self.vm, self.sig2 = get_omega_hom( + w.sparse, wA1, wA2, self, lambda2, moments[0] + ) + self.e_filtered = self.u - lambda2 * lag_spatial(w, self.u) + self.name_x = USER.set_name_x(name_x, x, constant=True) + self.name_yend = USER.set_name_yend(name_yend, yend) + self.name_z = self.name_x + self.name_yend + self.name_z.append("lambda") + self.name_q = USER.set_name_q(name_q, q) + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.kf += 1 + self.chow = REGI.Chow(self) + self._cache = {} + self.A1 = A1 + self.output = pd.DataFrame(self.name_z, + columns=['var_names']) + self.output['var_type'] = ['x'] * len(self.name_x) + ['yend'] * len(self.name_yend) + ['lambda'] + self.output['regime'] = x_rlist + yend_rlist + ['_Global'] + self.output['equation'] = 0 + if summ: + self.other_top = _summary_iteration(self) + if slx_lags == 0: + self.title = ("GM SPATIALLY WEIGHTED 2SLS (HOM) - REGIMES") + else: + self.title = ("GM SPATIALLY WEIGHTED 2SLS WITH SLX (SDEM-HOM) - REGIMES") + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + def _endog_error_hom_regimes_multi( + self, + y, + x, + regimes, + w, + yend, + q, + slx_lags, + cores, + max_iter, + epsilon, + A1, + cols2regi, + vm, + name_x, + name_yend, + name_q, + add_lag, + latex, + ): + + regi_ids = dict( + (r, list(np.where(np.array(regimes) == r)[0])) for r in self.regimes_set + ) + if add_lag != False: + self.cols2regi += [True] + cols2regi += [True] + self.predy_e = np.zeros((self.n, 1), float) + self.e_pred = np.zeros((self.n, 1), float) + results_p = {} + """ + for r in self.regimes_set: + if system() == 'Windows': + is_win = True + results_p[r] = _work_endog_error(*(y,x,yend,q,regi_ids,r,w,max_iter,epsilon,A1,self.name_ds,self.name_y,name_x,name_yend,name_q,self.name_w,self.name_regimes,add_lag)) + else: + pool = mp.Pool(cores) + results_p[r] = pool.apply_async(_work_endog_error,args=(y,x,yend,q,regi_ids,r,w,max_iter,epsilon,A1,self.name_ds,self.name_y,name_x,name_yend,name_q,self.name_w,self.name_regimes,add_lag, )) + is_win = False + """ + x_constant, name_x = REGI.check_const_regi(self, x, name_x, regi_ids) + self.name_x_r = name_x + name_yend + for r in self.regimes_set: + if cores: + pool = mp.Pool(None) + results_p[r] = pool.apply_async( + _work_endog_error, + args=( + y, + x_constant, + yend, + q, + regi_ids, + r, + w, + max_iter, + epsilon, + A1, + self.name_ds, + self.name_y, + name_x, + name_yend, + name_q, + self.name_w, + self.name_regimes, + add_lag, + slx_lags, + ), + ) + else: + results_p[r] = _work_endog_error( + *( + y, + x_constant, + yend, + q, + regi_ids, + r, + w, + max_iter, + epsilon, + A1, + self.name_ds, + self.name_y, + name_x, + name_yend, + name_q, + self.name_w, + self.name_regimes, + add_lag, + slx_lags, + ) + ) + + self.kryd, self.kf = 0, 0 + self.kr = len(cols2regi) + 1 + self.nr = len(self.regimes_set) + self.vm = np.zeros((self.nr * self.kr, self.nr * self.kr), float) + self.betas = np.zeros((self.nr * self.kr, 1), float) + self.u = np.zeros((self.n, 1), float) + self.predy = np.zeros((self.n, 1), float) + self.e_filtered = np.zeros((self.n, 1), float) + """ + if not is_win: + pool.close() + pool.join() + """ + if cores: + pool.close() + pool.join() + + results = {} + ( + self.name_y, + self.name_x, + self.name_yend, + self.name_q, + self.name_z, + self.name_h, + ) = ([], [], [], [], [], []) + counter = 0 + self.output = pd.DataFrame(columns=['var_names', 'var_type', 'regime', 'equation']) + for r in self.regimes_set: + """ + if is_win: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + """ + if not cores: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + + self.vm[ + (counter * self.kr) : ((counter + 1) * self.kr), + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].vm + self.betas[ + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].betas + self.u[ + regi_ids[r], + ] = results[r].u + self.predy[ + regi_ids[r], + ] = results[r].predy + self.e_filtered[ + regi_ids[r], + ] = results[r].e_filtered + self.name_y += results[r].name_y + self.name_x += results[r].name_x + self.name_yend += results[r].name_yend + self.name_q += results[r].name_q + self.name_z += results[r].name_z + self.name_h += results[r].name_h + if add_lag != False: + self.predy_e[ + regi_ids[r], + ] = results[r].predy_e + self.e_pred[ + regi_ids[r], + ] = results[r].e_pred + results[r].other_top = _spat_pseudo_r2(results[r]) + v_type = ['x'] * len(results[r].name_x) + ['yend'] * (len(results[r].name_yend)-1) + ['rho','lambda'] + else: + results[r].other_top = "" + v_type = ['x'] * len(results[r].name_x) + ['yend'] * len(results[r].name_yend) + ['lambda'] + results[r].A1 = A1 + results[r].other_top += _summary_iteration(results[r]) + self.output = pd.concat([self.output, pd.DataFrame({'var_names': results[r].name_z, + 'var_type': v_type, + 'regime': r, 'equation': r})], ignore_index=True) + counter += 1 + self.chow = REGI.Chow(self) + self.multi = results + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +
[docs]class GM_Combo_Hom_Regimes(GM_Endog_Error_Hom_Regimes): + + """ + GMM method for a spatial lag and error model with homoskedasticity, + regimes and endogenous variables, with results and diagnostics; + based on Drukker et al. (2013) :cite:`Drukker2013`, following Anselin (2011) + :cite:`Anselin2011`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + w : pysal W object + Spatial weights object (always needed) + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep : boolean + If True, a separate regression is run for each regime. + regime_lag_sep : boolean + If True, the spatial parameter for spatial lag is also + computed according to different regimes. If False (default), + the spatial parameter is fixed across regimes. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the GNSM type. + w_lags : integer + Orders of W to include as instruments for the spatially + lagged dependent variable. For example, w_lags=1, then + instruments are WX; if w_lags=2, then WX, WWX; and so on. + lag_q : boolean + If True, then include spatial lags of the additional + instruments (q). + max_iter : int + Maximum number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + Note: epsilon provides an additional stop condition. + epsilon : float + Minimum change in lambda required to stop iterations of + steps 2a and 2b from :cite:`Arraiz2010`. Note: max_iter provides + an additional stop condition. + A1 : string + If A1='het', then the matrix A1 is defined as in + :cite:`Arraiz2010`. If A1='hom', then as in :cite:`Anselin2011`. If + A1='hom_sc', then as in :cite:`Drukker2013` + and :cite:`Drukker:2013aa`. + vm : boolean + If True, include variance-covariance matrix in summary + results + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + e_pred : array + nx1 array of residuals (using reduced form) + predy : array + nx1 array of predicted y values + predy_e : array + nx1 array of predicted y values (using reduced form) + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z : array + nxk array of variables (combination of x and yend) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + h : array + nxl array of instruments (combination of x and q) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iter_stop : string + Stop criterion reached during iteration of steps 2a and 2b + from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + iteration : integer + Number of iterations of steps 2a and 2b from :cite:`Arraiz2010`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + sig2 : float + Sigma squared used in computations (based on filtered + residuals) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi : string + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep : boolean + If True, a separate regression is run for each regime. + regime_lag_sep : boolean + If True, the spatial parameter for spatial lag is also + computed according to different regimes. If False (default), + the spatial parameter is fixed across regimes. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path("natregimes.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to run a spatial combo model, we need to specify + the spatial weights matrix that includes the spatial configuration of the + observations. To do that, we can open an already existing gal file or + create a new one. In this case, we will create one from ``natregimes.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(nat.get_path("natregimes.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + Example only with spatial lag + + The Combo class runs an SARAR model, that is a spatial lag+error model. + In this case we will run a simple version of that, where we have the + spatial effects as well as exogenous variables. Since it is a spatial + model, we have to pass in the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. We can have a + summary of the output by typing: model.summary + Alternatively, we can check the betas: + + >>> from spreg import GM_Combo_Hom_Regimes + >>> reg = GM_Combo_Hom_Regimes(y, x, regimes, w=w, A1='hom_sc', name_y=y_var, name_x=x_var, name_regimes=r_var, name_ds='NAT') + >>> print(reg.name_z) + ['0_CONSTANT', '0_PS90', '0_UE90', '1_CONSTANT', '1_PS90', '1_UE90', '_Global_W_HR90', 'lambda'] + >>> print(np.around(reg.betas,4)) + [[ 1.4607] + [ 0.9579] + [ 0.5658] + [ 9.1129] + [ 1.1339] + [ 0.6517] + [-0.4583] + [ 0.6634]] + + This class also allows the user to run a spatial lag+error model with the + extra feature of including non-spatial endogenous regressors. This means + that, in addition to the spatial lag and error, we consider some of the + variables on the right-hand side of the equation as endogenous and we + instrument for this. In this case we consider RD90 (resource deprivation) + as an endogenous regressor. We use FP89 (families below poverty) + for this and hence put it in the instruments parameter, 'q'. + + >>> yd_var = ['RD90'] + >>> yd = np.array([db.by_col(name) for name in yd_var]).T + >>> q_var = ['FP89'] + >>> q = np.array([db.by_col(name) for name in q_var]).T + + And then we can run and explore the model analogously to the previous combo: + + >>> reg = GM_Combo_Hom_Regimes(y, x, regimes, yd, q, w=w, A1='hom_sc', name_y=y_var, name_x=x_var, name_yend=yd_var, name_q=q_var, name_regimes=r_var, name_ds='NAT') + >>> print(reg.name_z) + ['0_CONSTANT', '0_PS90', '0_UE90', '1_CONSTANT', '1_PS90', '1_UE90', '0_RD90', '1_RD90', '_Global_W_HR90', 'lambda'] + >>> print(reg.betas) + [[ 3.4196478 ] + [ 1.04065595] + [ 0.16630304] + [ 8.86570777] + [ 1.85134286] + [-0.24921597] + [ 2.43007651] + [ 3.61656899] + [ 0.03315061] + [ 0.22636055]] + >>> print(np.sqrt(reg.vm.diagonal())) + [0.53989913 0.13506086 0.06143434 0.77049956 0.18089997 0.07246848 + 0.29218837 0.25378655 0.06184801 0.06323236] + >>> print('lambda: ', np.around(reg.betas[-1], 4)) + lambda: [0.2264] + + """ + +
[docs] def __init__( + self, + y, + x, + regimes, + yend=None, + q=None, + w=None, + slx_lags=0, + w_lags=1, + lag_q=True, + cores=False, + max_iter=1, + epsilon=0.00001, + A1="het", + constant_regi="many", + cols2regi="all", + regime_err_sep=False, + regime_lag_sep=False, + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + name_regimes=None, + latex=False, + ): + + if regime_lag_sep and not regime_err_sep: + set_warn(self, "regime_err_sep set to True when regime_lag_sep=True.") + regime_err_sep = True + if regime_err_sep and not regime_lag_sep: + set_warn(self, "regime_err_sep set to False when regime_lag_sep=False.") + regime_err_sep = False + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + + self.name_y = USER.set_name_y(name_y) + name_yend = USER.set_name_yend(name_yend, yend) + name_q = USER.set_name_q(name_q, q) + + if regime_err_sep and any(col != True for col in cols2regi): + set_warn(self, "All coefficients must vary across regimes if regime_err_sep = True, so setting cols2regi = 'all'.") + cols2regi = "all" + + if slx_lags > 0: + yend2, q2, wx = set_endog(y, x_constant, w, yend, q, w_lags, lag_q, slx_lags) + x_constant = np.hstack((x_constant, wx)) + name_slx = USER.set_name_spatial_lags(name_x, slx_lags) + name_q.extend(USER.set_name_q_sp(name_slx[-len(name_x):], w_lags, name_q, lag_q, force_all=True)) + name_x += name_slx + cols2regi = REGI.check_cols2regi(constant_regi, cols2regi, x_constant[:, :-1], yend=yend2, add_cons=False) + else: + name_q.extend(USER.set_name_q_sp(name_x, w_lags, name_q, lag_q, force_all=True)) + yend2, q2 = yend, q + cols2regi = REGI.check_cols2regi(constant_regi, cols2regi, x_constant, yend=yend2, add_cons=False) + + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, n, x_constant.shape[1]) + self.regime_err_sep = regime_err_sep + self.regime_lag_sep = regime_lag_sep + + if regime_lag_sep == True: + if slx_lags == 0: + add_lag = [w_lags, lag_q] + else: + add_lag = False + cols2regi += [True] + else: + add_lag = False + cols2regi += [False] + if slx_lags == 0: + yend2, q2 = set_endog(y, x_constant, w, yend2, q2, w_lags, lag_q) + + + name_yend.append(USER.set_name_yend_sp(self.name_y)) + + GM_Endog_Error_Hom_Regimes.__init__( + self, + y=y, + x=x_constant, + yend=yend2, + q=q2, + regimes=regimes, + w=w, + vm=vm, + constant_regi=constant_regi, + cols2regi=cols2regi, + regime_err_sep=regime_err_sep, + max_iter=max_iter, + epsilon=epsilon, + A1=A1, + cores=cores, + name_y=self.name_y, + name_x=name_x, + name_yend=name_yend, + name_q=name_q, + name_w=name_w, + name_ds=name_ds, + name_regimes=name_regimes, + summ=False, + add_lag=add_lag, + latex=latex, + ) + + if regime_err_sep != True: + self.rho = self.betas[-2] + self.predy_e, self.e_pred, warn = sp_att( + w, self.y, self.predy, yend2[:, -1].reshape(self.n, 1), self.rho + ) + set_warn(self, warn) + self.regime_lag_sep = regime_lag_sep + if slx_lags == 0: + self.title = "GM SPATIALLY WEIGHTED 2SLS-COMBO MODEL (HOM) - REGIMES" + else: + self.title = "GM SPATIALLY WEIGHTED 2SLS-COMBO WITH SLX (GNSM-HOM) - REGIMES" + self.output.iat[-2, self.output.columns.get_loc('var_type')] = 'rho' + self.other_top = _spat_pseudo_r2(self) + self.other_top += _summary_iteration(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +def _work_error( + y, + x, + regi_ids, + r, + w, + max_iter, + epsilon, + A1, + name_ds, + name_y, + name_x, + name_w, + name_regimes, + slx_lags, +): + w_r, warn = REGI.w_regime(w, regi_ids[r], r, transform=True) + y_r = y[regi_ids[r]] + x_r = x[regi_ids[r]] + model = BaseGM_Error_Hom( + y_r, x_r, w_r.sparse, max_iter=max_iter, epsilon=epsilon, A1=A1 + ) + set_warn(model, warn) + model.w = w_r + if slx_lags == 0: + model.title = "GM SPATIALLY WEIGHTED 2SLS (HOM) - REGIME %s" % r + else: + model.title = "GM SPATIALLY WEIGHTED 2SLS + SLX (SDEM-HOM) - REGIME %s" % r + model.name_ds = name_ds + model.name_y = "%s_%s" % (str(r), name_y) + model.name_x = ["%s_%s" % (str(r), i) for i in name_x] + model.name_w = name_w + model.name_regimes = name_regimes + return model + + +def _work_endog_error( + y, + x, + yend, + q, + regi_ids, + r, + w, + max_iter, + epsilon, + A1, + name_ds, + name_y, + name_x, + name_yend, + name_q, + name_w, + name_regimes, + add_lag, + slx_lags, +): + w_r, warn = REGI.w_regime(w, regi_ids[r], r, transform=True) + y_r = y[regi_ids[r]] + x_r = x[regi_ids[r]] + if yend is not None: + yend_r = yend[regi_ids[r]] + q_r = q[regi_ids[r]] + else: + yend_r, q_r = None, None + if add_lag != False: + yend_r, q_r = set_endog( + y_r, x_r[:, 1:], w_r, yend_r, q_r, add_lag[0], add_lag[1] + ) + x_constant = USER.check_constant(x_r) + model = BaseGM_Endog_Error_Hom( + y_r, x_r, yend_r, q_r, w_r.sparse, max_iter=max_iter, epsilon=epsilon, A1=A1 + ) + set_warn(model, warn) + if add_lag != False: + model.rho = model.betas[-2] + model.predy_e, model.e_pred, warn = sp_att( + w_r, model.y, model.predy, model.yend[:, -1].reshape(model.n, 1), model.rho + ) + set_warn(model, warn) + if slx_lags == 0: + if add_lag != False: + model.title = "GM SPATIALLY WEIGHTED 2SLS-COMBO MODEL (HOM)- REGIME %s" % r + else: + model.title = "GM SPATIALLY WEIGHTED 2SLS (HOM) - REGIME %s" % r + else: + if add_lag != False: + model.title = "GM SPATIAL COMBO MODEL + SLX (GNSM-HOM) - REGIME %s" % r + else: + model.title = "GM SPATIALLY WEIGHTED 2SLS + SLX (SDEM-HOM) - REGIME %s" % r + model.name_ds = name_ds + model.name_y = "%s_%s" % (str(r), name_y) + model.name_x = ["%s_%s" % (str(r), i) for i in name_x] + model.name_yend = ["%s_%s" % (str(r), i) for i in name_yend] + model.name_z = model.name_x + model.name_yend + [str(r)+"_lambda"] + model.name_q = ["%s_%s" % (str(r), i) for i in name_q] + model.name_h = model.name_x + model.name_q + model.name_w = name_w + model.name_regimes = name_regimes + return model + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + + import numpy as np + import libpysal + + db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + y = np.array(db.by_col("HOVAL")) + y = np.reshape(y, (49,1)) + X = [] + X.append(db.by_col("INC")) + X = np.array(X).T + yd = [] + yd.append(db.by_col("CRIME")) + yd = np.array(yd).T + q = [] + q.append(db.by_col("DISCBD")) + q = np.array(q).T + + r_var = 'NSA' + regimes = db.by_col(r_var) + + w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + w.transform = 'r' + #reg = GM_Error_Hom_Regimes(y, X, regimes, w=w, name_x=['inc'], name_y='hoval', name_ds='columbus', vm=True, + # regime_err_sep=True) + #reg = GM_Endog_Error_Hom_Regimes(y, X, yd, q, regimes, w=w, name_x=['inc'], name_y='hoval', name_yend=['crime'], + # name_q=['discbd'], name_ds='columbus',vm=True, regime_err_sep=True) + reg = GM_Combo_Hom_Regimes(y, X, regimes, yd, q, w=w, name_x=['inc'], name_y='hoval', name_yend=['crime'], + name_q=['discbd'], name_ds='columbus', vm=True, regime_err_sep=False, regime_lag_sep=False) + print(reg.output) + print(reg.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/error_sp_regimes.html b/_modules/spreg/error_sp_regimes.html new file mode 100644 index 00000000..2239d957 --- /dev/null +++ b/_modules/spreg/error_sp_regimes.html @@ -0,0 +1,2222 @@ + + + + + + + spreg.error_sp_regimes — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.error_sp_regimes

+"""
+Spatial Error Models with regimes module
+"""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu, Pedro V. Amaral pedro.amaral@asu.edu"
+
+import numpy as np
+import multiprocessing as mp
+from . import regimes as REGI
+from . import user_output as USER
+from libpysal.weights.spatial_lag import lag_spatial
+from .ols import BaseOLS
+from .twosls import BaseTSLS
+from .error_sp import BaseGM_Error, BaseGM_Endog_Error, _momentsGM_Error
+from .utils import set_endog, iter_msg, sp_att, set_warn
+from .utils import optim_moments, get_spFilter, get_lags
+from .utils import spdot, RegressionPropsY
+from .sputils import sphstack
+import pandas as pd
+from .output import output, _spat_pseudo_r2
+from .error_sp_het_regimes import GM_Error_Het_Regimes, GM_Endog_Error_Het_Regimes, GM_Combo_Het_Regimes
+from .error_sp_hom_regimes import GM_Error_Hom_Regimes, GM_Endog_Error_Hom_Regimes, GM_Combo_Hom_Regimes
+
+
+
[docs]class GM_Error_Regimes(RegressionPropsY, REGI.Regimes_Frame): + + """ + GMM method for a spatial error model with regimes, with results and diagnostics; + based on Kelejian and Prucha (1998, 1999) :cite:`Kelejian1998` :cite:`Kelejian1999`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + w : pysal W object + Spatial weights object + constant_regi: string, optional + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + regime_lag_sep: boolean + Always False, kept for consistency, ignored. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + vm : boolean + If True, include variance-covariance matrix in summary + results + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + vm : array + Variance covariance matrix (kxk) + sig2 : float + Sigma squared used in computations + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi: string + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes + + * 'many': a vector of ones is appended to x and considered different per regime + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import libpysal + >>> import numpy as np + >>> from libpysal.examples import load_example + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path("natregimes.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to run a spatial error model, we need to specify + the spatial weights matrix that includes the spatial configuration of the + observations. To do that, we can open an already existing gal file or + create a new one. In this case, we will create one from ``NAT.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(nat.get_path("natregimes.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import GM_Error_Regimes + >>> model = GM_Error_Regimes(y, x, regimes, w=w, name_y=y_var, name_x=x_var, name_regimes=r_var, name_ds='NAT.dbf') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. Note that because we are running the classical GMM error + model from 1998/99, the spatial parameter is obtained as a point estimate, so + although you get a value for it (there are for coefficients under + model.betas), you cannot perform inference on it (there are only three + values in model.se_betas). Alternatively, we can have a summary of the + output by typing: model.summary + + >>> print(model.output) + var_names coefficients std_err zt_stat prob + 0 0_CONSTANT 0.074811 0.379864 0.196942 0.843873 + 1 0_PS90 0.786105 0.152315 5.161043 0.0 + 2 0_UE90 0.538848 0.051942 10.373969 0.0 + 3 1_CONSTANT 5.103761 0.471284 10.82949 0.0 + 4 1_PS90 1.196009 0.19867 6.020074 0.0 + 5 1_UE90 0.600532 0.057252 10.489217 0.0 + 6 lambda 0.3641 None None None + """ + +
[docs] def __init__( + self, + y, + x, + regimes, + w, + vm=False, + name_y=None, + name_x=None, + name_w=None, + constant_regi="many", + cols2regi="all", + regime_err_sep=False, + regime_lag_sep=False, + slx_lags=0, + cores=False, + name_ds=None, + name_regimes=None, + latex=False, + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant( + x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + + if slx_lags >0: + lag_x = get_lags(w, x_constant, slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + + self.name_x_r = USER.set_name_x(name_x, x_constant) + + self.constant_regi = constant_regi + self.cols2regi = cols2regi + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_w = USER.set_name_w(name_w, w) + self.name_regimes = USER.set_name_ds(name_regimes) + self.n = n + self.y = y + + cols2regi = REGI.check_cols2regi(constant_regi, cols2regi, x_constant) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, self.n, x_constant.shape[1]) + self.regime_err_sep = regime_err_sep + if regime_err_sep == True: + if set(cols2regi) == set([True]): + self._error_regimes_multi( + y, x_constant, regimes, w, slx_lags, cores, cols2regi, vm, name_x, latex + ) + else: + raise Exception( + "All coefficients must vary across regimes if regime_err_sep = True." + ) + else: + x_constant = sphstack( + np.ones((x_constant.shape[0], 1)), x_constant) + name_x = USER.set_name_x(name_x, x_constant) + self.x, self.name_x, x_rlist = REGI.Regimes_Frame.__init__( + self, + x_constant, + regimes, + constant_regi=None, + cols2regi=cols2regi, + names=name_x, + rlist=True, + ) + ols = BaseOLS(y=y, x=self.x) + self.k = ols.x.shape[1] + moments = _momentsGM_Error(w, ols.u) + lambda1 = optim_moments(moments) + xs = get_spFilter(w, lambda1, x_constant) + ys = get_spFilter(w, lambda1, y) + xs = REGI.Regimes_Frame.__init__( + self, xs, regimes, constant_regi=None, cols2regi=cols2regi + )[0] + ols2 = BaseOLS(y=ys, x=xs) + + # Output + self.predy = spdot(self.x, ols2.betas) + self.u = y - self.predy + self.betas = np.vstack((ols2.betas, np.array([[lambda1]]))) + self.sig2 = ols2.sig2n + self.e_filtered = self.u - lambda1 * lag_spatial(w, self.u) + self.vm = self.sig2 * ols2.xtxi + if slx_lags == 0: + self.title = "GM SPATIALLY WEIGHTED MODEL - REGIMES" + else: + self.title = "GM SPATIALLY WEIGHTED MODEL + SLX (SDEM) - REGIMES" + self.name_x.append("lambda") + self.kf += 1 + self.chow = REGI.Chow(self) + self._cache = {} + self.output = pd.DataFrame(self.name_x, + columns=['var_names']) + self.output['var_type'] = ['x']*(len(self.name_x)-1)+['lambda'] + self.output['regime'] = x_rlist + ['_Global'] + self.output['equation'] = 0 + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + def _error_regimes_multi(self, y, x, regimes, w, slx_lags, cores, cols2regi, vm, name_x, latex): + regi_ids = dict( + (r, list(np.where(np.array(regimes) == r)[0])) for r in self.regimes_set + ) + results_p = {} + """ + for r in self.regimes_set: + if system() == 'Windows': + results_p[r] = _work_error(*(y,x,regi_ids,r,w,self.name_ds,self.name_y,name_x+['lambda'],self.name_w,self.name_regimes)) + is_win = True + else: + pool = mp.Pool(cores) + results_p[r] = pool.apply_async(_work_error,args=(y,x,regi_ids,r,w,self.name_ds,self.name_y,name_x+['lambda'],self.name_w,self.name_regimes, )) + is_win = False + """ + x_constant, name_x = REGI.check_const_regi(self, x, name_x, regi_ids) + self.name_x_r = name_x + for r in self.regimes_set: + if cores: + pool = mp.Pool(None) + results_p[r] = pool.apply_async( + _work_error, + args=( + y, + x_constant, + regi_ids, + r, + w, + self.name_ds, + self.name_y, + name_x + ["lambda"], + self.name_w, + self.name_regimes, + slx_lags, + ), + ) + else: + results_p[r] = _work_error( + *( + y, + x_constant, + regi_ids, + r, + w, + self.name_ds, + self.name_y, + name_x + ["lambda"], + self.name_w, + self.name_regimes, + slx_lags, + ) + ) + + self.kryd = 0 + self.kr = len(cols2regi) + self.kf = 0 + self.nr = len(self.regimes_set) + self.vm = np.zeros((self.nr * self.kr, self.nr * self.kr), float) + self.betas = np.zeros((self.nr * (self.kr + 1), 1), float) + self.u = np.zeros((self.n, 1), float) + self.predy = np.zeros((self.n, 1), float) + self.e_filtered = np.zeros((self.n, 1), float) + """ + if not is_win: + pool.close() + pool.join() + """ + if cores: + pool.close() + pool.join() + + results = {} + self.name_y, self.name_x = [], [] + self.output = pd.DataFrame( + columns=['var_names', 'var_type', 'regime', 'equation']) + counter = 0 + for r in self.regimes_set: + """ + if is_win: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + """ + if not cores: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + + self.vm[ + (counter * self.kr): ((counter + 1) * self.kr), + (counter * self.kr): ((counter + 1) * self.kr), + ] = results[r].vm + self.betas[ + (counter * (self.kr + 1)): ((counter + 1) * (self.kr + 1)), + ] = results[r].betas + self.u[ + regi_ids[r], + ] = results[r].u + self.predy[ + regi_ids[r], + ] = results[r].predy + self.e_filtered[ + regi_ids[r], + ] = results[r].e_filtered + self.name_y += results[r].name_y + self.name_x += results[r].name_x + self.output = pd.concat([self.output, pd.DataFrame({'var_names': results[r].name_x, + 'var_type': ['x'] * (len(results[r].name_x) - 1) + + ['lambda'], + 'regime': r, 'equation': r})], ignore_index=True) + counter += 1 + self.chow = REGI.Chow(self) + self.multi = results + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +
[docs]class GM_Endog_Error_Regimes(RegressionPropsY, REGI.Regimes_Frame): + + """ + GMM method for a spatial error model with regimes and endogenous variables, with + results and diagnostics; based on Kelejian and Prucha (1998, + 1999) :cite:`Kelejian1998` :cite:`Kelejian1999`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + w : pysal W object + Spatial weights object + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + regime_lag_sep: boolean + Always False, kept for consistency, ignored. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + vm : boolean + If True, include variance-covariance matrix in summary + results + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z : array + nxk array of variables (combination of x and yend) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + sig2 : float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + Sigma squared used in computations + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi : ['one', 'many'] + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import libpysal + >>> import numpy as np + >>> from libpysal.examples import load_example + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path("natregimes.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + For the endogenous models, we add the endogenous variable RD90 (resource deprivation) + and we decide to instrument for it with FP89 (families below poverty): + + >>> yd_var = ['RD90'] + >>> yend = np.array([db.by_col(name) for name in yd_var]).T + >>> q_var = ['FP89'] + >>> q = np.array([db.by_col(name) for name in q_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``NAT.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(nat.get_path("natregimes.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables (exogenous and endogenous), the + instruments and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import GM_Endog_Error_Regimes + >>> model = GM_Endog_Error_Regimes(y, x, yend, q, regimes, w=w, name_y=y_var, name_x=x_var, name_yend=yd_var, name_q=q_var, name_regimes=r_var, name_ds='NAT.dbf') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. Note that because we are running the classical GMM error + model from 1998/99, the spatial parameter is obtained as a point estimate, so + although you get a value for it (there are for coefficients under + model.betas), you cannot perform inference on it (there are only three + values in model.se_betas). Also, this regression uses a two stage least + squares estimation method that accounts for the endogeneity created by the + endogenous variables included. Alternatively, we can have a summary of the + output by typing: model.summary + + >>> print(model.output) + var_names coefficients std_err zt_stat prob + 0 0_CONSTANT 3.597178 0.522633 6.882796 0.0 + 1 0_PS90 1.065203 0.137555 7.743852 0.0 + 2 0_UE90 0.15822 0.063054 2.509282 0.012098 + 6 0_RD90 2.461609 0.300711 8.185967 0.0 + 3 1_CONSTANT 9.197542 0.473654 19.418268 0.0 + 4 1_PS90 1.880815 0.18335 10.258046 0.0 + 5 1_UE90 -0.248777 0.072786 -3.417919 0.000631 + 7 1_RD90 3.579429 0.240413 14.888666 0.0 + 8 lambda 0.255639 None None None + """ + +
[docs] def __init__( + self, + y, + x, + yend, + q, + regimes, + w, + cores=False, + vm=False, + constant_regi="many", + cols2regi="all", + regime_err_sep=False, + regime_lag_sep=False, + slx_lags=0, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + name_regimes=None, + summ=True, + add_lag=False, + latex=False, + ): + + n = USER.check_arrays(y, x, yend, q) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant( + x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + + if slx_lags > 0: + lag_x = get_lags(w, x_constant, slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + + self.constant_regi = constant_regi + self.cols2regi = cols2regi + self.name_ds = USER.set_name_ds(name_ds) + self.name_regimes = USER.set_name_ds(name_regimes) + self.name_w = USER.set_name_w(name_w, w) + self.n = n + self.y = y + + if summ: + name_yend = USER.set_name_yend(name_yend, yend) + self.name_y = USER.set_name_y(name_y) + name_q = USER.set_name_q(name_q, q) + self.name_x_r = USER.set_name_x(name_x, x_constant) + name_yend + + cols2regi = REGI.check_cols2regi( + constant_regi, cols2regi, x_constant, yend=yend + ) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, self.n, x_constant.shape[1]) + self.regime_err_sep = regime_err_sep + + if regime_err_sep == True: + if set(cols2regi) == set([True]): + self._endog_error_regimes_multi( + y, + x_constant, + regimes, + w, + yend, + q, + slx_lags, + cores, + cols2regi, + vm, + name_x, + name_yend, + name_q, + add_lag, + latex, + ) + else: + raise Exception( + "All coefficients must vary across regimes if regime_err_sep = True." + ) + else: + x_constant = sphstack( + np.ones((x_constant.shape[0], 1)), x_constant) + name_x = USER.set_name_x(name_x, x_constant) + q, name_q = REGI.Regimes_Frame.__init__( + self, q, regimes, constant_regi=None, cols2regi="all", names=name_q + ) + x, name_x, x_rlist = REGI.Regimes_Frame.__init__( + self, + x_constant, + regimes, + constant_regi=None, + cols2regi=cols2regi, + names=name_x, + rlist=True, + ) + yend2, name_yend, yend_rlist = REGI.Regimes_Frame.__init__( + self, + yend, + regimes, + constant_regi=None, + cols2regi=cols2regi, + yend=True, + names=name_yend, + rlist=True, + ) + + tsls = BaseTSLS(y=y, x=x, yend=yend2, q=q) + self.k = tsls.z.shape[1] + self.x = tsls.x + self.yend, self.z = tsls.yend, tsls.z + moments = _momentsGM_Error(w, tsls.u) + lambda1 = optim_moments(moments) + xs = get_spFilter(w, lambda1, x_constant) + xs = REGI.Regimes_Frame.__init__( + self, xs, regimes, constant_regi=None, cols2regi=cols2regi + )[0] + ys = get_spFilter(w, lambda1, y) + yend_s = get_spFilter(w, lambda1, yend) + yend_s = REGI.Regimes_Frame.__init__( + self, + yend_s, + regimes, + constant_regi=None, + cols2regi=cols2regi, + yend=True, + )[0] + tsls2 = BaseTSLS(ys, xs, yend_s, h=tsls.h) + + # Output + self.betas = np.vstack((tsls2.betas, np.array([[lambda1]]))) + self.predy = spdot(tsls.z, tsls2.betas) + self.u = y - self.predy + self.sig2 = float(np.dot(tsls2.u.T, tsls2.u)) / self.n + self.e_filtered = self.u - lambda1 * lag_spatial(w, self.u) + self.vm = self.sig2 * tsls2.varb + self.name_x = USER.set_name_x(name_x, x_constant, constant=True) + self.name_yend = USER.set_name_yend(name_yend, yend) + self.name_z = self.name_x + self.name_yend + self.name_z.append("lambda") + self.name_q = USER.set_name_q(name_q, q) + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.kf += 1 + self.chow = REGI.Chow(self) + self._cache = {} + self.output = pd.DataFrame(self.name_z, + columns=['var_names']) + self.output['var_type'] = [ + 'x'] * len(self.name_x) + ['yend'] * len(self.name_yend) + ['lambda'] + self.output['regime'] = x_rlist + yend_rlist + ['_Global'] + self.output['equation'] = 0 + if summ: + if slx_lags == 0: + self.title = ("GM SPATIALLY WEIGHTED 2SLS - REGIMES") + else: + self.title = ("GM SPATIALLY WEIGHTED 2SLS WITH SLX (SDEM) - REGIMES") + output(reg=self, vm=vm, robust=False, + other_end=False, latex=latex)
+ + def _endog_error_regimes_multi( + self, + y, + x, + regimes, + w, + yend, + q, + slx_lags, + cores, + cols2regi, + vm, + name_x, + name_yend, + name_q, + add_lag, + latex, + ): + + regi_ids = dict( + (r, list(np.where(np.array(regimes) == r)[0])) for r in self.regimes_set + ) + if add_lag != False: + self.cols2regi += [True] + cols2regi += [True] + self.predy_e = np.zeros((self.n, 1), float) + self.e_pred = np.zeros((self.n, 1), float) + results_p = {} + """ + for r in self.regimes_set: + if system() == 'Windows': + results_p[r] = _work_endog_error(*(y,x,yend,q,regi_ids,r,w,self.name_ds,self.name_y,name_x,name_yend,name_q,self.name_w,self.name_regimes,add_lag)) + is_win = True + else: + pool = mp.Pool(cores) + results_p[r] = pool.apply_async(_work_endog_error,args=(y,x,yend,q,regi_ids,r,w,self.name_ds,self.name_y,name_x,name_yend,name_q,self.name_w,self.name_regimes,add_lag, )) + is_win = False + """ + x_constant, name_x = REGI.check_const_regi(self, x, name_x, regi_ids) + self.name_x_r = name_x + name_yend + for r in self.regimes_set: + if cores: + pool = mp.Pool(None) + results_p[r] = pool.apply_async( + _work_endog_error, + args=( + y, + x_constant, + yend, + q, + regi_ids, + r, + w, + self.name_ds, + self.name_y, + name_x, + name_yend, + name_q, + self.name_w, + self.name_regimes, + add_lag, + slx_lags, + ), + ) + else: + results_p[r] = _work_endog_error( + *( + y, + x_constant, + yend, + q, + regi_ids, + r, + w, + self.name_ds, + self.name_y, + name_x, + name_yend, + name_q, + self.name_w, + self.name_regimes, + add_lag, + slx_lags, + ) + ) + + self.kryd, self.kf = 0, 0 + self.kr = len(cols2regi) + self.nr = len(self.regimes_set) + self.vm = np.zeros((self.nr * self.kr, self.nr * self.kr), float) + self.betas = np.zeros((self.nr * (self.kr + 1), 1), float) + self.u = np.zeros((self.n, 1), float) + self.predy = np.zeros((self.n, 1), float) + self.e_filtered = np.zeros((self.n, 1), float) + """ + if not is_win: + pool.close() + pool.join() + """ + if cores: + pool.close() + pool.join() + + results = {} + ( + self.name_y, + self.name_x, + self.name_yend, + self.name_q, + self.name_z, + self.name_h, + ) = ([], [], [], [], [], []) + counter = 0 + self.output = pd.DataFrame( + columns=['var_names', 'var_type', 'regime', 'equation']) + for r in self.regimes_set: + """ + if is_win: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + """ + if not cores: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + + self.vm[ + (counter * self.kr): ((counter + 1) * self.kr), + (counter * self.kr): ((counter + 1) * self.kr), + ] = results[r].vm + self.betas[ + (counter * (self.kr + 1)): ((counter + 1) * (self.kr + 1)), + ] = results[r].betas + self.u[ + regi_ids[r], + ] = results[r].u + self.predy[ + regi_ids[r], + ] = results[r].predy + self.e_filtered[ + regi_ids[r], + ] = results[r].e_filtered + self.name_y += results[r].name_y + self.name_x += results[r].name_x + self.name_yend += results[r].name_yend + self.name_q += results[r].name_q + self.name_z += results[r].name_z + self.name_h += results[r].name_h + if add_lag != False: + self.predy_e[ + regi_ids[r], + ] = results[r].predy_e + self.e_pred[ + regi_ids[r], + ] = results[r].e_pred + results[r].other_top = _spat_pseudo_r2(results[r]) + v_type = ['x'] * len(results[r].name_x) + ['yend'] * \ + (len(results[r].name_yend) - 1) + ['rho', 'lambda'] + else: + results[r].other_top = "" + v_type = ['x'] * len(results[r].name_x) + ['yend'] * \ + len(results[r].name_yend) + ['lambda'] + self.output = pd.concat([self.output, pd.DataFrame({'var_names': results[r].name_z, + 'var_type': v_type, + 'regime': r, 'equation': r})], ignore_index=True) + counter += 1 + self.chow = REGI.Chow(self) + self.multi = results + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +
[docs]class GM_Combo_Regimes(GM_Endog_Error_Regimes, REGI.Regimes_Frame): + + """ + GMM method for a spatial lag and error model with regimes and endogenous + variables, with results and diagnostics; based on Kelejian and Prucha (1998, + 1999) :cite:`Kelejian1998` :cite:`Kelejian1999`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : pysal W object + Spatial weights object (always needed) + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + regime_lag_sep: boolean + If True, the spatial parameter for spatial lag is also + computed according to different regimes. If False (default), + the spatial parameter is fixed accross regimes. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the GNSM type. + w_lags : integer + Orders of W to include as instruments for the spatially + lagged dependent variable. For example, w_lags=1, then + instruments are WX; if w_lags=2, then WX, WWX; and so on. + lag_q : boolean + If True, then include spatial lags of the additional + instruments (q). + vm : boolean + If True, include variance-covariance matrix in summary + results + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + e_pred : array + nx1 array of residuals (using reduced form) + predy : array + nx1 array of predicted y values + predy_e : array + nx1 array of predicted y values (using reduced form) + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z : array + nxk array of variables (combination of x and yend) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + sig2 : float + Sigma squared used in computations (based on filtered + residuals) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi : string + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + regime_lag_sep: boolean + If True, the spatial parameter for spatial lag is also + computed according to different regimes. If False (default), + the spatial parameter is fixed accross regimes. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path("natregimes.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to run a spatial lag model, we need to specify + the spatial weights matrix that includes the spatial configuration of the + observations. To do that, we can open an already existing gal file or + create a new one. In this case, we will create one from ``NAT.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(nat.get_path("natregimes.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + The Combo class runs an SARAR model, that is a spatial lag+error model. + In this case we will run a simple version of that, where we have the + spatial effects as well as exogenous variables. Since it is a spatial + model, we have to pass in the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import GM_Combo_Regimes + >>> model = GM_Combo_Regimes(y, x, regimes, w=w, name_y=y_var, name_x=x_var, name_regimes=r_var, name_ds='NAT') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. Note that because we are running the classical GMM error + model from 1998/99, the spatial parameter is obtained as a point estimate, so + although you get a value for it (there are for coefficients under + model.betas), you cannot perform inference on it (there are only three + values in model.se_betas). Also, this regression uses a two stage least + squares estimation method that accounts for the endogeneity created by the + spatial lag of the dependent variable. We can have a summary of the + output by typing: model.summary + Alternatively, we can check the betas: + + >>> print(model.output) + var_names coefficients std_err zt_stat prob + 0 0_CONSTANT 1.460707 0.704174 2.074356 0.038046 + 1 0_PS90 0.95795 0.171485 5.586214 0.0 + 2 0_UE90 0.565805 0.053665 10.543203 0.0 + 3 1_CONSTANT 9.112998 1.525875 5.972311 0.0 + 4 1_PS90 1.13382 0.20552 5.51683 0.0 + 5 1_UE90 0.65169 0.061106 10.664938 0.0 + 6 _Global_W_HR90 -0.458326 0.145599 -3.147859 0.001645 + 7 lambda 0.613599 None None None + + This class also allows the user to run a spatial lag+error model with the + extra feature of including non-spatial endogenous regressors. This means + that, in addition to the spatial lag and error, we consider some of the + variables on the right-hand side of the equation as endogenous and we + instrument for this. In this case we consider RD90 (resource deprivation) + as an endogenous regressor. We use FP89 (families below poverty) + for this and hence put it in the instruments parameter, 'q'. + + >>> yd_var = ['RD90'] + >>> yd = np.array([db.by_col(name) for name in yd_var]).T + >>> q_var = ['FP89'] + >>> q = np.array([db.by_col(name) for name in q_var]).T + + And then we can run and explore the model analogously to the previous combo: + + >>> model = GM_Combo_Regimes(y, x, regimes, yd, q, w=w, name_y=y_var, name_x=x_var, name_yend=yd_var, name_q=q_var, name_regimes=r_var, name_ds='NAT') + >>> print(model.output) + var_names coefficients std_err zt_stat prob + 0 0_CONSTANT 3.419638 0.530676 6.443931 0.0 + 1 0_PS90 1.040658 0.132714 7.841346 0.0 + 2 0_UE90 0.166344 0.06058 2.745844 0.006036 + 6 0_RD90 2.43014 0.289431 8.396263 0.0 + 3 1_CONSTANT 8.865446 0.764064 11.603014 0.0 + 4 1_PS90 1.851205 0.179698 10.301769 0.0 + 5 1_UE90 -0.249085 0.071674 -3.475235 0.00051 + 7 1_RD90 3.616455 0.253083 14.289586 0.0 + 8 _Global_W_HR90 0.033087 0.061265 0.540057 0.589158 + 9 lambda 0.18685 None None None + """ + +
[docs] def __init__( + self, + y, + x, + regimes, + yend=None, + q=None, + w=None, + slx_lags=0, + w_lags=1, + lag_q=True, + cores=False, + constant_regi="many", + cols2regi="all", + regime_err_sep=False, + regime_lag_sep=False, + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_ds=None, + name_regimes=None, + latex=False, + ): + if regime_lag_sep and not regime_err_sep: + set_warn(self, "regime_err_sep set to True when regime_lag_sep=True.") + regime_err_sep = True + if regime_err_sep and not regime_lag_sep: + set_warn(self, "regime_err_sep set to False when regime_lag_sep=False.") + regime_err_sep = False + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant( + x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + self.name_y = USER.set_name_y(name_y) + name_yend = USER.set_name_yend(name_yend, yend) + name_q = USER.set_name_q(name_q, q) + + if regime_err_sep and any(col != True for col in cols2regi): + set_warn(self, "All coefficients must vary across regimes if regime_err_sep = True, so setting cols2regi = 'all'.") + cols2regi = "all" + + if slx_lags > 0: + yend2, q2, wx = set_endog(y, x_constant, w, yend, q, w_lags, lag_q, slx_lags) + x_constant = np.hstack((x_constant, wx)) + name_slx = USER.set_name_spatial_lags(name_x, slx_lags) + name_q.extend(USER.set_name_q_sp(name_slx[-len(name_x):], w_lags, name_q, lag_q, force_all=True)) + name_x += name_slx + cols2regi = REGI.check_cols2regi(constant_regi, cols2regi, x_constant[:, :-1], yend=yend2, add_cons=False) + else: + name_q.extend(USER.set_name_q_sp(name_x, w_lags, name_q, lag_q, force_all=True)) + yend2, q2 = yend, q + cols2regi = REGI.check_cols2regi(constant_regi, cols2regi, x_constant, yend=yend2, add_cons=False) + + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, n, x_constant.shape[1]) + self.regime_err_sep = regime_err_sep + self.regime_lag_sep = regime_lag_sep + + if regime_lag_sep == True: + if slx_lags == 0: + add_lag = [w_lags, lag_q] + else: + add_lag = False + cols2regi += [True] + + else: + add_lag = False + cols2regi += [False] + if slx_lags == 0: + yend2, q2 = set_endog(y, x_constant, w, yend2, q2, w_lags, lag_q) + + name_yend.append(USER.set_name_yend_sp(self.name_y)) + + print(cols2regi, x_constant.shape[1], yend2.shape[1], name_x, name_yend, name_q) + GM_Endog_Error_Regimes.__init__( + self, + y=y, + x=x_constant, + yend=yend2, + q=q2, + regimes=regimes, + w=w, + vm=vm, + constant_regi=constant_regi, + cols2regi=cols2regi, + regime_err_sep=regime_err_sep, + cores=cores, + name_y=self.name_y, + name_x=name_x, + name_yend=name_yend, + name_q=name_q, + name_w=name_w, + name_ds=name_ds, + name_regimes=name_regimes, + summ=False, + add_lag=add_lag, + latex=latex, + ) + + if regime_err_sep != True: + self.rho = self.betas[-2] + self.predy_e, self.e_pred, warn = sp_att( + w, self.y, self.predy, yend2[:, -1].reshape(self.n, 1), self.rho + ) + set_warn(self, warn) + if slx_lags == 0: + self.title = "SPATIALLY WEIGHTED 2SLS - GM-COMBO MODEL - REGIMES" + else: + self.title = "SPATIALLY WEIGHTED 2SLS - GM-COMBO WITH SLX (GNSM) - REGIMES" + self.output.iat[-2, + self.output.columns.get_loc('var_type')] = 'rho' + self.other_top = _spat_pseudo_r2(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +class GMM_Error_Regimes(GM_Error_Regimes, GM_Combo_Regimes, GM_Endog_Error_Regimes, + GM_Error_Het_Regimes, GM_Combo_Het_Regimes, GM_Endog_Error_Het_Regimes, + GM_Error_Hom_Regimes, GM_Combo_Hom_Regimes, GM_Endog_Error_Hom_Regimes + ): + + """ + Wrapper function to call any of the GM methods for a spatial error regimes model available in spreg + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + w : pysal W object + Spatial weights object (always needed) + yend : array + Two dimensional array with n rows and one column for each + endogenous variable (if any) + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (if any) + (note: this should not contain any variables from x) + estimator : string + Choice of estimator to be used. Options are: 'het', which + is robust to heteroskedasticity, 'hom', which assumes + homoskedasticity, and 'kp98', which does not provide + inference on the spatial parameter for the error term. + constant_regi: string, optional + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + regime_lag_sep: boolean + Always False, kept for consistency, ignored. + add_wy : boolean + If True, then a spatial lag of the dependent variable is included. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM or GNSM type. + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_regimes : string + Name of regime variable for use in the output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + **kwargs : keywords + Additional arguments to pass on to the estimators. + See the specific functions for details on what can be used. + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + vm : array + Variance covariance matrix (kxk) + sig2 : float + Sigma squared used in computations + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi: string + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes + + * 'many': a vector of ones is appended to x and considered different per regime + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + name_yend : list of strings (optional) + Names of endogenous variables for use in output + name_z : list of strings (optional) + Names of exogenous and endogenous variables for use in + output + name_q : list of strings (optional) + Names of external instruments + name_h : list of strings (optional) + Names of all instruments used in ouput + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``libpysal`` to + handle the weights and file management. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path("natregimes.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to run a spatial error model, we need to specify + the spatial weights matrix that includes the spatial configuration of the + observations. To do that, we can open an already existing gal file or + create a new one. In this case, we will create one from ``NAT.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(nat.get_path("natregimes.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + The GMM_Error_Regimes class can run error models and SARAR models, that is a spatial lag+error model. + In this example we will run a simple version of the latter, where we have the + spatial effects as well as exogenous variables. Since it is a spatial + model, we have to pass in the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import GMM_Error_Regimes + >>> model = GMM_Error_Regimes(y, x, regimes, w=w, add_wy=True, name_y=y_var, name_x=x_var, name_regimes=r_var, name_ds='NAT') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. + + >>> print(model.output) + var_names coefficients std_err zt_stat prob + 0 0_CONSTANT 1.461317 0.848361 1.722517 0.084976 + 1 0_PS90 0.958711 0.239834 3.997388 0.000064 + 2 0_UE90 0.565825 0.063726 8.879088 0.0 + 3 1_CONSTANT 9.115738 1.976874 4.611189 0.000004 + 4 1_PS90 1.132419 0.334107 3.389387 0.0007 + 5 1_UE90 0.651804 0.105518 6.177197 0.0 + 6 _Global_W_HR90 -0.458677 0.180997 -2.534173 0.011271 + 7 lambda 0.734354 0.035255 20.829823 0.0 + + This class also allows the user to run a spatial lag+error model with the + extra feature of including non-spatial endogenous regressors. This means + that, in addition to the spatial lag and error, we consider some of the + variables on the right-hand side of the equation as endogenous and we + instrument for this. In this case we consider RD90 (resource deprivation) + as an endogenous regressor. We use FP89 (families below poverty) + for this and hence put it in the instruments parameter, 'q'. + + >>> yd_var = ['RD90'] + >>> yd = np.array([db.by_col(name) for name in yd_var]).T + >>> q_var = ['FP89'] + >>> q = np.array([db.by_col(name) for name in q_var]).T + + And then we can run and explore the model analogously to the previous combo: + + >>> model = GMM_Error_Regimes(y, x, regimes, yend=yd, q=q, w=w, add_wy=True, name_y=y_var, name_x=x_var, name_yend=yd_var, name_q=q_var, name_regimes=r_var, name_ds='NAT') + >>> print(model.output) + var_names coefficients std_err zt_stat prob + 0 0_CONSTANT 1.461317 0.848361 1.722517 0.084976 + 1 0_PS90 0.958711 0.239834 3.997388 0.000064 + 2 0_UE90 0.565825 0.063726 8.879088 0.0 + 3 1_CONSTANT 9.115738 1.976874 4.611189 0.000004 + 4 1_PS90 1.132419 0.334107 3.389387 0.0007 + 5 1_UE90 0.651804 0.105518 6.177197 0.0 + 6 _Global_W_HR90 -0.458677 0.180997 -2.534173 0.011271 + 7 lambda 0.734354 0.035255 20.829823 0.0 + + The class also allows for estimating a GNS model by adding spatial lags of the exogenous variables, using the argument slx_lags: + + >>> model = GMM_Error_Regimes(y, x, regimes, w=w, add_wy=True, slx_lags=1, name_y=y_var, name_x=x_var, name_regimes=r_var, name_ds='NAT') + >>> print(model.output) + var_names coefficients std_err zt_stat prob + 0 0_CONSTANT 0.192699 0.256922 0.75003 0.453237 + 1 0_PS90 1.098019 0.232054 4.731743 0.000002 + 2 0_UE90 0.606622 0.07762 7.815325 0.0 + 3 0_W_PS90 -1.068778 0.203911 -5.241381 0.0 + 4 0_W_UE90 -0.657932 0.176073 -3.73671 0.000186 + 5 1_CONSTANT -0.104299 1.790953 -0.058237 0.95356 + 6 1_PS90 1.219796 0.316425 3.854936 0.000116 + 7 1_UE90 0.678922 0.120491 5.634647 0.0 + 8 1_W_PS90 -1.308599 0.536231 -2.440366 0.014672 + 9 1_W_UE90 -0.708492 0.167057 -4.24102 0.000022 + 10 _Global_W_HR90 1.033956 0.269252 3.840111 0.000123 + 11 lambda -0.384968 0.192256 -2.002366 0.045245 + + + """ + + def __init__( + self, y, x, regimes, w, yend=None, q=None, estimator='het', constant_regi="many", cols2regi="all", regime_err_sep=False, + regime_lag_sep=False, add_wy=False, slx_lags=0, vm=False, name_y=None, name_x=None, name_w=None, name_regimes=None, name_yend=None, + name_q=None, name_ds=None, latex=False, **kwargs): + + if estimator == 'het': + if yend is None and not add_wy: + GM_Error_Het_Regimes.__init__(self, y=y, x=x, regimes=regimes, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, + name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex, **kwargs) + elif yend is not None and not add_wy: + GM_Endog_Error_Het_Regimes.__init__(self, y=y, x=x, regimes=regimes, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex, **kwargs) + elif add_wy: + GM_Combo_Het_Regimes.__init__(self, y=y, x=x, regimes=regimes, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, regime_lag_sep=regime_lag_sep, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex, **kwargs) + else: + set_warn(self, 'Combination of arguments passed to GMM_Error_Regimes not allowed. Using default arguments instead.') + GM_Error_Het_Regimes.__init__(self, y=y, x=x, regimes=regimes, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, + name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex) + elif estimator == 'hom': + if yend is None and not add_wy: + GM_Error_Hom_Regimes.__init__(self, y=y, x=x, regimes=regimes, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, + name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex, **kwargs) + elif yend is not None and not add_wy: + GM_Endog_Error_Hom_Regimes.__init__(self, y=y, x=x, regimes=regimes, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex, **kwargs) + elif add_wy: + GM_Combo_Hom_Regimes.__init__(self, y=y, x=x, regimes=regimes, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, regime_lag_sep=regime_lag_sep, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex, **kwargs) + else: + set_warn(self, 'Combination of arguments passed to GMM_Error_Regimes not allowed. Using default arguments instead.') + GM_Error_Hom_Regimes.__init__(self, y=y, x=x, regimes=regimes, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, + name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex) + elif estimator == 'kp98': + if yend is None and not add_wy: + GM_Error_Regimes.__init__(self, y=y, x=x, regimes=regimes, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, + name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex, **kwargs) + elif yend is not None and not add_wy: + GM_Endog_Error_Regimes.__init__(self, y=y, x=x, regimes=regimes, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex, **kwargs) + elif add_wy: + GM_Combo_Regimes.__init__(self, y=y, x=x, regimes=regimes, yend=yend, q=q, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, regime_lag_sep=regime_lag_sep, + name_yend=name_yend, name_q=name_q, name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex, **kwargs) + else: + set_warn(self, 'Combination of arguments passed to GMM_Error_Regimes not allowed. Using default arguments instead.') + GM_Error_Regimes.__init__(self, y=y, x=x, regimes=regimes, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, + name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex) + else: + set_warn(self, 'Combination of arguments passed to GMM_Error_Regimes not allowed. Using default arguments instead.') + GM_Error_Het_Regimes.__init__(self, y=y, x=x, regimes=regimes, w=w, slx_lags=slx_lags, vm=vm, name_y=name_y, name_x=name_x, + constant_regi=constant_regi, cols2regi=cols2regi, regime_err_sep=regime_err_sep, + name_w=name_w, name_regimes=name_regimes, name_ds=name_ds, latex=latex) + +def _work_error(y, x, regi_ids, r, w, name_ds, name_y, name_x, name_w, name_regimes): + w_r, warn = REGI.w_regime(w, regi_ids[r], r, transform=True) + y_r = y[regi_ids[r]] + x_r = x[regi_ids[r]] + model = BaseGM_Error(y_r, x_r, w_r.sparse) + set_warn(model, warn) + model.w = w_r + model.title = "GM SPATIALLY WEIGHTED LEAST SQUARES ESTIMATION - REGIME %s" % r + model.name_ds = name_ds + model.name_y = "%s_%s" % (str(r), name_y) + model.name_x = ["%s_%s" % (str(r), i) for i in name_x] + model.name_w = name_w + model.name_regimes = name_regimes + return model + + +def _work_endog_error( + y, + x, + yend, + q, + regi_ids, + r, + w, + name_ds, + name_y, + name_x, + name_yend, + name_q, + name_w, + name_regimes, + add_lag, + slx_lags, +): + w_r, warn = REGI.w_regime(w, regi_ids[r], r, transform=True) + y_r = y[regi_ids[r]] + x_r = x[regi_ids[r]] + if yend is not None: + yend_r = yend[regi_ids[r]] + q_r = q[regi_ids[r]] + else: + yend_r, q_r = None, None + if add_lag != False: + yend_r, q_r = set_endog( + y_r, x_r[:, 1:], w_r, yend_r, q_r, add_lag[0], add_lag[1] + ) + model = BaseGM_Endog_Error(y_r, x_r, yend_r, q_r, w_r.sparse) + set_warn(model, warn) + if add_lag != False: + model.rho = model.betas[-2] + model.predy_e, model.e_pred, warn = sp_att( + w_r, model.y, model.predy, model.yend[:, - + 1].reshape(model.n, 1), model.rho + ) + set_warn(model, warn) + model.w = w_r + if slx_lags == 0: + if add_lag != False: + model.title = "SPATIALLY WEIGHTED 2SLS - GM-COMBO MODEL - REGIME %s" % r + else: + model.title = "SPATIALLY WEIGHTED 2SLS (GM) - REGIME %s" % r + else: + if add_lag != False: + model.title = "GM SPATIAL COMBO MODEL + SLX (GNSM) - REGIME %s" % r + else: + model.title = "GM SPATIALLY WEIGHTED 2SLS + SLX (SDEM) - REGIME %s" % r + model.name_ds = name_ds + model.name_y = "%s_%s" % (str(r), name_y) + model.name_x = ["%s_%s" % (str(r), i) for i in name_x] + model.name_yend = ["%s_%s" % (str(r), i) for i in name_yend] + model.name_z = model.name_x + model.name_yend + [str(r)+"_lambda"] + model.name_q = ["%s_%s" % (str(r), i) for i in name_q] + model.name_h = model.name_x + model.name_q + model.name_w = name_w + model.name_regimes = name_regimes + return model + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + import numpy as np + import libpysal + + db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'), 'r') + y = np.array(db.by_col("HOVAL")) + y = np.reshape(y, (49, 1)) + X = [] + X.append(db.by_col("INC")) + X = np.array(X).T + yd = [] + yd.append(db.by_col("CRIME")) + yd = np.array(yd).T + q = [] + q.append(db.by_col("DISCBD")) + q = np.array(q).T + + r_var = 'NSA' + regimes = db.by_col(r_var) + + w = libpysal.weights.Rook.from_shapefile( + libpysal.examples.get_path("columbus.shp")) + w.transform = 'r' + # reg = GM_Error_Regimes(y, X, regimes, w=w, name_x=['inc'], name_y='hoval', name_ds='columbus', + # regime_err_sep=True) + # reg = GM_Endog_Error_Regimes(y, X, yd, q, regimes, w=w, name_x=['inc'], name_y='hoval', name_yend=['crime'], + # name_q=['discbd'], name_ds='columbus', regime_err_sep=True) + reg = GM_Combo_Regimes(y, X, regimes, yd, q, w=w, name_x=['inc'], name_y='hoval', name_yend=['crime'], + name_q=['discbd'], name_ds='columbus', regime_err_sep=True, regime_lag_sep=True) + print(reg.output) + print(reg.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/ml_error.html b/_modules/spreg/ml_error.html new file mode 100644 index 00000000..ea5da88f --- /dev/null +++ b/_modules/spreg/ml_error.html @@ -0,0 +1,761 @@ + + + + + + + spreg.ml_error — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.ml_error

+"""
+ML Estimation of Spatial Error Model
+"""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu,\
+              Serge Rey srey@asu.edu, \
+              Levi Wolf levi.john.wolf@asu.edu"
+
+import numpy as np
+import numpy.linalg as la
+from scipy import sparse as sp
+from scipy.sparse.linalg import splu as SuperLU
+from .utils import RegressionPropsY, RegressionPropsVM, set_warn, get_lags
+from . import diagnostics as DIAG
+from . import user_output as USER
+from . import regimes as REGI
+from .w_utils import symmetrize
+import pandas as pd
+from .output import output, _nonspat_top
+
+try:
+    from scipy.optimize import minimize_scalar
+
+    minimize_scalar_available = True
+except ImportError:
+    minimize_scalar_available = False
+from .sputils import spdot, spfill_diagonal, spinv
+from libpysal import weights
+
+__all__ = ["ML_Error"]
+
+
+class BaseML_Error(RegressionPropsY, RegressionPropsVM, REGI.Regimes_Frame):
+
+    """
+    ML estimation of the spatial error model (note no consistency
+    checks, diagnostics or constants added): :cite:`Anselin1988`
+
+    Parameters
+    ----------
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, excluding the constant
+    w            : Sparse matrix
+                   Spatial weights sparse matrix
+    method       : string
+                   if 'full', brute force calculation (full matrix expressions)
+                   if 'ord', Ord eigenvalue calculation
+                   if 'LU', LU decomposition for sparse matrices
+    epsilon      : float
+                   tolerance criterion in mimimize_scalar function and inverse_product
+    regimes_att  : dictionary
+                   Dictionary containing elements to be used in case of a regimes model,
+                   i.e. 'x' before regimes, 'regimes' list and 'cols2regi'
+
+
+    Attributes
+    ----------
+    betas        : array
+                   kx1 array of estimated coefficients
+    lam          : float
+                   estimate of spatial autoregressive coefficient
+    u            : array
+                   nx1 array of residuals
+    e_filtered   : array
+                   spatially filtered residuals
+    predy        : array
+                   nx1 array of predicted y values
+    n            : integer
+                   Number of observations
+    k            : integer
+                   Number of variables for which coefficients are estimated
+                   (including the constant, excluding the rho)
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, including the constant
+    method       : string
+                   log Jacobian method
+                   if 'full': brute force (full matrix computations)
+                   if 'ord' : Ord eigenvalue method
+    epsilon      : float
+                   tolerance criterion used in minimize_scalar function and inverse_product
+    mean_y       : float
+                   Mean of dependent variable
+    std_y        : float
+                   Standard deviation of dependent variable
+    vm           : array
+                   Variance covariance matrix (k+1 x k+1) - includes lambda
+    vm1          : array
+                   2x2 array of variance covariance for lambda, sigma
+    sig2         : float
+                   Sigma squared used in computations
+    logll        : float
+                   maximized log-likelihood (including constant terms)
+
+    Examples
+    --------
+    >>> import numpy as np
+    >>> import libpysal
+    >>> from libpysal import examples
+    >>> from libpysal.examples import load_example
+    >>> import spreg
+    >>> np.set_printoptions(suppress=True) #prevent scientific format
+    >>> south = load_example('South')
+    >>> db = libpysal.io.open(south.get_path("south.dbf"),'r')
+    >>> y_name = "HR90"
+    >>> y = np.array(db.by_col(y_name))
+    >>> y.shape = (len(y),1)
+    >>> x_names = ["RD90","PS90","UE90","DV90"]
+    >>> x = np.array([db.by_col(var) for var in x_names]).T
+    >>> x = np.hstack((np.ones((len(y),1)),x))
+    >>> w = libpysal.weights.Queen.from_shapefile(south.get_path("south.shp"))
+    >>> w.transform = 'r'
+    >>> mlerr = spreg.ml.error.BaseML_Error(y,x,w) #doctest: +SKIP
+    >>> "{0:.6f}".format(mlerr.lam) #doctest: +SKIP
+    '0.299078'
+    >>> np.around(mlerr.betas, decimals=4) #doctest: +SKIP
+    array([[ 6.1492],
+           [ 4.4024],
+           [ 1.7784],
+           [-0.3781],
+           [ 0.4858],
+           [ 0.2991]])
+    >>> "{0:.6f}".format(mlerr.mean_y) #doctest: +SKIP
+    '9.549293'
+    >>> "{0:.6f}".format(mlerr.std_y) #doctest: +SKIP
+    '7.038851'
+    >>> np.diag(mlerr.vm) #doctest: +SKIP
+    array([ 1.06476526,  0.05548248,  0.04544514,  0.00614425,  0.01481356,
+            0.00143001])
+    >>> "{0:.6f}".format(mlerr.sig2[0][0]) #doctest: +SKIP
+    '32.406854'
+    >>> "{0:.6f}".format(mlerr.logll) #doctest: +SKIP
+    '-4471.407067'
+    >>> mlerr1 = BaseML_Error(y,x,w,method='ord') #doctest: +SKIP
+    >>> "{0:.6f}".format(mlerr1.lam) #doctest: +SKIP
+    '0.299078'
+    >>> np.around(mlerr1.betas, decimals=4) #doctest: +SKIP
+    array([[ 6.1492],
+           [ 4.4024],
+           [ 1.7784],
+           [-0.3781],
+           [ 0.4858],
+           [ 0.2991]])
+    >>> "{0:.6f}".format(mlerr1.mean_y) #doctest: +SKIP
+    '9.549293'
+    >>> "{0:.6f}".format(mlerr1.std_y) #doctest: +SKIP
+    '7.038851'
+    >>> np.around(np.diag(mlerr1.vm), decimals=4) #doctest: +SKIP
+    array([ 1.0648,  0.0555,  0.0454,  0.0061,  0.0148,  0.0014])
+    >>> "{0:.4f}".format(mlerr1.sig2[0][0]) #doctest: +SKIP
+    '32.4069'
+    >>> "{0:.4f}".format(mlerr1.logll) #doctest: +SKIP
+    '-4471.4071'
+
+    """
+
+    def __init__(self, y, x, w, method="full", epsilon=0.0000001, regimes_att=None):
+        # set up main regression variables and spatial filters
+        self.y = y
+        if regimes_att:
+            self.x = x.toarray()
+        else:
+            self.x = x
+        self.n, self.k = self.x.shape
+        self.method = method
+        self.epsilon = epsilon
+
+        # W = w.full()[0] #wait to build pending what is needed
+        # Wsp = w.sparse
+
+        ylag = weights.lag_spatial(w, self.y)
+        xlag = self.get_x_lag(w, regimes_att)
+
+        # call minimizer using concentrated log-likelihood to get lambda
+        methodML = method.upper()
+        if methodML in ["FULL", "LU", "ORD"]:
+            if methodML == "FULL":
+                W = w.full()[0]  # need dense here
+                res = minimize_scalar(
+                    err_c_loglik,
+                    0.0,
+                    bounds=(-1.0, 1.0),
+                    args=(self.n, self.y, ylag, self.x, xlag, W),
+                    method="bounded",
+                    tol=epsilon,
+                )
+            elif methodML == "LU":
+                I = sp.identity(w.n)
+                Wsp = w.sparse  # need sparse here
+                res = minimize_scalar(
+                    err_c_loglik_sp,
+                    0.0,
+                    bounds=(-1.0, 1.0),
+                    args=(self.n, self.y, ylag, self.x, xlag, I, Wsp),
+                    method="bounded",
+                    tol=epsilon,
+                )
+                W = Wsp
+            elif methodML == "ORD":
+                # check on symmetry structure
+                if w.asymmetry(intrinsic=False) == []:
+                    ww = symmetrize(w)
+                    WW = np.array(ww.todense())
+                    evals = la.eigvalsh(WW)
+                    W = WW
+                else:
+                    W = w.full()[0]  # need dense here
+                    evals = la.eigvals(W)
+                res = minimize_scalar(
+                    err_c_loglik_ord,
+                    0.0,
+                    bounds=(-1.0, 1.0),
+                    args=(self.n, self.y, ylag, self.x, xlag, evals),
+                    method="bounded",
+                    tol=epsilon,
+                )
+        else:
+            raise Exception("{0} is an unsupported method".format(method))
+
+        self.lam = res.x
+
+        # compute full log-likelihood, including constants
+        ln2pi = np.log(2.0 * np.pi)
+        llik = -res.fun - self.n / 2.0 * ln2pi - self.n / 2.0
+
+        self.logll = llik
+
+        # b, residuals and predicted values
+
+        ys = self.y - self.lam * ylag
+        xs = self.x - self.lam * xlag
+        xsxs = np.dot(xs.T, xs)
+        xsxsi = np.linalg.inv(xsxs)
+        xsys = np.dot(xs.T, ys)
+        b = np.dot(xsxsi, xsys)
+
+        self.betas = np.vstack((b, self.lam))
+
+        self.u = y - np.dot(self.x, b)
+        self.predy = self.y - self.u
+
+        # residual variance
+
+        self.e_filtered = self.u - self.lam * weights.lag_spatial(w, self.u)
+        self.sig2 = np.dot(self.e_filtered.T, self.e_filtered) / self.n
+
+        # variance-covariance matrix betas
+
+        varb = self.sig2 * xsxsi
+
+        # variance-covariance matrix lambda, sigma
+
+        a = -self.lam * W
+        spfill_diagonal(a, 1.0)
+        ai = spinv(a)
+        wai = spdot(W, ai)
+        tr1 = wai.diagonal().sum()
+
+        wai2 = spdot(wai, wai)
+        tr2 = wai2.diagonal().sum()
+
+        waiTwai = spdot(wai.T, wai)
+        tr3 = waiTwai.diagonal().sum()
+
+        v1 = np.vstack((tr2 + tr3, tr1 / self.sig2))
+        v2 = np.vstack((tr1 / self.sig2, self.n / (2.0 * self.sig2 ** 2)))
+
+        v = np.hstack((v1, v2))
+
+        self.vm1 = np.linalg.inv(v)
+
+        # create variance matrix for beta, lambda
+        vv = np.hstack((varb, np.zeros((self.k, 1))))
+        vv1 = np.hstack((np.zeros((1, self.k)), self.vm1[0, 0] * np.ones((1, 1))))
+
+        self.vm = np.vstack((vv, vv1))
+
+    def get_x_lag(self, w, regimes_att):
+        if regimes_att:
+            xlag = weights.lag_spatial(w, regimes_att["x"])
+            xlag = REGI.Regimes_Frame.__init__(
+                self,
+                xlag,
+                regimes_att["regimes"],
+                constant_regi=None,
+                cols2regi=regimes_att["cols2regi"],
+            )[0]
+            xlag = xlag.toarray()
+        else:
+            xlag = weights.lag_spatial(w, self.x)
+        return xlag
+
+
+
[docs]class ML_Error(BaseML_Error): + + """ + ML estimation of the spatial error model with all results and diagnostics; + :cite:`Anselin1988` + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + w : Sparse matrix + Spatial weights sparse matrix + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + method : string + if 'full', brute force calculation (full matrix expressions) + if 'ord', Ord eigenvalue method + if 'LU', LU sparse matrix decomposition + epsilon : float + tolerance criterion in mimimize_scalar function and inverse_product + vm : boolean + if True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + betas : array + (k+1)x1 array of estimated coefficients (rho first) + lam : float + estimate of spatial autoregressive coefficient + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant, excluding lambda) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + method : string + log Jacobian method + if 'full': brute force (full matrix computations) + epsilon : float + tolerance criterion used in minimize_scalar function and inverse_product + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + varb : array + Variance covariance matrix (k+1 x k+1) - includes var(lambda) + vm1 : array + variance covariance matrix for lambda, sigma (2 x 2) + sig2 : float + Sigma squared used in computations + logll : float + maximized log-likelihood (including constant terms) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + utu : float + Sum of squared residuals + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + >>> from libpysal.weights import Queen + >>> from spreg import ML_Error + >>> np.set_printoptions(suppress=True) #prevent scientific format + >>> south = load_example('South') + >>> db = libpysal.io.open(south.get_path("south.dbf"),'r') + >>> y_name = "HR90" + >>> y = np.array(db.by_col(y_name)) + >>> y.shape = (len(y),1) + >>> x_names = ["RD90","PS90","UE90","DV90"] + >>> x = np.array([db.by_col(var) for var in x_names]).T + >>> w = Queen.from_shapefile(south.get_path("south.shp")) + >>> w_name = "south_q.gal" + >>> w.transform = 'r' + >>> mlerr = ML_Error(y,x,w,name_y=y_name,name_x=x_names,\ + name_w=w_name,name_ds=ds_name) #doctest: +SKIP + >>> np.around(mlerr.betas, decimals=4) #doctest: +SKIP + array([[ 6.1492], + [ 4.4024], + [ 1.7784], + [-0.3781], + [ 0.4858], + [ 0.2991]]) + >>> "{0:.4f}".format(mlerr.lam) #doctest: +SKIP + '0.2991' + >>> "{0:.4f}".format(mlerr.mean_y) #doctest: +SKIP + '9.5493' + >>> "{0:.4f}".format(mlerr.std_y) #doctest: +SKIP + '7.0389' + >>> np.around(np.diag(mlerr.vm), decimals=4) #doctest: +SKIP + array([ 1.0648, 0.0555, 0.0454, 0.0061, 0.0148, 0.0014]) + >>> np.around(mlerr.sig2, decimals=4) #doctest: +SKIP + array([[ 32.4069]]) + >>> "{0:.4f}".format(mlerr.logll) #doctest: +SKIP + '-4471.4071' + >>> "{0:.4f}".format(mlerr.aic) #doctest: +SKIP + '8952.8141' + >>> "{0:.4f}".format(mlerr.schwarz) #doctest: +SKIP + '8979.0779' + >>> "{0:.4f}".format(mlerr.pr2) #doctest: +SKIP + '0.3058' + >>> "{0:.4f}".format(mlerr.utu) #doctest: +SKIP + '48534.9148' + >>> np.around(mlerr.std_err, decimals=4) #doctest: +SKIP + array([ 1.0319, 0.2355, 0.2132, 0.0784, 0.1217, 0.0378]) + >>> np.around(mlerr.z_stat, decimals=4) #doctest: +SKIP + array([[ 5.9593, 0. ], + [ 18.6902, 0. ], + [ 8.3422, 0. ], + [ -4.8233, 0. ], + [ 3.9913, 0.0001], + [ 7.9089, 0. ]]) + >>> mlerr.name_y #doctest: +SKIP + 'HR90' + >>> mlerr.name_x #doctest: +SKIP + ['CONSTANT', 'RD90', 'PS90', 'UE90', 'DV90', 'lambda'] + >>> mlerr.name_w #doctest: +SKIP + 'south_q.gal' + >>> mlerr.name_ds #doctest: +SKIP + 'south.dbf' + >>> mlerr.title #doctest: +SKIP + 'MAXIMUM LIKELIHOOD SPATIAL ERROR (METHOD = FULL)' + + + """ + +
[docs] def __init__( + self, + y, + x, + w, + slx_lags=0, + method="full", + epsilon=0.0000001, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + latex=False, + ): + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + + self.title = "ML SPATIAL ERROR" + if slx_lags >0: + lag_x = get_lags(w, x_constant[:, 1:], slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + self.title += " WITH SLX (SDEM)" + self.title += " (METHOD = " + method + ")" + + method = method.upper() + BaseML_Error.__init__( + self, y=y, x=x_constant, w=w, method=method, epsilon=epsilon + ) + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x_constant) + self.name_x.append("lambda") + self.name_w = USER.set_name_w(name_w, w) + self.aic = DIAG.akaike(reg=self) + self.schwarz = DIAG.schwarz(reg=self) + self.output = pd.DataFrame(self.name_x, columns=['var_names']) + self.output['var_type'] = ['x'] * (len(self.name_x) - 1) + ['lambda'] + self.output['regime'], self.output['equation'] = (0, 0) + self.other_top = _nonspat_top(self, ml=True) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +def err_c_loglik(lam, n, y, ylag, x, xlag, W): + # concentrated log-lik for error model, no constants, brute force + ys = y - lam * ylag + xs = x - lam * xlag + ysys = np.dot(ys.T, ys) + xsxs = np.dot(xs.T, xs) + xsxsi = np.linalg.inv(xsxs) + xsys = np.dot(xs.T, ys) + x1 = np.dot(xsxsi, xsys) + x2 = np.dot(xsys.T, x1) + ee = ysys - x2 + sig2 = ee[0][0] / n + nlsig2 = (n / 2.0) * np.log(sig2) + a = -lam * W + np.fill_diagonal(a, 1.0) + jacob = np.log(np.linalg.det(a)) + # this is the negative of the concentrated log lik for minimization + clik = nlsig2 - jacob + return clik + + +def err_c_loglik_sp(lam, n, y, ylag, x, xlag, I, Wsp): + # concentrated log-lik for error model, no constants, LU + if isinstance(lam, np.ndarray): + if lam.shape == (1, 1): + lam = lam[0][0] # why does the interior value change? + ys = y - lam * ylag + xs = x - lam * xlag + ysys = np.dot(ys.T, ys) + xsxs = np.dot(xs.T, xs) + xsxsi = np.linalg.inv(xsxs) + xsys = np.dot(xs.T, ys) + x1 = np.dot(xsxsi, xsys) + x2 = np.dot(xsys.T, x1) + ee = ysys - x2 + sig2 = ee[0][0] / n + nlsig2 = (n / 2.0) * np.log(sig2) + a = I - lam * Wsp + LU = SuperLU(a.tocsc()) + jacob = np.sum(np.log(np.abs(LU.U.diagonal()))) + # this is the negative of the concentrated log lik for minimization + clik = nlsig2 - jacob + return clik + + +def err_c_loglik_ord(lam, n, y, ylag, x, xlag, evals): + # concentrated log-lik for error model, no constants, eigenvalues + ys = y - lam * ylag + xs = x - lam * xlag + ysys = np.dot(ys.T, ys) + xsxs = np.dot(xs.T, xs) + xsxsi = np.linalg.inv(xsxs) + xsys = np.dot(xs.T, ys) + x1 = np.dot(xsxsi, xsys) + x2 = np.dot(xsys.T, x1) + ee = ysys - x2 + sig2 = ee[0][0] / n + nlsig2 = (n / 2.0) * np.log(sig2) + revals = lam * evals + jacob = np.log(1 - revals).sum() + if isinstance(jacob, complex): + jacob = jacob.real + # this is the negative of the concentrated log lik for minimization + clik = nlsig2 - jacob + return clik + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + +if __name__ == "__main__": + _test() + + import numpy as np + import libpysal + + db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"), "r") + y_var = "CRIME" + y = np.array([db.by_col(y_var)]).reshape(49, 1) + x_var = ["INC"] + x = np.array([db.by_col(name) for name in x_var]).T + w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + w.transform = "r" + model = ML_Error( + y, + x, + w=w, + vm=False, + name_y=y_var, + name_x=x_var, + name_ds="columbus", + name_w="columbus.gal", + ) + print(model.output) + print(model.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/ml_error_regimes.html b/_modules/spreg/ml_error_regimes.html new file mode 100644 index 00000000..22dd2eaf --- /dev/null +++ b/_modules/spreg/ml_error_regimes.html @@ -0,0 +1,731 @@ + + + + + + + spreg.ml_error_regimes — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.ml_error_regimes

+"""
+ML Estimation of Spatial Error Model
+"""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu, Pedro V. Amaral pedro.amaral@asu.edu"
+
+import libpysal
+import numpy as np
+import multiprocessing as mp
+from . import regimes as REGI
+from . import user_output as USER
+from . import diagnostics as DIAG
+from .utils import set_warn, get_lags
+from .sputils import sphstack
+from .ml_error import BaseML_Error
+from platform import system
+import pandas as pd
+from .output import output, _nonspat_top
+
+__all__ = ["ML_Error_Regimes"]
+
+
+
[docs]class ML_Error_Regimes(BaseML_Error, REGI.Regimes_Frame): + + """ + ML estimation of the spatial error model with regimes (note no consistency + checks, diagnostics or constants added); :cite:`Anselin1988` + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + w : Sparse matrix + Spatial weights sparse matrix + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SDEM type. + method : string + if 'full', brute force calculation (full matrix expressions) + if 'ord', Ord eigenvalue computation + if 'LU', LU sparse matrix decomposition + epsilon : float + tolerance criterion in mimimize_scalar function and inverse_product + regime_err_sep: boolean + If True, a separate regression is run for each regime. + regime_lag_sep: boolean + Always False, kept for consistency in function call, ignored. + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + vm : boolean + if True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + (k+1)x1 array of estimated coefficients (lambda last) + lam : float + estimate of spatial autoregressive coefficient + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant, excluding the rho) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + method : string + log Jacobian method. + if 'full': brute force (full matrix computations) + if 'ord', Ord eigenvalue computation + if 'LU', LU sparse matrix decomposition + epsilon : float + tolerance criterion used in minimize_scalar function and inverse_product + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (k+1 x k+1), all coefficients + vm1 : array + variance covariance matrix for lambda, sigma (2 x 2) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + sig2 : float + Sigma squared used in computations + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + logll : float + maximized log-likelihood (including constant terms) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi: string + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_lag_sep: boolean + If True, the spatial parameter for spatial lag is also + computed according to different regimes. If False (default), + the spatial parameter is fixed accross regimes. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + Open data baltim.dbf using pysal and create the variables matrices and weights matrix. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + >>> from libpysal.weights import Queen + >>> from spreg import ML_Error_Regimes + >>> import geopandas as gpd + >>> np.set_printoptions(suppress=True) #prevent scientific format + >>> baltimore = load_example('Baltimore') + >>> db = libpysal.io.open(baltimore.get_path("baltim.dbf"),'r') + >>> df = gpd.read_file(baltimore.get_path("baltim.shp")) + >>> ds_name = "baltim.dbf" + >>> y_name = "PRICE" + >>> y = np.array(db.by_col(y_name)).T + >>> y.shape = (len(y),1) + >>> x_names = ["NROOM","AGE","SQFT"] + >>> x = np.array([db.by_col(var) for var in x_names]).T + >>> w = Queen.from_dataframe(df) + >>> w_name = "baltim_q.gal" + >>> w.transform = 'r' + + Since in this example we are interested in checking whether the results vary + by regimes, we use CITCOU to define whether the location is in the city or + outside the city (in the county): + + >>> regimes = db.by_col("CITCOU") + + Now we can run the regression with all parameters: + + >>> mlerr = ML_Error_Regimes(y,x,regimes,w=w,name_y=y_name,name_x=x_names,\ + name_w=w_name,name_ds=ds_name,name_regimes="CITCOU") + >>> np.around(mlerr.betas, decimals=4) + array([[-2.076 ], + [ 4.8615], + [-0.0295], + [ 0.3355], + [32.3457], + [ 2.8708], + [-0.2401], + [ 0.799 ], + [ 0.6 ]]) + >>> "{0:.6f}".format(mlerr.lam) + '0.599951' + >>> "{0:.6f}".format(mlerr.mean_y) + '44.307180' + >>> "{0:.6f}".format(mlerr.std_y) + '23.606077' + >>> np.around(mlerr.vm1, decimals=4) + array([[ 0.0053, -0.3643], + [ -0.3643, 465.3559]]) + >>> np.around(np.diag(mlerr.vm), decimals=4) + array([58.7121, 2.5036, 0.0074, 0.0659, 81.9796, 3.2676, 0.0124, + 0.0514, 0.0053]) + >>> np.around(mlerr.sig2, decimals=4) + array([[215.554]]) + >>> "{0:.6f}".format(mlerr.logll) + '-872.860883' + >>> "{0:.6f}".format(mlerr.aic) + '1761.721765' + >>> "{0:.6f}".format(mlerr.schwarz) + '1788.536630' + >>> mlerr.title + 'MAXIMUM LIKELIHOOD SPATIAL ERROR - REGIMES (METHOD = full)' + """ + +
[docs] def __init__( + self, + y, + x, + regimes, + w=None, + slx_lags=0, + constant_regi="many", + cols2regi="all", + method="full", + epsilon=0.0000001, + regime_err_sep=False, + regime_lag_sep=False, + cores=False, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + name_regimes=None, + latex=False, + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + self.constant_regi = constant_regi + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_w = USER.set_name_w(name_w, w) + self.name_regimes = USER.set_name_ds(name_regimes) + self.n = n + self.y = y + + x_constant, name_x, warn = USER.check_constant(x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + + if slx_lags >0: + lag_x = get_lags(w, x_constant, slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + + self.name_x_r = USER.set_name_x(name_x, x_constant) + + cols2regi = REGI.check_cols2regi(constant_regi, cols2regi, x_constant) + self.cols2regi = cols2regi + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, self.n, x.shape[1]) + self.regime_err_sep = regime_err_sep + + if regime_err_sep == True: + if set(cols2regi) == set([True]): + self._error_regimes_multi( + y, + x_constant, + regimes, + w, + slx_lags, + cores, + method, + epsilon, + cols2regi, + vm, + name_x, + latex, + ) + else: + raise Exception( + "All coefficients must vary across regimes if regime_err_sep = True." + ) + else: + x_constant = sphstack(np.ones((x_constant.shape[0], 1)), x_constant) + name_x = USER.set_name_x(name_x, x_constant) + regimes_att = {} + regimes_att["x"] = x_constant + regimes_att["regimes"] = regimes + regimes_att["cols2regi"] = cols2regi + x, name_x, x_rlist = REGI.Regimes_Frame.__init__( + self, + x_constant, + regimes, + constant_regi=None, + cols2regi=cols2regi, + names=name_x, + rlist=True + ) + BaseML_Error.__init__( + self, + y=y, + x=x, + w=w, + method=method, + epsilon=epsilon, + regimes_att=regimes_att, + ) + + self.title = "ML SPATIAL ERROR" + if slx_lags >0: + self.title += " WITH SLX (SDEM)" + self.title += " - REGIMES (METHOD = " + method + ")" + + self.name_x = USER.set_name_x(name_x, x, constant=True) + self.name_x.append("lambda") + self.kf += 1 # Adding a fixed k to account for lambda. + self.chow = REGI.Chow(self) + self.aic = DIAG.akaike(reg=self) + self.schwarz = DIAG.schwarz(reg=self) + self.output = pd.DataFrame(self.name_x, columns=['var_names']) + self.output['var_type'] = ['x'] * (len(self.name_x) - 1) + ['lambda'] + self.output['regime'] = x_rlist + ['_Global'] + self.output['equation'] = 0 + self.other_top = _nonspat_top(self, ml=True) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + def _error_regimes_multi( + self, y, x, regimes, w, slx_lags, cores, method, epsilon, cols2regi, vm, name_x, latex + ): + + regi_ids = dict( + (r, list(np.where(np.array(regimes) == r)[0])) for r in self.regimes_set + ) + results_p = {} + """ + for r in self.regimes_set: + if system() == 'Windows': + is_win = True + results_p[r] = _work_error(*(y,x,regi_ids,r,w,method,epsilon,self.name_ds,self.name_y,name_x+['lambda'],self.name_w,self.name_regimes)) + else: + pool = mp.Pool(cores) + results_p[r] = pool.apply_async(_work_error,args=(y,x,regi_ids,r,w,method,epsilon,self.name_ds,self.name_y,name_x+['lambda'],self.name_w,self.name_regimes, )) + is_win = False + """ + x_constant, name_x = REGI.check_const_regi(self, x, name_x, regi_ids) + self.name_x_r = name_x + for r in self.regimes_set: + if cores: + pool = mp.Pool(None) + results_p[r] = pool.apply_async( + _work_error, + args=( + y, + x_constant, + regi_ids, + r, + w, + slx_lags, + method, + epsilon, + self.name_ds, + self.name_y, + name_x + ["lambda"], + self.name_w, + self.name_regimes, + ), + ) + else: + results_p[r] = _work_error( + *( + y, + x_constant, + regi_ids, + r, + w, + slx_lags, + method, + epsilon, + self.name_ds, + self.name_y, + name_x + ["lambda"], + self.name_w, + self.name_regimes, + ) + ) + + self.kryd = 0 + self.kr = len(cols2regi) + 1 + self.kf = 0 + self.nr = len(self.regimes_set) + self.vm = np.zeros((self.nr * self.kr, self.nr * self.kr), float) + self.betas = np.zeros((self.nr * self.kr, 1), float) + self.u = np.zeros((self.n, 1), float) + self.predy = np.zeros((self.n, 1), float) + self.e_filtered = np.zeros((self.n, 1), float) + self.name_y, self.name_x = [], [] + """ + if not is_win: + pool.close() + pool.join() + """ + if cores: + pool.close() + pool.join() + + results = {} + counter = 0 + self.output = pd.DataFrame(columns=['var_names', 'var_type', 'regime', 'equation']) + for r in self.regimes_set: + """ + if is_win: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + """ + if not cores: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + + self.vm[ + (counter * self.kr) : ((counter + 1) * self.kr), + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].vm + self.betas[ + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].betas + self.u[ + regi_ids[r], + ] = results[r].u + self.predy[ + regi_ids[r], + ] = results[r].predy + self.e_filtered[ + regi_ids[r], + ] = results[r].e_filtered + self.name_y += results[r].name_y + self.name_x += results[r].name_x + results[r].other_top = _nonspat_top(results[r], ml=True) + self.output = pd.concat([self.output, pd.DataFrame({'var_names': results[r].name_x, + 'var_type': ['x'] * (len(results[r].name_x) - 1) + ['lambda'], + 'regime': r, 'equation': r})], ignore_index=True) + counter += 1 + self.chow = REGI.Chow(self) + self.multi = results + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +def _work_error( + y, x, regi_ids, r, w, slx_lags, method, epsilon, name_ds, name_y, name_x, name_w, name_regimes +): + w_r, warn = REGI.w_regime(w, regi_ids[r], r, transform=True) + y_r = y[regi_ids[r]] + x_r = x[regi_ids[r]] + model = BaseML_Error(y=y_r, x=x_r, w=w_r, method=method, epsilon=epsilon) + set_warn(model, warn) + model.w = w_r + model.title = "ML SPATIAL ERROR" + if slx_lags >0: + model.title += " WITH SLX (SDEM)" + model.title += " - REGIME " + str(r) + " (METHOD = " + method + ")" + model.name_ds = name_ds + model.name_y = "%s_%s" % (str(r), name_y) + model.name_x = ["%s_%s" % (str(r), i) for i in name_x] + model.name_w = name_w + model.name_regimes = name_regimes + model.aic = DIAG.akaike(reg=model) + model.schwarz = DIAG.schwarz(reg=model) + return model + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + import numpy as np + import libpysal as ps + + db = ps.io.open(ps.examples.get_path("baltim.dbf"), "r") + ds_name = "baltim.dbf" + y_name = "PRICE" + y = np.array(db.by_col(y_name)).T + y.shape = (len(y), 1) + x_names = ["NROOM", "NBATH", "PATIO", "FIREPL", "AC", "GAR", "AGE", "LOTSZ", "SQFT"] + x = np.array([db.by_col(var) for var in x_names]).T + ww = ps.io.open(ps.examples.get_path("baltim_q.gal")) + w = ww.read() + ww.close() + w_name = "baltim_q.gal" + w.transform = "r" + regimes = db.by_col("CITCOU") + + model = ML_Error_Regimes( + y, + x, + regimes, + w=w, + method="full", + name_y=y_name, + name_x=x_names, + name_w=w_name, + name_ds=ds_name, + regime_err_sep=True, + constant_regi="many", + name_regimes="CITCOU", + ) + print(model.output) + print(model.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/ml_lag.html b/_modules/spreg/ml_lag.html new file mode 100644 index 00000000..496403d3 --- /dev/null +++ b/_modules/spreg/ml_lag.html @@ -0,0 +1,847 @@ + + + + + + + spreg.ml_lag — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.ml_lag

+"""
+ML Estimation of Spatial Lag Model
+"""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu, \
+              Serge Rey srey@asu.edu, \
+              Levi Wolf levi.john.wolf@gmail.com"
+
+import numpy as np
+import numpy.linalg as la
+from scipy import sparse as sp
+from scipy.sparse.linalg import splu as SuperLU
+from .utils import RegressionPropsY, RegressionPropsVM, inverse_prod, set_warn, get_lags
+from .sputils import spdot, spfill_diagonal, spinv, spbroadcast
+from . import diagnostics as DIAG
+from . import user_output as USER
+import pandas as pd
+from .output import output, _nonspat_top, _spat_pseudo_r2
+from .w_utils import symmetrize
+from libpysal import weights
+
+try:
+    from scipy.optimize import minimize_scalar
+
+    minimize_scalar_available = True
+except ImportError:
+    minimize_scalar_available = False
+
+__all__ = ["ML_Lag"]
+
+
+class BaseML_Lag(RegressionPropsY, RegressionPropsVM):
+
+    """
+    ML estimation of the spatial lag model (note no consistency
+    checks, diagnostics or constants added) :cite:`Anselin1988`
+
+    Parameters
+    ----------
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, excluding the constant
+    w            : pysal W object
+                   Spatial weights object
+    slx_lags     : integer
+                   Number of spatial lags of X to include in the model specification.
+                   If slx_lags>0, the specification becomes of the Spatial Durbin type.
+    method       : string
+                   if 'full', brute force calculation (full matrix expressions)
+                   if 'ord', Ord eigenvalue method
+                   if 'LU', LU sparse matrix decomposition
+    epsilon      : float
+                   tolerance criterion in mimimize_scalar function and inverse_product
+
+    Attributes
+    ----------
+    betas        : array
+                   (k+1)x1 array of estimated coefficients (rho first)
+    rho          : float
+                   estimate of spatial autoregressive coefficient
+    u            : array
+                   nx1 array of residuals
+    predy        : array
+                   nx1 array of predicted y values
+    n            : integer
+                   Number of observations
+    k            : integer
+                   Number of variables for which coefficients are estimated
+                   (including the constant, excluding the rho)
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, including the constant
+    method       : string
+                   log Jacobian method
+                   if 'full': brute force (full matrix computations)
+                   if 'ord' : Ord eigenvalue method
+    epsilon      : float
+                   tolerance criterion used in minimize_scalar function and inverse_product
+    mean_y       : float
+                   Mean of dependent variable
+    std_y        : float
+                   Standard deviation of dependent variable
+    vm           : array
+                   Variance covariance matrix (k+1 x k+1)
+    vm1          : array
+                   Variance covariance matrix (k+2 x k+2) includes sigma2
+    sig2         : float
+                   Sigma squared used in computations
+    logll        : float
+                   maximized log-likelihood (including constant terms)
+    predy_e      : array
+                   predicted values from reduced form
+    e_pred       : array
+                   prediction errors using reduced form predicted values
+
+
+    Examples
+    --------
+
+    >>> import numpy as np
+    >>> import libpysal
+    >>> from libpysal.examples import load_example
+    >>> import geopandas as gpd
+    >>> from libpysal.weights import Queen
+    >>> import spreg
+    >>> np.set_printoptions(suppress=True) #prevent scientific format
+    >>> baltimore = load_example('Baltimore')
+    >>> db =  libpysal.io.open(baltimore.get_path("baltim.dbf"),'r')
+    >>> df = gpd.read_file(baltimore.get_path("baltim.shp"))
+    >>> ds_name = "baltim.dbf"
+    >>> y_name = "PRICE"
+    >>> y = np.array(db.by_col(y_name)).T
+    >>> y.shape = (len(y),1)
+    >>> x_names = ["NROOM","NBATH","PATIO","FIREPL","AC","GAR","AGE","LOTSZ","SQFT"]
+    >>> x = np.array([db.by_col(var) for var in x_names]).T
+    >>> x = np.hstack((np.ones((len(y),1)),x))
+    >>> w = Queen.from_dataframe(df)
+    >>> w.transform = 'r'
+    >>> w_name = "baltim_q.gal"
+    >>> mllag = spreg.ml_lag.BaseML_Lag(y,x,w,method='ord') #doctest: +SKIP
+    >>> "{0:.6f}".format(mllag.rho) #doctest: +SKIP
+    '0.425885'
+    >>> np.around(mllag.betas, decimals=4) #doctest: +SKIP
+    array([[ 4.3675],
+           [ 0.7502],
+           [ 5.6116],
+           [ 7.0497],
+           [ 7.7246],
+           [ 6.1231],
+           [ 4.6375],
+           [-0.1107],
+           [ 0.0679],
+           [ 0.0794],
+           [ 0.4259]])
+    >>> "{0:.6f}".format(mllag.mean_y) #doctest: +SKIP
+    '44.307180'
+    >>> "{0:.6f}".format(mllag.std_y) #doctest: +SKIP
+    '23.606077'
+    >>> np.around(np.diag(mllag.vm1), decimals=4) #doctest: +SKIP
+    array([  23.8716,    1.1222,    3.0593,    7.3416,    5.6695,    5.4698,
+              2.8684,    0.0026,    0.0002,    0.0266,    0.0032,  220.1292])
+    >>> np.around(np.diag(mllag.vm), decimals=4) #doctest: +SKIP
+    array([ 23.8716,   1.1222,   3.0593,   7.3416,   5.6695,   5.4698,
+             2.8684,   0.0026,   0.0002,   0.0266,   0.0032])
+    >>> "{0:.6f}".format(mllag.sig2) #doctest: +SKIP
+    '151.458698'
+    >>> "{0:.6f}".format(mllag.logll) #doctest: +SKIP
+    '-832.937174'
+    >>> mllag = spreg.ml_lag.BaseML_Lag(y,x,w) #doctest: +SKIP
+    >>> "{0:.6f}".format(mllag.rho) #doctest: +SKIP
+    '0.425885'
+    >>> np.around(mllag.betas, decimals=4) #doctest: +SKIP
+    array([[ 4.3675],
+           [ 0.7502],
+           [ 5.6116],
+           [ 7.0497],
+           [ 7.7246],
+           [ 6.1231],
+           [ 4.6375],
+           [-0.1107],
+           [ 0.0679],
+           [ 0.0794],
+           [ 0.4259]])
+    >>> "{0:.6f}".format(mllag.mean_y) #doctest: +SKIP
+    '44.307180'
+    >>> "{0:.6f}".format(mllag.std_y) #doctest: +SKIP
+    '23.606077'
+    >>> np.around(np.diag(mllag.vm1), decimals=4) #doctest: +SKIP
+    array([  23.8716,    1.1222,    3.0593,    7.3416,    5.6695,    5.4698,
+              2.8684,    0.0026,    0.0002,    0.0266,    0.0032,  220.1292])
+    >>> np.around(np.diag(mllag.vm), decimals=4) #doctest: +SKIP
+    array([ 23.8716,   1.1222,   3.0593,   7.3416,   5.6695,   5.4698,
+             2.8684,   0.0026,   0.0002,   0.0266,   0.0032])
+    >>> "{0:.6f}".format(mllag.sig2) #doctest: +SKIP
+    '151.458698'
+    >>> "{0:.6f}".format(mllag.logll) #doctest: +SKIP
+    '-832.937174'
+
+
+    """
+
+    def __init__(self, y, x, w, slx_lags=0, method="full", epsilon=0.0000001):
+        # set up main regression variables and spatial filters
+        self.y = y
+        self.x = x
+        self.method = method
+        self.epsilon = epsilon
+        # W = w.full()[0]
+        # Wsp = w.sparse
+        ylag = weights.lag_spatial(w, y)
+        # b0, b1, e0 and e1
+
+        if slx_lags>0:
+            self.x = np.hstack((self.x, get_lags(w, self.x[:, 1:], slx_lags)))
+
+        self.n, self.k = self.x.shape
+        xtx = spdot(self.x.T, self.x)
+        xtxi = la.inv(xtx)
+        xty = spdot(self.x.T, self.y)
+        xtyl = spdot(self.x.T, ylag)
+        b0 = spdot(xtxi, xty)
+        b1 = spdot(xtxi, xtyl)
+        e0 = self.y - spdot(self.x, b0)
+        e1 = ylag - spdot(self.x, b1)
+        methodML = method.upper()
+        # call minimizer using concentrated log-likelihood to get rho
+        if methodML in ["FULL", "LU", "ORD"]:
+            if methodML == "FULL":
+                W = w.full()[0]  # moved here
+                res = minimize_scalar(
+                    lag_c_loglik,
+                    0.0,
+                    bounds=(-1.0, 1.0),
+                    args=(self.n, e0, e1, W),
+                    method="bounded",
+                    options={'xatol': epsilon},
+                )
+            elif methodML == "LU":
+                I = sp.identity(w.n)
+                Wsp = w.sparse  # moved here
+                W = Wsp#.tocsc()
+                res = minimize_scalar(
+                    lag_c_loglik_sp,
+                    0.0,
+                    bounds=(-1.0, 1.0),
+                    args=(self.n, e0, e1, I, Wsp),
+                    method="bounded",
+                    options={'xatol': epsilon},
+                )
+            elif methodML == "ORD":
+                # check on symmetry structure
+                if w.asymmetry(intrinsic=False) == []:
+                    ww = symmetrize(w)
+                    WW = np.array(ww.todense())
+                    evals = la.eigvalsh(WW)
+                    W = WW
+                else:
+                    W = w.full()[0]  # moved here
+                    evals = la.eigvals(W)
+                res = minimize_scalar(
+                    lag_c_loglik_ord,
+                    0.0,
+                    bounds=(-1.0, 1.0),
+                    args=(self.n, e0, e1, evals),
+                    method="bounded",
+                    options={'xatol': epsilon},
+                )
+        else:
+            # program will crash, need to catch
+            print(("{0} is an unsupported method".format(methodML)))
+            self = None
+            return
+
+        self.rho = res.x[0][0]
+
+        # compute full log-likelihood, including constants
+        ln2pi = np.log(2.0 * np.pi)
+        llik = -res.fun - self.n / 2.0 * ln2pi - self.n / 2.0
+        self.logll = llik[0][0]
+
+        # b, residuals and predicted values
+
+        b = b0 - self.rho * b1
+        self.betas = np.vstack((b, self.rho))  # rho added as last coefficient
+        self.u = e0 - self.rho * e1
+        self.predy = self.y - self.u
+
+        xb = spdot(self.x, b)
+
+        self.predy_e = inverse_prod(
+            w.sparse, xb, self.rho, inv_method="power_exp", threshold=epsilon
+        )
+        self.e_pred = self.y - self.predy_e
+
+        # residual variance
+        self._cache = {}
+        self.sig2 = self.sig2n  # no allowance for division by n-k
+
+        # information matrix
+        # if w should be kept sparse, how can we do the following:
+        a = -self.rho * W
+        spfill_diagonal(a, 1.0)
+        ai = spinv(a)
+        wai = spdot(W, ai)
+        tr1 = wai.diagonal().sum()  # same for sparse and dense
+
+        wai2 = spdot(wai, wai)
+        tr2 = wai2.diagonal().sum()
+
+        waiTwai = spdot(wai.T, wai)
+        tr3 = waiTwai.diagonal().sum()
+        ### to here
+
+        wpredy = weights.lag_spatial(w, self.predy_e)
+        wpyTwpy = spdot(wpredy.T, wpredy)
+        xTwpy = spdot(self.x.T, wpredy)
+
+        # order of variables is beta, rho, sigma2
+
+        v1 = np.vstack((xtx / self.sig2, xTwpy.T / self.sig2, np.zeros((1, self.k))))
+        v2 = np.vstack(
+            (xTwpy / self.sig2, tr2 + tr3 + wpyTwpy / self.sig2, tr1 / self.sig2)
+        )
+        v3 = np.vstack(
+            (np.zeros((self.k, 1)), tr1 / self.sig2, self.n / (2.0 * self.sig2 ** 2))
+        )
+
+        v = np.hstack((v1, v2, v3))
+
+        self.vm1 = la.inv(v)  # vm1 includes variance for sigma2
+        self.vm = self.vm1[:-1, :-1]  # vm is for coefficients only
+
+
+
[docs]class ML_Lag(BaseML_Lag): + + """ + ML estimation of the spatial lag model with all results and diagnostics; :cite:`Anselin1988` + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + w : pysal W object + Spatial weights object + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the Spatial Durbin type. + method : string + if 'full', brute force calculation (full matrix expressions) + if 'ord', Ord eigenvalue method + epsilon : float + tolerance criterion in mimimize_scalar function and inverse_product + vm : boolean + if True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + betas : array + (k+1)x1 array of estimated coefficients (rho first) + rho : float + estimate of spatial autoregressive coefficient + u : array + nx1 array of residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant, excluding the rho) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + method : string + log Jacobian method + if 'full': brute force (full matrix computations) + epsilon : float + tolerance criterion used in minimize_scalar function and inverse_product + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (k+1 x k+1), all coefficients + vm1 : array + Variance covariance matrix (k+2 x k+2), includes sig2 + sig2 : float + Sigma squared used in computations + logll : float + maximized log-likelihood (including constant terms) + aic : float + Akaike information criterion + schwarz : float + Schwarz criterion + predy_e : array + predicted values from reduced form + e_pred : array + prediction errors using reduced form predicted values + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + utu : float + Sum of squared residuals + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + >>> from libpysal.weights import Queen + >>> from spreg import ML_Error_Regimes + >>> import geopandas as gpd + >>> from spreg import ML_Lag + >>> np.set_printoptions(suppress=True) #prevent scientific format + >>> baltimore = load_example('Baltimore') + >>> db = libpysal.io.open(baltimore.get_path("baltim.dbf"),'r') + >>> df = gpd.read_file(baltimore.get_path("baltim.shp")) + >>> ds_name = "baltim.dbf" + >>> y_name = "PRICE" + >>> y = np.array(db.by_col(y_name)).T + >>> y.shape = (len(y),1) + >>> x_names = ["NROOM","NBATH","PATIO","FIREPL","AC","GAR","AGE","LOTSZ","SQFT"] + >>> x = np.array([db.by_col(var) for var in x_names]).T + >>> w = Queen.from_dataframe(df) + >>> w_name = "baltim_q.gal" + >>> w.transform = 'r' + >>> mllag = ML_Lag(y,x,w,name_y=y_name,name_x=x_names,\ + name_w=w_name,name_ds=ds_name) #doctest: +SKIP + >>> np.around(mllag.betas, decimals=4) #doctest: +SKIP + array([[ 4.3675], + [ 0.7502], + [ 5.6116], + [ 7.0497], + [ 7.7246], + [ 6.1231], + [ 4.6375], + [-0.1107], + [ 0.0679], + [ 0.0794], + [ 0.4259]]) + >>> "{0:.6f}".format(mllag.rho) #doctest: +SKIP + '0.425885' + >>> "{0:.6f}".format(mllag.mean_y) #doctest: +SKIP + '44.307180' + >>> "{0:.6f}".format(mllag.std_y) #doctest: +SKIP + '23.606077' + >>> np.around(np.diag(mllag.vm1), decimals=4) #doctest: +SKIP + array([ 23.8716, 1.1222, 3.0593, 7.3416, 5.6695, 5.4698, + 2.8684, 0.0026, 0.0002, 0.0266, 0.0032, 220.1292]) + >>> np.around(np.diag(mllag.vm), decimals=4) #doctest: +SKIP + array([ 23.8716, 1.1222, 3.0593, 7.3416, 5.6695, 5.4698, + 2.8684, 0.0026, 0.0002, 0.0266, 0.0032]) + >>> "{0:.6f}".format(mllag.sig2) #doctest: +SKIP + '151.458698' + >>> "{0:.6f}".format(mllag.logll) #doctest: +SKIP + '-832.937174' + >>> "{0:.6f}".format(mllag.aic) #doctest: +SKIP + '1687.874348' + >>> "{0:.6f}".format(mllag.schwarz) #doctest: +SKIP + '1724.744787' + >>> "{0:.6f}".format(mllag.pr2) #doctest: +SKIP + '0.727081' + >>> "{0:.4f}".format(mllag.pr2_e) #doctest: +SKIP + '0.7062' + >>> "{0:.4f}".format(mllag.utu) #doctest: +SKIP + '31957.7853' + >>> np.around(mllag.std_err, decimals=4) #doctest: +SKIP + array([ 4.8859, 1.0593, 1.7491, 2.7095, 2.3811, 2.3388, 1.6936, + 0.0508, 0.0146, 0.1631, 0.057 ]) + >>> np.around(mllag.z_stat, decimals=4) #doctest: +SKIP + array([[ 0.8939, 0.3714], + [ 0.7082, 0.4788], + [ 3.2083, 0.0013], + [ 2.6018, 0.0093], + [ 3.2442, 0.0012], + [ 2.6181, 0.0088], + [ 2.7382, 0.0062], + [-2.178 , 0.0294], + [ 4.6487, 0. ], + [ 0.4866, 0.6266], + [ 7.4775, 0. ]]) + >>> mllag.name_y #doctest: +SKIP + 'PRICE' + >>> mllag.name_x #doctest: +SKIP + ['CONSTANT', 'NROOM', 'NBATH', 'PATIO', 'FIREPL', 'AC', 'GAR', 'AGE', 'LOTSZ', 'SQFT', 'W_PRICE'] + >>> mllag.name_w #doctest: +SKIP + 'baltim_q.gal' + >>> mllag.name_ds #doctest: +SKIP + 'baltim.dbf' + >>> mllag.title #doctest: +SKIP + 'MAXIMUM LIKELIHOOD SPATIAL LAG (METHOD = FULL)' + >>> mllag = ML_Lag(y,x,w,method='ord',name_y=y_name,name_x=x_names,\ + name_w=w_name,name_ds=ds_name) #doctest: +SKIP + >>> np.around(mllag.betas, decimals=4) #doctest: +SKIP + array([[ 4.3675], + [ 0.7502], + [ 5.6116], + [ 7.0497], + [ 7.7246], + [ 6.1231], + [ 4.6375], + [-0.1107], + [ 0.0679], + [ 0.0794], + [ 0.4259]]) + >>> "{0:.6f}".format(mllag.rho) #doctest: +SKIP + '0.425885' + >>> "{0:.6f}".format(mllag.mean_y) #doctest: +SKIP + '44.307180' + >>> "{0:.6f}".format(mllag.std_y) #doctest: +SKIP + '23.606077' + >>> np.around(np.diag(mllag.vm1), decimals=4) #doctest: +SKIP + array([ 23.8716, 1.1222, 3.0593, 7.3416, 5.6695, 5.4698, + 2.8684, 0.0026, 0.0002, 0.0266, 0.0032, 220.1292]) + >>> np.around(np.diag(mllag.vm), decimals=4) #doctest: +SKIP + array([ 23.8716, 1.1222, 3.0593, 7.3416, 5.6695, 5.4698, + 2.8684, 0.0026, 0.0002, 0.0266, 0.0032]) + >>> "{0:.6f}".format(mllag.sig2) #doctest: +SKIP + '151.458698' + >>> "{0:.6f}".format(mllag.logll) #doctest: +SKIP + '-832.937174' + >>> "{0:.6f}".format(mllag.aic) #doctest: +SKIP + '1687.874348' + >>> "{0:.6f}".format(mllag.schwarz) #doctest: +SKIP + '1724.744787' + >>> "{0:.6f}".format(mllag.pr2) #doctest: +SKIP + '0.727081' + >>> "{0:.6f}".format(mllag.pr2_e) #doctest: +SKIP + '0.706198' + >>> "{0:.4f}".format(mllag.utu) #doctest: +SKIP + '31957.7853' + >>> np.around(mllag.std_err, decimals=4) #doctest: +SKIP + array([ 4.8859, 1.0593, 1.7491, 2.7095, 2.3811, 2.3388, 1.6936, + 0.0508, 0.0146, 0.1631, 0.057 ]) + >>> np.around(mllag.z_stat, decimals=4) #doctest: +SKIP + array([[ 0.8939, 0.3714], + [ 0.7082, 0.4788], + [ 3.2083, 0.0013], + [ 2.6018, 0.0093], + [ 3.2442, 0.0012], + [ 2.6181, 0.0088], + [ 2.7382, 0.0062], + [-2.178 , 0.0294], + [ 4.6487, 0. ], + [ 0.4866, 0.6266], + [ 7.4775, 0. ]]) + >>> mllag.name_y #doctest: +SKIP + 'PRICE' + >>> mllag.name_x #doctest: +SKIP + ['CONSTANT', 'NROOM', 'NBATH', 'PATIO', 'FIREPL', 'AC', 'GAR', 'AGE', 'LOTSZ', 'SQFT', 'W_PRICE'] + >>> mllag.name_w #doctest: +SKIP + 'baltim_q.gal' + >>> mllag.name_ds #doctest: +SKIP + 'baltim.dbf' + >>> mllag.title #doctest: +SKIP + 'MAXIMUM LIKELIHOOD SPATIAL LAG (METHOD = ORD)' + + + """ + +
[docs] def __init__( + self, + y, + x, + w, + slx_lags=0, + method="full", + epsilon=0.0000001, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + latex=False, + ): + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + method = method.upper() + BaseML_Lag.__init__( + self, y=y, x=x_constant, w=w, slx_lags=slx_lags, method=method, epsilon=epsilon + ) + # increase by 1 to have correct aic and sc, include rho in count + self.k += 1 + + if slx_lags>0: + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + self.title = "MAXIMUM LIKELIHOOD SPATIAL LAG WITH SLX - SPATIAL DURBIN MODEL" + " (METHOD = " + method + ")" + else: + self.title = "MAXIMUM LIKELIHOOD SPATIAL LAG" + " (METHOD = " + method + ")" + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x) + name_ylag = USER.set_name_yend_sp(self.name_y) + self.name_x.append(name_ylag) # rho changed to last position + self.name_w = USER.set_name_w(name_w, w) + self.aic = DIAG.akaike(reg=self) + self.schwarz = DIAG.schwarz(reg=self) + self.output = pd.DataFrame(self.name_x, columns=['var_names']) + self.output['var_type'] = ['x'] * (len(self.name_x)-1) + ['rho'] + self.output['regime'], self.output['equation'] = (0, 0) + self.other_top = _spat_pseudo_r2(self) + self.other_top += _nonspat_top(self, ml=True) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ +def lag_c_loglik(rho, n, e0, e1, W): + # concentrated log-lik for lag model, no constants, brute force + er = e0 - rho * e1 + sig2 = spdot(er.T, er) / n + nlsig2 = (n / 2.0) * np.log(sig2) + a = -rho * W + spfill_diagonal(a, 1.0) + jacob = np.log(np.linalg.det(a)) + # this is the negative of the concentrated log lik for minimization + clik = nlsig2 - jacob + return clik + + +def lag_c_loglik_sp(rho, n, e0, e1, I, Wsp): + # concentrated log-lik for lag model, sparse algebra + if isinstance(rho, np.ndarray): + if rho.shape == (1, 1): + rho = rho[0][0] # why does the interior value change? + er = e0 - rho * e1 + sig2 = spdot(er.T, er) / n + nlsig2 = (n / 2.0) * np.log(sig2) + a = I - rho * Wsp + LU = SuperLU(a.tocsc()) + jacob = np.sum(np.log(np.abs(LU.U.diagonal()))) + clike = nlsig2 - jacob + return clike + + +def lag_c_loglik_ord(rho, n, e0, e1, evals): + # concentrated log-lik for lag model, no constants, Ord eigenvalue method + er = e0 - rho * e1 + sig2 = spdot(er.T, er) / n + nlsig2 = (n / 2.0) * np.log(sig2) + revals = rho * evals + jacob = np.log(1 - revals).sum() + if isinstance(jacob, complex): + jacob = jacob.real + # this is the negative of the concentrated log lik for minimization + clik = nlsig2 - jacob + return clik + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + +if __name__ == "__main__": + _test() + + import numpy as np + import libpysal + + db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"), "r") + y_var = "CRIME" + y = np.array([db.by_col(y_var)]).reshape(49, 1) + x_var = ["INC"] + x = np.array([db.by_col(name) for name in x_var]).T + w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + w.transform = "r" + model = ML_Lag( + y, + x, + w=w, + vm=False, + name_y=y_var, + name_x=x_var, + name_ds="columbus", + name_w="columbus.gal", + ) + print(model.output) + print(model.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/ml_lag_regimes.html b/_modules/spreg/ml_lag_regimes.html new file mode 100644 index 00000000..952f26d2 --- /dev/null +++ b/_modules/spreg/ml_lag_regimes.html @@ -0,0 +1,793 @@ + + + + + + + spreg.ml_lag_regimes — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.ml_lag_regimes

+"""
+ML Estimation of Spatial Lag Model with Regimes
+"""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu, Pedro V. Amaral pedro.amaral@asu.edu"
+
+import numpy as np
+from . import regimes as REGI
+from . import user_output as USER
+from . import diagnostics as DIAG
+import multiprocessing as mp
+from .ml_lag import BaseML_Lag
+from .utils import set_warn, get_lags
+from platform import system
+import pandas as pd
+from .output import output, _nonspat_top, _spat_pseudo_r2
+
+
+__all__ = ["ML_Lag_Regimes"]
+
+
+
[docs]class ML_Lag_Regimes(BaseML_Lag, REGI.Regimes_Frame): + + """ + ML estimation of the spatial lag model with regimes (note no consistency + checks, diagnostics or constants added) :cite:`Anselin1988`. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes + + * 'many': a vector of ones is appended to x and considered different per regime (default) + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + w : Sparse matrix + Spatial weights sparse matrix + method : string + if 'full', brute force calculation (full matrix expressions) + if 'ord', Ord eigenvalue method + if 'LU', LU sparse matrix decomposition + epsilon : float + tolerance criterion in mimimize_scalar function and inverse_product + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the Spatial Durbin type. + regime_lag_sep: boolean + If True, the spatial parameter for spatial lag is also + computed according to different regimes. If False (default), + the spatial parameter is fixed accross regimes. + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + vm : boolean + if True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + (k+1)x1 array of estimated coefficients (rho first) + rho : float + estimate of spatial autoregressive coefficient + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + u : array + nx1 array of residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant, excluding the rho) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + method : string + log Jacobian method. + if 'full': brute force (full matrix computations) + if 'ord', Ord eigenvalue method + if 'LU', LU sparse matrix decomposition + epsilon : float + tolerance criterion used in minimize_scalar function and inverse_product + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (k+1 x k+1), all coefficients + vm1 : array + Variance covariance matrix (k+2 x k+2), includes sig2 + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + sig2 : float + Sigma squared used in computations + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + logll : float + maximized log-likelihood (including constant terms) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + aic : float + Akaike information criterion + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + schwarz : float + Schwarz criterion + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + predy_e : array + predicted values from reduced form + e_pred : array + prediction errors using reduced form predicted values + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi: ['one', 'many'] + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes + + * 'many': a vector of ones is appended to x and considered different per regime + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_lag_sep: boolean + If True, the spatial parameter for spatial lag is also + computed according to different regimes. If False (default), + the spatial parameter is fixed accross regimes. + regime_err_sep: boolean + always set to False - kept for compatibility with other + regime models + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + Open data baltim.dbf using pysal and create the variables matrices and weights matrix. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + >>> from libpysal.examples import load_example + >>> from libpysal.weights import Queen + >>> from spreg import ML_Lag_Regimes + >>> import geopandas as gpd + >>> np.set_printoptions(suppress=True) #prevent scientific format + >>> baltimore = load_example('Baltimore') + >>> db = libpysal.io.open(baltimore.get_path("baltim.dbf"),'r') + >>> df = gpd.read_file(baltimore.get_path("baltim.shp")) + >>> ds_name = "baltim.dbf" + >>> y_name = "PRICE" + >>> y = np.array(db.by_col(y_name)).T + >>> y.shape = (len(y),1) + >>> x_names = ["NROOM","AGE","SQFT"] + >>> x = np.array([db.by_col(var) for var in x_names]).T + >>> w = Queen.from_dataframe(df) + >>> w_name = "baltim_q.gal" + >>> w.transform = 'r' + + Since in this example we are interested in checking whether the results vary + by regimes, we use CITCOU to define whether the location is in the city or + outside the city (in the county): + + >>> regimes = db.by_col("CITCOU") + + Now we can run the regression with all parameters: + + >>> mllag = ML_Lag_Regimes(y,x,regimes,w=w,name_y=y_name,name_x=x_names,\ + name_w=w_name,name_ds=ds_name,name_regimes="CITCOU") + >>> np.around(mllag.betas, decimals=4) + array([[-14.5158], + [ 4.4923], + [ -0.0336], + [ 0.3541], + [ -3.601 ], + [ 3.8736], + [ -0.1747], + [ 0.8238], + [ 0.525 ]]) + >>> "{0:.6f}".format(mllag.rho) + '0.524971' + >>> "{0:.6f}".format(mllag.mean_y) + '44.307180' + >>> "{0:.6f}".format(mllag.std_y) + '23.606077' + >>> np.around(np.diag(mllag.vm1), decimals=4) + array([ 48.6818, 2.4524, 0.0052, 0.0663, 71.4439, 3.2837, + 0.0118, 0.0498, 0.0042, 409.1225]) + >>> np.around(np.diag(mllag.vm), decimals=4) + array([48.6818, 2.4524, 0.0052, 0.0663, 71.4439, 3.2837, 0.0118, + 0.0498, 0.0042]) + >>> "{0:.6f}".format(mllag.sig2) + '204.827093' + >>> "{0:.6f}".format(mllag.logll) + '-867.086467' + >>> "{0:.6f}".format(mllag.aic) + '1752.172934' + >>> "{0:.6f}".format(mllag.schwarz) + '1782.339657' + >>> mllag.title + 'MAXIMUM LIKELIHOOD SPATIAL LAG - REGIMES (METHOD = full)' + """ + +
[docs] def __init__( + self, + y, + x, + regimes, + w=None, + constant_regi="many", + cols2regi="all", + method="full", + epsilon=0.0000001, + slx_lags=0, + regime_lag_sep=False, + cores=False, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + name_regimes=None, + latex=False, + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + name_y = USER.set_name_y(name_y) + self.name_y = name_y + + x_constant, name_x, warn = USER.check_constant(x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + + if slx_lags >0: + lag_x = get_lags(w, x_constant, slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + + self.name_x_r = USER.set_name_x(name_x, x_constant) + [USER.set_name_yend_sp(name_y)] + self.method = method + self.epsilon = epsilon + self.name_regimes = USER.set_name_ds(name_regimes) + self.constant_regi = constant_regi + self.n = n + cols2regi = REGI.check_cols2regi( + constant_regi, cols2regi, x_constant, add_cons=False + ) + self.cols2regi = cols2regi + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + self.regime_lag_sep = regime_lag_sep + self._cache = {} + self.name_ds = USER.set_name_ds(name_ds) + self.name_w = USER.set_name_w(name_w, w) + USER.check_regimes(self.regimes_set, self.n, x_constant.shape[1]) + + # regime_err_sep is ignored, always False + + if regime_lag_sep == True: + if not (set(cols2regi) == set([True]) and constant_regi == "many"): + raise Exception( + "All variables must vary by regimes if regime_lag_sep = True." + ) + cols2regi += [True] + w_i, regi_ids, warn = REGI.w_regimes( + w, + regimes, + self.regimes_set, + transform=True, + get_ids=True, + min_n=len(cols2regi) + 1, + ) + set_warn(self, warn) + else: + cols2regi += [False] + + if set(cols2regi) == set([True]) and constant_regi == "many": + self.y = y + self.ML_Lag_Regimes_Multi( + y, + x_constant, + w_i, + w, + regi_ids, + slx_lags=slx_lags, + cores=cores, + cols2regi=cols2regi, + method=method, + epsilon=epsilon, + vm=vm, + name_y=name_y, + name_x=name_x, + name_regimes=self.name_regimes, + name_w=name_w, + name_ds=name_ds, + latex=latex, + ) + else: + # if regime_lag_sep == True: + # w = REGI.w_regimes_union(w, w_i, self.regimes_set) + x, self.name_x, x_rlist = REGI.Regimes_Frame.__init__( + self, + x_constant, + regimes, + constant_regi, + cols2regi=cols2regi[:-1], + names=name_x, + rlist=True + ) + self.name_x.append("_Global_" + USER.set_name_yend_sp(name_y)) + BaseML_Lag.__init__(self, y=y, x=x, w=w, method=method, epsilon=epsilon) + self.kf += 1 # Adding a fixed k to account for spatial lag in Chow + # adding a fixed k to account for spatial lag in aic, sc + self.k += 1 + self.chow = REGI.Chow(self) + self.aic = DIAG.akaike(reg=self) + self.schwarz = DIAG.schwarz(reg=self) + self.regime_lag_sep = regime_lag_sep + self.output = pd.DataFrame(self.name_x, columns=['var_names']) + self.output['var_type'] = ['x'] * (len(self.name_x) - 1) + ['rho'] + self.output['regime'] = x_rlist+['_Global'] + self.output['equation'] = 0 + self.other_top = _spat_pseudo_r2(self) + self.other_top += _nonspat_top(self, ml=True) + if slx_lags == 0: + self.title = ("MAXIMUM LIKELIHOOD SPATIAL LAG - REGIMES"+ " (METHOD = "+ method+ ")") + else: + self.title = ("MAXIMUM LIKELIHOOD SPATIAL DURBIN - REGIMES"+ " (METHOD = "+ method+ ")") + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ +
[docs] def ML_Lag_Regimes_Multi( + self, + y, + x, + w_i, + w, + regi_ids, + slx_lags, + cores, + cols2regi, + method, + epsilon, + vm, + name_y, + name_x, + name_regimes, + name_w, + name_ds, + latex, + ): + #pool = mp.Pool(cores) + results_p = {} + """ + for r in self.regimes_set: + if system() == 'Windows': + is_win = True + results_p[r] = _work(*(y,x,regi_ids,r,w_i[r],method,epsilon,name_ds,name_y,name_x,name_w,name_regimes)) + else: + results_p[r] = pool.apply_async(_work,args=(y,x,regi_ids,r,w_i[r],method,epsilon,name_ds,name_y,name_x,name_w,name_regimes, )) + is_win = False + """ + x_constant, name_x = REGI.check_const_regi(self, x, name_x, regi_ids) + name_x = name_x + [USER.set_name_yend_sp(name_y)] + for r in self.regimes_set: + if cores: + pool = mp.Pool(None) + results_p[r] = pool.apply_async( + _work, + args=( + y, + x_constant, + regi_ids, + r, + w_i[r], + slx_lags, + method, + epsilon, + name_ds, + name_y, + name_x, + name_w, + name_regimes, + ), + ) + else: + results_p[r] = _work( + *( + y, + x_constant, + regi_ids, + r, + w_i[r], + slx_lags, + method, + epsilon, + name_ds, + name_y, + name_x, + name_w, + name_regimes, + ) + ) + + self.kryd = 0 + self.kr = len(cols2regi) + 1 + self.kf = 0 + self.nr = len(self.regimes_set) + self.name_x_r = name_x + self.name_regimes = name_regimes + self.vm = np.zeros((self.nr * self.kr, self.nr * self.kr), float) + self.betas = np.zeros((self.nr * self.kr, 1), float) + self.u = np.zeros((self.n, 1), float) + self.predy = np.zeros((self.n, 1), float) + self.predy_e = np.zeros((self.n, 1), float) + self.e_pred = np.zeros((self.n, 1), float) + """ + if not is_win: + pool.close() + pool.join() + """ + if cores: + pool.close() + pool.join() + + results = {} + self.name_y, self.name_x = [], [] + counter = 0 + self.output = pd.DataFrame(columns=['var_names', 'var_type', 'regime', 'equation']) + for r in self.regimes_set: + """ + if is_win: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + """ + if not cores: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + self.vm[ + (counter * self.kr) : ((counter + 1) * self.kr), + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].vm + self.betas[ + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].betas + self.u[ + regi_ids[r], + ] = results[r].u + self.predy[ + regi_ids[r], + ] = results[r].predy + self.predy_e[ + regi_ids[r], + ] = results[r].predy_e + self.e_pred[ + regi_ids[r], + ] = results[r].e_pred + self.name_y += results[r].name_y + self.name_x += results[r].name_x + results[r].other_top = _spat_pseudo_r2(results[r]) + results[r].other_top += _nonspat_top(results[r], ml=True) + results[r].other_mid = "" + self.output = pd.concat([self.output, pd.DataFrame({'var_names': results[r].name_x, + 'var_type': ['x'] * (len(results[r].name_x) - 1) + ['rho'], + 'regime': r, 'equation': r})], ignore_index=True) + counter += 1 + self.multi = results + self.chow = REGI.Chow(self) + output(reg=self, vm=vm, robust=False, other_end=False, latex=latex)
+ + +def _work( + y, + x, + regi_ids, + r, + w_r, + slx_lags, + method, + epsilon, + name_ds, + name_y, + name_x, + name_w, + name_regimes, +): + y_r = y[regi_ids[r]] + x_r = x[regi_ids[r]] + model = BaseML_Lag(y_r, x_r, w_r, method=method, epsilon=epsilon) + if slx_lags == 0: + model.title = ("MAXIMUM LIKELIHOOD SPATIAL LAG - REGIME "+ str(r)+ " (METHOD = "+ method+ ")") + else: + model.title = ("MAXIMUM LIKELIHOOD SPATIAL DURBIN - REGIME "+ str(r)+ " (METHOD = "+ method+ ")") + model.name_ds = name_ds + model.name_y = "%s_%s" % (str(r), name_y) + model.name_x = ["%s_%s" % (str(r), i) for i in name_x] + model.name_w = name_w + model.name_regimes = name_regimes + model.k += 1 # add 1 for proper df and aic, sc + model.aic = DIAG.akaike(reg=model) + model.schwarz = DIAG.schwarz(reg=model) + return model + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + import numpy as np + import libpysal as ps + + db = ps.io.open(ps.examples.get_path("baltim.dbf"), "r") + ds_name = "baltim.dbf" + y_name = "PRICE" + y = np.array(db.by_col(y_name)).T + y.shape = (len(y), 1) + x_names = ["NROOM", "NBATH", "PATIO", "FIREPL", "AC", "GAR", "AGE", "LOTSZ", "SQFT"] + x = np.array([db.by_col(var) for var in x_names]).T + ww = ps.io.open(ps.examples.get_path("baltim_q.gal")) + w = ww.read() + ww.close() + w_name = "baltim_q.gal" + w.transform = "r" + regimes = db.by_col("CITCOU") + + mllag = ML_Lag_Regimes( + y, + x, + regimes, + w=w, + method="full", + name_y=y_name, + name_x=x_names, + name_w=w_name, + name_ds=ds_name, + regime_lag_sep=True, + regime_err_sep=False, + constant_regi="many", + name_regimes="CITCOU", + ) + print(mllag.output) + print(mllag.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/ols.html b/_modules/spreg/ols.html new file mode 100644 index 00000000..d3d0ef5c --- /dev/null +++ b/_modules/spreg/ols.html @@ -0,0 +1,686 @@ + + + + + + + spreg.ols — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.ols

+"""Ordinary Least Squares regression classes."""
+
+__author__ = "Luc Anselin lanselin@gmail.com, Pedro Amaral pedrovma@gmail.com, David C. Folch david.folch@asu.edu"
+import numpy as np
+import numpy.linalg as la
+from . import user_output as USER
+from .output import output, _spat_diag_out, _nonspat_mid, _nonspat_top
+from . import robust as ROBUST
+from .utils import spdot, RegressionPropsY, RegressionPropsVM, set_warn, get_lags
+import pandas as pd
+
+__all__ = ["OLS"]
+
+
+class BaseOLS(RegressionPropsY, RegressionPropsVM):
+
+    """
+    Ordinary least squares (OLS) (note: no consistency checks, diagnostics or
+    constant added)
+
+    Parameters
+    ----------
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, excluding the constant
+    robust       : string
+                   If 'white', then a White consistent estimator of the
+                   variance-covariance matrix is given.  If 'hac', then a
+                   HAC consistent estimator of the variance-covariance
+                   matrix is given. Default set to None.
+    gwk          : pysal W object
+                   Kernel spatial weights needed for HAC estimation. Note:
+                   matrix must have ones along the main diagonal.
+    sig2n_k      : boolean
+                   If True, then use n-k to estimate sigma^2. If False, use n.
+
+    Attributes
+    ----------
+    betas        : array
+                   kx1 array of estimated coefficients
+    u            : array
+                   nx1 array of residuals
+    predy        : array
+                   nx1 array of predicted y values
+    n            : integer
+                   Number of observations
+    k            : integer
+                   Number of variables for which coefficients are estimated
+                   (including the constant)
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, including the constant
+    mean_y       : float
+                   Mean of dependent variable
+    std_y        : float
+                   Standard deviation of dependent variable
+    vm           : array
+                   Variance covariance matrix (kxk)
+    utu          : float
+                   Sum of squared residuals
+    sig2         : float
+                   Sigma squared used in computations
+    sig2n        : float
+                   Sigma squared (computed with n in the denominator)
+    sig2n_k      : float
+                   Sigma squared (computed with n-k in the denominator)
+    xtx          : float
+                   X'X
+    xtxi         : float
+                   (X'X)^-1
+
+    Examples
+    --------
+    >>> import numpy as np
+    >>> import libpysal
+    >>> import spreg
+    >>> np.set_printoptions(suppress=True) #prevent scientific format
+    >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r')
+    >>> y = np.array(db.by_col("HOVAL"))
+    >>> y = np.reshape(y, (49,1))
+    >>> X = []
+    >>> X.append(db.by_col("INC"))
+    >>> X.append(db.by_col("CRIME"))
+    >>> X = np.array(X).T
+    >>> X = np.hstack((np.ones(y.shape),X))
+    >>> ols = spreg.ols.BaseOLS(y,X)
+    >>> ols.betas
+    array([[46.42818268],
+           [ 0.62898397],
+           [-0.48488854]])
+    >>> ols.vm
+    array([[174.02245348,  -6.52060364,  -2.15109867],
+           [ -6.52060364,   0.28720001,   0.06809568],
+           [ -2.15109867,   0.06809568,   0.03336939]])
+    """
+
+    def __init__(self, y, x, robust=None, gwk=None, sig2n_k=True):
+        self.x = x
+        self.xtx = spdot(self.x.T, self.x)
+        xty = spdot(self.x.T, y)
+
+        self.xtxi = la.inv(self.xtx)
+        self.betas = np.dot(self.xtxi, xty)
+        predy = spdot(self.x, self.betas)
+
+        u = y - predy
+        self.u = u
+        self.predy = predy
+        self.y = y
+        self.n, self.k = self.x.shape
+
+        if sig2n_k:
+            self.sig2 = self.sig2n_k
+        else:
+            self.sig2 = self.sig2n
+
+        if robust is not None:
+            self.vm = ROBUST.robust_vm(reg=self, gwk=gwk, sig2n_k=sig2n_k)
+
+
+
[docs]class OLS(BaseOLS): + """ + Ordinary least squares with results and diagnostics. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + w : pysal W object + Spatial weights object (required if running spatial + diagnostics) + robust : string + If 'white', then a White consistent estimator of the + variance-covariance matrix is given. If 'hac', then a + HAC consistent estimator of the variance-covariance + matrix is given. Default set to None. + gwk : pysal W object + Kernel spatial weights needed for HAC estimation. Note: + matrix must have ones along the main diagonal. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SLX type. + sig2n_k : boolean + If True, then use n-k to estimate sigma^2. If False, use n. + nonspat_diag : boolean + If True, then compute non-spatial diagnostics on + the regression. + spat_diag : boolean + If True, then compute Lagrange multiplier tests (requires + w). Note: see moran for further tests. + moran : boolean + If True, compute Moran's I on the residuals. Note: + requires spat_diag=True. + white_test : boolean + If True, compute White's specification robust test. + (requires nonspat_diag=True) + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + robust : string + Adjustment for robust standard errors + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + r2 : float + R squared + ar2 : float + Adjusted R squared + utu : float + Sum of squared residuals + sig2 : float + Sigma squared used in computations + sig2ML : float + Sigma squared (maximum likelihood) + f_stat : tuple + Statistic (float), p-value (float) + logll : float + Log likelihood + aic : float + Akaike information criterion + schwarz : float + Schwarz information criterion + std_err : array + 1xk array of standard errors of the betas + t_stat : list of tuples + t statistic; each tuple contains the pair (statistic, + p-value), where each is a float + mulColli : float + Multicollinearity condition number + jarque_bera : dictionary + 'jb': Jarque-Bera statistic (float); 'pvalue': p-value + (float); 'df': degrees of freedom (int) + breusch_pagan : dictionary + 'bp': Breusch-Pagan statistic (float); 'pvalue': p-value + (float); 'df': degrees of freedom (int) + koenker_bassett : dictionary + 'kb': Koenker-Bassett statistic (float); 'pvalue': + p-value (float); 'df': degrees of freedom (int) + white : dictionary + 'wh': White statistic (float); 'pvalue': p-value (float); + 'df': degrees of freedom (int) + lm_error : tuple + Lagrange multiplier test for spatial error model; tuple + contains the pair (statistic, p-value), where each is a + float + lm_lag : tuple + Lagrange multiplier test for spatial lag model; tuple + contains the pair (statistic, p-value), where each is a + float + rlm_error : tuple + Robust lagrange multiplier test for spatial error model; + tuple contains the pair (statistic, p-value), where each + is a float + rlm_lag : tuple + Robust lagrange multiplier test for spatial lag model; + tuple contains the pair (statistic, p-value), where each + is a float + lm_sarma : tuple + Lagrange multiplier test for spatial SARMA model; tuple + contains the pair (statistic, p-value), where each is a + float + moran_res : tuple + Moran's I for the residuals; tuple containing the triple + (Moran's I, standardized Moran's I, p-value) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + sig2n : float + Sigma squared (computed with n in the denominator) + sig2n_k : float + Sigma squared (computed with n-k in the denominator) + xtx : float + :math:`X'X` + xtxi : float + :math:`(X'X)^{-1}` + + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from spreg import OLS + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; also, the actual OLS class + requires data to be passed in as numpy arrays so the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + + Extract the HOVAL column (home values) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an nx1 numpy array. + + >>> hoval = db.by_col("HOVAL") + >>> y = np.array(hoval) + >>> y.shape = (len(hoval), 1) + + Extract CRIME (crime) and INC (income) vectors from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). spreg.OLS adds a vector of ones to the + independent variables passed in. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("CRIME")) + >>> X = np.array(X).T + + The minimum parameters needed to run an ordinary least squares regression + are the two numpy arrays containing the independent variable and dependent + variables respectively. To make the printed results more meaningful, the + user can pass in explicit names for the variables used; this is optional. + + >>> ols = OLS(y, X, name_y='home value', name_x=['income','crime'], name_ds='columbus', white_test=True) + + spreg.OLS computes the regression coefficients and their standard + errors, t-stats and p-values. It also computes a large battery of + diagnostics on the regression. In this example we compute the white test + which by default isn't ('white_test=True'). All of these results can be independently + accessed as attributes of the regression object created by running + spreg.OLS. They can also be accessed at one time by printing the + summary attribute of the regression object. In the example below, the + parameter on crime is -0.4849, with a t-statistic of -2.6544 and p-value + of 0.01087. + + >>> ols.betas + array([[46.42818268], + [ 0.62898397], + [-0.48488854]]) + >>> print(round(ols.t_stat[2][0],3)) + -2.654 + >>> print(round(ols.t_stat[2][1],3)) + 0.011 + >>> print(round(ols.r2,3)) + 0.35 + + Or we can easily obtain a full summary of all the results nicely formatted and + ready to be printed: + + >>> print(ols.summary) + REGRESSION RESULTS + ------------------ + <BLANKLINE> + SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES + ----------------------------------------- + Data set : columbus + Weights matrix : None + Dependent Variable : home value Number of Observations: 49 + Mean dependent var : 38.4362 Number of Variables : 3 + S.D. dependent var : 18.4661 Degrees of Freedom : 46 + R-squared : 0.3495 + Adjusted R-squared : 0.3212 + Sum squared residual: 10647 F-statistic : 12.3582 + Sigma-square : 231.457 Prob(F-statistic) : 5.064e-05 + S.E. of regression : 15.214 Log likelihood : -201.368 + Sigma-square ML : 217.286 Akaike info criterion : 408.735 + S.E of regression ML: 14.7406 Schwarz criterion : 414.411 + <BLANKLINE> + ------------------------------------------------------------------------------------ + Variable Coefficient Std.Error t-Statistic Probability + ------------------------------------------------------------------------------------ + CONSTANT 46.4281827 13.1917570 3.5194844 0.0009867 + income 0.6289840 0.5359104 1.1736736 0.2465669 + crime -0.4848885 0.1826729 -2.6544086 0.0108745 + ------------------------------------------------------------------------------------ + <BLANKLINE> + REGRESSION DIAGNOSTICS + MULTICOLLINEARITY CONDITION NUMBER 12.538 + <BLANKLINE> + TEST ON NORMALITY OF ERRORS + TEST DF VALUE PROB + Jarque-Bera 2 39.706 0.0000 + <BLANKLINE> + DIAGNOSTICS FOR HETEROSKEDASTICITY + RANDOM COEFFICIENTS + TEST DF VALUE PROB + Breusch-Pagan test 2 5.767 0.0559 + Koenker-Bassett test 2 2.270 0.3214 + <BLANKLINE> + SPECIFICATION ROBUST TEST + TEST DF VALUE PROB + White 5 2.906 0.7145 + ================================ END OF REPORT ===================================== + + If the optional parameters w and spat_diag are passed to spreg.OLS, + spatial diagnostics will also be computed for the regression. These + include Lagrange multiplier tests and Moran's I of the residuals. The w + parameter is a PySAL spatial weights matrix. In this example, w is built + directly from the shapefile columbus.shp, but w can also be read in from a + GAL or GWT file. In this case a rook contiguity weights matrix is built, + but PySAL also offers queen contiguity, distance weights and k nearest + neighbor weights among others. In the example, the Moran's I of the + residuals is 0.204 with a standardized value of 2.592 and a p-value of + 0.0095. + + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + >>> ols = OLS(y, X, w, spat_diag=True, moran=True, name_y='home value', name_x=['income','crime'], name_ds='columbus') + >>> ols.betas + array([[46.42818268], + [ 0.62898397], + [-0.48488854]]) + + >>> print(round(ols.moran_res[0],3)) + 0.204 + >>> print(round(ols.moran_res[1],3)) + 2.592 + >>> print(round(ols.moran_res[2],4)) + 0.0095 + + """ + +
[docs] def __init__( + self, + y, + x, + w=None, + robust=None, + gwk=None, + slx_lags = 0, + sig2n_k=True, + nonspat_diag=True, + spat_diag=False, + moran=False, + white_test=False, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_gwk=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_robust(robust, gwk) + if robust == "hac" and spat_diag: + set_warn( + self, + "Spatial diagnostics are not available for HAC estimation. Hence, spatial diagnostics have been disabled for this model.", + ) + spat_diag = False + if robust in ["hac", "white"] and white_test: + set_warn( + self, + "White test not available when standard errors are estimated by HAC or White correction.", + ) + white_test = False + USER.check_spat_diag(spat_diag, w) + x_constant, name_x, warn = USER.check_constant(x, name_x) + self.name_x = USER.set_name_x(name_x, x_constant) + if slx_lags >0: + USER.check_weights(w, y, w_required=True) + lag_x = get_lags(w, x_constant[:, 1:], slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + self.name_x += USER.set_name_spatial_lags(self.name_x[1:], slx_lags) + else: + USER.check_weights(w, y, w_required=False) + set_warn(self, warn) + BaseOLS.__init__( + self, y=y, x=x_constant, robust=robust, gwk=gwk, sig2n_k=sig2n_k + ) + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.title = "ORDINARY LEAST SQUARES" + if slx_lags > 0: + self.title += " WITH SPATIALLY LAGGED X (SLX)" + self.robust = USER.set_robust(robust) + self.name_w = USER.set_name_w(name_w, w) + self.name_gwk = USER.set_name_w(name_gwk, gwk) + self.output = pd.DataFrame(self.name_x, columns=['var_names']) + self.output['var_type'] = ['x'] * len(self.name_x) + self.output['regime'], self.output['equation'] = (0, 0) + self.other_top, self.other_mid, other_end = ("", "", "") # strings where function-specific diag. are stored + if nonspat_diag: + self.other_mid += _nonspat_mid(self, white_test=white_test) + self.other_top += _nonspat_top(self) + if spat_diag: + other_end += _spat_diag_out(self, w, 'ols', moran=moran) + output(reg=self, vm=vm, robust=robust, other_end=other_end, latex=latex)
+ + + +def _test(): + import doctest + + # the following line could be used to define an alternative to the '<BLANKLINE>' flag + # doctest.BLANKLINE_MARKER = 'something better than <BLANKLINE>' + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + + import numpy as np + import libpysal + + db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"), "r") + y_var = "CRIME" + y = np.array([db.by_col(y_var)]).reshape(49, 1) + x_var = ["INC", "HOVAL"] + x = np.array([db.by_col(name) for name in x_var]).T + w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + w.transform = "r" + ols = OLS( + y, + x, + w=w, + nonspat_diag=True, + spat_diag=True, + name_y=y_var, + name_x=x_var, + name_ds="columbus", + name_w="columbus.gal", + robust="white", + sig2n_k=True, + moran=True, + ) + print(ols.output) + print(ols.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/ols_regimes.html b/_modules/spreg/ols_regimes.html new file mode 100644 index 00000000..32a8a113 --- /dev/null +++ b/_modules/spreg/ols_regimes.html @@ -0,0 +1,899 @@ + + + + + + + spreg.ols_regimes — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.ols_regimes

+"""
+Ordinary Least Squares regression with regimes.
+"""
+
+__author__ = "Luc Anselin, Pedro V. Amaral, Daniel Arribas-Bel"
+
+import numpy as np
+import multiprocessing as mp
+import pandas as pd
+from . import regimes as REGI
+from . import user_output as USER
+from .utils import set_warn, RegressionProps_basic, spdot, RegressionPropsY, get_lags
+from .ols import BaseOLS
+from .robust import hac_multi
+from .output import output, _spat_diag_out, _nonspat_mid, _nonspat_top
+
+
+
[docs]class OLS_Regimes(BaseOLS, REGI.Regimes_Frame, RegressionPropsY): + """ + Ordinary least squares with results and diagnostics. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + w : pysal W object + Spatial weights object (required if running spatial + diagnostics) + robust : string + If 'white', then a White consistent estimator of the + variance-covariance matrix is given. If 'hac', then a + HAC consistent estimator of the variance-covariance + matrix is given. Default set to None. + gwk : pysal W object + Kernel spatial weights needed for HAC estimation. Note: + matrix must have ones along the main diagonal. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SLX type. + Note: WX is computed using the complete weights matrix + sig2n_k : boolean + If True, then use n-k to estimate sigma^2. If False, use n. + nonspat_diag : boolean + If True, then compute non-spatial diagnostics on + the regression. + spat_diag : boolean + If True, then compute Lagrange multiplier tests (requires + w). Note: see moran for further tests. + moran : boolean + If True, compute Moran's I on the residuals. Note: + requires spat_diag=True. + white_test : boolean + If True, compute White's specification robust test. + (requires nonspat_diag=True) + vm : boolean + If True, include variance-covariance matrix in summary + results + constant_regi: string, optional + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes + + * 'many': a vector of ones is appended to x and considered different per regime (default) + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep : boolean + If True, a separate regression is run for each regime. + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + robust : string + Adjustment for robust standard errors + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + r2 : float + R squared + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + ar2 : float + Adjusted R squared + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + utu : float + Sum of squared residuals + sig2 : float + Sigma squared used in computations + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + sig2ML : float + Sigma squared (maximum likelihood) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + f_stat : tuple + Statistic (float), p-value (float) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + logll : float + Log likelihood + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + aic : float + Akaike information criterion + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + schwarz : float + Schwarz information criterion + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + t_stat : list of tuples + t statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mulColli : float + Multicollinearity condition number + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + jarque_bera : dictionary + 'jb': Jarque-Bera statistic (float); 'pvalue': p-value + (float); 'df': degrees of freedom (int) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + breusch_pagan : dictionary + 'bp': Breusch-Pagan statistic (float); 'pvalue': p-value + (float); 'df': degrees of freedom (int) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + koenker_bassett: dictionary + 'kb': Koenker-Bassett statistic (float); 'pvalue': p-value (float); + 'df': degrees of freedom (int). Only available in dictionary + 'multi' when multiple regressions (see 'multi' below for details). + white : dictionary + 'wh': White statistic (float); 'pvalue': p-value (float); + 'df': degrees of freedom (int). + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + lm_error : tuple + Lagrange multiplier test for spatial error model; tuple + contains the pair (statistic, p-value), where each is a + float. Only available in dictionary 'multi' when multiple + regressions (see 'multi' below for details) + lm_lag : tuple + Lagrange multiplier test for spatial lag model; tuple + contains the pair (statistic, p-value), where each is a + float. Only available in dictionary 'multi' when multiple + regressions (see 'multi' below for details) + rlm_error : tuple + Robust lagrange multiplier test for spatial error model; + tuple contains the pair (statistic, p-value), where each + is a float. Only available in dictionary 'multi' when multiple + regressions (see 'multi' below for details) + rlm_lag : tuple + Robust lagrange multiplier test for spatial lag model; + tuple contains the pair (statistic, p-value), where each + is a float. Only available in dictionary 'multi' when + multiple regressions (see 'multi' below for details) + lm_sarma : tuple + Lagrange multiplier test for spatial SARMA model; tuple + contains the pair (statistic, p-value), where each is a + float. Only available in dictionary 'multi' when multiple + regressions (see 'multi' below for details) + moran_res : tuple + Moran's I for the residuals; tuple containing the triple + (Moran's I, standardized Moran's I, p-value) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + title : string + Name of the regression method used. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + sig2n : float + Sigma squared (computed with n in the denominator) + sig2n_k : float + Sigma squared (computed with n-k in the denominator) + xtx : float + :math:`X'X`. Only available in dictionary 'multi' when multiple + regressions (see 'multi' below for details) + xtxi : float + :math:`(X'X)^{-1}`. Only available in dictionary 'multi' when multiple + regressions (see 'multi' below for details) + regimes : list + List of n values with the mapping of each observation to + a regime. Assumed to be aligned with 'x'. + constant_regi : string + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime. + cols2regi : list + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate. + nr : int + Number of different regimes in the 'regimes' list. + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression. + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> from spreg import OLS_Regimes + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path("NAT.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it + the dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = db.by_col(y_var) + >>> y = np.array(y) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + We can now run the regression and then have a summary of the output + by typing: olsr.summary + + >>> olsr = OLS_Regimes(y, x, regimes, nonspat_diag=False, name_y=y_var, name_x=['PS90','UE90'], name_regimes=r_var, name_ds='NAT') + >>> print(olsr.summary) + REGRESSION RESULTS + ------------------ + <BLANKLINE> + SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 0 + --------------------------------------------------------------- + Data set : NAT + Weights matrix : None + Dependent Variable : 0_HR90 Number of Observations: 1673 + Mean dependent var : 3.3416 Number of Variables : 3 + S.D. dependent var : 4.6795 Degrees of Freedom : 1670 + R-squared : 0.1271 + Adjusted R-squared : 0.1260 + <BLANKLINE> + ------------------------------------------------------------------------------------ + Variable Coefficient Std.Error t-Statistic Probability + ------------------------------------------------------------------------------------ + 0_CONSTANT 0.3964290 0.2481634 1.5974512 0.1103544 + 0_PS90 0.6558330 0.0966268 6.7872800 0.0000000 + 0_UE90 0.4870394 0.0362863 13.4221336 0.0000000 + ------------------------------------------------------------------------------------ + Regimes variable: SOUTH + <BLANKLINE> + SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 1 + --------------------------------------------------------------- + Data set : NAT + Weights matrix : None + Dependent Variable : 1_HR90 Number of Observations: 1412 + Mean dependent var : 9.5493 Number of Variables : 3 + S.D. dependent var : 7.0389 Degrees of Freedom : 1409 + R-squared : 0.0661 + Adjusted R-squared : 0.0647 + <BLANKLINE> + ------------------------------------------------------------------------------------ + Variable Coefficient Std.Error t-Statistic Probability + ------------------------------------------------------------------------------------ + 1_CONSTANT 5.5983500 0.4689456 11.9381640 0.0000000 + 1_PS90 1.1621045 0.2166740 5.3633790 0.0000001 + 1_UE90 0.5316389 0.0594565 8.9416422 0.0000000 + ------------------------------------------------------------------------------------ + Regimes variable: SOUTH + ------------------------------------------------------------------------------------ + GLOBAL DIAGNOSTICS + <BLANKLINE> + REGIMES DIAGNOSTICS - CHOW TEST + VARIABLE DF VALUE PROB + CONSTANT 1 96.129 0.0000 + PS90 1 4.554 0.0328 + UE90 1 0.410 0.5220 + Global test 3 680.960 0.0000 + ================================ END OF REPORT ===================================== + """ + +
[docs] def __init__( + self, + y, + x, + regimes, + w=None, + robust=None, + gwk=None, + slx_lags=0, + sig2n_k=True, + nonspat_diag=True, + spat_diag=False, + moran=False, + white_test=False, + vm=False, + constant_regi="many", + cols2regi="all", + regime_err_sep=True, + cores=False, + name_y=None, + name_x=None, + name_regimes=None, + name_w=None, + name_gwk=None, + name_ds=None, + latex=False + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_robust(robust, gwk) + if robust == "hac": + if regime_err_sep: + set_warn( + self, + "Error by regimes is not available for HAC estimation. The error by regimes has been disabled for this model.", + ) + regime_err_sep = False + if spat_diag: + set_warn( + self, + "Spatial diagnostics are not available for HAC estimation. The spatial diagnostics have been disabled for this model.", + ) + spat_diag = False + if robust in ["hac", "white"] and white_test: + set_warn( + self, + "White test not available when standard errors are estimated by HAC or White correction.", + ) + white_test = False + USER.check_spat_diag(spat_diag, w) + x_constant, name_x, warn = USER.check_constant(x, name_x, just_rem=True) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + if slx_lags > 0: + USER.check_weights(w, y, w_required=True) + lag_x = get_lags(w, x_constant, slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + else: + USER.check_weights(w, y, w_required=False) + set_warn(self, warn) + self.name_x_r = USER.set_name_x(name_x, x_constant) + self.constant_regi = constant_regi + self.cols2regi = cols2regi + self.name_w = USER.set_name_w(name_w, w) + self.name_gwk = USER.set_name_w(name_gwk, gwk) + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_regimes = USER.set_name_ds(name_regimes) + self.n = n + cols2regi = REGI.check_cols2regi( + constant_regi, cols2regi, x_constant, add_cons=False + ) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, self.n, x_constant.shape[1]) + self.regime_err_sep = regime_err_sep + if ( + regime_err_sep == True + and set(cols2regi) == set([True]) + and constant_regi == "many" + ): + self.y = y + regi_ids = dict( + (r, list(np.where(np.array(regimes) == r)[0])) for r in self.regimes_set + ) + self._ols_regimes_multi( + x_constant, + w, + regi_ids, + cores, + gwk, + slx_lags, + sig2n_k, + robust, + nonspat_diag, + spat_diag, + vm, + name_x, + moran, + white_test, + latex + ) + else: + x, self.name_x, x_rlist = REGI.Regimes_Frame.__init__( + self, x_constant, regimes, constant_regi, cols2regi, name_x, rlist=True + ) + + self.output = pd.DataFrame(self.name_x, + columns=['var_names']) + self.output['var_type'] = ['x'] * len(self.name_x) + self.output['regime'] = x_rlist + self.output['equation'] = 0 + + BaseOLS.__init__(self, y=y, x=x, robust=robust, gwk=gwk, sig2n_k=sig2n_k) + if regime_err_sep == True and robust == None: + y2, x2 = REGI._get_weighted_var( + regimes, self.regimes_set, sig2n_k, self.u, y, x + ) + ols2 = BaseOLS(y=y2, x=x2, sig2n_k=sig2n_k) + RegressionProps_basic(self, betas=ols2.betas, vm=ols2.vm) + self.title = ( + "ORDINARY LEAST SQUARES - REGIMES (Group-wise heteroskedasticity)" + ) + if slx_lags > 0: + self.title = "ORDINARY LEAST SQUARES WITH SLX - REGIMES (Group-wise heteroskedasticity)" + nonspat_diag = None + set_warn( + self, + "Residuals treated as homoskedastic for the purpose of diagnostics.", + ) + else: + if slx_lags == 0: + self.title = "ORDINARY LEAST SQUARES - REGIMES" + else: + self.title = "ORDINARY LEAST SQUARES WITH SLX - REGIMES" + self.robust = USER.set_robust(robust) + self.chow = REGI.Chow(self) + self.other_top, self.other_mid, other_end = ("", "", "") # strings where function-specific diag. are stored + if nonspat_diag: + self.other_mid += _nonspat_mid(self, white_test=white_test) + self.other_top += _nonspat_top(self) + if spat_diag: + other_end += _spat_diag_out(self, w, 'ols', moran=moran) + output(reg=self, vm=vm, robust=robust, other_end=other_end, latex=latex)
+ + def _ols_regimes_multi( + self, + x, + w, + regi_ids, + cores, + gwk, + slx_lags, + sig2n_k, + robust, + nonspat_diag, + spat_diag, + vm, + name_x, + moran, + white_test, + latex + ): + results_p = {} + """ + for r in self.regimes_set: + if system() == 'Windows': + is_win = True + results_p[r] = _work(*(self.y,x,w,regi_ids,r,robust,sig2n_k,self.name_ds,self.name_y,name_x,self.name_w,self.name_regimes)) + else: + pool = mp.Pool(cores) + results_p[r] = pool.apply_async(_work,args=(self.y,x,w,regi_ids,r,robust,sig2n_k,self.name_ds,self.name_y,name_x,self.name_w,self.name_regimes)) + is_win = False + """ + x_constant, name_x = REGI.check_const_regi(self, x, name_x, regi_ids) + self.name_x_r = name_x + for r in self.regimes_set: + if cores: + pool = mp.Pool(None) + results_p[r] = pool.apply_async( + _work, + args=( + self.y, + x_constant, + w, + regi_ids, + r, + robust, + sig2n_k, + self.name_ds, + self.name_y, + name_x, + self.name_w, + self.name_regimes, + slx_lags + ), + ) + else: + results_p[r] = _work( + *( + self.y, + x_constant, + w, + regi_ids, + r, + robust, + sig2n_k, + self.name_ds, + self.name_y, + name_x, + self.name_w, + self.name_regimes, + slx_lags + ) + ) + self.kryd = 0 + self.kr = x_constant.shape[1] + self.kf = 0 + self.nr = len(self.regimes_set) + self.vm = np.zeros((self.nr * self.kr, self.nr * self.kr), float) + self.betas = np.zeros((self.nr * self.kr, 1), float) + self.u = np.zeros((self.n, 1), float) + self.predy = np.zeros((self.n, 1), float) + """ + if not is_win: + pool.close() + pool.join() + """ + if cores: + pool.close() + pool.join() + + results = {} + self.name_y, self.name_x = [], [] + counter = 0 + self.output = pd.DataFrame(columns=['var_names', 'var_type', 'regime', 'equation']) + for r in self.regimes_set: + """ + if is_win: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + """ + if not cores: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + + self.vm[ + (counter * self.kr): ((counter + 1) * self.kr), + (counter * self.kr): ((counter + 1) * self.kr), + ] = results[r].vm + self.betas[ + (counter * self.kr): ((counter + 1) * self.kr), + ] = results[r].betas + self.u[ + regi_ids[r], + ] = results[r].u + self.predy[ + regi_ids[r], + ] = results[r].predy + self.name_y += results[r].name_y + self.name_x += results[r].name_x + self.output = pd.concat([self.output, pd.DataFrame({'var_names': results[r].name_x, + 'var_type': ['x']*len(results[r].name_x), + 'regime': r, 'equation': r})], ignore_index=True) + results[r].other_top, results[r].other_mid = ("", "") + if nonspat_diag: + results[r].other_mid += _nonspat_mid(results[r], white_test=white_test) + results[r].other_top += _nonspat_top(results[r]) + counter += 1 + self.multi = results + self.hac_var = x_constant[:, 1:] + if robust == "hac": + hac_multi(self, gwk) + self.chow = REGI.Chow(self) + other_end = "" + if spat_diag: + self._get_spat_diag_props(x_constant, sig2n_k) + other_end += _spat_diag_out(self, w, 'ols', moran=moran) + output(reg=self, vm=vm, robust=robust, other_end=other_end, latex=latex) + + def _get_spat_diag_props(self, x, sig2n_k): + self.k = self.kr + self._cache = {} + self.x = REGI.regimeX_setup( + x, self.regimes, [True] * x.shape[1], self.regimes_set + ) + self.xtx = spdot(self.x.T, self.x) + self.xtxi = np.linalg.inv(self.xtx)
+ + +def _work( + y, x, w, regi_ids, r, robust, sig2n_k, name_ds, name_y, name_x, name_w, name_regimes, slx_lags +): + y_r = y[regi_ids[r]] + x_r = x[regi_ids[r]] + # x_constant,name_x,warn = USER.check_constant(x_r, name_x) + # name_x = USER.set_name_x(name_x, x_constant) + if robust == "hac": + robust = None + model = BaseOLS(y_r, x_r, robust=robust, sig2n_k=sig2n_k) + if slx_lags == 0: + model.title = "ORDINARY LEAST SQUARES ESTIMATION - REGIME %s" % r + else: + model.title = "ORDINARY LEAST SQUARES ESTIMATION WITH SLX - REGIME %s" % r + model.robust = USER.set_robust(robust) + model.name_ds = name_ds + model.name_y = "%s_%s" % (str(r), name_y) + model.name_x = ["%s_%s" % (str(r), i) for i in name_x] + model.name_w = name_w + model.name_regimes = name_regimes + if w: + w_r, warn = REGI.w_regime(w, regi_ids[r], r, transform=True) + set_warn(model, warn) + model.w = w_r + return model + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + import numpy as np + import libpysal + import pysal + + db = libpysal.io.open(libpysal.examples.get_path("NAT.dbf"), "r") + y_var = "HR90" + y = np.array(db.by_col(y_var)).reshape(-1,1) + x_var = ['PS90','UE90'] + x = np.array([db.by_col(name) for name in x_var]).T + r_var = "SOUTH" + regimes = db.by_col(r_var) + w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("NAT.shp")) + w.transform = "r" + #olsr = pysal.model.spreg.OLS_Regimes( + olsr = OLS_Regimes( + y, + x, + regimes, + w=w, + constant_regi="many", + nonspat_diag=True, + spat_diag=True, + name_y=y_var, + name_x=x_var, + name_ds="NAT", + name_regimes=r_var, + regime_err_sep=True, + cols2regi=[True, True], + sig2n_k=False, + white_test=True, + #robust="white" + ) + print(olsr.output) + print(olsr.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/panel_fe.html b/_modules/spreg/panel_fe.html new file mode 100644 index 00000000..97ca9158 --- /dev/null +++ b/_modules/spreg/panel_fe.html @@ -0,0 +1,825 @@ + + + + + + + spreg.panel_fe — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.panel_fe

+"""
+Spatial Fixed Effects Panel model based on: :cite:`Elhorst2003`
+"""
+
+__author__ = "Wei Kang weikang9009@gmail.com, \
+              Pedro Amaral pedroamaral@cedeplar.ufmg.br, \
+              Pablo Estrada pabloestradace@gmail.com"
+
+import numpy as np
+import numpy.linalg as la
+from scipy import sparse as sp
+from scipy.sparse.linalg import splu as SuperLU
+from .utils import RegressionPropsY, RegressionPropsVM, inverse_prod, set_warn
+from .sputils import spdot, spfill_diagonal, spinv
+from . import diagnostics as DIAG
+from . import user_output as USER
+from . import summary_output as SUMMARY
+
+try:
+    from scipy.optimize import minimize_scalar
+
+    minimize_scalar_available = True
+except ImportError:
+    minimize_scalar_available = False
+
+from .panel_utils import check_panel, demean_panel
+
+__all__ = ["Panel_FE_Lag", "Panel_FE_Error"]
+
+
+class BasePanel_FE_Lag(RegressionPropsY, RegressionPropsVM):
+
+    """
+    Base ML method for a fixed effects spatial lag model (note no consistency
+    checks, diagnostics or constants added) :cite:`Elhorst2003`.
+
+    Parameters
+    ----------
+    y         : array
+                (n*t)x1 array for dependent variable
+    x         : array
+                Two dimensional array with n*t rows and one column for each
+                independent (exogenous) variable
+                (note: must already include constant term)
+    w         : pysal W object
+                Spatial weights matrix
+    epsilon   : float
+                tolerance criterion in mimimize_scalar function and
+                inverse_product
+
+    Attributes
+    ----------
+    betas        : array
+                   (k+1)x1 array of estimated coefficients (rho last)
+    rho          : float
+                   estimate of spatial autoregressive coefficient
+    u            : array
+                   (nxt)x1 array of residuals
+    predy        : array
+                   (nxt)x1 array of predicted y values
+    n            : integer
+                   Total number of observations
+    t            : integer
+                   Number of time periods
+    k            : integer
+                   Number of variables for which coefficients are estimated
+                   (no constant, excluding the rho)
+    y            : array
+                   (nxt)x1 array for dependent variable
+    x            : array
+                   Two dimensional array with nxt rows and one column for each
+                   independent (exogenous) variable, no constant
+    mean_y       : float
+                   Mean of dependent variable
+    std_y        : float
+                   Standard deviation of dependent variable
+    vm           : array
+                   Variance covariance matrix (k+1 x k+1)
+    vm1          : array
+                   Variance covariance matrix (k+2 x k+2) includes sigma2
+    sig2         : float
+                   Sigma squared used in computations
+    logll        : float
+                   maximized log-likelihood (including constant terms)
+    predy_e      : array
+                   predicted values from reduced form
+    e_pred       : array
+                   prediction errors using reduced form predicted values
+    """
+
+    def __init__(self, y, x, w, epsilon=0.0000001):
+        # set up main regression variables and spatial filters
+        self.n = w.n
+        self.t = y.shape[0] // self.n
+        self.k = x.shape[1]
+        self.epsilon = epsilon
+        # Demeaned variables
+        self.y = demean_panel(y, self.n, self.t)
+        self.x = demean_panel(x, self.n, self.t)
+        # Big W matrix
+        W = w.full()[0]
+        Wsp = w.sparse
+        Wsp_nt = sp.kron(sp.identity(self.t), Wsp, format="csr")
+        # lag dependent variable
+        ylag = spdot(Wsp_nt, self.y)
+        # b0, b1, e0 and e1
+        xtx = spdot(self.x.T, self.x)
+        xtxi = la.inv(xtx)
+        xty = spdot(self.x.T, self.y)
+        xtyl = spdot(self.x.T, ylag)
+        b0 = spdot(xtxi, xty)
+        b1 = spdot(xtxi, xtyl)
+        e0 = self.y - spdot(self.x, b0)
+        e1 = ylag - spdot(self.x, b1)
+
+        # concentrated Log Likelihood
+        I = sp.identity(self.n)
+        res = minimize_scalar(
+            lag_c_loglik_sp,
+            0.0,
+            bounds=(-1.0, 1.0),
+            args=(self.n, self.t, e0, e1, I, Wsp),
+            method="bounded",
+            options={"xatol": epsilon},
+        )
+        self.rho = res.x[0][0]
+
+        # compute full log-likelihood, including constants
+        ln2pi = np.log(2.0 * np.pi)
+        llik = -res.fun - (self.n * self.t) / 2.0 * ln2pi - (self.n * self.t) / 2.0
+        self.logll = llik[0][0]
+
+        # b, residuals and predicted values
+        b = b0 - self.rho * b1
+        self.betas = np.vstack((b, self.rho))  # rho added as last coefficient
+        self.u = e0 - self.rho * e1
+        self.predy = self.y - self.u
+
+        xb = spdot(self.x, b)
+
+        self.predy_e = inverse_prod(
+            Wsp_nt, xb, self.rho, inv_method="power_exp", threshold=epsilon
+        )
+        self.e_pred = self.y - self.predy_e
+
+        # residual variance
+        self._cache = {}
+        self.sig2 = spdot(self.u.T, self.u) / (self.n * self.t)
+
+        # information matrix
+        a = -self.rho * W
+        spfill_diagonal(a, 1.0)
+        ai = spinv(a)
+        wai = spdot(Wsp, ai)
+        tr1 = wai.diagonal().sum()  # same for sparse and dense
+
+        wai2 = spdot(wai, wai)
+        tr2 = wai2.diagonal().sum()
+
+        waiTwai = spdot(wai.T, wai)
+        tr3 = waiTwai.diagonal().sum()
+
+        wai_nt = sp.kron(sp.identity(self.t), wai, format="csr")
+        wpredy = spdot(wai_nt, xb)
+        xTwpy = spdot(x.T, wpredy)
+
+        waiTwai_nt = sp.kron(sp.identity(self.t), waiTwai, format="csr")
+        wTwpredy = spdot(waiTwai_nt, xb)
+        wpyTwpy = spdot(xb.T, wTwpredy)
+
+        # order of variables is beta, rho, sigma2
+        v1 = np.vstack((xtx / self.sig2, xTwpy.T / self.sig2, np.zeros((1, self.k))))
+        v2 = np.vstack(
+            (
+                xTwpy / self.sig2,
+                self.t * (tr2 + tr3) + wpyTwpy / self.sig2,
+                self.t * tr1 / self.sig2,
+            )
+        )
+        v3 = np.vstack(
+            (
+                np.zeros((self.k, 1)),
+                self.t * tr1 / self.sig2,
+                self.n * self.t / (2.0 * self.sig2 ** 2),
+            )
+        )
+
+        v = np.hstack((v1, v2, v3))
+
+        self.vm1 = la.inv(v)  # vm1 includes variance for sigma2
+        self.vm = self.vm1[:-1, :-1]  # vm is for coefficients only
+        self.varb = la.inv(np.hstack((v1[:-1], v2[:-1])))
+        self.n = self.n * self.t  # change the n, for degree of freedom
+
+
+
[docs]class Panel_FE_Lag(BasePanel_FE_Lag): + + """ + ML estimation of the fixed effects spatial lag model with all results and + diagnostics :cite:`Elhorst2003`. + + Parameters + ---------- + y : array + nxt or (nxt)x1 array for dependent variable + x : array + nx(txk) or (nxt)xk array for independent (exogenous) + variables, no constant + w : pysal W object + Spatial weights object + epsilon : float + tolerance criterion in mimimize_scalar function and + inverse_product + vm : boolean + if True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + + Attributes + ---------- + betas : array + (k+1)x1 array of estimated coefficients (rho last) + rho : float + estimate of spatial autoregressive coefficient + u : array + (nxt)x1 array of residuals + predy : array + (nxt)x1 array of predicted y values + n : integer + Total number of observations + t : integer + Number of time periods + k : integer + Number of variables for which coefficients are estimated + (no constant, excluding the rho) + y : array + (nxt)x1 array for dependent variable + x : array + Two dimensional array with nxt rows and one column for each + independent (exogenous) variable, no constant + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (k+1 x k+1), all coefficients + vm1 : array + Variance covariance matrix (k+2 x k+2), includes sig2 + sig2 : float + Sigma squared used in computations + logll : float + maximized log-likelihood (including constant terms) + aic : float + Akaike information criterion + schwarz : float + Schwarz criterion + predy_e : array + predicted values from reduced form + e_pred : array + prediction errors using reduced form predicted values + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + utu : float + Sum of squared residuals + std_err : array + 1x(k+1) array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> import spreg + >>> nat = libpysal.examples.load_example("NCOVR") + >>> db = libpysal.io.open(nat.get_path("NAT.dbf"), "r") + >>> nat_shp = libpysal.examples.get_path("NAT.shp") + >>> w = libpysal.weights.Queen.from_shapefile(nat_shp) + >>> w.transform = 'r' + >>> name_y = ["HR70", "HR80", "HR90"] + >>> y = np.array([db.by_col(name) for name in name_y]).T + >>> name_x = ["RD70", "RD80", "RD90", "PS70", "PS80", "PS90"] + >>> x = np.array([db.by_col(name) for name in name_x]).T + >>> fe_lag = spreg.Panel_FE_Lag(y, x, w, name_y=name_y, name_x=name_x, name_ds="NAT") + Warning: Assuming panel is in wide format, i.e. y[:, 0] refers to T0, y[:, 1] refers to T1, etc. + Similarly, assuming x[:, 0:T] refers to T periods of k1, x[:, T+1:2T] refers to k2, etc. + >>> np.around(fe_lag.betas, decimals=4) + array([[ 0.8006], + [-2.6004], + [ 0.1903]]) + """ + +
[docs] def __init__( + self, + y, + x, + w, + epsilon=0.0000001, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + ): + n_rows = USER.check_arrays(y, x) + x_constant, name_x, warn = USER.check_constant(x, name_x, True) + set_warn(self, warn) + bigy, bigx, name_y, name_x, warn = check_panel(y, x_constant, w, name_y, name_x) + set_warn(self, warn) + USER.check_weights(w, bigy, w_required=True, time=True) + + BasePanel_FE_Lag.__init__(self, bigy, bigx, w, epsilon=epsilon) + # increase by 1 to have correct aic and sc, include rho in count + self.k += 1 + self.title = "MAXIMUM LIKELIHOOD SPATIAL LAG PANEL" + " - FIXED EFFECTS" + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, bigx, constant=True) + name_ylag = USER.set_name_yend_sp(self.name_y) + self.name_x.append(name_ylag) # rho changed to last position + self.name_w = USER.set_name_w(name_w, w) + self.aic = DIAG.akaike(reg=self) + self.schwarz = DIAG.schwarz(reg=self) + SUMMARY.Panel_FE_Lag(reg=self, w=w, vm=vm)
+ + +class BasePanel_FE_Error(RegressionPropsY, RegressionPropsVM): + + """ + Base ML method for a fixed effects spatial error model (note no consistency + checks, diagnostics or constants added) :cite:`Elhorst2003`. + + Parameters + ---------- + y : array + (n*t)x1 array for dependent variable + x : array + Two dimensional array with n*t rows and one column for each + independent (exogenous) variable + (note: must already include constant term) + w : pysal W object + Spatial weights matrix + epsilon : float + tolerance criterion in mimimize_scalar function and + inverse_product + + Attributes + ---------- + betas : array + kx1 array of estimated coefficients + lam : float + estimate of spatial autoregressive coefficient + u : array + (nxt)x1 array of residuals + predy : array + (nxt)x1 array of predicted y values + n : integer + Total number of observations + t : integer + Number of time periods + k : integer + Number of variables for which coefficients are estimated + (no constant, excluding the lambda) + y : array + (nxt)x1 array for dependent variable + x : array + Two dimensional array with nxt rows and one column for each + independent (exogenous) variable, no constant + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (k+1 x k+1) + vm1 : array + Variance covariance matrix (k+2 x k+2) includes sigma2 + sig2 : float + Sigma squared used in computations + logll : float + maximized log-likelihood (including constant terms) + """ + + def __init__(self, y, x, w, epsilon=0.0000001): + # set up main regression variables and spatial filters + self.n = w.n + self.t = y.shape[0] // self.n + self.k = x.shape[1] + self.epsilon = epsilon + # Demeaned variables + self.y = demean_panel(y, self.n, self.t) + self.x = demean_panel(x, self.n, self.t) + # Big W matrix + W = w.full()[0] + Wsp = w.sparse + Wsp_nt = sp.kron(sp.identity(self.t), Wsp, format="csr") + # lag dependent variable + ylag = spdot(Wsp_nt, self.y) + xlag = spdot(Wsp_nt, self.x) + + # concentrated Log Likelihood + I = sp.identity(self.n) + res = minimize_scalar( + err_c_loglik_sp, + 0.0, + bounds=(-1.0, 1.0), + args=(self.n, self.t, self.y, ylag, self.x, xlag, I, Wsp), + method="bounded", + options={"xatol": epsilon}, + ) + self.lam = res.x + + # compute full log-likelihood + ln2pi = np.log(2.0 * np.pi) + self.logll = ( + -res.fun - (self.n * self.t) / 2.0 * ln2pi - (self.n * self.t) / 2.0 + ) + + # b, residuals and predicted values + ys = self.y - self.lam * ylag + xs = self.x - self.lam * xlag + xsxs = spdot(xs.T, xs) + xsxsi = la.inv(xsxs) + xsys = spdot(xs.T, ys) + b = spdot(xsxsi, xsys) + + self.betas = np.vstack((b, self.lam)) + + self.u = self.y - spdot(self.x, b) + self.predy = self.y - self.u + + # residual variance + self.e_filtered = self.u - self.lam * spdot(Wsp_nt, self.u) + self.sig2 = spdot(self.e_filtered.T, self.e_filtered) / (self.n * self.t) + + # variance-covariance matrix betas + varb = self.sig2 * xsxsi + + # variance-covariance matrix lambda, sigma + a = -self.lam * W + spfill_diagonal(a, 1.0) + ai = spinv(a) + wai = spdot(Wsp, ai) + tr1 = wai.diagonal().sum() + + wai2 = spdot(wai, wai) + tr2 = wai2.diagonal().sum() + + waiTwai = spdot(wai.T, wai) + tr3 = waiTwai.diagonal().sum() + + v1 = np.vstack((self.t * (tr2 + tr3), self.t * tr1 / self.sig2)) + v2 = np.vstack( + (self.t * tr1 / self.sig2, self.t * self.n / (2.0 * self.sig2 ** 2)) + ) + + v = np.hstack((v1, v2)) + + self.vm1 = la.inv(v) + + # create variance matrix for beta, lambda + vv = np.hstack((varb, np.zeros((self.k, 1)))) + vv1 = np.hstack((np.zeros((1, self.k)), self.vm1[0, 0] * np.ones((1, 1)))) + + self.vm = np.vstack((vv, vv1)) + self.varb = varb + self.n = self.n * self.t + + +
[docs]class Panel_FE_Error(BasePanel_FE_Error): + + """ + ML estimation of the fixed effects spatial error model with all results and + diagnostics :cite:`Elhorst2003`. + + Parameters + ---------- + y : array + nxt or (nxt)x1 array for dependent variable + x : array + nx(txk) or (nxt)xk array for independent (exogenous) + variables, no constant + w : pysal W object + Spatial weights object + epsilon : float + tolerance criterion in mimimize_scalar function and + inverse_product + vm : boolean + if True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + + Attributes + ---------- + betas : array + kx1 array of estimated coefficients + lam : float + estimate of spatial autoregressive coefficient + u : array + (nxt)x1 array of residuals + e_filtered : array + (nxt)x1 array of spatially filtered residuals + predy : array + (nxt)x1 array of predicted y values + n : integer + Total number of observations + t : integer + Number of time periods + k : integer + Number of variables for which coefficients are estimated + (no constant, excluding the lambda) + y : array + (nxt)x1 array for dependent variable + x : array + Two dimensional array with nxt rows and one column for each + independent (exogenous) variable, including the constant + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (k+1 x k+1), all coefficients + vm1 : array + Variance covariance matrix (k+2 x k+2), includes sig2 + sig2 : float + Sigma squared used in computations + logll : float + maximized log-likelihood (including constant terms) + aic : float + Akaike information criterion + schwarz : float + Schwarz criterion + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + utu : float + Sum of squared residuals + std_err : array + 1x(k+1) array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + >>> import numpy as np + >>> import libpysal + >>> import spreg + >>> nat = libpysal.examples.load_example("NCOVR") + >>> db = libpysal.io.open(nat.get_path("NAT.dbf"), "r") + >>> nat_shp = libpysal.examples.get_path("NAT.shp") + >>> w = libpysal.weights.Queen.from_shapefile(nat_shp) + >>> w.transform = 'r' + >>> name_y = ["HR70", "HR80", "HR90"] + >>> y = np.array([db.by_col(name) for name in name_y]).T + >>> name_x = ["RD70", "RD80", "RD90", "PS70", "PS80", "PS90"] + >>> x = np.array([db.by_col(name) for name in name_x]).T + >>> fe_error = spreg.Panel_FE_Error(y, x, w, name_y=name_y, name_x=name_x, name_ds="NAT") + Warning: Assuming panel is in wide format, i.e. y[:, 0] refers to T0, y[:, 1] refers to T1, etc. + Similarly, assuming x[:, 0:T] refers to T periods of k1, x[:, T+1:2T] refers to k2, etc. + >>> np.around(fe_error.betas, decimals=4) + array([[ 0.8698], + [-2.9661], + [ 0.1943]]) + """ + +
[docs] def __init__( + self, + y, + x, + w, + epsilon=0.0000001, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + ): + n_rows = USER.check_arrays(y, x) + x_constant, name_x, warn = USER.check_constant(x, name_x, True) + set_warn(self, warn) + bigy, bigx, name_y, name_x, warn = check_panel(y, x_constant, w, name_y, name_x) + set_warn(self, warn) + USER.check_weights(w, bigy, w_required=True, time=True) + + BasePanel_FE_Error.__init__(self, bigy, bigx, w, epsilon=epsilon) + self.title = "MAXIMUM LIKELIHOOD SPATIAL ERROR PANEL" + " - FIXED EFFECTS" + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, bigx, constant=True) + self.name_x.append("lambda") + self.name_w = USER.set_name_w(name_w, w) + self.aic = DIAG.akaike(reg=self) + self.schwarz = DIAG.schwarz(reg=self) + SUMMARY.Panel_FE_Error(reg=self, w=w, vm=vm)
+ + +def lag_c_loglik_sp(rho, n, t, e0, e1, I, Wsp): + # concentrated log-lik for lag model, sparse algebra + if isinstance(rho, np.ndarray): + if rho.shape == (1, 1): + rho = rho[0][0] + er = e0 - rho * e1 + sig2 = spdot(er.T, er) + nlsig2 = (n * t / 2.0) * np.log(sig2) + a = I - rho * Wsp + LU = SuperLU(a.tocsc()) + jacob = t * np.sum(np.log(np.abs(LU.U.diagonal()))) + clike = nlsig2 - jacob + return clike + + +def err_c_loglik_sp(lam, n, t, y, ylag, x, xlag, I, Wsp): + # concentrated log-lik for error model, no constants, LU + if isinstance(lam, np.ndarray): + if lam.shape == (1, 1): + lam = lam[0][0] + ys = y - lam * ylag + xs = x - lam * xlag + ysys = np.dot(ys.T, ys) + xsxs = np.dot(xs.T, xs) + xsxsi = la.inv(xsxs) + xsys = np.dot(xs.T, ys) + x1 = np.dot(xsxsi, xsys) + x2 = np.dot(xsys.T, x1) + ee = ysys - x2 + sig2 = ee[0][0] + nlsig2 = (n * t / 2.0) * np.log(sig2) + a = I - lam * Wsp + LU = SuperLU(a.tocsc()) + jacob = t * np.sum(np.log(np.abs(LU.U.diagonal()))) + # this is the negative of the concentrated log lik for minimization + clik = nlsig2 - jacob + return clik + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/panel_re.html b/_modules/spreg/panel_re.html new file mode 100644 index 00000000..c654b5a5 --- /dev/null +++ b/_modules/spreg/panel_re.html @@ -0,0 +1,974 @@ + + + + + + + spreg.panel_re — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.panel_re

+"""
+Spatial Random Effects Panel model based on: :cite:`Elhorst2003`
+"""
+
+__author__ = "Wei Kang weikang9009@gmail.com, \
+              Pedro Amaral pedroamaral@cedeplar.ufmg.br, \
+              Pablo Estrada pabloestradace@gmail.com"
+
+import numpy as np
+import numpy.linalg as la
+from scipy import sparse as sp
+from scipy.sparse.linalg import splu as SuperLU
+from .utils import RegressionPropsY, RegressionPropsVM, inverse_prod, set_warn
+from .sputils import spdot, spfill_diagonal, spinv
+from spreg.w_utils import symmetrize
+from . import diagnostics as DIAG
+from . import user_output as USER
+from . import summary_output as SUMMARY
+
+try:
+    from scipy.optimize import minimize_scalar
+
+    minimize_scalar_available = True
+except ImportError:
+    minimize_scalar_available = False
+try:
+    from scipy.optimize import minimize
+
+    minimize_available = True
+except ImportError:
+    minimize_available = False
+
+from .panel_utils import check_panel, demean_panel
+
+__all__ = ["Panel_RE_Lag", "Panel_RE_Error"]
+
+
+class BasePanel_RE_Lag(RegressionPropsY, RegressionPropsVM):
+
+    """
+    Base ML method for a random effects spatial lag model (note no consistency
+    checks, diagnostics or constants added) :cite:`Elhorst2003`.
+
+    Parameters
+    ----------
+    y         : array
+                (n*t)x1 array for dependent variable
+    x         : array
+                Two dimensional array with n*t rows and one column for each
+                independent (exogenous) variable
+                (note: must already include constant term)
+    w         : pysal W object
+                Spatial weights matrix
+    epsilon   : float
+                tolerance criterion in mimimize_scalar function and
+                inverse_product
+
+    Attributes
+    ----------
+    betas        : array
+                   (k+2)x1 array of estimated coefficients (rho and phi last)
+    rho          : float
+                   estimate of spatial autoregressive coefficient
+    phi          : float
+                   estimate of weight attached to the cross-sectional component
+                   phi^2 = sig2 / (t*sig2_u + sig2)
+    u            : array
+                   (nxt)x1 array of residuals
+    predy        : array
+                   (nxt)x1 array of predicted y values
+    n            : integer
+                   Total number of observations
+    t            : integer
+                   Number of time periods
+    k            : integer
+                   Number of variables for which coefficients are estimated
+                   (no constant, excluding the rho and phi)
+    y            : array
+                   (nxt)x1 array for dependent variable
+    x            : array
+                   Two dimensional array with nxt rows and one column for each
+                   independent (exogenous) variable, no constant
+    mean_y       : float
+                   Mean of dependent variable
+    std_y        : float
+                   Standard deviation of dependent variable
+    vm           : array
+                   Variance covariance matrix (k+2 x k+2)
+    vm1          : array
+                   Variance covariance matrix (k+3 x k+3) includes sigma2
+    sig2         : float
+                   Sigma squared used in computations
+    logll        : float
+                   maximized log-likelihood (including constant terms)
+    predy_e      : array
+                   predicted values from reduced form
+    e_pred       : array
+                   prediction errors using reduced form predicted values
+    """
+
+    def __init__(self, bigy, bigx, w, epsilon=0.0000001):
+        # set up main regression variables and spatial filters
+        self.n = w.n
+        self.t = bigy.shape[0] // self.n
+        self.k = bigx.shape[1]
+        self.epsilon = epsilon
+        # Big W matrix
+        W = w.full()[0]
+        Wsp = w.sparse
+        Wsp_nt = sp.kron(sp.identity(self.t), Wsp, format="csr")
+        # Set up parameters
+        converge = 1
+        criteria = 0.0000001
+        i = 0
+        itermax = 100
+        self.rho = 0.1
+        self.phi = 0.1
+        I = sp.identity(self.n)
+        xtx = spdot(bigx.T, bigx)
+        xtxi = la.inv(xtx)
+        xty = spdot(bigx.T, bigy)
+        b = spdot(xtxi, xty)
+
+        # Iterative procedure
+        while converge > criteria and i < itermax:
+            phiold = self.phi
+            res_phi = minimize_scalar(
+                phi_c_loglik,
+                0.1,
+                bounds=(0.0, 1.0),
+                args=(self.rho, b, bigy, bigx, self.n, self.t, Wsp_nt),
+                method="bounded",
+                options={"xatol": epsilon},
+            )
+            self.phi = res_phi.x[0][0]
+            # Demeaned variables
+            self.y = demean_panel(bigy, self.n, self.t, phi=self.phi)
+            self.x = demean_panel(bigx, self.n, self.t, phi=self.phi)
+            # lag dependent variable
+            ylag = spdot(Wsp_nt, self.y)
+            # b0, b1, e0 and e1
+            xtx = spdot(self.x.T, self.x)
+            xtxi = la.inv(xtx)
+            xty = spdot(self.x.T, self.y)
+            xtyl = spdot(self.x.T, ylag)
+            b0 = spdot(xtxi, xty)
+            b1 = spdot(xtxi, xtyl)
+            e0 = self.y - spdot(self.x, b0)
+            e1 = ylag - spdot(self.x, b1)
+            res_rho = minimize_scalar(
+                lag_c_loglik_sp,
+                0.0,
+                bounds=(-1.0, 1.0),
+                args=(self.n, self.t, e0, e1, I, Wsp),
+                method="bounded",
+                options={"xatol": epsilon},
+            )
+            self.rho = res_rho.x[0][0]
+            b = b0 - self.rho * b1
+            i += 1
+            converge = np.abs(phiold - self.phi)
+
+        # compute full log-likelihood, including constants
+        ln2pi = np.log(2.0 * np.pi)
+        llik = -res_rho.fun - (self.n * self.t) / 2.0 * ln2pi - (self.n * self.t) / 2.0
+        self.logll = llik[0][0]
+
+        # b, residuals and predicted values
+        self.betas = np.vstack((b, self.rho, self.phi))
+        self.u = e0 - self.rho * e1
+        self.predy = self.y - self.u
+        xb = spdot(self.x, b)
+
+        self.predy_e = inverse_prod(
+            Wsp_nt, xb, self.rho, inv_method="power_exp", threshold=epsilon
+        )
+        self.e_pred = self.y - self.predy_e
+
+        # residual variance
+        self._cache = {}
+        self.sig2 = spdot(self.u.T, self.u) / (self.n * self.t)
+
+        # information matrix
+        a = -self.rho * W
+        spfill_diagonal(a, 1.0)
+        ai = spinv(a)
+        wai = spdot(W, ai)
+        tr1 = wai.diagonal().sum()  # same for sparse and dense
+
+        wai2 = spdot(wai, wai)
+        tr2 = wai2.diagonal().sum()
+
+        waiTwai = spdot(wai.T, wai)
+        tr3 = waiTwai.diagonal().sum()
+
+        wai_nt = sp.kron(sp.identity(self.t), wai, format="csr")
+        wpredy = spdot(wai_nt, xb)
+        xTwpy = spdot(self.x.T, wpredy)
+
+        waiTwai_nt = sp.kron(sp.identity(self.t), waiTwai, format="csr")
+        wTwpredy = spdot(waiTwai_nt, xb)
+        wpyTwpy = spdot(xb.T, wTwpredy)
+
+        # order of variables is beta, rho, sigma2
+        v1 = np.vstack((xtx / self.sig2, xTwpy.T / self.sig2, np.zeros((2, self.k))))
+        v2 = np.vstack(
+            (
+                xTwpy / self.sig2,
+                self.t * (tr2 + tr3) + wpyTwpy / self.sig2,
+                -tr1 / self.sig2,
+                self.t * tr1 / self.sig2,
+            )
+        )
+        v3 = np.vstack(
+            (
+                np.zeros((self.k, 1)),
+                -tr1 / self.sig2,
+                self.n * (1 + 1 / self.phi ** 2),
+                -self.n / self.sig2,
+            )
+        )
+        v4 = np.vstack(
+            (
+                np.zeros((self.k, 1)),
+                self.t * tr1 / self.sig2,
+                -self.n / self.sig2 ** 2,
+                self.n * self.t / (2.0 * self.sig2 ** 2),
+            )
+        )
+
+        v = np.hstack((v1, v2, v3, v4))
+
+        self.vm1 = la.inv(v)  # vm1 includes variance for sigma2
+        self.vm = self.vm1[:-1, :-1]  # vm is for coefficients and phi
+        self.varb = la.inv(np.hstack((v1[:-2], v2[:-2])))
+        self.n = self.n * self.t
+
+
+
[docs]class Panel_RE_Lag(BasePanel_RE_Lag): + + """ + ML estimation of the random effects spatial lag model with all results and + diagnostics :cite:`Elhorst2003`. + + Parameters + ---------- + y : array + nxt or (nxt)x1 array for dependent variable + x : array + nx(txk) or (nxt)xk array for independent (exogenous) + variables, excluding the constant + w : pysal W object + Spatial weights object + epsilon : float + tolerance criterion in mimimize_scalar function and + inverse_product + vm : boolean + if True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + + Attributes + ---------- + betas : array + (k+2)x1 array of estimated coefficients (rho and phi last) + rho : float + estimate of spatial autoregressive coefficient + phi : float + estimate of weight attached to the cross-sectional component + phi^2 = sig2 / (t*sig2_u + sig2) + u : array + (nxt)x1 array of residuals + predy : array + (nxt)x1 array of predicted y values + n : integer + Total number of observations + t : integer + Number of time periods + k : integer + Number of variables for which coefficients are estimated + (excluding the phi) + y : array + (nxt)x1 array for dependent variable + x : array + Two dimensional array with nxt rows and one column for each + independent (exogenous) variable + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (k+2 x k+2) + vm1 : array + Variance covariance matrix (k+3 x k+3) includes sigma2 + sig2 : float + Sigma squared used in computations + logll : float + maximized log-likelihood (including constant terms) + predy_e : array + predicted values from reduced form + e_pred : array + prediction errors using reduced form predicted values + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + utu : float + Sum of squared residuals + std_err : array + 1x(k+1) array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + >>> import numpy as np + >>> import pandas as pd + >>> import libpysal + >>> import spreg + >>> nat = libpysal.examples.load_example("NCOVR") + >>> db = libpysal.io.open(nat.get_path("NAT.dbf"), "r") + >>> nat_shp = libpysal.examples.get_path("NAT.shp") + >>> w_full = libpysal.weights.Queen.from_shapefile(nat_shp) + >>> name_y = ["HR70", "HR80", "HR90"] + >>> y_full = np.array([db.by_col(name) for name in name_y]).T + >>> name_x = ["RD70", "RD80", "RD90", "PS70", "PS80", "PS90"] + >>> x_full = np.array([db.by_col(name) for name in name_x]).T + >>> name_c = ["STATE_NAME", "FIPSNO"] + >>> df_counties = pd.DataFrame([db.by_col(name) for name in name_c], index=name_c).T + >>> filter_states = ["Kansas", "Missouri", "Oklahoma", "Arkansas"] + >>> filter_counties = df_counties[df_counties["STATE_NAME"].isin(filter_states)]["FIPSNO"].values + >>> counties = np.array(db.by_col("FIPSNO")) + >>> subid = np.where(np.isin(counties, filter_counties))[0] + >>> w = w_subset(w_full, subid) + >>> w.transform = 'r' + >>> y = y_full[subid, ] + >>> x = x_full[subid, ] + >>> re_lag = spreg.Panel_RE_Lag(y, x, w, name_y=name_y, name_x=name_x, name_ds="NAT") + Warning: Assuming panel is in wide format, i.e. y[:, 0] refers to T0, y[:, 1] refers to T1, etc. + Similarly, assuming x[:, 0:T] refers to T periods of k1, x[:, T+1:2T] refers to k2, etc. + np.around(re_lag.betas, decimals=4) + array([[4.44421994], + [2.52821717], + [2.24768846], + [0.25846846], + [0.68426639]]) + """ + +
[docs] def __init__( + self, + y, + x, + w, + epsilon=0.0000001, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + ): + n_rows = USER.check_arrays(y, x) + bigy, bigx, name_y, name_x, warn = check_panel(y, x, w, name_y, name_x) + set_warn(self, warn) + bigx, name_x, warn = USER.check_constant(bigx, name_x) + set_warn(self, warn) + USER.check_weights(w, bigy, w_required=True, time=True) + + BasePanel_RE_Lag.__init__(self, bigy, bigx, w, epsilon=epsilon) + # increase by 1 to have correct aic and sc, include rho in count + self.k += 1 + self.title = "MAXIMUM LIKELIHOOD SPATIAL LAG PANEL" + " - RANDOM EFFECTS" + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, bigx, constant=False) + name_ylag = USER.set_name_yend_sp(self.name_y) + self.name_x.append(name_ylag) # rho changed to last position + self.name_x.append("phi") # error variance parameter + self.name_w = USER.set_name_w(name_w, w) + self.aic = DIAG.akaike(reg=self) + self.schwarz = DIAG.schwarz(reg=self) + SUMMARY.Panel_FE_Lag(reg=self, w=w, vm=vm)
+ + +class BasePanel_RE_Error(RegressionPropsY, RegressionPropsVM): + + """ + Base ML method for a random effects spatial error model (note no + consistency checks, diagnostics or constants added) :cite:`Elhorst2003`. + + Parameters + ---------- + y : array + (n*t)x1 array for dependent variable + x : array + Two dimensional array with n*t rows and one column for each + independent (exogenous) variable + (note: must already include constant term) + w : pysal W object + Spatial weights matrix + epsilon : float + tolerance criterion in mimimize_scalar function and + inverse_product + + Attributes + ---------- + betas : array + kx1 array of estimated coefficients + lam : float + estimate of spatial autoregressive coefficient + sig2_u : float + Sigma squared for random effects + u : array + (nxt)x1 array of residuals + predy : array + (nxt)x1 array of predicted y values + n : integer + Total number of observations + t : integer + Number of time periods + k : integer + Number of variables for which coefficients are estimated + (no constant, excluding the lambda) + y : array + (nxt)x1 array for dependent variable + x : array + Two dimensional array with nxt rows and one column for each + independent (exogenous) variable, no constant + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (k+2 x k+2) + vm1 : array + Variance covariance matrix (k+3 x k+3) includes sigma2 + sig2 : float + Sigma squared used in computations + logll : float + maximized log-likelihood (including constant terms) + """ + + def __init__(self, y, x, w, epsilon=0.0000001): + # set up main regression variables and spatial filters + self.n = w.n + self.t = y.shape[0] // self.n + self.k = x.shape[1] + self.epsilon = epsilon + # Demeaned variables + self.y = y + self.x = x + # Big W matrix + W = w.full()[0] + Wsp = w.sparse + Wsp_nt = sp.kron(sp.identity(self.t), Wsp, format="csr") + # lag dependent variable + ylag = spdot(Wsp_nt, self.y) + xlag = spdot(Wsp_nt, self.x) + + # concentrated Log Likelihood + I = np.identity(self.n) + if w.asymmetry(intrinsic=False) == []: + ww = symmetrize(w) + WW = np.array(ww.todense()) + evals, evecs = la.eigh(WW) + W = WW + else: # need dense here + evals, evecs = la.eig(W) + one = np.ones((self.t, 1)) + J = (1 / self.t) * spdot(one, one.T) + Q = sp.kron(J, I, format="csr") + y_mean = spdot(Q, self.y) + x_mean = spdot(Q, self.x) + res = minimize( + err_c_loglik_ord, + (0.0, 0.1), + bounds=((-1.0, 1.0), (0.0, 10000.0)), + method="L-BFGS-B", + args=( + evals, + evecs, + self.n, + self.t, + self.y, + self.x, + ylag, + xlag, + y_mean, + x_mean, + I, + Wsp, + ), + ) + self.lam, self.phi = res.x + + # compute full log-likelihood + ln2pi = np.log(2.0 * np.pi) + self.logll = ( + -res.fun - (self.n * self.t) / 2.0 * ln2pi - (self.n * self.t) / 2.0 + ) + + # b, residuals and predicted values + cvals = self.t * self.phi ** 2 + 1 / (1 - self.lam * evals) ** 2 + P = spdot(np.diag(cvals ** (-0.5)), evecs.T) + pr = P - (I - self.lam * W) + pr_nt = sp.kron(sp.identity(self.t), pr, format="csr") + yrand = self.y + spdot(pr_nt, y_mean) + xrand = self.x + spdot(pr_nt, x_mean) + ys = yrand - self.lam * ylag + xs = xrand - self.lam * xlag + xsxs = spdot(xs.T, xs) + xsxsi = la.inv(xsxs) + xsys = spdot(xs.T, ys) + b = spdot(xsxsi, xsys) + + self.u = self.y - spdot(self.x, b) + self.predy = self.y - self.u + + # residual variance + self.e_filtered = ys - spdot(xs, b) + self.sig2 = spdot(self.e_filtered.T, self.e_filtered) / (self.n * self.t) + + # variance-covariance matrix betas + varb = self.sig2 * xsxsi + # variance of random effects + self.sig2_u = self.phi ** 2 * self.sig2 + + self.betas = np.vstack((b, self.lam, self.sig2_u)) + + # variance-covariance matrix lambda, sigma + a = -self.lam * W + spfill_diagonal(a, 1.0) + aTai = la.inv(spdot(a.T, a)) + wa_aw = spdot(W.T, a) + spdot(a.T, W) + gamma = spdot(wa_aw, aTai) + vi = la.inv(self.t * self.phi * I + aTai) + sigma = spdot(vi, aTai) + + tr1 = gamma.diagonal().sum() + tr2 = vi.diagonal().sum() + tr3 = sigma.diagonal().sum() + + sigma_gamma = spdot(sigma, gamma) + tr4 = sigma_gamma.diagonal().sum() + + sigma_vi = spdot(sigma, vi) + tr5 = sigma_vi.diagonal().sum() + + sigma_gamma_vi = spdot(sigma_gamma, vi) + tr6 = sigma_gamma_vi.diagonal().sum() + + sigma_gamma_sigma = spdot(sigma_gamma, sigma) + tr7 = sigma_gamma_sigma.diagonal().sum() + + v1 = np.vstack( + ( + (self.t - 1) / 2 * tr1 ** 2 + 1 / 2 * tr4 ** 2, + self.t / (2 * self.sig2) * tr6, + (self.t - 1) / (2 * self.sig2) * tr1 + 1 / (2 * self.sig2) * tr7, + ) + ) + v2 = np.vstack( + ( + self.t / (2 * self.sig2) * tr6, + self.t ** 2 / (2.0 * self.sig2 ** 2) * tr2 ** 2, + self.t / (2.0 * self.sig2 ** 2) * tr5, + ) + ) + v3 = np.vstack( + ( + (self.t - 1) / (2 * self.sig2) * tr1 + 1 / (2 * self.sig2) * tr7, + self.t / (2.0 * self.sig2 ** 2) * tr5, + 1 / (2.0 * self.sig2 ** 2) * ((self.t - 1) * self.n + tr3 ** 2), + ) + ) + + v = np.hstack((v1, v2, v3)) + + vm1 = np.linalg.inv(v) + + # create variance matrix for beta, lambda + vv = np.hstack((varb, np.zeros((self.k, 2)))) + vv1 = np.hstack((np.zeros((2, self.k)), vm1[:2, :2])) + + self.vm = np.vstack((vv, vv1)) + self.varb = varb + self.n = self.n * self.t + + +
[docs]class Panel_RE_Error(BasePanel_RE_Error): + + """ + ML estimation of the random effects spatial error model with all results and + diagnostics :cite:`Elhorst2003`. + + Parameters + ---------- + y : array + nxt or (nxt)x1 array for dependent variable + x : array + nx(txk) or (nxt)xk array for independent (exogenous) + variables, no constant + w : pysal W object + Spatial weights object + epsilon : float + tolerance criterion in mimimize_scalar function and + inverse_product + vm : boolean + if True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + + Attributes + ---------- + betas : array + kx1 array of estimated coefficients + lam : float + estimate of spatial autoregressive coefficient + sig2_u : float + Sigma squared for random effects + u : array + (nxt)x1 array of residuals + e_filtered : array + (nxt)x1 array of spatially filtered residuals + predy : array + (nxt)x1 array of predicted y values + n : integer + Total number of observations + t : integer + Number of time periods + k : integer + Number of variables for which coefficients are estimated + (no constant, excluding the lambda) + y : array + (nxt)x1 array for dependent variable + x : array + Two dimensional array with nxt rows and one column for each + independent (exogenous) variable, including the constant + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (k+2 x k+2), all coefficients + vm1 : array + Variance covariance matrix (k+3 x k+3), includes sig2 + sig2 : float + Sigma squared used in computations + logll : float + maximized log-likelihood (including constant terms) + aic : float + Akaike information criterion + schwarz : float + Schwarz criterion + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + utu : float + Sum of squared residuals + std_err : array + 1x(k+1) array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + >>> import numpy as np + >>> import pandas as pd + >>> import libpysal + >>> import spreg + >>> nat = libpysal.examples.load_example("NCOVR") + >>> db = libpysal.io.open(nat.get_path("NAT.dbf"), "r") + >>> nat_shp = libpysal.examples.get_path("NAT.shp") + >>> w_full = libpysal.weights.Queen.from_shapefile(nat_shp) + >>> name_y = ["HR70", "HR80", "HR90"] + >>> y_full = np.array([db.by_col(name) for name in name_y]).T + >>> name_x = ["RD70", "RD80", "RD90", "PS70", "PS80", "PS90"] + >>> x_full = np.array([db.by_col(name) for name in name_x]).T + >>> name_c = ["STATE_NAME", "FIPSNO"] + >>> df_counties = pd.DataFrame([db.by_col(name) for name in name_c], index=name_c).T + >>> filter_states = ["Kansas", "Missouri", "Oklahoma", "Arkansas"] + >>> filter_counties = df_counties[df_counties["STATE_NAME"].isin(filter_states)]["FIPSNO"].values + >>> counties = np.array(db.by_col("FIPSNO")) + >>> subid = np.where(np.isin(counties, filter_counties))[0] + >>> w = w_subset(w_full, subid) + >>> w.transform = 'r' + >>> y = y_full[subid, ] + >>> x = x_full[subid, ] + >>> re_error = spreg.Panel_RE_Error(y, x, w, name_y=name_y, name_x=name_x, name_ds="NAT") + Warning: Assuming panel is in wide format, i.e. y[:, 0] refers to T0, y[:, 1] refers to T1, etc. + Similarly, assuming x[:, 0:T] refers to T periods of k1, x[:, T+1:2T] refers to k2, etc. + >>> np.around(re_error.betas, decimals=4) + array([[5.87893756], + [3.23269025], + [2.62996804], + [0.34042682], + [4.9782446]]) + """ + +
[docs] def __init__( + self, + y, + x, + w, + epsilon=0.0000001, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + ): + n_rows = USER.check_arrays(y, x) + bigy, bigx, name_y, name_x, warn = check_panel(y, x, w, name_y, name_x) + set_warn(self, warn) + bigx, name_x, warn = USER.check_constant(bigx, name_x) + set_warn(self, warn) + USER.check_weights(w, bigy, w_required=True, time=True) + + BasePanel_RE_Error.__init__(self, bigy, bigx, w, epsilon=epsilon) + self.title = "MAXIMUM LIKELIHOOD SPATIAL ERROR PANEL" + " - RANDOM EFFECTS" + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, bigx, constant=False) + self.name_x.append("lambda") + self.name_x.append("sig2_u") # error variance parameter + self.name_w = USER.set_name_w(name_w, w) + self.aic = DIAG.akaike(reg=self) + self.schwarz = DIAG.schwarz(reg=self) + SUMMARY.Panel_FE_Error(reg=self, w=w, vm=vm)
+ + +def lag_c_loglik_sp(rho, n, t, e0, e1, I, Wsp): + # concentrated log-lik for lag model, sparse algebra + if isinstance(rho, np.ndarray): + if rho.shape == (1, 1): + rho = rho[0][0] + er = e0 - rho * e1 + sig2 = spdot(er.T, er) / (n * t) + nlsig2 = (n * t / 2.0) * np.log(sig2) + a = I - rho * Wsp + LU = SuperLU(a.tocsc()) + jacob = t * np.sum(np.log(np.abs(LU.U.diagonal()))) + clike = nlsig2 - jacob + return clike + + +def phi_c_loglik(phi, rho, beta, bigy, bigx, n, t, W_nt): + # Demeaned variables + y = demean_panel(bigy, n, t, phi=phi) + x = demean_panel(bigx, n, t, phi=phi) + # Lag dependent variable + ylag = spdot(W_nt, y) + er = y - rho * ylag - spdot(x, beta) + sig2 = spdot(er.T, er) + nlsig2 = (n * t / 2.0) * np.log(sig2) + nphi2 = (n / 2.0) * np.log(phi ** 2) + clike = nlsig2 - nphi2 + return clike + + +def err_c_loglik_ord( + lam_phi, evals, evecs, n, t, bigy, bigx, ylag, xlag, y_mean, x_mean, I, Wsp +): + # concentrated log-lik for error model, no constants, eigenvalues + lam, phi = lam_phi + cvals = t * phi ** 2 + 1 / (1 - lam * evals) ** 2 + P = spdot(np.diag(cvals ** (-0.5)), evecs.T) + pr = P - (I - lam * Wsp) + pr_nt = sp.kron(sp.identity(t), pr, format="csr") + # Term 1 + yrand = bigy + spdot(pr_nt, y_mean) + xrand = bigx + spdot(pr_nt, x_mean) + ys = yrand - lam * ylag + xs = xrand - lam * xlag + ysys = np.dot(ys.T, ys) + xsxs = np.dot(xs.T, xs) + xsxsi = la.inv(xsxs) + xsys = np.dot(xs.T, ys) + x1 = np.dot(xsxsi, xsys) + x2 = np.dot(xsys.T, x1) + ee = ysys - x2 + sig2 = ee[0][0] + nlsig2 = (n * t / 2.0) * np.log(sig2) + # Term 2 + revals = t * phi ** 2 * (1 - lam * evals) ** 2 + phi_jacob = 1 / 2 * np.log(1 + revals).sum() + # Term 3 + jacob = t * np.log(1 - lam * evals).sum() + if isinstance(jacob, complex): + jacob = jacob.real + # this is the negative of the concentrated log lik for minimization + clik = nlsig2 + phi_jacob - jacob + return clik +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/probit.html b/_modules/spreg/probit.html new file mode 100644 index 00000000..238a80a2 --- /dev/null +++ b/_modules/spreg/probit.html @@ -0,0 +1,1152 @@ + + + + + + + spreg.probit — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.probit

+"""Probit regression class and diagnostics."""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu, Pedro V. Amaral pedro.amaral@asu.edu"
+
+import numpy as np
+import numpy.linalg as la
+import scipy.optimize as op
+from scipy.stats import norm, chi2
+
+chisqprob = chi2.sf
+import scipy.sparse as SP
+from . import user_output as USER
+from . import summary_output as SUMMARY
+from .utils import spdot, spbroadcast, set_warn
+
+__all__ = ["Probit"]
+
+
+class BaseProbit(object):
+
+    """
+    Probit class to do all the computations
+
+    Parameters
+    ----------
+
+    x           : array
+                  nxk array of independent variables (assumed to be aligned with y)
+    y           : array
+                  nx1 array of dependent binary variable
+    w           : W
+                  PySAL weights instance or spatial weights sparse matrix
+                  aligned with y
+    optim       : string
+                  Optimization method.
+                  Default: 'newton' (Newton-Raphson).
+                  Alternatives: 'ncg' (Newton-CG), 'bfgs' (BFGS algorithm)
+    scalem      : string
+                  Method to calculate the scale of the marginal effects.
+                  Default: 'phimean' (Mean of individual marginal effects)
+                  Alternative: 'xmean' (Marginal effects at variables mean)
+    maxiter     : int
+                  Maximum number of iterations until optimizer stops
+
+    Attributes
+    ----------
+
+    x           : array
+                  Two dimensional array with n rows and one column for each
+                  independent (exogenous) variable, including the constant
+    y           : array
+                  nx1 array of dependent variable
+    betas       : array
+                  kx1 array with estimated coefficients
+    predy       : array
+                  nx1 array of predicted y values
+    n           : int
+                  Number of observations
+    k           : int
+                  Number of variables
+    vm          : array
+                  Variance-covariance matrix (kxk)
+    z_stat      : list of tuples
+                  z statistic; each tuple contains the pair (statistic,
+                  p-value), where each is a float
+    xmean       : array
+                  Mean of the independent variables (kx1)
+    predpc      : float
+                  Percent of y correctly predicted
+    logl        : float
+                  Log-Likelihhod of the estimation
+    scalem      : string
+                  Method to calculate the scale of the marginal effects.
+    scale       : float
+                  Scale of the marginal effects.
+    slopes      : array
+                  Marginal effects of the independent variables (k-1x1)
+                          Note: Disregards the presence of dummies.
+    slopes_vm   : array
+                  Variance-covariance matrix of the slopes (k-1xk-1)
+    LR          : tuple
+                  Likelihood Ratio test of all coefficients = 0
+                          (test statistics, p-value)
+    Pinkse_error: float
+                  Lagrange Multiplier test against spatial error correlation.
+                  Implemented as presented in :cite:`Pinkse2004`.
+    KP_error    : float
+                  Moran's I type test against spatial error correlation.
+                  Implemented as presented in  :cite:`Kelejian2001`.
+    PS_error    : float
+                  Lagrange Multiplier test against spatial error correlation.
+                  Implemented as presented in :cite:`Pinkse1998`.
+    warning     : boolean
+                  if True Maximum number of iterations exceeded or gradient
+                  and/or function calls not changing.
+
+    Examples
+    --------
+    >>> import numpy as np
+    >>> import libpysal
+    >>> import spreg
+    >>> np.set_printoptions(suppress=True) #prevent scientific format
+    >>> dbf = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r')
+    >>> y = np.array([dbf.by_col('CRIME')]).T
+    >>> x = np.array([dbf.by_col('INC'), dbf.by_col('HOVAL')]).T
+    >>> x = np.hstack((np.ones(y.shape),x))
+    >>> w = libpysal.io.open(libpysal.examples.get_path("columbus.gal"), 'r').read()
+    >>> w.transform='r'
+    >>> model = spreg.probit.BaseProbit((y>40).astype(float), x, w=w)
+    >>> print(np.around(model.betas, decimals=6))
+    [[ 3.353811]
+     [-0.199653]
+     [-0.029514]]
+
+    >>> print(np.around(model.vm, decimals=6))
+    [[ 0.852814 -0.043627 -0.008052]
+     [-0.043627  0.004114 -0.000193]
+     [-0.008052 -0.000193  0.00031 ]]
+
+    >>> tests = np.array([['Pinkse_error','KP_error','PS_error']])
+    >>> stats = np.array([[model.Pinkse_error[0],model.KP_error[0],model.PS_error[0]]])
+    >>> pvalue = np.array([[model.Pinkse_error[1],model.KP_error[1],model.PS_error[1]]])
+    >>> print(np.hstack((tests.T,np.around(np.hstack((stats.T,pvalue.T)),6))))
+    [['Pinkse_error' '3.131719' '0.076783']
+     ['KP_error' '1.721312' '0.085194']
+     ['PS_error' '2.558166' '0.109726']]
+    """
+
+    def __init__(self, y, x, w=None, optim="newton", scalem="phimean", maxiter=100):
+        self.y = y
+        self.x = x
+        self.n, self.k = x.shape
+        self.optim = optim
+        self.scalem = scalem
+        self.w = w
+        self.maxiter = maxiter
+        par_est, self.warning = self.par_est()
+        self.betas = np.reshape(par_est[0], (self.k, 1))
+        self.logl = -float(par_est[1])
+
+    @property
+    def vm(self):
+        try:
+            return self._cache["vm"]
+        except AttributeError:
+            self._cache = {}
+            H = self.hessian(self.betas)
+            self._cache["vm"] = -la.inv(H)
+        except KeyError:
+            H = self.hessian(self.betas)
+            self._cache["vm"] = -la.inv(H)
+        return self._cache["vm"]
+
+    @vm.setter
+    def vm(self, val):
+        try:
+            self._cache["vm"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["vm"] = val
+
+    @property  # could this get packaged into a separate function or something? It feels weird to duplicate this.
+    def z_stat(self):
+        try:
+            return self._cache["z_stat"]
+        except AttributeError:
+            self._cache = {}
+            variance = self.vm.diagonal()
+            zStat = (
+                self.betas.reshape(
+                    len(self.betas),
+                )
+                / np.sqrt(variance)
+            )
+            rs = {}
+            for i in range(len(self.betas)):
+                rs[i] = (zStat[i], norm.sf(abs(zStat[i])) * 2)
+            self._cache["z_stat"] = rs.values()
+        except KeyError:
+            variance = self.vm.diagonal()
+            zStat = (
+                self.betas.reshape(
+                    len(self.betas),
+                )
+                / np.sqrt(variance)
+            )
+            rs = {}
+            for i in range(len(self.betas)):
+                rs[i] = (zStat[i], norm.sf(abs(zStat[i])) * 2)
+            self._cache["z_stat"] = rs.values()
+        return self._cache["z_stat"]
+
+    @z_stat.setter
+    def z_stat(self, val):
+        try:
+            self._cache["z_stat"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["z_stat"] = val
+
+    @property
+    def slopes_std_err(self):
+        try:
+            return self._cache["slopes_std_err"]
+        except AttributeError:
+            self._cache = {}
+            self._cache["slopes_std_err"] = np.sqrt(self.slopes_vm.diagonal())
+        except KeyError:
+            self._cache["slopes_std_err"] = np.sqrt(self.slopes_vm.diagonal())
+        return self._cache["slopes_std_err"]
+
+    @slopes_std_err.setter
+    def slopes_std_err(self, val):
+        try:
+            self._cache["slopes_std_err"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["slopes_std_err"] = val
+
+    @property
+    def slopes_z_stat(self):
+        try:
+            return self._cache["slopes_z_stat"]
+        except AttributeError:
+            self._cache = {}
+            return self.slopes_z_stat
+        except KeyError:
+            zStat = (
+                self.slopes.reshape(
+                    len(self.slopes),
+                )
+                / self.slopes_std_err
+            )
+            rs = {}
+            for i in range(len(self.slopes)):
+                rs[i] = (zStat[i], norm.sf(abs(zStat[i])) * 2)
+            self._cache["slopes_z_stat"] = list(rs.values())
+        return self._cache["slopes_z_stat"]
+
+    @slopes_z_stat.setter
+    def slopes_z_stat(self, val):
+        try:
+            self._cache["slopes_z_stat"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["slopes_z_stat"] = val
+
+    @property
+    def xmean(self):
+        try:
+            return self._cache["xmean"]
+        except AttributeError:
+            self._cache = {}
+            try:  # why is this try-accept? can x be a list??
+                self._cache["xmean"] = np.reshape(sum(self.x) / self.n, (self.k, 1))
+            except:
+                self._cache["xmean"] = np.reshape(
+                    sum(self.x).toarray() / self.n, (self.k, 1)
+                )
+        except KeyError:
+            try:
+                self._cache["xmean"] = np.reshape(sum(self.x) / self.n, (self.k, 1))
+            except:
+                self._cache["xmean"] = np.reshape(
+                    sum(self.x).toarray() / self.n, (self.k, 1)
+                )
+        return self._cache["xmean"]
+
+    @xmean.setter
+    def xmean(self, val):
+        try:
+            self._cache["xmean"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["xmean"] = val
+
+    @property
+    def xb(self):
+        try:
+            return self._cache["xb"]
+        except AttributeError:
+            self._cache = {}
+            self._cache["xb"] = spdot(self.x, self.betas)
+        except KeyError:
+            self._cache["xb"] = spdot(self.x, self.betas)
+        return self._cache["xb"]
+
+    @xb.setter
+    def xb(self, val):
+        try:
+            self._cache["xb"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["xb"] = val
+
+    @property
+    def predy(self):
+        try:
+            return self._cache["predy"]
+        except AttributeError:
+            self._cache = {}
+            self._cache["predy"] = norm.cdf(self.xb)
+        except KeyError:
+            self._cache["predy"] = norm.cdf(self.xb)
+        return self._cache["predy"]
+
+    @predy.setter
+    def predy(self, val):
+        try:
+            self._cache["predy"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["predy"] = val
+
+    @property
+    def predpc(self):
+        try:
+            return self._cache["predpc"]
+        except AttributeError:
+            self._cache = {}
+            predpc = abs(self.y - self.predy)
+            for i in range(len(predpc)):
+                if predpc[i] > 0.5:
+                    predpc[i] = 0
+                else:
+                    predpc[i] = 1
+            self._cache["predpc"] = float(100.0 * np.sum(predpc) / self.n)
+        except KeyError:
+            predpc = abs(self.y - self.predy)
+            for i in range(len(predpc)):
+                if predpc[i] > 0.5:
+                    predpc[i] = 0
+                else:
+                    predpc[i] = 1
+            self._cache["predpc"] = float(100.0 * np.sum(predpc) / self.n)
+        return self._cache["predpc"]
+
+    @predpc.setter
+    def predpc(self, val):
+        try:
+            self._cache["predpc"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["predpc"] = val
+
+    @property
+    def phiy(self):
+        try:
+            return self._cache["phiy"]
+        except AttributeError:
+            self._cache = {}
+            self._cache["phiy"] = norm.pdf(self.xb)
+        except KeyError:
+            self._cache["phiy"] = norm.pdf(self.xb)
+        return self._cache["phiy"]
+
+    @phiy.setter
+    def phiy(self, val):
+        try:
+            self._cache["phiy"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["phiy"] = val
+
+    @property
+    def scale(self):
+        try:
+            return self._cache["scale"]
+        except AttributeError:
+            self._cache = {}
+            if self.scalem == "phimean":
+                self._cache["scale"] = float(1.0 * np.sum(self.phiy) / self.n)
+            elif self.scalem == "xmean":
+                self._cache["scale"] = float(norm.pdf(np.dot(self.xmean.T, self.betas)))
+        except KeyError:
+            if self.scalem == "phimean":
+                self._cache["scale"] = float(1.0 * np.sum(self.phiy) / self.n)
+            if self.scalem == "xmean":
+                self._cache["scale"] = float(norm.pdf(np.dot(self.xmean.T, self.betas)))
+        return self._cache["scale"]
+
+    @scale.setter
+    def scale(self, val):
+        try:
+            self._cache["scale"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["scale"] = val
+
+    @property
+    def slopes(self):
+        try:
+            return self._cache["slopes"]
+        except AttributeError:
+            self._cache = {}
+            self._cache["slopes"] = self.betas[1:] * self.scale
+        except KeyError:
+            self._cache["slopes"] = self.betas[1:] * self.scale
+        return self._cache["slopes"]
+
+    @slopes.setter
+    def slopes(self, val):
+        try:
+            self._cache["slopes"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["slopes"] = val
+
+    @property
+    def slopes_vm(self):
+        try:
+            return self._cache["slopes_vm"]
+        except AttributeError:
+            self._cache = {}
+            x = self.xmean
+            b = self.betas
+            dfdb = np.eye(self.k) - spdot(b.T, x) * spdot(b, x.T)
+            slopes_vm = (self.scale ** 2) * np.dot(np.dot(dfdb, self.vm), dfdb.T)
+            self._cache["slopes_vm"] = slopes_vm[1:, 1:]
+        except KeyError:
+            x = self.xmean
+            b = self.betas
+            dfdb = np.eye(self.k) - spdot(b.T, x) * spdot(b, x.T)
+            slopes_vm = (self.scale ** 2) * np.dot(np.dot(dfdb, self.vm), dfdb.T)
+            self._cache["slopes_vm"] = slopes_vm[1:, 1:]
+        return self._cache["slopes_vm"]
+
+    @slopes_vm.setter
+    def slopes_vm(self, val):
+        try:
+            self._cache["slopes_vm"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["slopes_vm"] = val
+
+    @property
+    def LR(self):
+        try:
+            return self._cache["LR"]
+        except AttributeError:
+            self._cache = {}
+            P = 1.0 * np.sum(self.y) / self.n
+            LR = float(
+                -2 * (self.n * (P * np.log(P) + (1 - P) * np.log(1 - P)) - self.logl)
+            )
+            self._cache["LR"] = (LR, chisqprob(LR, self.k))
+        except KeyError:
+            P = 1.0 * np.sum(self.y) / self.n
+            LR = float(
+                -2 * (self.n * (P * np.log(P) + (1 - P) * np.log(1 - P)) - self.logl)
+            )
+            self._cache["LR"] = (LR, chisqprob(LR, self.k))
+        return self._cache["LR"]
+
+    @LR.setter
+    def LR(self, val):
+        try:
+            self._cache["LR"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["LR"] = val
+
+    @property
+    def u_naive(self):
+        try:
+            return self._cache["u_naive"]
+        except AttributeError:
+            self._cache = {}
+            self._cache["u_naive"] = self.y - self.predy
+        except KeyError:
+            u_naive = self.y - self.predy
+            self._cache["u_naive"] = u_naive
+        return self._cache["u_naive"]
+
+    @u_naive.setter
+    def u_naive(self, val):
+        try:
+            self._cache["u_naive"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["u_naive"] = val
+
+    @property
+    def u_gen(self):
+        try:
+            return self._cache["u_gen"]
+        except AttributeError:
+            self._cache = {}
+            Phi_prod = self.predy * (1 - self.predy)
+            u_gen = self.phiy * (self.u_naive / Phi_prod)
+            self._cache["u_gen"] = u_gen
+        except KeyError:
+            Phi_prod = self.predy * (1 - self.predy)
+            u_gen = self.phiy * (self.u_naive / Phi_prod)
+            self._cache["u_gen"] = u_gen
+        return self._cache["u_gen"]
+
+    @u_gen.setter
+    def u_gen(self, val):
+        try:
+            self._cache["u_gen"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["u_gen"] = val
+
+    @property
+    def Pinkse_error(self):
+        try:
+            return self._cache["Pinkse_error"]
+        except AttributeError:
+            self._cache = {}
+            (
+                self._cache["Pinkse_error"],
+                self._cache["KP_error"],
+                self._cache["PS_error"],
+            ) = sp_tests(self)
+        except KeyError:
+            (
+                self._cache["Pinkse_error"],
+                self._cache["KP_error"],
+                self._cache["PS_error"],
+            ) = sp_tests(self)
+        return self._cache["Pinkse_error"]
+
+    @Pinkse_error.setter
+    def Pinkse_error(self, val):
+        try:
+            self._cache["Pinkse_error"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["Pinkse_error"] = val
+
+    @property
+    def KP_error(self):
+        try:
+            return self._cache["KP_error"]
+        except AttributeError:
+            self._cache = {}
+            (
+                self._cache["Pinkse_error"],
+                self._cache["KP_error"],
+                self._cache["PS_error"],
+            ) = sp_tests(self)
+        except KeyError:
+            (
+                self._cache["Pinkse_error"],
+                self._cache["KP_error"],
+                self._cache["PS_error"],
+            ) = sp_tests(self)
+        return self._cache["KP_error"]
+
+    @KP_error.setter
+    def KP_error(self, val):
+        try:
+            self._cache["KP_error"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["KP_error"] = val
+
+    @property
+    def PS_error(self):
+        try:
+            return self._cache["PS_error"]
+        except AttributeError:
+            self._cache = {}
+            (
+                self._cache["Pinkse_error"],
+                self._cache["KP_error"],
+                self._cache["PS_error"],
+            ) = sp_tests(self)
+        except KeyError:
+            (
+                self._cache["Pinkse_error"],
+                self._cache["KP_error"],
+                self._cache["PS_error"],
+            ) = sp_tests(self)
+        return self._cache["PS_error"]
+
+    @PS_error.setter
+    def PS_error(self, val):
+        try:
+            self._cache["PS_error"] = val
+        except AttributeError:
+            self._cache = {}
+        self._cache["PS_error"] = val
+
+    def par_est(self):
+        start = np.dot(la.inv(spdot(self.x.T, self.x)), spdot(self.x.T, self.y))
+        flogl = lambda par: -self.ll(par)
+        if self.optim == "newton":
+            fgrad = lambda par: self.gradient(par)
+            fhess = lambda par: self.hessian(par)
+            par_hat = newton(flogl, start, fgrad, fhess, self.maxiter)
+            warn = par_hat[2]
+        else:
+            fgrad = lambda par: -self.gradient(par)
+            if self.optim == "bfgs":
+                par_hat = op.fmin_bfgs(flogl, start, fgrad, full_output=1, disp=0)
+                warn = par_hat[6]
+            if self.optim == "ncg":
+                fhess = lambda par: -self.hessian(par)
+                par_hat = op.fmin_ncg(
+                    flogl, start, fgrad, fhess=fhess, full_output=1, disp=0
+                )
+                warn = par_hat[5]
+        if warn > 0:
+            warn = True
+        else:
+            warn = False
+        return par_hat, warn
+
+    def ll(self, par):
+        beta = np.reshape(np.array(par), (self.k, 1))
+        q = 2 * self.y - 1
+        qxb = q * spdot(self.x, beta)
+        ll = sum(np.log(norm.cdf(qxb)))
+        return ll
+
+    def gradient(self, par):
+        beta = np.reshape(np.array(par), (self.k, 1))
+        q = 2 * self.y - 1
+        qxb = q * spdot(self.x, beta)
+        lamb = q * norm.pdf(qxb) / norm.cdf(qxb)
+        gradient = spdot(lamb.T, self.x)[0]
+        return gradient
+
+    def hessian(self, par):
+        beta = np.reshape(np.array(par), (self.k, 1))
+        q = 2 * self.y - 1
+        xb = spdot(self.x, beta)
+        qxb = q * xb
+        lamb = q * norm.pdf(qxb) / norm.cdf(qxb)
+        hessian = spdot(self.x.T, spbroadcast(self.x, -lamb * (lamb + xb)))
+        return hessian
+
+
+
[docs]class Probit(BaseProbit): + + """ + Classic non-spatial Probit and spatial diagnostics. The class includes a + printout that formats all the results and tests in a nice format. + + The diagnostics for spatial dependence currently implemented are: + + * Pinkse Error :cite:`Pinkse2004` + + * Kelejian and Prucha Moran's I :cite:`Kelejian2001` + + * Pinkse & Slade Error :cite:`Pinkse1998` + + Parameters + ---------- + + x : array + nxk array of independent variables (assumed to be aligned with y) + y : array + nx1 array of dependent binary variable + w : W + PySAL weights instance aligned with y + optim : string + Optimization method. + Default: 'newton' (Newton-Raphson). + Alternatives: 'ncg' (Newton-CG), 'bfgs' (BFGS algorithm) + scalem : string + Method to calculate the scale of the marginal effects. + Default: 'phimean' (Mean of individual marginal effects) + Alternative: 'xmean' (Marginal effects at variables mean) + maxiter : int + Maximum number of iterations until optimizer stops + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + + Attributes + ---------- + + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + y : array + nx1 array of dependent variable + betas : array + kx1 array with estimated coefficients + predy : array + nx1 array of predicted y values + n : int + Number of observations + k : int + Number of variables + vm : array + Variance-covariance matrix (kxk) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + xmean : array + Mean of the independent variables (kx1) + predpc : float + Percent of y correctly predicted + logl : float + Log-Likelihhod of the estimation + scalem : string + Method to calculate the scale of the marginal effects. + scale : float + Scale of the marginal effects. + slopes : array + Marginal effects of the independent variables (k-1x1) + slopes_vm : array + Variance-covariance matrix of the slopes (k-1xk-1) + LR : tuple + Likelihood Ratio test of all coefficients = 0 + (test statistics, p-value) + Pinkse_error: float + Lagrange Multiplier test against spatial error correlation. + Implemented as presented in :cite:`Pinkse2004` + KP_error : float + Moran's I type test against spatial error correlation. + Implemented as presented in :cite:`Kelejian2001` + PS_error : float + Lagrange Multiplier test against spatial error correlation. + Implemented as presented in :cite:`Pinkse1998` + warning : boolean + if True Maximum number of iterations exceeded or gradient + and/or function calls not changing. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``libpysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> np.set_printoptions(suppress=True) #prevent scientific format + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> dbf = libpysal.io.open(libpysal.examples.get_path('columbus.dbf'),'r') + + Extract the CRIME column (crime) from the DBF file and make it the + dependent variable for the regression. Note that libpysal requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. Since we want to run a probit model and for this + example we use the Columbus data, we also need to transform the continuous + CRIME variable into a binary variable. As in :cite:`McMillen1992`, we define + y = 1 if CRIME > 40. + + >>> y = np.array([dbf.by_col('CRIME')]).T + >>> y = (y>40).astype(float) + + Extract HOVAL (home values) and INC (income) vectors from the DBF to be used as + independent variables in the regression. Note that libpysal requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this class adds a vector of ones to the + independent variables passed in. + + >>> names_to_extract = ['INC', 'HOVAL'] + >>> x = np.array([dbf.by_col(name) for name in names_to_extract]).T + + Since we want to the test the probit model for spatial dependence, we need to + specify the spatial weights matrix that includes the spatial configuration of + the observations into the error component of the model. To do that, we can open + an already existing gal file or create a new one. In this case, we will use + ``columbus.gal``, which contains contiguity relationships between the + observations in the Columbus dataset we are using throughout this example. + Note that, in order to read the file, not only to open it, we need to + append '.read()' at the end of the command. + + >>> w = libpysal.io.open(libpysal.examples.get_path("columbus.gal"), 'r').read() + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. In libpysal, this + can be easily performed in the following way: + + >>> w.transform='r' + + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import Probit + >>> model = Probit(y, x, w=w, name_y='crime', name_x=['income','home value'], name_ds='columbus', name_w='columbus.gal') + + Once we have run the model, we can explore a little bit the output. The + regression object we have created has many attributes so take your time to + discover them. + + >>> np.around(model.betas, decimals=6) + array([[ 3.353811], + [-0.199653], + [-0.029514]]) + + >>> np.around(model.vm, decimals=6) + array([[ 0.852814, -0.043627, -0.008052], + [-0.043627, 0.004114, -0.000193], + [-0.008052, -0.000193, 0.00031 ]]) + + Since we have provided a spatial weigths matrix, the diagnostics for + spatial dependence have also been computed. We can access them and their + p-values individually: + + >>> tests = np.array([['Pinkse_error','KP_error','PS_error']]) + >>> stats = np.array([[model.Pinkse_error[0],model.KP_error[0],model.PS_error[0]]]) + >>> pvalue = np.array([[model.Pinkse_error[1],model.KP_error[1],model.PS_error[1]]]) + >>> print(np.hstack((tests.T,np.around(np.hstack((stats.T,pvalue.T)),6)))) + [['Pinkse_error' '3.131719' '0.076783'] + ['KP_error' '1.721312' '0.085194'] + ['PS_error' '2.558166' '0.109726']] + + Or we can easily obtain a full summary of all the results nicely formatted and + ready to be printed simply by typing 'print model.summary' + + """ + +
[docs] def __init__( + self, + y, + x, + w=None, + optim="newton", + scalem="phimean", + maxiter=100, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + spat_diag=False, + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + if w != None: + USER.check_weights(w, y) + spat_diag = True + ws = w.sparse + else: + ws = None + x_constant, name_x, warn = USER.check_constant(x, name_x) + set_warn(self, warn) + + BaseProbit.__init__( + self, y=y, x=x_constant, w=ws, optim=optim, scalem=scalem, maxiter=maxiter + ) + self.title = "CLASSIC PROBIT ESTIMATOR" + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x) + self.name_w = USER.set_name_w(name_w, w) + SUMMARY.Probit(reg=self, w=w, vm=vm, spat_diag=spat_diag)
+ + +def newton(flogl, start, fgrad, fhess, maxiter): + """ + Calculates the Newton-Raphson method + + Parameters + ---------- + + flogl : lambda + Function to calculate the log-likelihood + start : array + kx1 array of starting values + fgrad : lambda + Function to calculate the gradient + fhess : lambda + Function to calculate the hessian + maxiter : int + Maximum number of iterations until optimizer stops + """ + warn = 0 + iteration = 0 + par_hat0 = start + m = 1 + while iteration < maxiter and m >= 1e-04: + H = -la.inv(fhess(par_hat0)) + g = fgrad(par_hat0).reshape(start.shape) + Hg = np.dot(H, g) + par_hat0 = par_hat0 + Hg + iteration += 1 + m = np.dot(g.T, Hg) + if iteration == maxiter: + warn = 1 + logl = flogl(par_hat0) + return (par_hat0, logl, warn) + + +def sp_tests(reg): + """ + Calculates tests for spatial dependence in Probit models + + Parameters + ---------- + reg : regression object + output instance from a probit model + """ + if reg.w != None: + try: + w = reg.w.sparse + except: + w = reg.w + Phi = reg.predy + phi = reg.phiy + # Pinkse_error: + Phi_prod = Phi * (1 - Phi) + u_naive = reg.u_naive + u_gen = reg.u_gen + sig2 = np.sum((phi * phi) / Phi_prod) / reg.n + LM_err_num = np.dot(u_gen.T, (w * u_gen)) ** 2 + trWW = np.sum((w * w).diagonal()) + trWWWWp = trWW + np.sum((w * w.T).diagonal()) + LM_err = float(1.0 * LM_err_num / (sig2 ** 2 * trWWWWp)) + LM_err = np.array([LM_err, chisqprob(LM_err, 1)]) + # KP_error: + moran = moran_KP(reg.w, u_naive, Phi_prod) + # Pinkse-Slade_error: + u_std = u_naive / np.sqrt(Phi_prod) + ps_num = np.dot(u_std.T, (w * u_std)) ** 2 + trWpW = np.sum((w.T * w).diagonal()) + ps = float(ps_num / (trWW + trWpW)) + # chi-square instead of bootstrap. + ps = np.array([ps, chisqprob(ps, 1)]) + else: + raise Exception("W matrix must be provided to calculate spatial tests.") + return LM_err, moran, ps + + +def moran_KP(w, u, sig2i): + """ + Calculates Moran-flavoured tests + + Parameters + ---------- + + w : W + PySAL weights instance aligned with y + u : array + nx1 array of naive residuals + sig2i : array + nx1 array of individual variance + """ + try: + w = w.sparse + except: + pass + moran_num = np.dot(u.T, (w * u)) + E = SP.lil_matrix(w.get_shape()) + E.setdiag(sig2i.flat) + E = E.asformat("csr") + WE = w * E + moran_den = np.sqrt(np.sum((WE * WE + (w.T * E) * WE).diagonal())) + moran = float(1.0 * moran_num / moran_den) + moran = np.array([moran, norm.sf(abs(moran)) * 2.0]) + return moran + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + import numpy as np + import libpysal + + dbf = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"), "r") + y = np.array([dbf.by_col("CRIME")]).T + var_x = ["INC", "HOVAL"] + x = np.array([dbf.by_col(name) for name in var_x]).T + w = libpysal.io.open(libpysal.examples.get_path("columbus.gal"), "r").read() + w.transform = "r" + probit1 = Probit( + (y > 40).astype(float), + x, + w=w, + name_x=var_x, + name_y="CRIME", + name_ds="Columbus", + name_w="columbus.dbf", + ) + print(probit1.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/skater_reg.html b/_modules/spreg/skater_reg.html new file mode 100644 index 00000000..9b0a0fbe --- /dev/null +++ b/_modules/spreg/skater_reg.html @@ -0,0 +1,813 @@ + + + + + + + spreg.skater_reg — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.skater_reg

+"""Skater Regression classes."""
+
+__author__ = "Luc Anselin anselin@uchicago.edu, Pedro Amaral pedroamaral@cedeplar.ufmg.br, Levi Wolf levi.john.wolf@bristol.ac.uk"
+
+from scipy.sparse import csgraph as cg
+from scipy.optimize import OptimizeWarning
+from scipy.spatial.distance import cdist
+from collections import namedtuple
+from warnings import warn
+from libpysal.weights import w_subset
+from .utils import set_endog
+import time
+import numpy as np
+import copy
+
+try:
+    from sklearn.metrics import euclidean_distances
+except ImportError:
+    from scipy.spatial.distance import pdist, cdist, squareform
+
+    def euclidean_distances(X, Y=None):
+        """
+        fallback function to compute pairwise euclidean distances
+        for a single input, or point-to-point euclidean distances
+        for two inputs.
+        """
+        if Y is None:
+            return squareform(pdist(X))
+        else:
+            return cdist(X, Y)
+
+
+__all__ = ["Skater_reg"]
+
+deletion = namedtuple("deletion", ("in_node", "out_node", "score"))
+
+
+
[docs]class Skater_reg(object): + """ + Initialize the Skater_reg algorithm based on :cite:`Anselin2021`. + The function can currently estimate OLS, from + spreg or stats_models, and Spatial Lag models from spreg. + Fit method performs estimation and returns a Skater_reg object. + + Parameters + ---------- + dissimilarity : a callable distance metric. + Default: sklearn.metrics.pairwise.euclidean_distances + affinity : a callable affinity metric between 0,1. + Will be inverted to provide a + dissimilarity metric. + reduction : the reduction applied over all clusters + to provide the map score. + Default: numpy.sum + center : way to compute the center of each region in attribute space + Default: numpy.mean + + NOTE: Optimization occurs with respect to a *dissimilarity* metric, so the reduction should + yield some kind of score where larger values are *less desirable* than smaller values. + Typically, this means we use addition. + + + Attributes + ---------- + coords : array-like + n*2, collection of n sets of (x,y) coordinates used for + calibration locations + y : array + n*1, dependent variable + X : array + n*k, independent variable, exlcuding the constant + bw : scalar + bandwidth value consisting of either a distance or N + nearest neighbors; user specified or obtained using + Sel_BW + family : family object + underlying probability model; provides + distribution-specific calculations + offset : array + n*1, the offset variable at the ith location. For Poisson model + this term is often the size of the population at risk or + the expected size of the outcome in spatial epidemiology + Default is None where Ni becomes 1.0 for all locations + sigma2_v1 : boolean + specify form of corrected denominator of sigma squared to use for + model diagnostics; Acceptable options are: + 'True': n-tr(S) (defualt) + 'False': n-2(tr(S)+tr(S'S)) + kernel : string + type of kernel function used to weight observations; + available options: + 'gaussian' + 'bisquare' + 'exponential' + fixed : boolean + True for distance based kernel function and False for + adaptive (nearest neighbor) kernel function (default) + constant : boolean + True to include intercept (default) in model and False to exclude + intercept + spherical : boolean + True for shperical coordinates (long-lat), + False for projected coordinates (defalut). + hat_matrix : boolean + True to store full n by n hat matrix, + False to not store full hat matrix to minimize memory footprint (defalut). + n : integer + number of observations + k : integer + number of independent variables + mean_y : float + mean of y + std_y : float + standard deviation of y + fit_params : dict + parameters passed into fit method to define estimation + routine + points : array-like + n*2, collection of n sets of (x,y) coordinates used for + calibration locations instead of all observations; + defaults to None unles specified in predict method + P : array + n*k, independent variables used to make prediction; + exlcuding the constant; default to None unless specified + in predict method + exog_scale : scalar + estimated scale using sampled locations; defualt is None + unless specified in predict method + exog_resid : array-like + estimated residuals using sampled locations; defualt is None + unless specified in predict method + Examples + -------- + >>> import libpysal as ps + >>> import numpy as np + >>> import spreg + >>> from spreg.skater_reg import Skater_reg + >>> data = ps.io.open(ps.examples.get_path('columbus.dbf')) + >>> y = np.array(data.by_col('HOVAL')).reshape((-1,1)) + >>> x_var = ['INC','CRIME'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + >>> w = ps.weights.Queen.from_shapefile(ps.examples.get_path("columbus.shp")) + >>> x_std = (x - np.mean(x,axis=0)) / np.std(x,axis=0) + >>> results = Skater_reg().fit(3, w, x_std, {'reg':spreg.OLS,'y':y,'x':x}, quorum=10, trace=False) + >>> results.current_labels_ + array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, + 0, 1, 0, 0, 2, 2, 0, 0, 1, 0, 2, 1, 2, 1, 2, 0, 1, 0, 0, 1, 2, 2, + 2, 1, 0, 2, 2], dtype=int32) + """ + +
[docs] def __init__( + self, + dissimilarity=euclidean_distances, + affinity=None, + reduction=np.sum, + center=np.mean, + ): + if affinity is not None: + # invert the 0,1 affinity to + # to an unbounded positive dissimilarity + metric = lambda x: -np.log(affinity(x)) + else: + metric = dissimilarity + self.metric = metric + self.reduction = reduction + self.center = center
+ + def __repr__(self): + return "Skater_reg_object(metric = {}, reduction = {}, center = {})".format( + self.metric, self.reduction, self.center + ) + +
[docs] def fit( + self, + n_clusters, + W, + data=None, + data_reg=None, + quorum=-np.inf, + trace=True, + islands="increase", + verbose=False, + model_family="spreg", + ): + """ + Method that fits a model with a particular estimation routine. + + Parameters + ---------- + n_clusters : int of clusters wanted + W : pysal W object expressing the neighbor relationships between observations. + Should be symmetric and binary, so Queen/Rook, DistanceBand, or a symmetrized KNN. + data : np.ndarray of (N,P) shape with N observations and P features + This is the data that is used to evaluate the similarity between each observation. + data_reg : list containing: + 1- a callable regression method (ex. OLS or GM_Lag from spreg or OLS from statsmodels) + 2- np.ndarray of (N,1) shape with N observations on the depedent variable for the regression + 3- np.ndarray of (N,k) shape with N observations and k columns containing the explanatory variables (constant must not be included) + 4- pysal W object to be used in the regression (optional) + quorum : int with minimum size of each region. + trace : bool denoting whether to store intermediate + labelings as the tree gets pruned + islands : string describing what to do with islands. + If "ignore", will discover `n_clusters` regions, treating islands as their own regions. + If "increase", will discover `n_clusters` regions, treating islands as separate from n_clusters. + verbose : bool/int describing how much output to provide to the user, + in terms of print statements or progressbars. + model_family : string describing the fFamily of estimation method used for the regression. + Must be either 'spreg' (default) or 'statsmodels' + + Returns + ------- + : Skater_reg object. + """ + if trace: + self._trace = [] + if data is None: + attribute_kernel = np.ones((W.n, W.n)) + data = np.ones((W.n, 1)) + else: + attribute_kernel = self.metric(data) + W.transform = "b" + W = W.sparse + start = time.time() + + super_verbose = verbose > 1 + start_W = time.time() + dissim = W.multiply(attribute_kernel) + dissim.eliminate_zeros() + end_W = time.time() - start_W + + if super_verbose: + print("Computing Affinity Kernel took {:.2f}s".format(end_W)) + + tree_time = time.time() + MSF = cg.minimum_spanning_tree(dissim) + tree_time = time.time() - tree_time + if super_verbose: + print("Computing initial MST took {:.2f}s".format(tree_time)) + + initial_component_time = time.time() + current_n_subtrees, current_labels = cg.connected_components( + MSF, directed=False + ) + initial_component_time = time.time() - initial_component_time + + if super_verbose: + print( + "Computing connected components took {:.2f}s.".format( + initial_component_time + ) + ) + + if current_n_subtrees > 1: + island_warnings = [ + "Increasing `n_clusters` from {} to {} in order to account for islands.".format( + n_clusters, n_clusters + current_n_subtrees + ), + "Counting islands towards the remaining {} clusters.".format( + n_clusters - (current_n_subtrees) + ), + ] + ignoring_islands = int(islands.lower() == "ignore") + chosen_warning = island_warnings[ignoring_islands] + warn( + "By default, the graph is disconnected! {}".format(chosen_warning), + OptimizeWarning, + stacklevel=2, + ) + if not ignoring_islands: + n_clusters += current_n_subtrees + _, island_populations = np.unique(current_labels, return_counts=True) + if (island_populations < quorum).any(): + raise ValueError( + "Islands must be larger than the quorum. If not, drop the small islands and solve for" + " clusters in the remaining field." + ) + if trace: + self._trace.append(([], deletion(np.nan, np.nan, np.inf))) + if super_verbose: + print(self._trace[-1]) + trees_scores = None + prev_score = np.inf + while current_n_subtrees < n_clusters: # while we don't have enough regions + ( + best_deletion, + trees_scores, + new_MSF, + current_n_subtrees, + current_labels, + ) = self.find_cut( + MSF, + data, + data_reg, + current_n_subtrees, + current_labels, + quorum=quorum, + trees_scores=trees_scores, + labels=None, + target_label=None, + verbose=verbose, + model_family=model_family, + ) + + if np.isfinite(best_deletion.score): # if our search succeeds + # accept the best move as *the* move + if super_verbose: + print("cut made {}...".format(best_deletion)) + if best_deletion.score > prev_score: + raise ValueError( + "The score increased with the number of clusters. Please check your data." + ) + prev_score = best_deletion.score + MSF = new_MSF + else: # otherwise, it means the MSF admits no further cuts + prev_n_subtrees, _ = cg.connected_components(MSF, directed=False) + warn( + "MSF contains no valid moves after finding {} subtrees. " + "Decrease the size of your quorum to find the remaining {} subtrees.".format( + prev_n_subtrees, n_clusters - prev_n_subtrees + ), + OptimizeWarning, + stacklevel=2, + ) + if trace: + self._trace.append((current_labels, best_deletion)) + + self.current_labels_ = current_labels + self.minimum_spanning_forest_ = MSF + self._elapsed_time = time.time() - start + return self
+ +
[docs] def score_spreg( + self, + data=None, + data_reg=None, + all_labels=None, + quorum=-np.inf, + current_labels=None, + current_tree=None, + ): + """ + This yields a score for the data using methods from the spreg library, given the labels provided. If no labels are provided, + and the object has been fit, then the labels discovered from the previous fit are used. + + If a quorum is not passed, it is assumed to be irrelevant. + + If a quorum is passed and the labels do not meet quorum, the score is inf. + + data : (N,P) array of data on which to compute the score of the regions expressed in labels + data_reg : list containing: + 1- a callable spreg regression method (ex. OLS or GM_Lag) + 2- np.ndarray of (N,1) shape with N observations on the depedent variable for the regression + 3- np.ndarray of (N,k) shape with N observations and k columns containing the explanatory variables (constant must not be included) + 4- pysal W object to be used in the regression (optional) + all_labels : (N,) flat vector of labels expressing the classification of each observation into a region considering the cut under evaluation. + quorum : int expressing the minimum size of regions. Can be -inf if there is no lower bound. + Any region below quorum makes the score inf. + current_labels: (N,) flat vector of labels expressing the classification of each observation into a region not considering the cut under evaluation. + + current_tree: integer indicating the tree label is currently being considered for division + """ + + labels, subtree_quorums = self._prep_score( + all_labels, current_tree, current_labels + ) + if (subtree_quorums < quorum).any(): + return np.inf, None + set_labels = set(labels) + if data_reg is not None: + kargs = { + k: v + for k, v in data_reg.items() + if k not in ["reg", "y", "x", "w", "x_nd"] + } + trees_scores = {} + l_arrays = np.array(all_labels) + w_regi_i = None + for l in set_labels: + x = data_reg["x"][all_labels == l] + if np.linalg.matrix_rank(x) < x.shape[1]: + x = np.delete( + x, np.nonzero(np.abs(np.diag(np.linalg.qr(x)[1])) < 1e-10), 1 + ) + + if "w" not in data_reg: + try: + x = np.hstack((np.ones((x.shape[0], 1)), x)) + reg = data_reg["reg"]( + y=data_reg["y"][all_labels == l], x=x, **kargs + ) + except np.linalg.LinAlgError: + x = np.delete(x, np.nonzero(np.ptp(x, axis=0) == 0), 1) + x = np.hstack((np.ones((x.shape[0], 1)), x)) + reg = data_reg["reg"]( + y=data_reg["y"][all_labels == l], x=x, **kargs + ) + + else: + regi_ids = list(np.where(l_arrays == l)[0]) + w_ids = list(map(data_reg["w"].id_order.__getitem__, regi_ids)) + w_regi_i = w_subset(data_reg["w"], w_ids, silence_warnings=True) + try: + x = np.hstack((np.ones((x.shape[0], 1)), x)) + reg = data_reg["reg"]( + y=data_reg["y"][all_labels == l], x=x, w=w_regi_i, **kargs + ) + except np.linalg.LinAlgError: + x = np.delete(x, np.nonzero(np.ptp(x, axis=0) == 0), 1) + reg = data_reg["reg"]( + y=data_reg["y"][all_labels == l], x=x, w=w_regi_i, **kargs + ) + trees_scores[l] = np.sum(reg.u ** 2) + score = sum(trees_scores.values()) + else: + part_scores, score, trees_scores = self._data_reg_none( + data, all_labels, l, set_labels + ) + + return score, trees_scores
+ +
[docs] def score_stats( + self, + data=None, + data_reg=None, + all_labels=None, + quorum=-np.inf, + current_labels=None, + current_tree=None, + ): + """ + This yields a score for the data using methods from the stats_models library, given the labels provided. If no labels are provided, + and the object has been fit, then the labels discovered from the previous fit are used. + + If a quorum is not passed, it is assumed to be irrelevant. + + If a quorum is passed and the labels do not meet quorum, the score is inf. + + data : (N,P) array of data on which to compute the score of the regions expressed in labels + data_reg : list containing: + 1- a callable statsmodels regression method (ex. OLS) + 2- np.ndarray of (N,1) shape with N observations on the depedent variable for the regression + 3- np.ndarray of (N,k) shape with N observations and k columns containing the explanatory variables (constant must not be included) + 4- pysal W object to be used in the regression (optional) + all_labels : (N,) flat vector of labels expressing the classification of each observation into a region considering the cut under evaluation. + quorum : int expressing the minimum size of regions. Can be -inf if there is no lower bound. + Any region below quorum makes the score inf. + current_labels: (N,) flat vector of labels expressing the classification of each observation into a region not considering the cut under evaluation. + + current_tree: integer indicating the tree label is currently being considered for division + + NOTE: Optimization occurs with respect to a *dissimilarity* metric, so the problem *minimizes* + the map dissimilarity. So, lower scores are better. + """ + labels, subtree_quorums = self._prep_score( + all_labels, current_tree, current_labels + ) + if (subtree_quorums < quorum).any(): + return np.inf, None + set_labels = set(labels) + if data_reg is not None: + kargs = { + k: v + for k, v in data_reg.items() + if k not in ["reg", "y", "x", "w", "x_nd"] + } + trees_scores = {} + l_arrays = np.array(all_labels) + w_regi_i = None + for l in set_labels: + x = data_reg["x"][all_labels == l] + if np.linalg.matrix_rank(x) < x.shape[1]: + x = np.delete( + x, np.nonzero(np.abs(np.diag(np.linalg.qr(x)[1])) < 1e-10), 1 + ) + + try: + x = np.hstack((np.ones((x.shape[0], 1)), x)) + reg = data_reg["reg"]( + data_reg["y"][all_labels == l], x, **kargs + ).fit() + except np.linalg.LinAlgError: + x = np.delete(x, np.nonzero(np.ptp(x, axis=0) == 0), 1) + x = np.hstack((np.ones((x.shape[0], 1)), x)) + reg = data_reg["reg"]( + data_reg["y"][all_labels == l], x, **kargs + ).fit() + + trees_scores[l] = np.sum(reg.resid ** 2) + score = sum(trees_scores.values()) + else: + part_scores, score, trees_scores = self._data_reg_none( + data, all_labels, l, set_labels + ) + return score, trees_scores
+ + def _prep_score(self, all_labels, current_tree, current_labels): + if all_labels is None: + try: + labels = self.current_labels_ + except AttributeError: + raise ValueError( + "Labels not provided and MSF_Prune object has not been fit to data yet." + ) + if current_tree is not None: + labels = all_labels[current_labels == current_tree] + _, subtree_quorums = np.unique(labels, return_counts=True) + return labels, subtree_quorums + + def _data_reg_none(self, data, all_labels, l, set_labels): + assert data.shape[0] == len( + all_labels + ), "Length of label array ({}) does not match " "length of data ({})! ".format( + all_labels.shape[0], data.shape[0] + ) + part_scores = [ + self.reduction( + self.metric( + X=data[all_labels == l], + Y=self.center(data[all_labels == l], axis=0).reshape(1, -1), + ) + ) + for l in set_labels + ] + + score = self.reduction(part_scores).item() + trees_scores = {l: part_scores[i] for i, l in enumerate(set_labels)} + return part_scores, score, trees_scores + +
[docs] def find_cut( + self, + MSF, + data=None, + data_reg=None, + current_n_subtrees=None, + current_labels=None, + quorum=-np.inf, + trees_scores=None, + labels=None, + target_label=None, + make=False, + verbose=False, + model_family="spreg", + ): + """ + Find the best cut from the MSF. + + MSF: (N,N) scipy sparse matrix with zero elements removed. + Represents the adjacency matrix for the minimum spanning forest. + Constructed from sparse.csgraph.sparse_from_dense or using MSF.eliminate_zeros(). + You MUST remove zero entries for this to work, otherwise they are considered no-cost paths. + data: (N,p) attribute matrix. If not provided, replaced with (N,1) vector of ones. + data_reg: optional list containing: + 1- a callable spreg or statsmodels regression method (ex. OLS or GM_Lag) + 2- np.ndarray of (N,1) shape with N observations on the depedent variable for the regression + 3- np.ndarray of (N,k) shape with N observations and k columns containing the explanatory variables (constant must not be included) + 4- pysal W object to be used in the regression (optional) + current_n_subtrees: integer indication the current number of subtrees. + current_labels: (N,) flat vector of labels expressing the classification of each observation into a region not considering the cut under evaluation. + quorum: int denoting the minimum number of elements in the region + trees_scores: dictionary indicating subtress's labels and their respective current score. + labels: (N,) flat vector of labels for each point. Represents the "cluster labels" + for disconnected components of the graph. + target_label: int from the labels array to subset the MSF. If passed along with `labels`, then a cut + will be found that is restricted to that subset of the MSF. + make: bool, whether or not to modify the input MSF in order to make the best cut that was found. + verbose: bool/int, denoting how much output to provide to the user, in terms + of print statements or progressbars + + Returns a namedtuple with in_node, out_node, and score. + """ + if data is None: + data = np.ones(MSF.shape) + + if (labels is None) != (target_label is None): + raise ValueError( + "Both labels and target_label must be supplied! Only {} provided.".format( + ["labels", "target_label"][int(target_label is None)] + ) + ) + if verbose: + try: + from tqdm import tqdm + except ImportError: + + def tqdm(noop, desc=""): + return noop + + else: + + def tqdm(noop, desc=""): + return noop + + zero_in = (labels is not None) and (target_label is not None) + best_deletion = deletion(np.nan, np.nan, np.inf) + best_d_score = -np.inf + try: + old_score = sum(trees_scores.values()) + except: + pass + best_scores = {} + current_list = current_labels.tolist() + for in_node, out_node in tqdm( + np.vstack(MSF.nonzero()).T, desc="finding cut..." + ): # iterate over MSF edges + if zero_in: + if labels[in_node] != target_label: + continue + + local_MSF = copy.deepcopy(MSF) + # delete a candidate edge + local_MSF[in_node, out_node] = 0 + local_MSF.eliminate_zeros() + current_tree = current_labels[in_node] + + # get the connected components + local_n_subtrees, local_labels = cg.connected_components( + local_MSF, directed=False + ) + + if local_n_subtrees <= current_n_subtrees: + raise Exception("Malformed MSF!") + + # compute the score of these components + if model_family == "spreg": + new_score, new_trees_scores = self.score_spreg( + data, data_reg, local_labels, quorum, current_labels, current_tree + ) + elif model_family == "statsmodels": + new_score, new_trees_scores = self.score_stats( + data, data_reg, local_labels, quorum, current_labels, current_tree + ) + else: + raise ValueError("Model family must be either spreg or statsmodels.") + + if np.isfinite(new_score): + try: + d_score = trees_scores[current_tree] - new_score + score = old_score - d_score + except: + d_score = -new_score + score = new_score + # if the d_score is greater than the best score and quorum is met + if d_score > best_d_score: + best_deletion = deletion(in_node, out_node, score) + best_d_score = d_score + try: + for i in set(current_labels): + best_scores[ + local_labels[current_list.index(i)] + ] = trees_scores[i] + for i in new_trees_scores: + best_scores[i] = new_trees_scores[i] + except: + best_scores = new_trees_scores + best_MSF = local_MSF + best_labels = local_labels + try: + return best_deletion, best_scores, best_MSF, local_n_subtrees, best_labels + except UnboundLocalError: # in case no solution is found + return deletion(None, None, np.inf), np.inf, None, np.inf, None
+ + +def _const_x(x): + x = np.delete(x, np.nonzero(np.ptp(x, axis=0) == 0), 1) + x = np.hstack((np.ones((x.shape[0], 1)), x)) + return x +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/sp_panels.html b/_modules/spreg/sp_panels.html new file mode 100644 index 00000000..06297b2c --- /dev/null +++ b/_modules/spreg/sp_panels.html @@ -0,0 +1,676 @@ + + + + + + + spreg.sp_panels — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.sp_panels

+"""
+Spatial random effects panel model based on: :cite:`KKP2007`
+"""
+
+__author__ = (
+    "Luc Anselin anselin@uchicago.edu, Pedro Amaral pedroamaral@cedeplar.ufmg.br"
+)
+
+from scipy import sparse as SP
+import numpy as np
+from . import ols as OLS
+from .utils import optim_moments, RegressionPropsY, get_spFilter, spdot, set_warn
+from . import user_output as USER
+from . import summary_output as SUMMARY
+from . import regimes as REGI
+
+# import warnings
+
+
+__all__ = ["GM_KKP"]
+
+
+class BaseGM_KKP(RegressionPropsY):
+
+    '''
+    Base GMM method for a spatial random effects panel model based on
+    Kapoor, Kelejian and Prucha (2007) :cite:`KKP2007`.
+
+    Parameters
+    ----------
+    y          : array
+                 n*tx1 array for dependent variable
+    x          : array
+                 Two dimensional array with n*t rows and one column for each
+                 independent (exogenous) variable
+                 (note: must already include constant term)
+    w          : spatial weights object
+                 Spatial weights matrix
+    full_weights: boolean
+                  Considers different weights for each of the 6 moment
+                  conditions if True or only 2 sets of weights for the
+                  first 3 and the last 3 monent conditions if False (default)
+
+    Attributes
+    ----------
+    betas        : array
+                   kx1 array of estimated coefficients
+    u            : array
+                   nx1 array of residuals
+    e_filtered   : array
+                   nx1 array of spatially filtered residuals
+    predy        : array
+                   nx1 array of predicted y values
+    n            : integer
+                   Number of observations
+    t            : integer
+                   Number of time periods
+    k            : integer
+                   Number of variables for which coefficients are estimated
+                   (including the constant)
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, including the constant
+    vm           : array
+                   Variance covariance matrix (kxk)
+    """
+    '''
+
+    def __init__(self, y, x, w, full_weights=False):
+
+        # 1a. OLS --> \tilde{\delta}
+        ols = OLS.BaseOLS(y=y, x=x)
+        self.x, self.y, self.n, self.k, self.xtx = ols.x, ols.y, ols.n, ols.k, ols.xtx
+        N = w.n
+        T = y.shape[0] // N
+        moments, trace_w2 = _moments_kkp(w.sparse, ols.u, 0)
+        lambda1, sig_v = optim_moments(moments, all_par=True)
+        Tw = SP.kron(SP.identity(T), w.sparse)
+        ub = Tw.dot(ols.u)
+        ulu = ols.u - lambda1 * ub
+        Q1 = SP.kron(np.ones((T, T)) / T, SP.identity(N))
+        sig_1 = float(np.dot(ulu.T, Q1.dot(ulu)) / N)
+        # print('initial_lamb_sig:',lambda1,sig_v,sig_1)
+        # print('theta:', 1 - np.sqrt(sig_v)/ np.sqrt(sig_1))
+        Xi_a = SP.diags([(sig_v * sig_v) / (T - 1), sig_1 * sig_1])
+        if full_weights:
+            Tau = _get_Tau(w.sparse, trace_w2)
+        else:
+            Tau = SP.identity(3)
+        Xi = SP.kron(Xi_a, Tau)
+        moments_b, _ = _moments_kkp(w.sparse, ols.u, 1, trace_w2)
+        G = np.vstack((np.hstack((moments[0], np.zeros((3, 1)))), moments_b[0]))
+        moments6 = [G, np.vstack((moments[1], moments_b[1]))]
+        lambda2, sig_vb, sig_1b = optim_moments(
+            moments6, vcX=Xi.toarray(), all_par=True, start=[lambda1, sig_v, sig_1]
+        )
+        # 2a. reg -->\hat{betas}
+        theta = 1 - np.sqrt(sig_vb) / np.sqrt(sig_1b)
+        # print('theta:', theta)
+        gls_w = SP.identity(N * T) - theta * Q1
+
+        # With omega
+        xs = gls_w.dot(get_spFilter(w, lambda2, x))
+        ys = gls_w.dot(get_spFilter(w, lambda2, y))
+        ols_s = OLS.BaseOLS(y=ys, x=xs)
+        self.predy = spdot(self.x, ols_s.betas)
+        self.u = self.y - self.predy
+        self.vm = ols_s.vm  # Check
+        self.betas = np.vstack((ols_s.betas, lambda2, sig_vb, sig_1b))
+        self.e_filtered = self.u - lambda2 * SP.kron(SP.identity(T), w.sparse).dot(
+            self.u
+        )
+        self.t, self.n = T, N
+        self._cache = {}
+
+
+
[docs]class GM_KKP(BaseGM_KKP, REGI.Regimes_Frame): + + ''' + GMM method for a spatial random effects panel model based on + Kapoor, Kelejian and Prucha (2007) :cite:`KKP2007`. + + Parameters + ---------- + y : array + n*tx1 or nxt array for dependent variable + x : array + Two dimensional array with n*t rows and k columns for + independent (exogenous) variable or n rows and k*t columns + (note, must not include a constant term) + w : spatial weights object + Spatial weights matrix, nxn + full_weights: boolean + Considers different weights for each of the 6 moment + conditions if True or only 2 sets of weights for the + first 3 and the last 3 moment conditions if False (default) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'y'. + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string or list of strings + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + + Attributes + ---------- + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_filtered : array + nx1 array of spatially filtered residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + t : integer + Number of time periods + k : integer + Number of variables for which coefficients are estimated + (including the constant) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + vm : array + Variance covariance matrix (kxk) + chow : tuple + Contains 2 elements. 1: Pair of Wald statistic and p-value + for the setup of global regime stability. 2: array with Wald + statistic (col 0) and its p-value (col 1) for each beta that + varies across regimes. + Exists only if regimes is not None. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_w : string + Name of weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regime variable for use in the output + title : string + Name of the regression method used + """ + Examples + -------- + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + >>> from spreg import GM_KKP + >>> import numpy as np + >>> import libpysal + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; The GM_KKP function requires + data to be passed in as numpy arrays, hence the user can read their + data in using any method. + >>> nat = libpysal.examples.load_example('NCOVR') + >>> db = libpysal.io.open(nat.get_path("NAT.dbf"),'r') + Extract the HR (homicide rates) data in the 70's, 80's and 90's from the DBF file + and make it the dependent variable for the regression. Note that the data can also + be passed in the long format instead of wide format (i.e. a vector with n*t rows + and a single column for the dependent variable and a matrix of dimension n*txk + for the independent variables). + >>> name_y = ['HR70','HR80','HR90'] + >>> y = np.array([db.by_col(name) for name in name_y]).T + Extract RD and PS in the same time periods from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxk*t numpy array, where k is the number of independent variables (not + including a constant) and t is the number of time periods. Data must be + organized in a way that all time periods of a given variable are side-by-side + and in the correct time order. + By default a vector of ones will be added to the independent variables passed in. + >>> name_x = ['RD70','RD80','RD90','PS70','PS80','PS90'] + >>> x = np.array([db.by_col(name) for name in name_x]).T + Since we want to run a spatial error panel model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``NAT.shp``. + >>> w = libpysal.weights.Queen.from_shapefile(libpysal.examples.get_path("NAT.shp")) + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, his allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + >>> w.transform = 'r' + We are all set with the preliminaries, we are good to run the model. In this + case, we will need the variables and the weights matrix. If we want to + have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. In this example + we set full_weights to False (the default), indicating that we will use + only 2 sets of moments weights for the first 3 and the last 3 moment conditions. + >>> reg = GM_KKP(y,x,w,full_weights=False,name_y=name_y, name_x=name_x) + Warning: Assuming time data is in wide format, i.e. y[0] refers to T0, y[1], refers to T1, etc. + Similarly, assuming x[0:k] refers to independent variables for T0, x[k+1:2k] refers to T1, etc. + Once we have run the model, we can explore a little bit the output. We can + either request a printout of the results with the command print(reg.summary) or + check out the individual attributes of GM_KKP: + >>> print(reg.summary) + REGRESSION + ---------- + SUMMARY OF OUTPUT: GM SPATIAL ERROR PANEL MODEL - RANDOM EFFECTS (KKP) + ---------------------------------------------------------------------- + Data set : unknown + Weights matrix : unknown + Dependent Variable : HR Number of Observations: 3085 + Mean dependent var : 6.4983 Number of Variables : 3 + S.D. dependent var : 6.9529 Degrees of Freedom : 3082 + Pseudo R-squared : 0.3248 + <BLANKLINE> + ------------------------------------------------------------------------------------ + Variable Coefficient Std.Error z-Statistic Probability + ------------------------------------------------------------------------------------ + CONSTANT 6.4922156 0.1126713 57.6208690 0.0000000 + RD 3.6244575 0.0877475 41.3055536 0.0000000 + PS 1.3118778 0.0852516 15.3883058 0.0000000 + lambda 0.4177759 + sigma2_v 22.8190822 + sigma2_1 39.9099323 + ------------------------------------------------------------------------------------ + ================================ END OF REPORT ===================================== + >>> print(reg.name_x) + ['CONSTANT', 'RD', 'PS', 'lambda', ' sigma2_v', 'sigma2_1'] + The attribute reg.betas contains all the coefficients: betas, the spatial error + coefficient lambda, sig2_v and sig2_1: + >>> print(np.around(reg.betas,4)) + [[ 6.4922] + [ 3.6245] + [ 1.3119] + [ 0.4178] + [22.8191] + [39.9099]] + Finally, we can check the standard erros of the betas: + >>> print(np.around(np.sqrt(reg.vm.diagonal().reshape(3,1)),4)) + [[0.1127] + [0.0877] + [0.0853]] + ''' + +
[docs] def __init__( + self, + y, + x, + w, + full_weights=False, + regimes=None, + vm=False, + name_y=None, + name_x=None, + name_w=None, + name_ds=None, + name_regimes=None, + ): + n_rows = USER.check_arrays(y, x) + bigy, bigx, name_y, name_x = _get_panel_data(y, x, w, name_y, name_x) + USER.check_weights(w, bigy, w_required=True, time=True) + x_constant, name_x, warn = USER.check_constant(bigx, name_x) + set_warn(self, warn) + self.title = "GM SPATIAL ERROR PANEL MODEL - RANDOM EFFECTS (KKP)" + self.name_x = USER.set_name_x(name_x, x_constant) + + if regimes is not None: + self.regimes = regimes + self.name_regimes = USER.set_name_ds(name_regimes) + regimes_l = self._set_regimes(w, bigy.shape[0]) + self.name_x_r = self.name_x + x_constant, self.name_x = REGI.Regimes_Frame.__init__( + self, + x_constant, + regimes_l, + constant_regi=False, + cols2regi="all", + names=self.name_x, + ) + + BaseGM_KKP.__init__(self, bigy, x_constant, w, full_weights=full_weights) + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x.extend(["lambda", " sigma2_v", "sigma2_1"]) + self.name_w = USER.set_name_w(name_w, w) + if regimes is not None: + self.kf += 3 + self.chow = REGI.Chow(self) + self.title += " WITH REGIMES" + regimes = True + SUMMARY.GM_Panels(reg=self, w=w, vm=vm, regimes=regimes)
+ + def _set_regimes(self, w, n_rows): # Must add case for regime_err_sep = True + self.constant_regi = "many" + self.cols2regi = "all" + self.regime_err_sep = False + self.regimes_set = REGI._get_regimes_set(self.regimes) + if len(self.regimes) == w.n: + regimes_l = self.regimes * (n_rows // w.n) + elif len(self.regimes) == n_rows: + regimes_l = self.regimes + else: + raise Exception("The lenght of 'regimes' must be either equal to n or n*t.") + return regimes_l
+ + +def _moments_kkp(ws, u, i, trace_w2=None): + """ + Compute G and g matrices for the KKP model. + ... + + Parameters + ---------- + ws : Sparse matrix + Spatial weights sparse matrix + u : array + Residuals. nx1 array assumed to be aligned with w + + i : integer + 0 if Q0, 1 if Q1 + trace_w2 : float + trace of WW. Computed in 1st step and saved for step 2. + Returns + ------- + moments : list + List of two arrays corresponding to the matrices 'G' and + 'g', respectively. + trace_w2 : float + trace of WW. Computed in 1st step and saved for step 2. + """ + N = ws.shape[0] + T = u.shape[0] // N + if i == 0: + Q = SP.kron(SP.identity(T) - np.ones((T, T)) / T, SP.identity(N)) + else: + Q = SP.kron(np.ones((T, T)) / T, SP.identity(N)) + Tw = SP.kron(SP.identity(T), ws) + ub = Tw.dot(u) + ubb = Tw.dot(ub) + Qu = Q.dot(u) + Qub = Q.dot(ub) + Qubb = Q.dot(ubb) + G11 = float(2 * np.dot(u.T, Qub)) + G12 = float(-np.dot(ub.T, Qub)) + G21 = float(2 * np.dot(ubb.T, Qub)) + G22 = float(-np.dot(ubb.T, Qubb)) + G31 = float(np.dot(u.T, Qubb) + np.dot(ub.T, Qub)) + G32 = float(-np.dot(ub.T, Qubb)) + if trace_w2 == None: + trace_w2 = (ws.power(2)).sum() + G23 = ((T - 1) ** (1 - i)) * trace_w2 + if i == 0: + G = np.array( + [[G11, G12, N * (T - 1) ** (1 - i)], [G21, G22, G23], [G31, G32, 0]] + ) / (N * (T - 1) ** (1 - i)) + else: + G = np.array( + [ + [G11, G12, 0, N * (T - 1) ** (1 - i)], + [G21, G22, 0, G23], + [G31, G32, 0, 0], + ] + ) / (N * (T - 1) ** (1 - i)) + g1 = float(np.dot(u.T, Qu)) + g2 = float(np.dot(ub.T, Qub)) + g3 = float(np.dot(u.T, Qub)) + g = np.array([[g1, g2, g3]]).T / (N * (T - 1) ** (1 - i)) + return [G, g], trace_w2 + + +def _get_Tau(ws, trace_w2): + """ + Computes Tau as in :cite:`KKP2007`. + ... + + Parameters + ---------- + ws : Sparse matrix + Spatial weights sparse matrix + trace_w2 : float + trace of WW. Computed in 1st step of _moments_kkp + """ + N = ws.shape[0] + T12 = 2 * trace_w2 / N + wtw = ws.T.dot(ws) + T22 = wtw.power(2).sum() + wtpw = ws.T + ws + T23 = wtw.multiply(wtpw).sum() + d_wwpwtw = ws.multiply(ws.T).sum(0) + wtw.diagonal() + T33 = d_wwpwtw.sum() + Tau = np.array([[2 * N, T12, 0], [T12, T22, T23], [0, T23, T33]]) / N + return Tau + + +def _get_panel_data(y, x, w, name_y, name_x): + """ + Performs some checks on the data structure and converts from wide to long if needed. + ... + + Parameters + ---------- + y : array + n*tx1 or nxt array for dependent variable + x : array + Two dimensional array with n*t rows and k columns for + independent (exogenous) variable or n rows and k*t columns + (note, must not include a constant term) + name_y : string or list of strings + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + """ + + if y.shape[0] / w.n != y.shape[0] // w.n: + raise Exception("y must be ntx1 or nxt, and w must be an nxn PySAL W object.") + N, T = y.shape[0], y.shape[1] + k = x.shape[1] // T + if x.shape[0] != N and x.shape[0] != N * T: + raise Exception( + "X must have either n rows and k*t columns or n*t rows and k columns." + ) + if x.shape[1] != k and x.shape[1] != k * T: + raise Exception( + "X must have either n rows and k*t columns or n*t rows and k columns." + ) + if y.shape[1] > 1: + message = ( + "Assuming time data is in wide format, i.e. y[0] refers to T0, y[1], refers to T1, etc." + "\n Similarly, assuming x[0:k] refers to independent variables for T0, x[k+1:2k] refers to T1, etc." + ) + print("Warning: " + message) + # warnings.warn(message) + + if y.shape[1] != T: + raise Exception( + "y in wide format must have t columns and be compatible with x's k*t columns." + ) + + bigy = y.reshape((y.size, 1), order="F") + + bigx = x[:, 0:T].reshape((N * T, 1), order="F") + for i in range(1, k): + bigx = np.hstack( + (bigx, x[:, T * i : T * (i + 1)].reshape((N * T, 1), order="F")) + ) + else: + bigy, bigx = y, x + + if name_y: + if not isinstance(name_y, str) and not isinstance(name_y, list): + raise Exception("name_y must either be strings or a list of strings.") + if len(name_y) > 1 and isinstance(name_y, list): + name_y = "".join([i for i in name_y[0] if not i.isdigit()]) + if len(name_y) == 1 and isinstance(name_y, list): + name_y = name_y[0] + if name_x: + if len(name_x) != k * T and len(name_x) != k: + raise Exception( + "Names of columns in X must have exactly either k or k*t elements." + ) + if len(name_x) > k: + name_bigx = [] + for i in range(k): + name_bigx.append("".join([j for j in name_x[i * T] if not j.isdigit()])) + name_x = name_bigx + + return bigy, bigx, name_y, name_x + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/sur.html b/_modules/spreg/sur.html new file mode 100644 index 00000000..97f1f4b4 --- /dev/null +++ b/_modules/spreg/sur.html @@ -0,0 +1,1182 @@ + + + + + + + spreg.sur — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.sur

+"""
+SUR and 3SLS estimation
+"""
+
+__author__ = "Luc Anselin lanselin@gmail.com,    \
+             Pedro V. Amaral pedrovma@gmail.com"
+
+
+import numpy as np
+import numpy.linalg as la
+from scipy import stats
+from . import summary_output as SUMMARY
+from . import user_output as USER
+from . import regimes as REGI
+from .sur_utils import (
+    sur_dict2mat,
+    sur_mat2dict,
+    sur_corr,
+    sur_crossprod,
+    sur_est,
+    sur_resids,
+    sur_predict,
+    check_k,
+)
+from .diagnostics_sur import (
+    sur_setp,
+    sur_lrtest,
+    sur_lmtest,
+    surLMe,
+    surLMlag,
+    sur_chow,
+)
+from .sputils import sphstack, spdot
+
+
+__all__ = ["SUR", "ThreeSLS"]
+
+
+class BaseSUR:
+    """
+    Base class for SUR estimation, both two step as well as iterated
+
+    Parameters
+    ----------
+
+    bigy       : dictionary
+                 with vector for dependent variable by equation
+    bigX       : dictionary
+                 with matrix of explanatory variables by equation
+                 (note, already includes constant term)
+    iter       : boolean
+                 whether or not to use iterated estimation.
+                 default = False
+    maxiter    : int
+                 maximum iterations; default = 5
+    epsilon    : float
+                 precision criterion to end iterations.
+                 default = 0.00001
+    verbose    : boolean
+                 flag to print out iteration number and value of log det(sig)
+                 at the beginning and the end of the iteration
+
+    Attributes
+    ----------
+    bigy        : dictionary
+                  with y values
+    bigX        : dictionary
+                  with X values
+    bigXX       : dictionary
+                  with :math:`X_t'X_r` cross-products
+    bigXy       : dictionary
+                  with :math:`X_t'y_r` cross-products
+    n_eq        : int
+                  number of equations
+    n           : int
+                  number of observations in each cross-section
+    bigK        : array
+                  vector with number of explanatory variables (including constant)
+                  for each equation
+    bOLS        : dictionary
+                  with OLS regression coefficients for each equation
+    olsE        : array
+                  N x n_eq array with OLS residuals for each equation
+    bSUR        : dictionary
+                  with SUR regression coefficients for each equation
+    varb        : array
+                  variance-covariance matrix
+    bigE        : array
+                  N x n_eq array with SUR residuals for each equation
+    bigYP       : array
+                  N x n_eq array with SUR predicted values for each equation
+    sig         : array
+                  Sigma matrix of inter-equation error covariances
+    ldetS1      : float
+                  log det(Sigma) for SUR model
+    resids      : array
+                  n by n_eq array of residuals
+    sig_ols     : array
+                  Sigma matrix for OLS residuals
+    ldetS0      : float
+                  log det(Sigma) for null model (OLS by equation, diagonals only)
+    niter       : int
+                  number of iterations (=0 for iter=False)
+    corr        : array
+                  inter-equation SUR error correlation matrix
+    llik        : float
+                  log-likelihood (including the constant pi)
+    """
+
+    def __init__(
+        self, bigy, bigX, iter=False, maxiter=5, epsilon=0.00001, verbose=False
+    ):
+        # setting up the cross-products
+        self.bigy = bigy
+        self.bigX = bigX
+        self.n_eq = len(bigy.keys())
+        self.n = bigy[0].shape[0]
+        self.bigK = np.zeros((self.n_eq, 1), dtype=np.int_)
+        for r in range(self.n_eq):
+            self.bigK[r] = self.bigX[r].shape[1]
+        self.bigXX, self.bigXy = sur_crossprod(self.bigX, self.bigy)
+        # OLS regression by equation, sets up initial residuals
+        _sur_ols(self)  # creates self.bOLS and self.olsE
+        # SUR estimation using OLS residuals - two step estimation
+        self.bSUR, self.varb, self.sig = sur_est(
+            self.bigXX, self.bigXy, self.olsE, self.bigK
+        )
+        resids = sur_resids(self.bigy, self.bigX, self.bSUR)  # matrix of residuals
+        # Sigma and log det(Sigma) for null model
+        self.sig_ols = self.sig
+        sols = np.diag(np.diag(self.sig))
+        self.ldetS0 = np.log(np.diag(sols)).sum()
+        det0 = self.ldetS0
+        # setup for iteration
+        det1 = la.slogdet(self.sig)[1]
+        self.ldetS1 = det1
+        # self.niter = 0
+        if iter:  # iterated FGLS aka ML
+            n_iter = 0
+            while np.abs(det1 - det0) > epsilon and n_iter <= maxiter:
+                n_iter += 1
+                det0 = det1
+                self.bSUR, self.varb, self.sig = sur_est(
+                    self.bigXX, self.bigXy, resids, self.bigK
+                )
+                resids = sur_resids(self.bigy, self.bigX, self.bSUR)
+                det1 = la.slogdet(self.sig)[1]
+                if verbose:
+                    print(n_iter, det0, det1)
+            self.bigE = sur_resids(self.bigy, self.bigX, self.bSUR)
+            self.ldetS1 = det1
+            self.niter = n_iter
+        else:
+            self.niter = 1
+            self.bigE = resids
+        self.bigYP = sur_predict(self.bigy, self.bigX, self.bSUR)  # LA added 10/30/16
+        self.corr = sur_corr(self.sig)
+        lik = self.n_eq * (1.0 + np.log(2.0 * np.pi)) + self.ldetS1
+        self.llik = -(self.n / 2.0) * lik
+
+
+def _sur_ols(reg):
+    """
+    OLS estimation of SUR equations
+
+    Parameters
+    ----------
+    reg  : BaseSUR object
+
+    Return
+    -------
+    reg.bOLS    : dictionary
+                 with regression coefficients for each equation
+    reg.olsE    : array
+                 N x n_eq array with OLS residuals for each equation
+
+    """
+    reg.bOLS = {}
+    for r in range(reg.n_eq):
+        reg.bOLS[r] = np.dot(la.inv(reg.bigXX[(r, r)]), reg.bigXy[(r, r)])
+    reg.olsE = sur_resids(reg.bigy, reg.bigX, reg.bOLS)
+    return reg
+
+
+
[docs]class SUR(BaseSUR, REGI.Regimes_Frame): + """ + User class for SUR estimation, both two step as well as iterated + + Parameters + ---------- + bigy : dictionary + with vector for dependent variable by equation + bigX : dictionary + with matrix of explanatory variables by equation + (note, already includes constant term) + w : spatial weights object + default = None + regimes : list + default = None. + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + nonspat_diag: boolean + flag for non-spatial diagnostics, default = True + spat_diag : boolean + flag for spatial diagnostics, default = False + iter : boolean + whether or not to use iterated estimation. + default = False + maxiter : int + maximum iterations; default = 5 + epsilon : float + precision criterion to end iterations. + default = 0.00001 + verbose : boolean + flag to print out iteration number and value + of log det(sig) at the beginning and the end of the iteration + name_bigy : dictionary + with name of dependent variable for each equation. + default = None, but should be specified + is done when sur_stackxy is used + name_bigX : dictionary + with names of explanatory variables for each equation. + default = None, but should be specified + is done when sur_stackxy is used + name_ds : string + name for the data set + name_w : string + name for the weights file + name_regimes : string + name of regime variable for use in the output + + Attributes + ---------- + bigy : dictionary + with y values + bigX : dictionary + with X values + bigXX : dictionary + with :math:`X_t'X_r` cross-products + bigXy : dictionary + with :math:`X_t'y_r` cross-products + n_eq : int + number of equations + n : int + number of observations in each cross-section + bigK : array + vector with number of explanatory variables (including constant) + for each equation + bOLS : dictionary + with OLS regression coefficients for each equation + olsE : array + N x n_eq array with OLS residuals for each equation + bSUR : dictionary + with SUR regression coefficients for each equation + varb : array + variance-covariance matrix + bigE : array + n by n_eq array of residuals + sig_ols : array + Sigma matrix for OLS residuals (diagonal) + ldetS0 : float + log det(Sigma) for null model (OLS by equation) + niter : int + number of iterations (=0 for iter=False) + corr : array + inter-equation error correlation matrix + llik : float + log-likelihood (including the constant pi) + sur_inf : dictionary + with standard error, asymptotic t and p-value, + one for each equation + lrtest : tuple + Likelihood Ratio test on off-diagonal elements of sigma + (tuple with test,df,p-value) + lmtest : tuple + Lagrange Multipler test on off-diagonal elements of sigma + (tuple with test,df,p-value) + lmEtest : tuple + Lagrange Multiplier test on error spatial autocorrelation in SUR + (tuple with test, df, p-value) + lmlagtest : tuple + Lagrange Multiplier test on spatial lag autocorrelation in SUR + (tuple with test, df, p-value) + surchow : array + list with tuples for Chow test on regression coefficients. + each tuple contains test value, degrees of freedom, p-value + name_bigy : dictionary + with name of dependent variable for each equation + name_bigX : dictionary + with names of explanatory variables for each + equation + name_ds : string + name for the data set + name_w : string + name for the weights file + name_regimes : string + name of regime variable for use in the output + + + Examples + -------- + + First import libpysal to load the spatial analysis tools. + + >>> import libpysal + >>> from libpysal.examples import load_example + >>> from libpysal.weights import Queen + >>> from spreg import ML_Error_Regimes, sur_dictxy + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that libpysal.io.open() + also reads data in CSV format. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path("natregimes.dbf"),'r') + + The specification of the model to be estimated can be provided as lists. + Each equation should be listed separately. In this example, equation 1 + has HR80 as dependent variable and PS80 and UE80 as exogenous regressors. + For equation 2, HR90 is the dependent variable, and PS90 and UE90 the + exogenous regressors. + + >>> y_var = ['HR80','HR90'] + >>> x_var = [['PS80','UE80'],['PS90','UE90']] + + Although not required for this method, we can load a weights matrix file + to allow for spatial diagnostics. + + >>> w = libpysal.weights.Queen.from_shapefile(nat.get_path("natregimes.shp")) + >>> w.transform='r' + + The SUR method requires data to be provided as dictionaries. PySAL + provides the tool sur_dictxy to create these dictionaries from the + list of variables. The line below will create four dictionaries + containing respectively the dependent variables (bigy), the regressors + (bigX), the dependent variables' names (bigyvars) and regressors' names + (bigXvars). All these will be created from th database (db) and lists + of variables (y_var and x_var) created above. + + >>> bigy,bigX,bigyvars,bigXvars = sur_dictxy(db,y_var,x_var) + + We can now run the regression and then have a summary of the output by typing: + 'print(reg.summary)' + + >>> reg = SUR(bigy,bigX,w=w,name_bigy=bigyvars,name_bigX=bigXvars,spat_diag=True,name_ds="nat") + >>> print(reg.summary) + REGRESSION + ---------- + SUMMARY OF OUTPUT: SEEMINGLY UNRELATED REGRESSIONS (SUR) + -------------------------------------------------------- + Data set : nat + Weights matrix : unknown + Number of Equations : 2 Number of Observations: 3085 + Log likelihood (SUR): -19902.966 Number of Iterations : 1 + ---------- + <BLANKLINE> + SUMMARY OF EQUATION 1 + --------------------- + Dependent Variable : HR80 Number of Variables : 3 + Mean dependent var : 6.9276 Degrees of Freedom : 3082 + S.D. dependent var : 6.8251 + <BLANKLINE> + ------------------------------------------------------------------------------------ + Variable Coefficient Std.Error z-Statistic Probability + ------------------------------------------------------------------------------------ + Constant_1 5.1390718 0.2624673 19.5798587 0.0000000 + PS80 0.6776481 0.1219578 5.5564132 0.0000000 + UE80 0.2637240 0.0343184 7.6846277 0.0000000 + ------------------------------------------------------------------------------------ + <BLANKLINE> + SUMMARY OF EQUATION 2 + --------------------- + Dependent Variable : HR90 Number of Variables : 3 + Mean dependent var : 6.1829 Degrees of Freedom : 3082 + S.D. dependent var : 6.6403 + <BLANKLINE> + ------------------------------------------------------------------------------------ + Variable Coefficient Std.Error z-Statistic Probability + ------------------------------------------------------------------------------------ + Constant_2 3.6139403 0.2534996 14.2561949 0.0000000 + PS90 1.0260715 0.1121662 9.1477755 0.0000000 + UE90 0.3865499 0.0341996 11.3027760 0.0000000 + ------------------------------------------------------------------------------------ + <BLANKLINE> + <BLANKLINE> + REGRESSION DIAGNOSTICS + TEST DF VALUE PROB + LM test on Sigma 1 680.168 0.0000 + LR test on Sigma 1 768.385 0.0000 + <BLANKLINE> + OTHER DIAGNOSTICS - CHOW TEST BETWEEN EQUATIONS + VARIABLES DF VALUE PROB + Constant_1, Constant_2 1 26.729 0.0000 + PS80, PS90 1 8.241 0.0041 + UE80, UE90 1 9.384 0.0022 + <BLANKLINE> + DIAGNOSTICS FOR SPATIAL DEPENDENCE + TEST DF VALUE PROB + Lagrange Multiplier (error) 2 1333.586 0.0000 + Lagrange Multiplier (lag) 2 1275.821 0.0000 + <BLANKLINE> + ERROR CORRELATION MATRIX + EQUATION 1 EQUATION 2 + 1.000000 0.469548 + 0.469548 1.000000 + ================================ END OF REPORT ===================================== + """ + +
[docs] def __init__( + self, + bigy, + bigX, + w=None, + regimes=None, + nonspat_diag=True, + spat_diag=False, + vm=False, + iter=False, + maxiter=5, + epsilon=0.00001, + verbose=False, + name_bigy=None, + name_bigX=None, + name_ds=None, + name_w=None, + name_regimes=None, + ): + + self.name_ds = USER.set_name_ds(name_ds) + self.name_w = USER.set_name_w(name_w, w) + self.n_eq = len(bigy.keys()) + + # initialize names - should be generated by sur_stack + if name_bigy: + self.name_bigy = name_bigy + else: # need to construct y names + self.name_bigy = {} + for r in range(self.n_eq): + yn = "dep_var_" + str(r) + self.name_bigy[r] = yn + if name_bigX is None: + name_bigX = {} + for r in range(self.n_eq): + k = self.bigX[r].shape[1] - 1 + name_x = ["var_" + str(i + 1) + "_" + str(r) for i in range(k)] + ct = "Constant_" + str(r) # NOTE: constant always included in X + name_x.insert(0, ct) + name_bigX[r] = name_x + + if regimes is not None: + self.constant_regi = "many" + self.cols2regi = "all" + self.regime_err_sep = False + self.name_regimes = USER.set_name_ds(name_regimes) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + self.name_x_r = name_bigX + cols2regi_dic = {} + self.name_bigX = {} + for r in range(self.n_eq): + cols2regi_dic[r] = REGI.check_cols2regi( + self.constant_regi, self.cols2regi, bigX[r], add_cons=False + ) + USER.check_regimes(self.regimes_set, bigy[0].shape[0], bigX[r].shape[1]) + bigX[r], self.name_bigX[r] = REGI.Regimes_Frame.__init__( + self, + bigX[r], + regimes, + constant_regi=None, + cols2regi=cols2regi_dic[r], + names=name_bigX[r], + ) + else: + self.name_bigX = name_bigX + + # need checks on match between bigy, bigX dimensions + # init moved here before name check + BaseSUR.__init__( + self, + bigy=bigy, + bigX=bigX, + iter=iter, + maxiter=maxiter, + epsilon=epsilon, + verbose=verbose, + ) + + # inference + self.sur_inf = sur_setp(self.bSUR, self.varb) + + if nonspat_diag: + # LR test on off-diagonal elements of Sigma + self.lrtest = sur_lrtest(self.n, self.n_eq, self.ldetS0, self.ldetS1) + + # LM test on off-diagonal elements of Sigma + self.lmtest = sur_lmtest(self.n, self.n_eq, self.sig_ols) + else: + self.lrtest = None + self.lmtest = None + + if spat_diag: + if not w: + raise Exception("Error: spatial weights needed") + WS = w.sparse + # LM test on spatial error autocorrelation + self.lmEtest = surLMe(self.n_eq, WS, self.bigE, self.sig) + # LM test on spatial lag autocorrelation + self.lmlagtest = surLMlag( + self.n_eq, + WS, + self.bigy, + self.bigX, + self.bigE, + self.bigYP, + self.sig, + self.varb, + ) + else: + self.lmEtest = None + self.lmlagtest = None + + # test on constancy of coefficients across equations + if check_k(self.bigK): # only for equal number of variables + self.surchow = sur_chow(self.n_eq, self.bigK, self.bSUR, self.varb) + else: + self.surchow = None + + # Listing of the results + self.title = "SEEMINGLY UNRELATED REGRESSIONS (SUR)" + if regimes is not None: + self.title += " - REGIMES" + self.chow_regimes = {} + varb_counter = 0 + for r in range(self.n_eq): + counter_end = varb_counter + self.bSUR[r].shape[0] + self.chow_regimes[r] = REGI._chow_run( + len(cols2regi_dic[r]), + 0, + 0, + len(self.regimes_set), + self.bSUR[r], + self.varb[varb_counter:counter_end, varb_counter:counter_end], + ) + varb_counter = counter_end + regimes = True + + SUMMARY.SUR( + reg=self, + nonspat_diag=nonspat_diag, + spat_diag=spat_diag, + surlm=True, + regimes=regimes, + )
+ + +class BaseThreeSLS: + """ + Base class for 3SLS estimation, two step + + Parameters + ---------- + bigy : dictionary + with vector for dependent variable by equation + bigX : dictionary + with matrix of explanatory variables by equation + (note, already includes constant term) + bigyend : dictionary + with matrix of endogenous variables by equation + bigq : dictionary + with matrix of instruments by equation + + Attributes + ---------- + bigy : dictionary + with y values + bigZ : dictionary + with matrix of exogenous and endogenous variables + for each equation + bigZHZH : dictionary + with matrix of cross products Zhat_r'Zhat_s + bigZHy : dictionary + with matrix of cross products Zhat_r'y_end_s + n_eq : int + number of equations + n : int + number of observations in each cross-section + bigK : array + vector with number of explanatory variables (including constant, + exogenous and endogenous) for each equation + b2SLS : dictionary + with 2SLS regression coefficients for each equation + tslsE : array + N x n_eq array with OLS residuals for each equation + b3SLS : dictionary + with 3SLS regression coefficients for each equation + varb : array + variance-covariance matrix + sig : array + Sigma matrix of inter-equation error covariances + bigE : array + n by n_eq array of residuals + corr : array + inter-equation 3SLS error correlation matrix + + """ + + def __init__(self, bigy, bigX, bigyend, bigq): + # setting up the cross-products + self.bigy = bigy + self.n_eq = len(bigy.keys()) + self.n = bigy[0].shape[0] + # dictionary with exog and endog, Z + self.bigZ = {} + for r in range(self.n_eq): + self.bigZ[r] = sphstack(bigX[r], bigyend[r]) + # number of explanatory variables by equation + self.bigK = np.zeros((self.n_eq, 1), dtype=np.int_) + for r in range(self.n_eq): + self.bigK[r] = self.bigZ[r].shape[1] + # dictionary with instruments, H + bigH = {} + for r in range(self.n_eq): + bigH[r] = sphstack(bigX[r], bigq[r]) + # dictionary with instrumental variables, X and yend_predicted, Z-hat + bigZhat = _get_bigZhat(self, bigX, bigyend, bigH) + self.bigZHZH, self.bigZHy = sur_crossprod(bigZhat, self.bigy) + + # 2SLS regression by equation, sets up initial residuals + _sur_2sls(self) # creates self.b2SLS and self.tslsE + + self.b3SLS, self.varb, self.sig = sur_est( + self.bigZHZH, self.bigZHy, self.tslsE, self.bigK + ) + self.bigE = sur_resids(self.bigy, self.bigZ, self.b3SLS) # matrix of residuals + + # inter-equation correlation matrix + self.corr = sur_corr(self.sig) + + +
[docs]class ThreeSLS(BaseThreeSLS, REGI.Regimes_Frame): + """ + User class for 3SLS estimation + + Parameters + ---------- + + bigy : dictionary + with vector for dependent variable by equation + bigX : dictionary + with matrix of explanatory variables by equation + (note, already includes constant term) + bigyend : dictionary + with matrix of endogenous variables by equation + bigq : dictionary + with matrix of instruments by equation + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + nonspat_diag: boolean + flag for non-spatial diagnostics, default = True. + name_bigy : dictionary + with name of dependent variable for each equation. + default = None, but should be specified. + is done when sur_stackxy is used + name_bigX : dictionary + with names of explanatory variables for each equation. + default = None, but should be specified. + is done when sur_stackxy is used + name_bigyend : dictionary + with names of endogenous variables for each equation. + default = None, but should be specified. + is done when sur_stackZ is used + name_bigq : dictionary + with names of instrumental variables for each equation. + default = None, but should be specified. + is done when sur_stackZ is used. + name_ds : string + name for the data set. + name_regimes : string + name of regime variable for use in the output. + + Attributes + ---------- + + bigy : dictionary + with y values + bigZ : dictionary + with matrix of exogenous and endogenous variables + for each equation + bigZHZH : dictionary + with matrix of cross products Zhat_r'Zhat_s + bigZHy : dictionary + with matrix of cross products Zhat_r'y_end_s + n_eq : int + number of equations + n : int + number of observations in each cross-section + bigK : array + vector with number of explanatory variables (including constant, + exogenous and endogenous) for each equation + b2SLS : dictionary + with 2SLS regression coefficients for each equation + tslsE : array + N x n_eq array with OLS residuals for each equation + b3SLS : dictionary + with 3SLS regression coefficients for each equation + varb : array + variance-covariance matrix + sig : array + Sigma matrix of inter-equation error covariances + bigE : array + n by n_eq array of residuals + corr : array + inter-equation 3SLS error correlation matrix + tsls_inf : dictionary + with standard error, asymptotic t and p-value, + one for each equation + surchow : array + list with tuples for Chow test on regression coefficients + each tuple contains test value, degrees of freedom, p-value + name_ds : string + name for the data set + name_bigy : dictionary + with name of dependent variable for each equation + name_bigX : dictionary + with names of explanatory variables for each + equation + name_bigyend : dictionary + with names of endogenous variables for each + equation + name_bigq : dictionary + with names of instrumental variables for each + equations + name_regimes : string + name of regime variable for use in the output + + + Examples + -------- + First import libpysal to load the spatial analysis tools. + + >>> import libpysal + >>> from libpysal.examples import load_example + >>> from libpysal.weights import Queen + >>> import spreg + >>> np.set_printoptions(suppress=True) #prevent scientific format + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that libpysal.io.open() + also reads data in CSV format. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path("natregimes.dbf"),'r') + + The specification of the model to be estimated can be provided as lists. + Each equation should be listed separately. In this example, equation 1 + has HR80 as dependent variable, PS80 and UE80 as exogenous regressors, + RD80 as endogenous regressor and FP79 as additional instrument. + For equation 2, HR90 is the dependent variable, PS90 and UE90 the + exogenous regressors, RD90 as endogenous regressor and FP99 as + additional instrument + + >>> y_var = ['HR80','HR90'] + >>> x_var = [['PS80','UE80'],['PS90','UE90']] + >>> yend_var = [['RD80'],['RD90']] + >>> q_var = [['FP79'],['FP89']] + + The SUR method requires data to be provided as dictionaries. PySAL + provides two tools to create these dictionaries from the list of variables: + sur_dictxy and sur_dictZ. The tool sur_dictxy can be used to create the + dictionaries for Y and X, and sur_dictZ for endogenous variables (yend) and + additional instruments (q). + + >>> bigy,bigX,bigyvars,bigXvars = spreg.sur_dictxy(db,y_var,x_var) + >>> bigyend,bigyendvars = spreg.sur_dictZ(db,yend_var) + >>> bigq,bigqvars = spreg.sur_dictZ(db,q_var) + + We can now run the regression and then have a summary of the output by typing: + print(reg.summary) + + Alternatively, we can just check the betas and standard errors, asymptotic t + and p-value of the parameters: + + >>> reg = spreg.ThreeSLS(bigy,bigX,bigyend,bigq,name_bigy=bigyvars,name_bigX=bigXvars,name_bigyend=bigyendvars,name_bigq=bigqvars,name_ds="NAT") + >>> reg.b3SLS + {0: array([[6.92426353], + [1.42921826], + [0.00049435], + [3.5829275 ]]), 1: array([[ 7.62385875], + [ 1.65031181], + [-0.21682974], + [ 3.91250428]])} + + >>> reg.tsls_inf + {0: array([[ 0.23220853, 29.81916157, 0. ], + [ 0.10373417, 13.77770036, 0. ], + [ 0.03086193, 0.01601807, 0.98721998], + [ 0.11131999, 32.18584124, 0. ]]), 1: array([[ 0.28739415, 26.52753638, 0. ], + [ 0.09597031, 17.19606554, 0. ], + [ 0.04089547, -5.30204786, 0.00000011], + [ 0.13586789, 28.79638723, 0. ]])} + + """ + +
[docs] def __init__( + self, + bigy, + bigX, + bigyend, + bigq, + regimes=None, + nonspat_diag=True, + name_bigy=None, + name_bigX=None, + name_bigyend=None, + name_bigq=None, + name_ds=None, + name_regimes=None, + ): + + self.name_ds = USER.set_name_ds(name_ds) + self.n_eq = len(bigy.keys()) + + # initialize names - should be generated by sur_stack + if name_bigy: + self.name_bigy = name_bigy + else: # need to construct y names + self.name_bigy = {} + for r in range(self.n_eq): + yn = "dep_var_" + str(r + 1) + self.name_bigy[r] = yn + + if name_bigX is None: + name_bigX = {} + for r in range(self.n_eq): + k = bigX[r].shape[1] - 1 + name_x = ["var_" + str(i + 1) + "_" + str(r + 1) for i in range(k)] + ct = "Constant_" + str(r + 1) # NOTE: constant always included in X + name_x.insert(0, ct) + name_bigX[r] = name_x + + if name_bigyend is None: + name_bigyend = {} + for r in range(self.n_eq): + ky = bigyend[r].shape[1] + name_ye = ["end_" + str(i + 1) + "_" + str(r + 1) for i in range(ky)] + name_bigyend[r] = name_ye + + if name_bigq is None: + name_bigq = {} + for r in range(self.n_eq): + ki = bigq[r].shape[1] + name_i = ["inst_" + str(i + 1) + "_" + str(r + 1) for i in range(ki)] + name_bigq[r] = name_i + + if regimes is not None: + self.constant_regi = "many" + self.cols2regi = "all" + self.regime_err_sep = False + self.name_regimes = USER.set_name_ds(name_regimes) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + cols2regi_dic = {} + self.name_bigX, self.name_x_r, self.name_bigq, self.name_bigyend = ( + {}, + {}, + {}, + {}, + ) + + for r in range(self.n_eq): + self.name_x_r[r] = name_bigX[r] + name_bigyend[r] + cols2regi_dic[r] = REGI.check_cols2regi( + self.constant_regi, + self.cols2regi, + bigX[r], + yend=bigyend[r], + add_cons=False, + ) + USER.check_regimes(self.regimes_set, bigy[0].shape[0], bigX[r].shape[1]) + bigX[r], self.name_bigX[r] = REGI.Regimes_Frame.__init__( + self, + bigX[r], + regimes, + constant_regi=None, + cols2regi=cols2regi_dic[r], + names=name_bigX[r], + ) + bigq[r], self.name_bigq[r] = REGI.Regimes_Frame.__init__( + self, + bigq[r], + regimes, + constant_regi=None, + cols2regi="all", + names=name_bigq[r], + ) + bigyend[r], self.name_bigyend[r] = REGI.Regimes_Frame.__init__( + self, + bigyend[r], + regimes, + constant_regi=None, + cols2regi=cols2regi_dic[r], + yend=True, + names=name_bigyend[r], + ) + else: + self.name_bigX, self.name_bigq, self.name_bigyend = ( + name_bigX, + name_bigq, + name_bigyend, + ) + # need checks on match between bigy, bigX dimensions + BaseThreeSLS.__init__(self, bigy=bigy, bigX=bigX, bigyend=bigyend, bigq=bigq) + + # inference + self.tsls_inf = sur_setp(self.b3SLS, self.varb) + + # test on constancy of coefficients across equations + if check_k(self.bigK): # only for equal number of variables + self.surchow = sur_chow(self.n_eq, self.bigK, self.b3SLS, self.varb) + else: + self.surchow = None + + # Listing of the results + self.title = "THREE STAGE LEAST SQUARES (3SLS)" + if regimes is not None: + self.title += " - REGIMES" + self.chow_regimes = {} + varb_counter = 0 + for r in range(self.n_eq): + counter_end = varb_counter + self.b3SLS[r].shape[0] + self.chow_regimes[r] = REGI._chow_run( + len(cols2regi_dic[r]), + 0, + 0, + len(self.regimes_set), + self.b3SLS[r], + self.varb[varb_counter:counter_end, varb_counter:counter_end], + ) + varb_counter = counter_end + regimes = True + + SUMMARY.SUR( + reg=self, tsls=True, ml=False, nonspat_diag=nonspat_diag, regimes=regimes + )
+ + +def _sur_2sls(reg): + """ + 2SLS estimation of SUR equations + + Parameters + ---------- + + reg : BaseSUR object + + Return + ------ + + reg.b2SLS : dictionary + with regression coefficients for each equation + reg.tslsE : array + N x n_eq array with OLS residuals for each equation + + """ + reg.b2SLS = {} + for r in range(reg.n_eq): + reg.b2SLS[r] = np.dot(la.inv(reg.bigZHZH[(r, r)]), reg.bigZHy[(r, r)]) + reg.tslsE = sur_resids(reg.bigy, reg.bigZ, reg.b2SLS) + return reg + + +def _get_bigZhat(reg, bigX, bigyend, bigH): + bigZhat = {} + for r in range(reg.n_eq): + try: + HHi = la.inv(spdot(bigH[r].T, bigH[r])) + except: + raise Exception("ERROR: singular cross product matrix, check instruments") + Hye = spdot(bigH[r].T, bigyend[r]) + yp = spdot(bigH[r], spdot(HHi, Hye)) + bigZhat[r] = sphstack(bigX[r], yp) + return bigZhat + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + import numpy as np + import libpysal + from .sur_utils import sur_dictxy, sur_dictZ + from libpysal.examples import load_example + + nat = load_example("Natregimes") + db = libpysal.io.open(nat.get_path("NAT.dbf"), "r") + y_var = ["HR80", "HR90"] + x_var = [["PS80", "UE80"], ["PS90", "UE90"]] + regimes = db.by_col("SOUTH") + + # Example SUR + # """ + w = libpysal.weights.Queen.from_shapefile(nat.get_path("natregimes.shp")) + w.transform = "r" + bigy0, bigX0, bigyvars0, bigXvars0 = sur_dictxy(db, y_var, x_var) + reg0 = SUR( + bigy0, + bigX0, + w=w, + regimes=None, + name_bigy=bigyvars0, + name_bigX=bigXvars0, + spat_diag=True, + name_ds="NAT", + ) + print(reg0.summary) + """ + #Example 3SLS + yend_var = [['RD80'],['RD90']] + q_var = [['FP79'],['FP89']] + + bigy1,bigX1,bigyvars1,bigXvars1 = sur_dictxy(db,y_var,x_var) + bigyend1,bigyendvars1 = sur_dictZ(db,yend_var) + bigq1,bigqvars1 = sur_dictZ(db,q_var) + + reg1 = ThreeSLS(bigy1,bigX1,bigyend1,bigq1,regimes=regimes,name_bigy=bigyvars1,name_bigX=bigXvars1,name_bigyend=bigyendvars1,name_bigq=bigqvars1,name_ds="NAT",name_regimes="South") + + print reg1.summary + #""" +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/sur_error.html b/_modules/spreg/sur_error.html new file mode 100644 index 00000000..8ca22f78 --- /dev/null +++ b/_modules/spreg/sur_error.html @@ -0,0 +1,1281 @@ + + + + + + + spreg.sur_error — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.sur_error

+"""
+Spatial Error SUR estimation
+"""
+
+__author__ = "Luc Anselin lanselin@gmail.com,    \
+             Pedro V. Amaral pedrovma@gmail.com"
+
+
+import numpy as np
+import numpy.linalg as la
+from scipy import stats
+
+stats.chisqprob = stats.chi2.sf
+from . import summary_output as SUMMARY
+from . import user_output as USER
+from . import regimes as REGI
+from scipy.sparse.linalg import splu as SuperLU
+from scipy.optimize import minimize_scalar, minimize
+from scipy import sparse as sp
+
+from .ml_error import err_c_loglik_sp
+from .utils import optim_moments
+from .sur_utils import (
+    sur_dictxy,
+    sur_corr,
+    sur_dict2mat,
+    sur_crossprod,
+    sur_est,
+    sur_resids,
+    filter_dict,
+    check_k,
+)
+from .sur import BaseSUR, _sur_ols
+from .diagnostics_sur import sur_setp, lam_setp, sur_chow
+from .regimes import buildR, wald_test
+
+__all__ = ["BaseSURerrorGM", "SURerrorGM", "BaseSURerrorML", "SURerrorML"]
+
+
+class BaseSURerrorGM:
+    """Base class for SUR Error estimation by Generalized Moments
+
+    Parameters
+    ----------
+    bigy       : dictionary
+                 with vector for dependent variable by equation
+    bigX       : dictionary
+                 with matrix of explanatory variables by equation
+                 (note, already includes constant term)
+    w          : spatial weights object
+
+    Attributes
+    ----------
+    n_eq       : int
+                 number of equations
+    n          : int
+                 number of observations in each cross-section
+    bigy       : dictionary
+                 with vectors of dependent variable, one for
+                 each equation
+    bigX       : dictionary
+                 with matrices of explanatory variables,
+                 one for each equation
+    bigK       : array
+                 n_eq x 1 array with number of explanatory variables
+                 by equation
+    bigylag    : dictionary
+                 spatially lagged dependent variable
+    bigXlag    : dictionary
+                 spatially lagged explanatory variable
+    lamsur     : float
+                 spatial autoregressive coefficient in GM SUR Error
+    bSUR       : array
+                 beta coefficients in GM SUR Error
+    varb       : array
+                 variance of beta coefficients in GM SUR Error
+    sig        : array
+                 error variance-covariance matrix in GM SUR Error
+    corr       : array
+                 error correlation matrix
+    bigE       : array
+                 n by n_eq matrix of vectors of residuals for each equation
+
+    """
+
+    def __init__(self, bigy, bigX, w):
+        self.n = w.n
+        self.n_eq = len(bigy.keys())
+        WS = w.sparse
+        I = sp.identity(self.n)
+        # variables
+        self.bigy = bigy
+        self.bigX = bigX
+        # number of variables by equation
+        self.bigK = np.zeros((self.n_eq, 1), dtype=np.int_)
+        for r in range(self.n_eq):
+            self.bigK[r] = self.bigX[r].shape[1]
+
+        # OLS
+        self.bigXX, self.bigXy = sur_crossprod(self.bigX, self.bigy)
+        reg0 = _sur_ols(self)
+
+        # Moments
+        moments = _momentsGM_sur_Error(WS, reg0.olsE)
+        lam = np.zeros((self.n_eq, 1))
+        for r in range(self.n_eq):
+            lam[r] = optim_moments(moments[r])
+
+        # spatially lagged variables
+        self.bigylag = {}
+        for r in range(self.n_eq):
+            self.bigylag[r] = WS * self.bigy[r]
+        # note: unlike WX as instruments, this includes the constant
+        self.bigXlag = {}
+        for r in range(self.n_eq):
+            self.bigXlag[r] = WS * self.bigX[r]
+
+        # spatially filtered variables
+        sply = filter_dict(lam, self.bigy, self.bigylag)
+        splX = filter_dict(lam, self.bigX, self.bigXlag)
+        WbigE = WS * reg0.olsE
+        splbigE = reg0.olsE - WbigE * lam.T
+        splXX, splXy = sur_crossprod(splX, sply)
+        b1, varb1, sig1 = sur_est(splXX, splXy, splbigE, self.bigK)
+        bigE = sur_resids(self.bigy, self.bigX, b1)
+
+        self.lamsur = lam
+        self.bSUR = b1
+        self.varb = varb1
+        self.sig = sig1
+        self.corr = sur_corr(self.sig)
+        self.bigE = bigE
+
+
+def _momentsGM_sur_Error(w, u):
+    n = w.shape[0]
+    u2 = (u * u).sum(0)
+    wu = w * u
+    uwu = (u * wu).sum(0)
+    wu2 = (wu * wu).sum(0)
+    wwu = w * wu
+    uwwu = (u * wwu).sum(0)
+    wwu2 = (wwu * wwu).sum(0)
+    wwuwu = (wwu * wu).sum(0)
+    trWtW = w.multiply(w).sum()
+    moments = {}
+    for r in range(u.shape[1]):
+        g = np.array([[u2[r], wu2[r], uwu[r]]]).T / n
+        G = (
+            np.array(
+                [
+                    [2 * uwu[r], -wu2[r], n],
+                    [2 * wwuwu[r], -wwu2[r], trWtW],
+                    [uwwu[r] + wu2[r], -wwuwu[r], 0.0],
+                ]
+            )
+            / n
+        )
+        moments[r] = [G, g]
+    return moments
+
+
+
[docs]class SURerrorGM(BaseSURerrorGM, REGI.Regimes_Frame): + """ + User class for SUR Error estimation by Generalized Moments + + Parameters + ---------- + bigy : dictionary + with vectors of dependent variable, one for + each equation + bigX : dictionary + with matrices of explanatory variables, + one for each equation + w : spatial weights object + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + nonspat_diag : boolean + flag for non-spatial diagnostics, default = False + spat_diag : boolean + flag for spatial diagnostics, default = False (to be implemented) + vm : boolean + flag for asymptotic variance for lambda and Sigma, + default = False (to be implemented) + name_bigy : dictionary + with name of dependent variable for each equation. + default = None, but should be specified is done when + sur_stackxy is used + name_bigX : dictionary + with names of explanatory variables for each equation. + default = None, but should be specified is done when + sur_stackxy is used + name_ds : string + name for the data set + name_w : string + name for the weights file + name_regimes : string + name of regime variable for use in the output + + Attributes + ---------- + n : int + number of observations in each cross-section + n_eq : int + number of equations + bigy : dictionary + with vectors of dependent variable, one for + each equation + bigX : dictionary + with matrices of explanatory variables, + one for each equation + bigK : array + n_eq x 1 array with number of explanatory variables + by equation + bigylag : dictionary + spatially lagged dependent variable + bigXlag : dictionary + spatially lagged explanatory variable + lamsur : float + spatial autoregressive coefficient in ML SUR Error + bSUR : array + beta coefficients in ML SUR Error + varb : array + variance of beta coefficients in ML SUR Error + sig : array + error variance-covariance matrix in ML SUR Error + bigE : array + n by n_eq matrix of vectors of residuals for each equation + sur_inf : array + inference for regression coefficients, stand. error, t, p + surchow : array + list with tuples for Chow test on regression coefficients. + each tuple contains test value, degrees of freedom, p-value + name_bigy : dictionary + with name of dependent variable for each equation + name_bigX : dictionary + with names of explanatory variables for each + equation + name_ds : string + name for the data set + name_w : string + name for the weights file + name_regimes : string + name of regime variable for use in the output + + + Examples + -------- + + First import libpysal to load the spatial analysis tools. + + >>> import libpysal + >>> from libpysal.examples import load_example + >>> from libpysal.weights import Queen + >>> import spreg + >>> np.set_printoptions(suppress=True) #prevent scientific format + + Open data on NCOVR US County Homicides (3085 areas) using pysal.open(). + This is the DBF associated with the NAT shapefile. Note that pysal.open() + also reads data in CSV format. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path('natregimes.dbf'), 'r') + + The specification of the model to be estimated can be provided as lists. + Each equation should be listed separately. Equation 1 has HR80 as dependent + variable, and PS80 and UE80 as exogenous regressors. + For equation 2, HR90 is the dependent variable, and PS90 and UE90 the + exogenous regressors. + + >>> y_var = ['HR80','HR90'] + >>> x_var = [['PS80','UE80'],['PS90','UE90']] + >>> yend_var = [['RD80'],['RD90']] + >>> q_var = [['FP79'],['FP89']] + + The SUR method requires data to be provided as dictionaries. PySAL + provides the tool sur_dictxy to create these dictionaries from the + list of variables. The line below will create four dictionaries + containing respectively the dependent variables (bigy), the regressors + (bigX), the dependent variables' names (bigyvars) and regressors' names + (bigXvars). All these will be created from th database (db) and lists + of variables (y_var and x_var) created above. + + >>> bigy,bigX,bigyvars,bigXvars = spreg.sur_dictxy(db,y_var,x_var) + + To run a spatial error model, we need to specify the spatial weights matrix. + To do that, we can open an already existing gal file or create a new one. + In this example, we will create a new one from NAT.shp and transform it to + row-standardized. + + >>> w = Queen.from_shapefile(nat.get_path("natregimes.shp")) + >>> w.transform='r' + + We can now run the regression and then have a summary of the output by typing: + print(reg.summary) + + Alternatively, we can just check the betas and standard errors, asymptotic t + and p-value of the parameters: + + >>> reg = spreg.SURerrorGM(bigy,bigX,w=w,name_bigy=bigyvars,name_bigX=bigXvars,name_ds="NAT",name_w="nat_queen") + >>> reg.bSUR + {0: array([[3.97746866], + [0.89021219], + [0.43050363]]), 1: array([[2.93679119], + [1.11002826], + [0.48761542]])} + >>> reg.sur_inf + {0: array([[ 0.37251476, 10.67734504, 0. ], + [ 0.14224297, 6.25839153, 0. ], + [ 0.04322388, 9.95985608, 0. ]]), 1: array([[ 0.33694902, 8.71583245, 0. ], + [ 0.13413626, 8.27537783, 0. ], + [ 0.04033105, 12.09032288, 0. ]])} + """ + +
[docs] def __init__( + self, + bigy, + bigX, + w, + regimes=None, + nonspat_diag=True, + spat_diag=False, + vm=False, + name_bigy=None, + name_bigX=None, + name_ds=None, + name_w=None, + name_regimes=None, + ): + + # check on variable names for listing results + self.name_ds = USER.set_name_ds(name_ds) + self.name_w = USER.set_name_w(name_w, w) + # initialize names - should be generated by sur_stack + self.n_eq = len(bigy.keys()) + if name_bigy: + self.name_bigy = name_bigy + else: # need to construct y names + self.name_bigy = {} + for r in range(self.n_eq): + yn = "dep_var_" + str(r) + self.name_bigy[r] = yn + if name_bigX is None: + name_bigX = {} + for r in range(self.n_eq): + k = bigX[r].shape[1] - 1 + name_x = ["var_" + str(i + 1) + "_" + str(r + 1) for i in range(k)] + ct = "Constant_" + str(r + 1) # NOTE: constant always included in X + name_x.insert(0, ct) + name_bigX[r] = name_x + + if regimes is not None: + self.constant_regi = "many" + self.cols2regi = "all" + self.regime_err_sep = False + self.name_regimes = USER.set_name_ds(name_regimes) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + cols2regi_dic = {} + self.name_bigX = {} + self.name_x_r = name_bigX + + for r in range(self.n_eq): + cols2regi_dic[r] = REGI.check_cols2regi( + self.constant_regi, self.cols2regi, bigX[r], add_cons=False + ) + USER.check_regimes(self.regimes_set, bigy[0].shape[0], bigX[r].shape[1]) + bigX[r], self.name_bigX[r] = REGI.Regimes_Frame.__init__( + self, + bigX[r], + regimes, + constant_regi=None, + cols2regi=cols2regi_dic[r], + names=name_bigX[r], + ) + else: + self.name_bigX = name_bigX + + BaseSURerrorGM.__init__(self, bigy=bigy, bigX=bigX, w=w) + + # inference + self.sur_inf = sur_setp(self.bSUR, self.varb) + + # test on constancy of regression coefficients across equations + if check_k(self.bigK): # only for equal number of variables + self.surchow = sur_chow(self.n_eq, self.bigK, self.bSUR, self.varb) + else: + self.surchow = None + + # listing of results + self.title = "SEEMINGLY UNRELATED REGRESSIONS (SUR) - GM SPATIAL ERROR MODEL" + + if regimes is not None: + self.title = "SUR - GM SPATIAL ERROR MODEL WITH REGIMES" + self.chow_regimes = {} + varb_counter = 0 + for r in range(self.n_eq): + counter_end = varb_counter + self.bSUR[r].shape[0] + self.chow_regimes[r] = REGI._chow_run( + len(cols2regi_dic[r]), + 0, + 0, + len(self.regimes_set), + self.bSUR[r], + self.varb[varb_counter:counter_end, varb_counter:counter_end], + ) + varb_counter = counter_end + regimes = True + + SUMMARY.SUR( + reg=self, + nonspat_diag=nonspat_diag, + spat_diag=spat_diag, + lambd=True, + ml=False, + regimes=regimes, + )
+ + +class BaseSURerrorML: + """ + Base class for SUR Error estimation by Maximum Likelihood + + requires: scipy.optimize.minimize_scalar and scipy.optimize.minimize + + Parameters + ---------- + bigy : dictionary + with vectors of dependent variable, one for + each equation + bigX : dictionary + with matrices of explanatory variables, + one for each equation + w : spatial weights object + epsilon : float + convergence criterion for ML iterations + default 0.0000001 + + Attributes + ---------- + n : int + number of observations in each cross-section + n2 : int + n/2 + n_eq : int + number of equations + bigy : dictionary + with vectors of dependent variable, one for + each equation + bigX : dictionary + with matrices of explanatory variables, + one for each equation + bigK : array + n_eq x 1 array with number of explanatory variables + by equation + bigylag : dictionary + spatially lagged dependent variable + bigXlag : dictionary + spatially lagged explanatory variable + lamols : array + spatial autoregressive coefficients from equation by + equation ML-Error estimation + clikerr : float + concentrated log-likelihood from equation by equation + ML-Error estimation (no constant) + bSUR0 : array + SUR estimation for betas without spatial autocorrelation + llik : float + log-likelihood for classic SUR estimation (includes constant) + lamsur : float + spatial autoregressive coefficient in ML SUR Error + bSUR : array + beta coefficients in ML SUR Error + varb : array + variance of beta coefficients in ML SUR Error + sig : array + error variance-covariance matrix in ML SUR Error + corr : array + error correlation matrix + bigE : array + n by n_eq matrix of vectors of residuals for each equation + cliksurerr : float + concentrated log-likelihood from ML SUR Error (no constant) + + """ + + def __init__(self, bigy, bigX, w, epsilon=0.0000001): + # setting up constants + self.n = w.n + self.n2 = self.n / 2.0 + self.n_eq = len(bigy.keys()) + WS = w.sparse + I = sp.identity(self.n) + # variables + self.bigy = bigy + self.bigX = bigX + # number of variables by equation + self.bigK = np.zeros((self.n_eq, 1), dtype=np.int_) + for r in range(self.n_eq): + self.bigK[r] = self.bigX[r].shape[1] + # spatially lagged variables + self.bigylag = {} + for r in range(self.n_eq): + self.bigylag[r] = WS * self.bigy[r] + # note: unlike WX as instruments, this includes the constant + self.bigXlag = {} + for r in range(self.n_eq): + self.bigXlag[r] = WS * self.bigX[r] + + # spatial parameter starting values + lam = np.zeros((self.n_eq, 1)) # initialize as an array + fun0 = 0.0 + fun1 = 0.0 + for r in range(self.n_eq): + res = minimize_scalar( + err_c_loglik_sp, + 0.0, + bounds=(-1.0, 1.0), + args=( + self.n, + self.bigy[r], + self.bigylag[r], + self.bigX[r], + self.bigXlag[r], + I, + WS, + ), + method="bounded", + options={"xatol": epsilon}, + ) + lam[r] = res.x + fun1 += res.fun + self.lamols = lam + self.clikerr = -fun1 # negative because use in min + + # SUR starting values + reg0 = BaseSUR(self.bigy, self.bigX, iter=True) + bigE = reg0.bigE + self.bSUR0 = reg0.bSUR + self.llik = reg0.llik # as is, includes constant + + # iteration + lambdabounds = [(-1.0, +1.0) for i in range(self.n_eq)] + while abs(fun0 - fun1) > epsilon: + fun0 = fun1 + sply = filter_dict(lam, self.bigy, self.bigylag) + splX = filter_dict(lam, self.bigX, self.bigXlag) + WbigE = WS * bigE + splbigE = bigE - WbigE * lam.T + splXX, splXy = sur_crossprod(splX, sply) + b1, varb1, sig1 = sur_est(splXX, splXy, splbigE, self.bigK) + bigE = sur_resids(self.bigy, self.bigX, b1) + res = minimize( + clik, + np.array(lam).flatten(), + args=(self.n, self.n2, self.n_eq, bigE, I, WS), + method="L-BFGS-B", + bounds=lambdabounds, + ) + lam = res.x + lam.resize((self.n_eq, 1)) + fun1 = res.fun + self.lamsur = lam + self.bSUR = b1 + self.varb = varb1 + self.sig = sig1 + self.corr = sur_corr(self.sig) + self.bigE = bigE + self.cliksurerr = -fun1 # negative because use in min, no constant + + +
[docs]class SURerrorML(BaseSURerrorML, REGI.Regimes_Frame): + """ + User class for SUR Error estimation by Maximum Likelihood + + Parameters + ---------- + bigy : dictionary + with vectors of dependent variable, one for + each equation + bigX : dictionary + with matrices of explanatory variables, + one for each equation + w : spatial weights object + regimes : list + default = None. + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + epsilon : float + convergence criterion for ML iterations. + default 0.0000001 + nonspat_diag : boolean + flag for non-spatial diagnostics, default = True + spat_diag : boolean + flag for spatial diagnostics, default = False + vm : boolean + flag for asymptotic variance for lambda and Sigma, + default = False + name_bigy : dictionary + with name of dependent variable for each equation. + default = None, but should be specified is done when + sur_stackxy is used + name_bigX : dictionary + with names of explanatory variables for each equation. + default = None, but should be specified is done when + sur_stackxy is used + name_ds : string + name for the data set + name_w : string + name for the weights file + name_regimes : string + name of regime variable for use in the output + + Attributes + ---------- + n : int + number of observations in each cross-section + n2 : int + n/2 + n_eq : int + number of equations + bigy : dictionary + with vectors of dependent variable, one for + each equation + bigX : dictionary + with matrices of explanatory variables, + one for each equation + bigK : array + n_eq x 1 array with number of explanatory variables + by equation + bigylag : dictionary + spatially lagged dependent variable + bigXlag : dictionary + spatially lagged explanatory variable + lamols : array + spatial autoregressive coefficients from equation by + equation ML-Error estimation + clikerr : float + concentrated log-likelihood from equation by equation + ML-Error estimation (no constant) + bSUR0 : array + SUR estimation for betas without spatial autocorrelation + llik : float + log-likelihood for classic SUR estimation (includes constant) + lamsur : float + spatial autoregressive coefficient in ML SUR Error + bSUR : array + beta coefficients in ML SUR Error + varb : array + variance of beta coefficients in ML SUR Error + sig : array + error variance-covariance matrix in ML SUR Error + bigE : array + n by n_eq matrix of vectors of residuals for each equation + cliksurerr : float + concentrated log-likelihood from ML SUR Error (no constant) + sur_inf : array + inference for regression coefficients, stand. error, t, p + errllik : float + log-likelihood for error model without SUR (with constant) + surerrllik : float + log-likelihood for SUR error model (with constant) + lrtest : tuple + likelihood ratio test for off-diagonal Sigma elements + likrlambda : tuple + likelihood ratio test on spatial autoregressive coefficients + vm : array + asymptotic variance matrix for lambda and Sigma (only for vm=True) + lamsetp : array + inference for lambda, stand. error, t, p (only for vm=True) + lamtest : tuple + with test for constancy of lambda across equations + (test value, degrees of freedom, p-value) + joinlam : tuple + with test for joint significance of lambda across + equations (test value, degrees of freedom, p-value) + surchow : list + with tuples for Chow test on regression coefficients. + each tuple contains test value, degrees of freedom, p-value + name_bigy : dictionary + with name of dependent variable for each equation + name_bigX : dictionary + with names of explanatory variables for each + equation + name_ds : string + name for the data set + name_w : string + name for the weights file + name_regimes : string + name of regime variable for use in the output + + + Examples + -------- + + First import libpysal to load the spatial analysis tools. + + >>> import libpysal + >>> from libpysal.examples import load_example + >>> from libpysal.weights import Queen + >>> import spreg + >>> np.set_printoptions(suppress=True) #prevent scientific format + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that libpysal.io.open() + also reads data in CSV format. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path('natregimes.dbf'), 'r') + + The specification of the model to be estimated can be provided as lists. + Each equation should be listed separately. Equation 1 has HR80 as dependent + variable, and PS80 and UE80 as exogenous regressors. + For equation 2, HR90 is the dependent variable, and PS90 and UE90 the + exogenous regressors. + + >>> y_var = ['HR80','HR90'] + >>> x_var = [['PS80','UE80'],['PS90','UE90']] + >>> yend_var = [['RD80'],['RD90']] + >>> q_var = [['FP79'],['FP89']] + + The SUR method requires data to be provided as dictionaries. PySAL + provides the tool sur_dictxy to create these dictionaries from the + list of variables. The line below will create four dictionaries + containing respectively the dependent variables (bigy), the regressors + (bigX), the dependent variables' names (bigyvars) and regressors' names + (bigXvars). All these will be created from th database (db) and lists + of variables (y_var and x_var) created above. + + >>> bigy,bigX,bigyvars,bigXvars = spreg.sur_dictxy(db,y_var,x_var) + + To run a spatial error model, we need to specify the spatial weights matrix. + To do that, we can open an already existing gal file or create a new one. + In this example, we will create a new one from NAT.shp and transform it to + row-standardized. + + >>> w = Queen.from_shapefile(nat.get_path("natregimes.shp")) + >>> w.transform='r' + + We can now run the regression and then have a summary of the output by typing: + print(reg.summary) + + Alternatively, we can just check the betas and standard errors, asymptotic t + and p-value of the parameters: + + >>> reg = spreg.SURerrorML(bigy,bigX,w=w,name_bigy=bigyvars,name_bigX=bigXvars,name_ds="NAT",name_w="nat_queen") + >>> reg.bSUR + {0: array([[4.02228606], + [0.88489637], + [0.42402845]]), 1: array([[3.04923031], + [1.10972632], + [0.47075678]])} + + >>> reg.sur_inf + {0: array([[ 0.36692175, 10.96224484, 0. ], + [ 0.14129077, 6.26294545, 0. ], + [ 0.04267954, 9.93516909, 0. ]]), 1: array([[ 0.33139967, 9.20106629, 0. ], + [ 0.13352591, 8.31094381, 0. ], + [ 0.04004097, 11.75687747, 0. ]])} + + """ + +
[docs] def __init__( + self, + bigy, + bigX, + w, + regimes=None, + nonspat_diag=True, + spat_diag=False, + vm=False, + epsilon=0.0000001, + name_bigy=None, + name_bigX=None, + name_ds=None, + name_w=None, + name_regimes=None, + ): + + # need checks on match between bigy, bigX dimensions + # check on variable names for listing results + self.name_ds = USER.set_name_ds(name_ds) + self.name_w = USER.set_name_w(name_w, w) + self.n_eq = len(bigy.keys()) + # initialize names - should be generated by sur_stack + if name_bigy: + self.name_bigy = name_bigy + else: # need to construct y names + self.name_bigy = {} + for r in range(self.n_eq): + yn = "dep_var_" + str(r) + self.name_bigy[r] = yn + if name_bigX is None: + name_bigX = {} + for r in range(self.n_eq): + k = bigX[r].shape[1] - 1 + name_x = ["var_" + str(i + 1) + "_" + str(r + 1) for i in range(k)] + ct = "Constant_" + str(r + 1) # NOTE: constant always included in X + name_x.insert(0, ct) + name_bigX[r] = name_x + + if regimes is not None: + self.constant_regi = "many" + self.cols2regi = "all" + self.regime_err_sep = False + self.name_regimes = USER.set_name_ds(name_regimes) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + self.name_x_r = name_bigX + cols2regi_dic = {} + self.name_bigX = {} + for r in range(self.n_eq): + cols2regi_dic[r] = REGI.check_cols2regi( + self.constant_regi, self.cols2regi, bigX[r], add_cons=False + ) + USER.check_regimes(self.regimes_set, bigy[0].shape[0], bigX[r].shape[1]) + bigX[r], self.name_bigX[r] = REGI.Regimes_Frame.__init__( + self, + bigX[r], + regimes, + constant_regi=None, + cols2regi=cols2regi_dic[r], + names=name_bigX[r], + ) + else: + self.name_bigX = name_bigX + + # moved init here + BaseSURerrorML.__init__(self, bigy=bigy, bigX=bigX, w=w, epsilon=epsilon) + + # inference + self.sur_inf = sur_setp(self.bSUR, self.varb) + + # adjust concentrated log lik for constant + const = -self.n2 * (self.n_eq * (1.0 + np.log(2.0 * np.pi))) + self.errllik = const + self.clikerr + self.surerrllik = const + self.cliksurerr + + # LR test on off-diagonal sigma + if nonspat_diag: + M = self.n_eq * (self.n_eq - 1) / 2.0 + likrodiag = 2.0 * (self.surerrllik - self.errllik) + plik1 = stats.chisqprob(likrodiag, M) + self.lrtest = (likrodiag, int(M), plik1) + else: + self.lrtest = None + + # LR test on spatial autoregressive coefficients + if spat_diag: + liklambda = 2.0 * (self.surerrllik - self.llik) + plik2 = stats.chisqprob(liklambda, self.n_eq) + self.likrlambda = (liklambda, self.n_eq, plik2) + else: + self.likrlambda = None + + # asymptotic variance for spatial coefficient + if vm: + self.vm = surerrvm(self.n, self.n_eq, w, self.lamsur, self.sig) + vlam = self.vm[: self.n_eq, : self.n_eq] + self.lamsetp = lam_setp(self.lamsur, vlam) + # test on constancy of lambdas + R = REGI.buildR(kr=1, kf=0, nr=self.n_eq) + w, p = REGI.wald_test(self.lamsur, R, np.zeros((R.shape[0], 1)), vlam) + self.lamtest = (w, R.shape[0], p) + if spat_diag: # test on joint significance of lambdas + Rj = np.identity(self.n_eq) + wj, pj = REGI.wald_test( + self.lamsur, Rj, np.zeros((Rj.shape[0], 1)), vlam + ) + self.joinlam = (wj, Rj.shape[0], pj) + else: + self.joinlam = None + else: + self.vm = None + self.lamsetp = None + self.lamtest = None + self.joinlam = None + + # test on constancy of regression coefficients across equations + if check_k(self.bigK): # only for equal number of variables + self.surchow = sur_chow(self.n_eq, self.bigK, self.bSUR, self.varb) + else: + self.surchow = None + + # listing of results + self.title = "SEEMINGLY UNRELATED REGRESSIONS (SUR) - ML SPATIAL ERROR MODEL" + if regimes is not None: + self.title = "SUR - ML SPATIAL ERROR MODEL - REGIMES" + self.chow_regimes = {} + varb_counter = 0 + for r in range(self.n_eq): + counter_end = varb_counter + self.bSUR[r].shape[0] + self.chow_regimes[r] = REGI._chow_run( + len(cols2regi_dic[r]), + 0, + 0, + len(self.regimes_set), + self.bSUR[r], + self.varb[varb_counter:counter_end, varb_counter:counter_end], + ) + varb_counter = counter_end + regimes = True + + SUMMARY.SUR( + reg=self, + nonspat_diag=nonspat_diag, + spat_diag=spat_diag, + lambd=True, + regimes=regimes, + )
+ + +def jacob(lam, n_eq, I, WS): + """Log-Jacobian for SUR Error model + + Parameters + ---------- + lam : array + n_eq by 1 array of spatial autoregressive parameters + n_eq : int + number of equations + I : sparse matrix + sparse Identity matrix + WS : sparse matrix + sparse spatial weights matrix + + Returns + ------- + logjac : float + the log Jacobian + + """ + logjac = 0.0 + for r in range(n_eq): + lami = lam[r] + lamWS = WS.multiply(lami) + B = (I - lamWS).tocsc() + LU = SuperLU(B) + jj = np.sum(np.log(np.abs(LU.U.diagonal()))) + logjac += jj + return logjac + + +def clik(lam, n, n2, n_eq, bigE, I, WS): + """ + Concentrated (negative) log-likelihood for SUR Error model + + Parameters + ---------- + lam : array + n_eq x 1 array of spatial autoregressive parameters + n : int + number of observations in each cross-section + n2 : int + n/2 + n_eq : int + number of equations + bigE : array + n by n_eq matrix with vectors of residuals for + each equation + I : sparse Identity matrix + WS : sparse spatial weights matrix + + Returns + ------- + -clik : float + negative (for minimize) of the concentrated + log-likelihood function + + """ + WbigE = WS * bigE + spfbigE = bigE - WbigE * lam.T + sig = np.dot(spfbigE.T, spfbigE) / n + ldet = la.slogdet(sig)[1] + logjac = jacob(lam, n_eq, I, WS) + clik = -n2 * ldet + logjac + return -clik # negative for minimize + + +def surerrvm(n, n_eq, w, lam, sig): + """ + Asymptotic variance matrix for lambda and Sigma in + ML SUR Error estimation + + Source: Anselin (1988) :cite:`Anselin1988`, Chapter 10. + + Parameters + ---------- + n : int + number of cross-sectional observations + n_eq : int + number of equations + w : spatial weights object + lam : array + n_eq by 1 vector with spatial autoregressive coefficients + sig : array + n_eq by n_eq matrix with cross-equation error covariances + + Returns + ------- + vm : array + asymptotic variance-covariance matrix for spatial autoregressive + coefficients and the upper triangular elements of Sigma + n_eq + n_eq x (n_eq + 1) / 2 coefficients + + + """ + # inverse Sigma + sigi = la.inv(sig) + sisi = sigi * sig + # elements of Psi_lam,lam + # trace terms + trDi = np.zeros((n_eq, 1)) + trDDi = np.zeros((n_eq, 1)) + trDTDi = np.zeros((n_eq, 1)) + trDTiDj = np.zeros((n_eq, n_eq)) + WS = w.sparse + I = sp.identity(n) + for i in range(n_eq): + lami = lam[i][0] + lamWS = WS.multiply(lami) + B = I - lamWS + bb = B.todense() + Bi = la.inv(bb) + D = WS * Bi + trDi[i] = np.trace(D) + DD = np.dot(D, D) + trDDi[i] = np.trace(DD) + DD = np.dot(D.T, D) + trDTDi[i] = np.trace(DD) + for j in range(i + 1, n_eq): + lamj = lam[j][0] + lamWS = WS.multiply(lamj) + B = I - lamWS + bb = B.todense() + Bi = la.inv(bb) + Dj = WS * Bi + DD = np.dot(D.T, Dj) + trDTiDj[i, j] = np.trace(DD) + trDTiDj[j, i] = trDTiDj[i, j] + np.fill_diagonal(trDTiDj, trDTDi) + + sisjT = sisi * trDTiDj + Vll = np.diagflat(trDDi) + sisjT + + # elements of Psi_lam_sig + P = int(n_eq * (n_eq + 1) / 2) # force ints to be ints + tlist = [(i, j) for i in range(n_eq) for j in range(i, n_eq)] + zog = sigi * trDi + Vlsig = np.zeros((n_eq, P)) + for i in range(n_eq): + for j in range(n_eq): + if i > j: + jj = tlist.index((j, i)) + else: + jj = tlist.index((i, j)) + Vlsig[i, jj] = zog[i, j] + + # top of Psi + vtop = np.hstack((Vll, Vlsig)) + + # elements of Psi_sig_sig + + Vsig = np.zeros((P, P)) + for ij in range(P): + i, j = tlist[ij] + for hk in range(P): + h, k = tlist[hk] + if i == j: + if h == k: + Vsig[ij, hk] = 0.5 * (sigi[i, h] ** 2) + else: # h not equal to k + Vsig[ij, hk] = sigi[i, h] * sigi[i, k] + else: # i not equal to j + if h == k: + Vsig[ij, hk] = sigi[i, h] * sigi[j, h] + else: # h not equal to k + Vsig[ij, hk] = sigi[i, h] * sigi[j, k] + sigi[i, k] * sigi[j, h] + Vsig = n * Vsig + + # bottom of Psi + vbottom = np.hstack((Vlsig.T, Vsig)) + + # all of Psi + vbig = np.vstack((vtop, vbottom)) + + # inverse of Psi + vm = la.inv(vbig) + + return vm + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + import numpy as np + import libpysal + from .sur_utils import sur_dictxy, sur_dictZ + from libpysal.examples import load_example + from libpysal.weights import Queen + + nat = load_example("Natregimes") + db = libpysal.io.open(nat.get_path("natregimes.dbf"), "r") + y_var = ["HR80", "HR90"] + x_var = [["PS80", "UE80"], ["PS90", "UE90"]] + w = Queen.from_shapefile(nat.get_path("natregimes.shp")) + w.transform = "r" + bigy0, bigX0, bigyvars0, bigXvars0 = sur_dictxy(db, y_var, x_var) + reg0 = SURerrorML( + bigy0, + bigX0, + w, + #regimes=regimes, + name_bigy=bigyvars0, + name_bigX=bigXvars0, + name_w="natqueen", + name_ds="natregimes", + vm=True, + nonspat_diag=True, + spat_diag=True, + ) + + # reg0 = SURerrorGM(bigy0,bigX0,w,regimes=regimes,name_bigy=bigyvars0,name_bigX=bigXvars0,\ + # name_w="natqueen",name_ds="natregimes",vm=False,nonspat_diag=True,spat_diag=False) + + print(reg0.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/sur_lag.html b/_modules/spreg/sur_lag.html new file mode 100644 index 00000000..8703d9bd --- /dev/null +++ b/_modules/spreg/sur_lag.html @@ -0,0 +1,679 @@ + + + + + + + spreg.sur_lag — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.sur_lag

+"""
+Spatial Lag SUR estimation
+"""
+
+__author__ = "Luc Anselin lanselin@gmail.com,    \
+             Pedro V. Amaral pedrovma@gmail.com"
+
+
+import numpy as np
+from . import summary_output as SUMMARY
+from . import user_output as USER
+from . import regimes as REGI
+from .sur import BaseThreeSLS
+from .diagnostics_sur import sur_setp, sur_chow, sur_joinrho
+from .sur_utils import check_k
+
+__all__ = ["SURlagIV"]
+
+
+
[docs]class SURlagIV(BaseThreeSLS, REGI.Regimes_Frame): + """ + User class for spatial lag estimation using IV + + Parameters + ---------- + bigy : dictionary + with vector for dependent variable by equation + bigX : dictionary + with matrix of explanatory variables by equation + (note, already includes constant term) + bigyend : dictionary + with matrix of endogenous variables by equation + (optional) + bigq : dictionary + with matrix of instruments by equation + (optional) + w : spatial weights object, required + vm : boolean + listing of full variance-covariance matrix, default = False + w_lags : integer + order of spatial lags for WX instruments, default = 1 + lag_q : boolean + flag to apply spatial lag to other instruments, + default = True + nonspat_diag : boolean + flag for non-spatial diagnostics, default = True + spat_diag : boolean + flag for spatial diagnostics, default = False + name_bigy : dictionary + with name of dependent variable for each equation. + default = None, but should be specified. + is done when sur_stackxy is used. + name_bigX : dictionary + with names of explanatory variables for each + equation. + default = None, but should be specified. + is done when sur_stackxy is used. + name_bigyend : dictionary + with names of endogenous variables for each + equation. + default = None, but should be specified. + is done when sur_stackZ is used. + name_bigq : dictionary + with names of instrumental variables for each + equations. + default = None, but should be specified. + is done when sur_stackZ is used. + name_ds : string + name for the data set + name_w : string + name for the spatial weights + + Attributes + ---------- + w : spatial weights object + bigy : dictionary + with y values + bigZ : dictionary + with matrix of exogenous and endogenous variables + for each equation + bigyend : dictionary + with matrix of endogenous variables for each + equation; contains Wy only if no other endogenous specified + bigq : dictionary + with matrix of instrumental variables for each + equation; contains WX only if no other endogenous specified + bigZHZH : dictionary + with matrix of cross products Zhat_r'Zhat_s + bigZHy : dictionary + with matrix of cross products Zhat_r'y_end_s + n_eq : int + number of equations + n : int + number of observations in each cross-section + bigK : array + vector with number of explanatory variables (including constant, + exogenous and endogenous) for each equation + b2SLS : dictionary + with 2SLS regression coefficients for each equation + tslsE : array + N x n_eq array with OLS residuals for each equation + b3SLS : dictionary + with 3SLS regression coefficients for each equation + varb : array + variance-covariance matrix + sig : array + Sigma matrix of inter-equation error covariances + resids : array + n by n_eq array of residuals + corr : array + inter-equation 3SLS error correlation matrix + tsls_inf : dictionary + with standard error, asymptotic t and p-value, + one for each equation + joinrho : tuple + test on joint significance of spatial autoregressive coefficient. + tuple with test statistic, degrees of freedom, p-value + surchow : array + list with tuples for Chow test on regression coefficients + each tuple contains test value, degrees of freedom, p-value + name_w : string + name for the spatial weights + name_ds : string + name for the data set + name_bigy : dictionary + with name of dependent variable for each equation + name_bigX : dictionary + with names of explanatory variables for each + equation + name_bigyend : dictionary + with names of endogenous variables for each + equation + name_bigq : dictionary + with names of instrumental variables for each + equations + + + Examples + -------- + + First import libpysal to load the spatial analysis tools. + + >>> import libpysal + >>> from libpysal.examples import load_example + >>> from libpysal.weights import Queen + >>> import spreg + >>> np.set_printoptions(suppress=True) #prevent scientific format + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that libpysal.io.open() + also reads data in CSV format. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path('natregimes.dbf'), 'r') + + The specification of the model to be estimated can be provided as lists. + Each equation should be listed separately. Although not required, + in this example we will specify additional endogenous regressors. + Equation 1 has HR80 as dependent variable, PS80 and UE80 as exogenous regressors, + RD80 as endogenous regressor and FP79 as additional instrument. + For equation 2, HR90 is the dependent variable, PS90 and UE90 the + exogenous regressors, RD90 as endogenous regressor and FP99 as + additional instrument + + >>> y_var = ['HR80','HR90'] + >>> x_var = [['PS80','UE80'],['PS90','UE90']] + >>> yend_var = [['RD80'],['RD90']] + >>> q_var = [['FP79'],['FP89']] + + The SUR method requires data to be provided as dictionaries. PySAL + provides two tools to create these dictionaries from the list of variables: + sur_dictxy and sur_dictZ. The tool sur_dictxy can be used to create the + dictionaries for Y and X, and sur_dictZ for endogenous variables (yend) and + additional instruments (q). + + >>> bigy,bigX,bigyvars,bigXvars = spreg.sur_dictxy(db,y_var,x_var) + >>> bigyend,bigyendvars = spreg.sur_dictZ(db,yend_var) + >>> bigq,bigqvars = spreg.sur_dictZ(db,q_var) + + To run a spatial lag model, we need to specify the spatial weights matrix. + To do that, we can open an already existing gal file or create a new one. + In this example, we will create a new one from NAT.shp and transform it to + row-standardized. + + >>> w = Queen.from_shapefile(nat.get_path("natregimes.shp")) + >>> w.transform='r' + + We can now run the regression and then have a summary of the output by typing: + print(reg.summary) + + Alternatively, we can just check the betas and standard errors, asymptotic t + and p-value of the parameters: + + >>> reg = spreg.SURlagIV(bigy,bigX,bigyend,bigq,w=w,name_bigy=bigyvars,name_bigX=bigXvars,name_bigyend=bigyendvars,name_bigq=bigqvars,name_ds="NAT",name_w="nat_queen") + >>> reg.b3SLS + {0: array([[ 6.95472387], + [ 1.44044301], + [-0.00771893], + [ 3.65051153], + [ 0.00362663]]), 1: array([[ 5.61101925], + [ 1.38716801], + [-0.15512029], + [ 3.1884457 ], + [ 0.25832185]])} + + >>> reg.tsls_inf + {0: array([[ 0.49128435, 14.15620899, 0. ], + [ 0.11516292, 12.50787151, 0. ], + [ 0.03204088, -0.2409087 , 0.80962588], + [ 0.1876025 , 19.45875745, 0. ], + [ 0.05450628, 0.06653605, 0.94695106]]), 1: array([[ 0.44969956, 12.47726211, 0. ], + [ 0.10440241, 13.28674277, 0. ], + [ 0.04150243, -3.73761961, 0.00018577], + [ 0.19133145, 16.66451427, 0. ], + [ 0.04394024, 5.87893596, 0. ]])} + """ + +
[docs] def __init__( + self, + bigy, + bigX, + bigyend=None, + bigq=None, + w=None, + regimes=None, + vm=False, + regime_lag_sep=False, + w_lags=1, + lag_q=True, + nonspat_diag=True, + spat_diag=False, + name_bigy=None, + name_bigX=None, + name_bigyend=None, + name_bigq=None, + name_ds=None, + name_w=None, + name_regimes=None, + ): + if w is None: + raise Exception("Spatial weights required for SUR-Lag") + self.w = w + WS = w.sparse + self.name_ds = USER.set_name_ds(name_ds) + self.name_w = USER.set_name_w(name_w, w) + if bigyend and not (bigq): + raise Exception("Instruments needed when endogenous variables") + # initialize + self.bigy = bigy + self.n_eq = len(self.bigy.keys()) + if name_bigy: + self.name_bigy = name_bigy + else: # need to construct y names + self.name_bigy = {} + for r in range(self.n_eq): + yn = "dep_var_" + str(r + 1) + self.name_bigy[r] = yn + # self.bigX = bigX + if name_bigX is None: + name_bigX = {} + for r in range(self.n_eq): + k = bigX[r].shape[1] - 1 + name_x = ["var_" + str(i + 1) + "_" + str(r + 1) for i in range(k)] + ct = "Constant_" + str(r + 1) # NOTE: constant always included in X + name_x.insert(0, ct) + name_bigX[r] = name_x + if name_bigyend is None: + name_bigyend = {} + if bigyend is not None: # check on other endogenous + self.bigyend = bigyend + for r in range(self.n_eq): + ky = bigyend[r].shape[1] + name_ye = ["end_" + str(i + 1) + "_" + str(r + 1) for i in range(ky)] + name_bigyend[r] = name_ye + if name_bigq is None: + name_bigq = {} + if bigq is not None: # check on instruments + self.bigq = bigq + for r in range(self.n_eq): + ki = bigq[r].shape[1] + name_i = ["inst_" + str(i + 1) + "_" + str(r + 1) for i in range(ki)] + name_bigq[r] = name_i + + if regimes is not None: + self.constant_regi = "many" + self.cols2regi = "all" + self.regime_err_sep = False + self.name_regimes = USER.set_name_ds(name_regimes) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + cols2regi_dic = {} + self.name_bigX, self.name_bigq, self.name_bigyend = {}, {}, {} + self.name_x_r = name_bigX + + # spatial lag dependent variable varying across regimes + if regime_lag_sep == True: + bigyend, name_bigyend = _get_spatial_lag( + self, bigyend, WS, name_bigyend + ) + + for r in range(self.n_eq): + if bigyend is not None: + self.name_x_r[r] += name_bigyend[r] + cols2regi_dic[r] = REGI.check_cols2regi( + self.constant_regi, + self.cols2regi, + bigX[r], + yend=bigyend[r], + add_cons=False, + ) + else: + cols2regi_dic[r] = REGI.check_cols2regi( + self.constant_regi, self.cols2regi, bigX[r], add_cons=False + ) + USER.check_regimes(self.regimes_set, bigy[0].shape[0], bigX[r].shape[1]) + bigX[r], self.name_bigX[r] = REGI.Regimes_Frame.__init__( + self, + bigX[r], + regimes, + constant_regi=None, + cols2regi=cols2regi_dic[r], + names=name_bigX[r], + ) + if bigq is not None: + bigq[r], self.name_bigq[r] = REGI.Regimes_Frame.__init__( + self, + bigq[r], + regimes, + constant_regi=None, + cols2regi="all", + names=name_bigq[r], + ) + if bigyend is not None: + bigyend[r], self.name_bigyend[r] = REGI.Regimes_Frame.__init__( + self, + bigyend[r], + regimes, + constant_regi=None, + cols2regi=cols2regi_dic[r], + yend=True, + names=name_bigyend[r], + ) + else: + self.name_bigX, self.name_bigq, self.name_bigyend = ( + name_bigX, + name_bigq, + name_bigyend, + ) + + # spatial lag dependent variable fixed across regimes or no regimes + if regimes is None or regime_lag_sep == False: + bigyend, self.name_bigyend = _get_spatial_lag( + self, bigyend, WS, name_bigyend + ) + # spatially lagged exogenous variables + bigwx = {} + wxnames = {} + if w_lags == 1: + for r in range(self.n_eq): + bigwx[r] = WS * bigX[r][:, 1:] + wxnames[r] = ["W_" + i for i in self.name_bigX[r][1:]] + if bigq: # other instruments + if lag_q: # also lags for instruments + bigwq = {} + for r in range(self.n_eq): + bigwq = WS * bigq[r] + bigq[r] = np.hstack((bigq[r], bigwx[r], bigwq)) + wqnames = ["W_" + i for i in self.name_bigq[r]] + wxnames[r] = wxnames[r] + wqnames + self.name_bigq[r] = self.name_bigq[r] + wxnames[r] + else: # no lags for other instruments + for r in range(self.n_eq): + bigq[r] = np.hstack((bigq[r], bigwx[r])) + self.name_bigq[r] = self.name_bigq[r] + wxnames[r] + else: # no other instruments only wx + bigq = {} + for r in range(self.n_eq): + bigq[r] = bigwx[r] + self.name_bigq[r] = wxnames[r] + elif w_lags > 1: # higher order lags for WX + for r in range(self.n_eq): + bigwxwork = WS * bigX[r][:, 1:] + bigwx[r] = bigwxwork + nameswork = ["W_" + i for i in self.name_bigX[r][1:]] + wxnames[r] = nameswork + for i in range(1, w_lags): + bigwxwork = WS * bigwxwork + bigwx[r] = np.hstack((bigwx[r], bigwxwork)) + nameswork = ["W" + i for i in nameswork] + wxnames[r] = wxnames[r] + nameswork + if bigq: # other instruments + if lag_q: # lags for other instruments + wq = {} + wqnames = {} + for r in range(self.n_eq): + bigwq = WS * bigq[r] + wqnameswork = ["W_" + i for i in self.name_bigq[r]] + wqnames[r] = wqnameswork + wq[r] = bigwq + for i in range(1, w_lags): + bigwq = WS * bigwq + wq[r] = np.hstack((wq[r], bigwq)) + wqnameswork = ["W" + i for i in wqnameswork] + wqnames[r] = wqnames[r] + wqnameswork + bigq[r] = np.hstack((bigq[r], bigwx[r], wq[r])) + self.name_bigq[r] = self.name_bigq[r] + wxnames[r] + wqnames[r] + + else: # no lags for other instruments + for r in range(self.n_eq): + bigq[r] = np.hstack((bigq[r], bigwx[r])) + self.name_bigq[r] = self.name_bigq[r] + wxnames[r] + else: # no other instruments only wx + bigq = {} + for r in range(self.n_eq): + bigq[r] = bigwx[r] + self.name_bigq[r] = wxnames[r] + + else: + raise Exception("Lag order must be 1 or higher") + + BaseThreeSLS.__init__( + self, bigy=self.bigy, bigX=bigX, bigyend=bigyend, bigq=bigq + ) + + # inference + self.tsls_inf = sur_setp(self.b3SLS, self.varb) + + # test on joint significance of spatial coefficients + if spat_diag: + self.joinrho = sur_joinrho(self.n_eq, self.bigK, self.b3SLS, self.varb) + else: + self.joinrho = None + + # test on constancy of coefficients across equations + if check_k(self.bigK): # only for equal number of variables + self.surchow = sur_chow(self.n_eq, self.bigK, self.b3SLS, self.varb) + else: + self.surchow = None + + # list results + self.title = "SEEMINGLY UNRELATED REGRESSIONS (SUR) - SPATIAL LAG MODEL" + if regimes is not None: + self.title = "SUR - SPATIAL LAG MODEL - REGIMES" + self.chow_regimes = {} + varb_counter = 0 + fixed_lag = 1 + if regime_lag_sep == True: + fixed_lag += -1 + for r in range(self.n_eq): + counter_end = varb_counter + self.b3SLS[r].shape[0] + self.chow_regimes[r] = REGI._chow_run( + len(cols2regi_dic[r]), + fixed_lag, + 0, + len(self.regimes_set), + self.b3SLS[r], + self.varb[varb_counter:counter_end, varb_counter:counter_end], + ) + varb_counter = counter_end + regimes = True + SUMMARY.SUR( + reg=self, + tsls=True, + spat_diag=spat_diag, + nonspat_diag=nonspat_diag, + ml=False, + regimes=regimes, + )
+ + +def _get_spatial_lag(reg, bigyend, WS, name_bigyend): + bigylag = {} + for r in range(reg.n_eq): + bigylag[r] = WS * reg.bigy[r] + if bigyend is not None: + for r in range(reg.n_eq): + bigyend[r] = np.hstack((bigyend[r], bigylag[r])) + # adjust variable names + for r in range(reg.n_eq): + wyname = "W_" + reg.name_bigy[r] + name_bigyend[r].append(wyname) + else: # no other endogenous variables + bigyend = {} + for r in range(reg.n_eq): + bigyend[r] = bigylag[r] + # variable names + for r in range(reg.n_eq): + wyname = ["W_" + reg.name_bigy[r]] + name_bigyend[r] = wyname + return bigyend, name_bigyend + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + # _test() + import numpy as np + import libpysal + from .sur_utils import sur_dictxy + from libpysal.examples import load_example + from libpysal.weights import Queen + + nat = load_example("Natregimes") + db = libpysal.io.open(nat.get_path("natregimes.dbf"), "r") + w = Queen.from_shapefile(nat.get_path("natregimes.shp")) + w.transform = "r" + y_var0 = ["HR80", "HR90"] + x_var0 = [["PS80", "UE80"], ["PS90", "UE90"]] + regimes = db.by_col("SOUTH") + + bigy0, bigX0, bigyvars0, bigXvars0 = sur_dictxy(db, y_var0, x_var0) + + reg = SURlagIV( + bigy0, + bigX0, + w=w, + regimes=regimes, + name_bigy=bigyvars0, + name_bigX=bigXvars0, + name_ds="NAT", + name_w="nat_queen", + nonspat_diag=True, + spat_diag=True, + regime_lag_sep=True, + ) + print(reg.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/twosls.html b/_modules/spreg/twosls.html new file mode 100644 index 00000000..158ed8c3 --- /dev/null +++ b/_modules/spreg/twosls.html @@ -0,0 +1,696 @@ + + + + + + + spreg.twosls — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.twosls

+import numpy as np
+import numpy.linalg as la
+from . import robust as ROBUST
+from . import user_output as USER
+from .utils import spdot, sphstack, RegressionPropsY, RegressionPropsVM, set_warn, get_lags
+import pandas as pd
+from .output import output, _spat_diag_out
+
+__author__ = "Luc Anselin lanselin@gmail.com, Pedro Amaral pedrovma@gmail.com, David C. Folch david.folch@asu.edu, Jing Yao jingyao@asu.edu"
+__all__ = ["TSLS"]
+
+
+class BaseTSLS(RegressionPropsY, RegressionPropsVM):
+
+    """
+    Two stage least squares (2SLS) (note: no consistency checks,
+    diagnostics or constant added)
+
+    Parameters
+    ----------
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, excluding the constant
+    yend         : array
+                   Two dimensional array with n rows and one column for each
+                   endogenous variable
+    q            : array
+                   Two dimensional array with n rows and one column for each
+                   external exogenous variable to use as instruments (note:
+                   this should not contain any variables from x); cannot be
+                   used in combination with h
+    h            : array
+                   Two dimensional array with n rows and one column for each
+                   exogenous variable to use as instruments (note: this
+                   can contain variables from x); cannot be used in
+                   combination with q
+    robust       : string
+                   If 'white', then a White consistent estimator of the
+                   variance-covariance matrix is given.  If 'hac', then a
+                   HAC consistent estimator of the variance-covariance
+                   matrix is given. Default set to None.
+    gwk          : pysal W object
+                   Kernel spatial weights needed for HAC estimation. Note:
+                   matrix must have ones along the main diagonal.
+    sig2n_k      : boolean
+                   If True, then use n-k to estimate sigma^2. If False, use n.
+
+
+    Attributes
+    ----------
+    betas        : array
+                   kx1 array of estimated coefficients
+    u            : array
+                   nx1 array of residuals
+    predy        : array
+                   nx1 array of predicted y values
+    n            : integer
+                   Number of observations
+    k            : integer
+                   Number of variables for which coefficients are estimated
+                   (including the constant)
+    kstar        : integer
+                   Number of endogenous variables.
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, including the constant
+    yend         : array
+                   Two dimensional array with n rows and one column for each
+                   endogenous variable
+    q            : array
+                   Two dimensional array with n rows and one column for each
+                   external exogenous variable used as instruments
+    z            : array
+                   nxk array of variables (combination of x and yend)
+    h            : array
+                   nxl array of instruments (combination of x and q)
+    mean_y       : float
+                   Mean of dependent variable
+    std_y        : float
+                   Standard deviation of dependent variable
+    vm           : array
+                   Variance covariance matrix (kxk)
+    utu          : float
+                   Sum of squared residuals
+    sig2         : float
+                   Sigma squared used in computations
+    sig2n        : float
+                   Sigma squared (computed with n in the denominator)
+    sig2n_k      : float
+                   Sigma squared (computed with n-k in the denominator)
+    hth          : float
+                   :math:`H'H`
+    hthi         : float
+                   :math:`(H'H)^{-1}`
+    varb         : array
+                   :math:`(Z'H (H'H)^{-1} H'Z)^{-1}`
+    zthhthi      : array
+                   :math:`Z'H(H'H)^{-1}`
+    pfora1a2     : array
+                   :math:`n(zthhthi)'varb`
+
+
+    Examples
+    --------
+
+    >>> import numpy as np
+    >>> import libpysal
+    >>> import spreg
+    >>> db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"),'r')
+    >>> y = np.array(db.by_col("CRIME"))
+    >>> y = np.reshape(y, (49,1))
+    >>> X = []
+    >>> X.append(db.by_col("INC"))
+    >>> X = np.array(X).T
+    >>> X = np.hstack((np.ones(y.shape),X))
+    >>> yd = []
+    >>> yd.append(db.by_col("HOVAL"))
+    >>> yd = np.array(yd).T
+    >>> q = []
+    >>> q.append(db.by_col("DISCBD"))
+    >>> q = np.array(q).T
+    >>> reg = spreg.twosls.BaseTSLS(y, X, yd, q=q)
+    >>> print(reg.betas.T)
+    [[88.46579584  0.5200379  -1.58216593]]
+    >>> reg = spreg.twosls.BaseTSLS(y, X, yd, q=q, robust="white")
+
+    """
+
+    def __init__(
+        self, y, x, yend, q=None, h=None, robust=None, gwk=None, sig2n_k=False
+    ):
+
+        if issubclass(type(q), np.ndarray) and issubclass(type(h), np.ndarray):
+            raise Exception("Please do not provide 'q' and 'h' together")
+        if q is None and h is None:
+            raise Exception("Please provide either 'q' or 'h'")
+
+        self.y = y
+        self.n = y.shape[0]
+        self.x = x
+
+        self.kstar = yend.shape[1]
+        # including exogenous and endogenous variables
+        z = sphstack(self.x, yend)
+        if type(h).__name__ not in ["ndarray", "csr_matrix"]:
+            # including exogenous variables and instrument
+            h = sphstack(self.x, q)
+        self.z = z
+        self.h = h
+        self.q = q
+        self.yend = yend
+        # k = number of exogenous variables and endogenous variables
+        self.k = z.shape[1]
+        hth = spdot(h.T, h)
+        hthi = la.inv(hth)
+        zth = spdot(z.T, h)
+        hty = spdot(h.T, y)
+
+        factor_1 = np.dot(zth, hthi)
+        factor_2 = np.dot(factor_1, zth.T)
+        # this one needs to be in cache to be used in AK
+        varb = la.inv(factor_2)
+        factor_3 = np.dot(varb, factor_1)
+        betas = np.dot(factor_3, hty)
+        self.betas = betas
+        self.varb = varb
+        self.zthhthi = factor_1
+
+        # predicted values
+        self.predy = spdot(z, betas)
+
+        # residuals
+        u = y - self.predy
+        self.u = u
+
+        # attributes used in property
+        self.hth = hth  # Required for condition index
+        self.hthi = hthi  # Used in error models
+        self.htz = zth.T
+
+        if robust:
+            self.vm = ROBUST.robust_vm(reg=self, gwk=gwk, sig2n_k=sig2n_k)
+
+        if sig2n_k:
+            self.sig2 = self.sig2n_k
+        else:
+            self.sig2 = self.sig2n
+
+    @property
+    def pfora1a2(self):
+        if "pfora1a2" not in self._cache:
+            self._cache["pfora1a2"] = self.n * np.dot(self.zthhthi.T, self.varb)
+        return self._cache["pfora1a2"]
+
+    @property
+    def vm(self):
+        try:
+            return self._cache["vm"]
+        except AttributeError:
+            self._cache = {}
+            self._cache["vm"] = np.dot(self.sig2, self.varb)
+        except KeyError:
+            self._cache["vm"] = np.dot(self.sig2, self.varb)
+        return self._cache["vm"]
+
+    @vm.setter
+    def vm(self, val):
+        try:
+            self._cache["vm"] = val
+        except AttributeError:
+            self._cache = {}
+            self._cache["vm"] = val
+        except KeyError:
+            self._cache["vm"] = val
+
+
+
[docs]class TSLS(BaseTSLS): + """ + Two stage least squares with results and diagnostics. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + w : pysal W object + Spatial weights object (required if running spatial + diagnostics) + robust : string + If 'white', then a White consistent estimator of the + variance-covariance matrix is given. If 'hac', then a + HAC consistent estimator of the variance-covariance + matrix is given. Default set to None. + gwk : pysal W object + Kernel spatial weights needed for HAC estimation. Note: + matrix must have ones along the main diagonal. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SLX type. + sig2n_k : boolean + If True, then use n-k to estimate sigma^2. If False, use n. + spat_diag : boolean + If True, then compute Anselin-Kelejian test (requires w) + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + kstar : integer + Number of endogenous variables. + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + z : array + nxk array of variables (combination of x and yend) + h : array + nxl array of instruments (combination of x and q) + robust : string + Adjustment for robust standard errors + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + utu : float + Sum of squared residuals + sig2 : float + Sigma squared used in computations + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + ak_test : tuple + Anselin-Kelejian test; tuple contains the pair (statistic, + p-value) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + sig2n : float + Sigma squared (computed with n in the denominator) + sig2n_k : float + Sigma squared (computed with n-k in the denominator) + hth : float + :math:`H'H` + hthi : float + :math:`(H'H)^{-1}` + varb : array + :math:`(Z'H (H'H)^{-1} H'Z)^{-1}` + zthhthi : array + :math:`Z'H(H'H)^{-1}` + pfora1a2 : array + :math:`n(zthhthi)'varb` + + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"),'r') + + Extract the CRIME column (crime rates) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array(db.by_col("CRIME")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) vector from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this model adds a vector of ones to the + independent variables passed in, but this can be overridden by passing + constant=False. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X = np.array(X).T + + In this case we consider HOVAL (home value) is an endogenous regressor. + We tell the model that this is so by passing it in a different parameter + from the exogenous variables (x). + + >>> yd = [] + >>> yd.append(db.by_col("HOVAL")) + >>> yd = np.array(yd).T + + Because we have endogenous variables, to obtain a correct estimate of the + model, we need to instrument for HOVAL. We use DISCBD (distance to the + CBD) for this and hence put it in the instruments parameter, 'q'. + + >>> q = [] + >>> q.append(db.by_col("DISCBD")) + >>> q = np.array(q).T + + We are all set with the preliminars, we are good to run the model. In this + case, we will need the variables (exogenous and endogenous) and the + instruments. If we want to have the names of the variables printed in the + output summary, we will have to pass them in as well, although this is optional. + + >>> from spreg import TSLS + >>> reg = TSLS(y, X, yd, q, name_x=['inc'], name_y='crime', name_yend=['hoval'], name_q=['discbd'], name_ds='columbus') + >>> print(reg.betas.T) + [[88.46579584 0.5200379 -1.58216593]] + """ + +
[docs] def __init__( + self, + y, + x, + yend, + q, + w=None, + robust=None, + gwk=None, + slx_lags=0, + sig2n_k=False, + spat_diag=False, + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_gwk=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(y, x, yend, q) + y = USER.check_y(y, n) + USER.check_robust(robust, gwk) + if robust == "hac" and spat_diag: + set_warn( + self, + "Spatial diagnostics are not available for HAC estimation. The spatial diagnostics have been disabled for this model.", + ) + spat_diag = False + USER.check_spat_diag(spat_diag, w) + x_constant, name_x, warn = USER.check_constant(x, name_x) + self.name_x = USER.set_name_x(name_x, x_constant) + if slx_lags>0: + USER.check_weights(w, y, w_required=True) + lag_x = get_lags(w, x_constant[:, 1:], slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + self.name_x += USER.set_name_spatial_lags(self.name_x[1:], slx_lags) + else: + USER.check_weights(w, y, w_required=False) + set_warn(self, warn) + BaseTSLS.__init__( + self, + y=y, + x=x_constant, + yend=yend, + q=q, + robust=robust, + gwk=gwk, + sig2n_k=sig2n_k, + ) + self.title = "TWO STAGE LEAST SQUARES" + if slx_lags > 0: + self.title += " WITH SPATIALLY LAGGED X (2SLS-SLX)" + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_yend = USER.set_name_yend(name_yend, yend) + self.name_z = self.name_x + self.name_yend + self.name_q = USER.set_name_q(name_q, q) + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.robust = USER.set_robust(robust) + self.name_w = USER.set_name_w(name_w, w) + self.name_gwk = USER.set_name_w(name_gwk, gwk) + self.output = pd.DataFrame(self.name_x + self.name_yend, + columns=['var_names']) + self.output['var_type'] = ['x'] * len(self.name_x) + ['yend'] * len(self.name_yend) + self.output['regime'], self.output['equation'] = (0, 0) + if spat_diag: + diag_out = _spat_diag_out(self, w, 'yend') + else: + diag_out = None + output(reg=self, vm=vm, robust=robust, other_end=diag_out, latex=latex)
+ +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + + import libpysal + + db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"), "r") + y_var = "CRIME" + y = np.array([db.by_col(y_var)]).reshape(49, 1) + x_var = ["INC"] + x = np.array([db.by_col(name) for name in x_var]).T + yd_var = ["HOVAL"] + yd = np.array([db.by_col(name) for name in yd_var]).T + q_var = ["DISCBD"] + q = np.array([db.by_col(name) for name in q_var]).T + w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + w.transform = "r" + tsls = TSLS( + y, + x, + yd, + q, + w=w, + spat_diag=True, + name_y=y_var, + name_x=x_var, + name_yend=yd_var, + name_q=q_var, + name_ds="columbus", + name_w="columbus.gal", + ) + print(tsls.output) + print(tsls.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/twosls_regimes.html b/_modules/spreg/twosls_regimes.html new file mode 100644 index 00000000..cbf399d5 --- /dev/null +++ b/_modules/spreg/twosls_regimes.html @@ -0,0 +1,957 @@ + + + + + + + spreg.twosls_regimes — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.twosls_regimes

+import numpy as np
+import multiprocessing as mp
+import pandas as pd
+from . import regimes as REGI
+from . import user_output as USER
+from .utils import set_warn, RegressionProps_basic, spdot, sphstack, get_lags
+from .twosls import BaseTSLS
+from .robust import hac_multi
+from .output import output, _spat_diag_out
+
+"""
+Two-stage Least Squares estimation with regimes.
+"""
+
+__author__ = "Luc Anselin, Pedro V. Amaral, David C. Folch"
+
+
+
[docs]class TSLS_Regimes(BaseTSLS, REGI.Regimes_Frame): + + """ + Two stage least squares (2SLS) with regimes. + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + robust : string + If 'white', then a White consistent estimator of the + variance-covariance matrix is given. + If 'hac', then a HAC consistent estimator of the + variance-covariance matrix is given. + If 'ogmm', then Optimal GMM is used to estimate + betas and the variance-covariance matrix. + Default set to None. + gwk : pysal W object + Kernel spatial weights needed for HAC estimation. Note: + matrix must have ones along the main diagonal. + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the SLX type. + Note: WX is computed using the complete weights matrix + sig2n_k : boolean + If True, then use n-k to estimate sigma^2. If False, use n. + vm : boolean + If True, include variance-covariance matrix in summary + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_regimes : string + Name of regimes variable for use in output + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + predy : array + nx1 array of predicted y values + n : integer + Number of observations + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + vm : array + Variance covariance matrix (kxk) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi: [False, 'one', 'many'] + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_regimes : string + Name of regimes variable for use in output + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal.examples import load_example + >>> from libpysal.weights import Rook + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> nat = load_example('Natregimes') + >>> db = libpysal.io.open(nat.get_path('natregimes.dbf'), 'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + In this case we consider RD90 (resource deprivation) as an endogenous regressor. + We tell the model that this is so by passing it in a different parameter + from the exogenous variables (x). + + >>> yd_var = ['RD90'] + >>> yd = np.array([db.by_col(name) for name in yd_var]).T + + Because we have endogenous variables, to obtain a correct estimate of the + model, we need to instrument for RD90. We use FP89 (families below poverty) + for this and hence put it in the instruments parameter, 'q'. + + >>> q_var = ['FP89'] + >>> q = np.array([db.by_col(name) for name in q_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to perform tests for spatial dependence, we need to specify + the spatial weights matrix that includes the spatial configuration of the + observations into the error component of the model. To do that, we can open + an already existing gal file or create a new one. In this case, we will + create one from ``NAT.shp``. + + >>> w = Rook.from_shapefile(nat.get_path("natregimes.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + We can now run the regression and then have a summary of the output + by typing: model.summary + Alternatively, we can just check the betas and standard errors of the + parameters: + + >>> from spreg import TSLS_Regimes + >>> tslsr = TSLS_Regimes(y, x, yd, q, regimes, w=w, constant_regi='many', spat_diag=False, name_y=y_var, name_x=x_var, name_yend=yd_var, name_q=q_var, name_regimes=r_var, name_ds='NAT', name_w='NAT.shp') + + >>> tslsr.betas + array([[ 3.66973562], + [ 1.06950466], + [ 0.14680946], + [ 2.45864196], + [ 9.55873243], + [ 1.94666348], + [-0.30810214], + [ 3.68718119]]) + + >>> np.sqrt(tslsr.vm.diagonal()) + array([0.38389901, 0.09963973, 0.04672091, 0.22725012, 0.49181223, + 0.19630774, 0.07784587, 0.25529011]) + + >>> print(tslsr.summary) + REGRESSION RESULTS + ------------------ + <BLANKLINE> + SUMMARY OF OUTPUT: TWO STAGE LEAST SQUARES ESTIMATION - REGIME 0 + ---------------------------------------------------------------- + Data set : NAT + Weights matrix : NAT.shp + Dependent Variable : 0_HR90 Number of Observations: 1673 + Mean dependent var : 3.3416 Number of Variables : 4 + S.D. dependent var : 4.6795 Degrees of Freedom : 1669 + Pseudo R-squared : 0.2092 + <BLANKLINE> + ------------------------------------------------------------------------------------ + Variable Coefficient Std.Error z-Statistic Probability + ------------------------------------------------------------------------------------ + 0_CONSTANT 3.6697356 0.3838990 9.5591172 0.0000000 + 0_PS90 1.0695047 0.0996397 10.7337170 0.0000000 + 0_UE90 0.1468095 0.0467209 3.1422643 0.0016765 + 0_RD90 2.4586420 0.2272501 10.8191009 0.0000000 + ------------------------------------------------------------------------------------ + Instrumented: 0_RD90 + Instruments: 0_FP89 + Regimes variable: SOUTH + <BLANKLINE> + SUMMARY OF OUTPUT: TWO STAGE LEAST SQUARES ESTIMATION - REGIME 1 + ---------------------------------------------------------------- + Data set : NAT + Weights matrix : NAT.shp + Dependent Variable : 1_HR90 Number of Observations: 1412 + Mean dependent var : 9.5493 Number of Variables : 4 + S.D. dependent var : 7.0389 Degrees of Freedom : 1408 + Pseudo R-squared : 0.2987 + <BLANKLINE> + ------------------------------------------------------------------------------------ + Variable Coefficient Std.Error z-Statistic Probability + ------------------------------------------------------------------------------------ + 1_CONSTANT 9.5587324 0.4918122 19.4357356 0.0000000 + 1_PS90 1.9466635 0.1963077 9.9163867 0.0000000 + 1_UE90 -0.3081021 0.0778459 -3.9578483 0.0000756 + 1_RD90 3.6871812 0.2552901 14.4431026 0.0000000 + ------------------------------------------------------------------------------------ + Instrumented: 1_RD90 + Instruments: 1_FP89 + Regimes variable: SOUTH + ------------------------------------------------------------------------------------ + GLOBAL DIAGNOSTICS + <BLANKLINE> + REGIMES DIAGNOSTICS - CHOW TEST + VARIABLE DF VALUE PROB + CONSTANT 1 89.093 0.0000 + PS90 1 15.876 0.0001 + UE90 1 25.106 0.0000 + RD90 1 12.920 0.0003 + Global test 4 201.237 0.0000 + ================================ END OF REPORT ===================================== + """ + +
[docs] def __init__( + self, + y, + x, + yend, + q, + regimes, + w=None, + robust=None, + gwk=None, + slx_lags=0, + sig2n_k=True, + spat_diag=False, + vm=False, + constant_regi="many", + cols2regi="all", + regime_err_sep=True, + name_y=None, + name_x=None, + cores=False, + name_yend=None, + name_q=None, + name_regimes=None, + name_w=None, + name_gwk=None, + name_ds=None, + summ=True, + latex=False, + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_robust(robust, gwk) + if robust == "hac": + if regime_err_sep: + set_warn( + self, + "Error by regimes is not available for HAC estimation. The error by regimes has been disabled for this model.", + ) + regime_err_sep = False + if spat_diag: + set_warn( + self, + "Spatial diagnostics are not available for HAC estimation. The spatial diagnostics have been disabled for this model.", + ) + spat_diag = False + USER.check_spat_diag(spat_diag, w) + x_constant, name_x, warn = USER.check_constant(x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + if slx_lags > 0: + USER.check_weights(w, y, w_required=True) + lag_x = get_lags(w, x_constant, slx_lags) + x_constant = np.hstack((x_constant, lag_x)) + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + else: + USER.check_weights(w, y, w_required=False) + self.constant_regi = constant_regi + self.cols2regi = cols2regi + self.name_ds = USER.set_name_ds(name_ds) + self.name_regimes = USER.set_name_ds(name_regimes) + self.name_w = USER.set_name_w(name_w, w) + self.name_gwk = USER.set_name_w(name_gwk, gwk) + self.name_y = USER.set_name_y(name_y) + name_yend = USER.set_name_yend(name_yend, yend) + name_q = USER.set_name_q(name_q, q) + self.name_x_r = USER.set_name_x(name_x, x_constant) + name_yend + self.n = n + cols2regi = REGI.check_cols2regi( + constant_regi, cols2regi, x_constant, yend=yend, add_cons=False + ) + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, self.n, x_constant.shape[1]) + self.regime_err_sep = regime_err_sep + if ( + regime_err_sep == True + and set(cols2regi) == set([True]) + and constant_regi == "many" + ): + self.y = y + regi_ids = dict( + (r, list(np.where(np.array(regimes) == r)[0])) for r in self.regimes_set + ) + self._tsls_regimes_multi( + x_constant, + yend, + q, + w, + regi_ids, + cores, + gwk, + slx_lags, + sig2n_k, + robust, + spat_diag, + vm, + name_x, + name_yend, + name_q, + summ, + latex + ) + else: + q, self.name_q = REGI.Regimes_Frame.__init__( + self, q, regimes, constant_regi=None, cols2regi="all", names=name_q + ) + x, self.name_x, x_rlist = REGI.Regimes_Frame.__init__( + self, + x_constant, + regimes, + constant_regi, + cols2regi=cols2regi, + names=name_x, + rlist=True + ) + yend, self.name_yend, yend_rlist = REGI.Regimes_Frame.__init__( + self, + yend, + regimes, + constant_regi=None, + cols2regi=cols2regi, + yend=True, + names=name_yend, + rlist=True + ) + self.output = pd.DataFrame(self.name_x+self.name_yend, + columns=['var_names']) + self.output['var_type'] = ['x']*len(self.name_x)+['yend']*len(self.name_yend) + self.output['regime'] = x_rlist+yend_rlist + self.output['equation'] = 0 + + BaseTSLS.__init__( + self, y=y, x=x, yend=yend, q=q, robust=robust, gwk=gwk, sig2n_k=sig2n_k + ) + + if slx_lags == 0: + self.title = "TWO STAGE LEAST SQUARES - REGIMES" + else: + self.title = "TWO STAGE LEAST SQUARES WITH SPATIALLY LAGGED X (2SLS-SLX) - REGIMES" + + if robust == "ogmm": + _optimal_weight(self, sig2n_k) + self.name_z = self.name_x + self.name_yend + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.chow = REGI.Chow(self) + self.robust = USER.set_robust(robust) + if summ: + if spat_diag: + diag_out = _spat_diag_out(self, w, 'yend') + else: + diag_out = None + output(reg=self, vm=vm, robust=robust, other_end=diag_out, latex=latex)
+ + + def _tsls_regimes_multi( + self, + x, + yend, + q, + w, + regi_ids, + cores, + gwk, + slx_lags, + sig2n_k, + robust, + spat_diag, + vm, + name_x, + name_yend, + name_q, + summ, + latex + ): + results_p = {} + """ + for r in self.regimes_set: + if system() != 'Windows': + is_win = True + results_p[r] = _work(*(self.y,x,w,regi_ids,r,yend,q,robust,sig2n_k,self.name_ds,self.name_y,name_x,name_yend,name_q,self.name_w,self.name_regimes)) + else: + pool = mp.Pool(cores) + results_p[r] = pool.apply_async(_work,args=(self.y,x,w,regi_ids,r,yend,q,robust,sig2n_k,self.name_ds,self.name_y,name_x,name_yend,name_q,self.name_w,self.name_regimes)) + is_win = False + """ + x_constant, name_x = REGI.check_const_regi(self, x, name_x, regi_ids) + self.name_x_r = name_x + name_yend + for r in self.regimes_set: + if cores: + pool = mp.Pool(None) + results_p[r] = pool.apply_async( + _work, + args=( + self.y, + x_constant, + w, + regi_ids, + r, + yend, + q, + robust, + sig2n_k, + self.name_ds, + self.name_y, + name_x, + name_yend, + name_q, + self.name_w, + self.name_regimes, + slx_lags + ), + ) + else: + results_p[r] = _work( + *( + self.y, + x_constant, + w, + regi_ids, + r, + yend, + q, + robust, + sig2n_k, + self.name_ds, + self.name_y, + name_x, + name_yend, + name_q, + self.name_w, + self.name_regimes, + slx_lags + ) + ) + + self.kryd = 0 + self.kr = x_constant.shape[1] + yend.shape[1] + self.kf = 0 + self.nr = len(self.regimes_set) + self.vm = np.zeros((self.nr * self.kr, self.nr * self.kr), float) + self.betas = np.zeros((self.nr * self.kr, 1), float) + self.u = np.zeros((self.n, 1), float) + self.predy = np.zeros((self.n, 1), float) + """ + if not is_win: + pool.close() + pool.join() + """ + if cores: + pool.close() + pool.join() + + results = {} + ( + self.name_y, + self.name_x, + self.name_yend, + self.name_q, + self.name_z, + self.name_h, + ) = ([], [], [], [], [], []) + counter = 0 + self.output = pd.DataFrame(columns=['var_names', 'var_type', 'regime', 'equation']) + for r in self.regimes_set: + """ + if is_win: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + """ + if not cores: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + + self.vm[ + (counter * self.kr) : ((counter + 1) * self.kr), + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].vm + self.betas[ + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].betas + self.u[ + regi_ids[r], + ] = results[r].u + self.predy[ + regi_ids[r], + ] = results[r].predy + self.name_y += results[r].name_y + self.name_x += results[r].name_x + self.name_yend += results[r].name_yend + self.name_q += results[r].name_q + self.name_z += results[r].name_z + self.name_h += results[r].name_h + self.output = pd.concat([self.output, pd.DataFrame({'var_names': results[r].name_x+results[r].name_yend, + 'var_type': ['x']*len(results[r].name_x)+['yend']*len(results[r].name_yend), + 'regime': r, 'equation': r})], ignore_index=True) + + counter += 1 + self.multi = results + + self.hac_var = sphstack(x_constant[:, 1:], q) + if robust == "hac": + hac_multi(self, gwk) + if robust == "ogmm": + set_warn( + self, + "Residuals treated as homoskedastic for the purpose of diagnostics.", + ) + self.chow = REGI.Chow(self) + if spat_diag: + self._get_spat_diag_props(results, regi_ids, x_constant, yend, q) + diag_out = _spat_diag_out(self, w, 'yend') + else: + diag_out = None + if summ: + self.output.sort_values(by='regime', inplace=True) + output(reg=self, vm=vm, robust=robust, other_end=diag_out, latex=latex) + + def _get_spat_diag_props(self, results, regi_ids, x, yend, q): + self._cache = {} + x = REGI.regimeX_setup(x, self.regimes, [True] * x.shape[1], self.regimes_set) + self.z = sphstack( + x, + REGI.regimeX_setup( + yend, self.regimes, [True] * yend.shape[1], self.regimes_set + ), + ) + self.h = sphstack( + x, + REGI.regimeX_setup(q, self.regimes, [True] * q.shape[1], self.regimes_set), + ) + hthi = np.linalg.inv(spdot(self.h.T, self.h)) + zth = spdot(self.z.T, self.h) + self.varb = np.linalg.inv(spdot(spdot(zth, hthi), zth.T))
+ + +def _work( + y, + x, + w, + regi_ids, + r, + yend, + q, + robust, + sig2n_k, + name_ds, + name_y, + name_x, + name_yend, + name_q, + name_w, + name_regimes, + slx_lags, +): + y_r = y[regi_ids[r]] + x_r = x[regi_ids[r]] + yend_r = yend[regi_ids[r]] + q_r = q[regi_ids[r]] + if robust == "hac" or robust == "ogmm": + robust2 = None + else: + robust2 = robust + model = BaseTSLS(y_r, x_r, yend_r, q_r, robust=robust2, sig2n_k=sig2n_k) + if slx_lags == 0: + model.title = "TWO STAGE LEAST SQUARES ESTIMATION - REGIME %s" % r + else: + model.title = "TWO STAGE LEAST SQUARES ESTIMATION WITH SLX - REGIME %s" % r + if robust == "ogmm": + _optimal_weight(model, sig2n_k, warn=False) + model.robust = USER.set_robust(robust) + model.name_ds = name_ds + model.name_y = "%s_%s" % (str(r), name_y) + model.name_x = ["%s_%s" % (str(r), i) for i in name_x] + model.name_yend = ["%s_%s" % (str(r), i) for i in name_yend] + model.name_z = model.name_x + model.name_yend + model.name_q = ["%s_%s" % (str(r), i) for i in name_q] + model.name_h = model.name_x + model.name_q + model.name_w = name_w + model.name_regimes = name_regimes + if w: + w_r, warn = REGI.w_regime(w, regi_ids[r], r, transform=True) + set_warn(model, warn) + model.w = w_r + return model + + +def _optimal_weight(reg, sig2n_k, warn=True): + try: + Hu = reg.h.toarray() * reg.u ** 2 + except: + Hu = reg.h * reg.u ** 2 + if sig2n_k: + S = spdot(reg.h.T, Hu, array_out=True) / (reg.n - reg.k) + else: + S = spdot(reg.h.T, Hu, array_out=True) / reg.n + Si = np.linalg.inv(S) + ZtH = spdot(reg.z.T, reg.h) + ZtHSi = spdot(ZtH, Si) + fac2 = np.linalg.inv(spdot(ZtHSi, ZtH.T, array_out=True)) + fac3 = spdot(ZtHSi, spdot(reg.h.T, reg.y), array_out=True) + betas = np.dot(fac2, fac3) + if sig2n_k: + vm = fac2 * (reg.n - reg.k) + else: + vm = fac2 * reg.n + RegressionProps_basic(reg, betas=betas, vm=vm, sig2=False) + #reg.title += " (Optimal-Weighted GMM)" + if warn: + set_warn( + reg, "Residuals treated as homoskedastic for the purpose of diagnostics." + ) + return + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + import numpy as np + import libpysal + from libpysal.examples import load_example + + nat = load_example("Natregimes") + db = libpysal.io.open(nat.get_path("natregimes.dbf"), "r") + y_var = "HR60" + y = np.array([db.by_col(y_var)]).T + x_var = ["PS60", "DV60", "RD60"] + x = np.array([db.by_col(name) for name in x_var]).T + yd_var = ["UE60"] + yd = np.array([db.by_col(name) for name in yd_var]).T + q_var = ["FP59", "MA60"] + q = np.array([db.by_col(name) for name in q_var]).T + r_var = "SOUTH" + regimes = db.by_col(r_var) + w = libpysal.weights.Rook.from_shapefile(nat.get_path("natregimes.shp")) + w.transform = "r" + tslsr = TSLS_Regimes( + y, + x, + yd, + q, + regimes, + w = w, + constant_regi="many", + spat_diag=True, + name_y=y_var, + name_x=x_var, + name_yend=yd_var, + name_q=q_var, + name_regimes=r_var, + #cols2regi=[False, True, True, False], + sig2n_k=False, + regime_err_sep = True, + #robust = 'hac', + vm = False + ) + print(tslsr.output) + print(tslsr.summary) + + + + +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/twosls_sp.html b/_modules/spreg/twosls_sp.html new file mode 100644 index 00000000..753b64f8 --- /dev/null +++ b/_modules/spreg/twosls_sp.html @@ -0,0 +1,768 @@ + + + + + + + spreg.twosls_sp — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.twosls_sp

+"""
+Spatial Two Stages Least Squares
+"""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu, David C. Folch david.folch@asu.edu"
+
+import numpy as np
+from . import twosls as TSLS
+from . import user_output as USER
+from .utils import set_endog, sp_att, set_warn
+import pandas as pd
+from .output import output, _spat_diag_out, _spat_pseudo_r2
+
+__all__ = ["GM_Lag"]
+
+
+class BaseGM_Lag(TSLS.BaseTSLS):
+
+    """
+    Spatial two stage least squares (S2SLS) (note: no consistency checks,
+    diagnostics or constant added); Anselin (1988) [Anselin1988]_
+
+    Parameters
+    ----------
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable; assumes the constant is
+                   in column 0.
+    yend         : array
+                   Two dimensional array with n rows and one column for each
+                   endogenous variable
+    q            : array
+                   Two dimensional array with n rows and one column for each
+                   external exogenous variable to use as instruments (note:
+                   this should not contain any variables from x); cannot be
+                   used in combination with h
+    w            : Pysal weights matrix
+                   Spatial weights matrix
+    w_lags       : integer
+                   Orders of W to include as instruments for the spatially
+                   lagged dependent variable. For example, w_lags=1, then
+                   instruments are WX; if w_lags=2, then WX, WWX; and so on.
+    lag_q        : boolean
+                   If True, then include spatial lags of the additional
+                   instruments (q).
+    slx_lags     : integer
+                   Number of spatial lags of X to include in the model specification.
+                   If slx_lags>0, the specification becomes of the Spatial Durbin type.
+    robust       : string
+                   If 'white', then a White consistent estimator of the
+                   variance-covariance matrix is given.  If 'hac', then a
+                   HAC consistent estimator of the variance-covariance
+                   matrix is given. Default set to None.
+    gwk          : pysal W object
+                   Kernel spatial weights needed for HAC estimation. Note:
+                   matrix must have ones along the main diagonal.
+    sig2n_k      : boolean
+                   If True, then use n-k to estimate sigma^2. If False, use n.
+
+
+    Attributes
+    ----------
+    betas        : array
+                   kx1 array of estimated coefficients
+    u            : array
+                   nx1 array of residuals
+    predy        : array
+                   nx1 array of predicted y values
+    n            : integer
+                   Number of observations
+    k            : integer
+                   Number of variables for which coefficients are estimated
+                   (including the constant)
+    kstar        : integer
+                   Number of endogenous variables.
+    y            : array
+                   nx1 array for dependent variable
+    x            : array
+                   Two dimensional array with n rows and one column for each
+                   independent (exogenous) variable, including the constant
+    yend         : array
+                   Two dimensional array with n rows and one column for each
+                   endogenous variable
+    q            : array
+                   Two dimensional array with n rows and one column for each
+                   external exogenous variable used as instruments
+    z            : array
+                   nxk array of variables (combination of x and yend)
+    h            : array
+                   nxl array of instruments (combination of x and q)
+    mean_y       : float
+                   Mean of dependent variable
+    std_y        : float
+                   Standard deviation of dependent variable
+    vm           : array
+                   Variance covariance matrix (kxk)
+    utu          : float
+                   Sum of squared residuals
+    sig2         : float
+                   Sigma squared used in computations
+    sig2n        : float
+                   Sigma squared (computed with n in the denominator)
+    sig2n_k      : float
+                   Sigma squared (computed with n-k in the denominator)
+    hth          : float
+                   H'H
+    hthi         : float
+                   (H'H)^-1
+    varb         : array
+                   (Z'H (H'H)^-1 H'Z)^-1
+    zthhthi      : array
+                   Z'H(H'H)^-1
+    pfora1a2     : array
+                   n(zthhthi)'varb
+
+    Examples
+    --------
+
+    >>> import numpy as np
+    >>> import libpysal
+    >>> import spreg
+    >>> np.set_printoptions(suppress=True) #prevent scientific format
+    >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp"))
+    >>> w.transform = 'r'
+    >>> db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"),'r')
+    >>> y = np.array(db.by_col("HOVAL"))
+    >>> y = np.reshape(y, (49,1))
+    >>> # no non-spatial endogenous variables
+    >>> X = []
+    >>> X.append(db.by_col("INC"))
+    >>> X.append(db.by_col("CRIME"))
+    >>> X = np.array(X).T
+    >>> X = np.hstack((np.ones(y.shape),X))
+    >>> reg = spreg.twosls_sp.BaseGM_Lag(y, X, w=w, w_lags=2)
+    >>> reg.betas
+    array([[45.30170561],
+           [ 0.62088862],
+           [-0.48072345],
+           [ 0.02836221]])
+    >>> spreg.se_betas(reg)
+    array([17.91278862,  0.52486082,  0.1822815 ,  0.31740089])
+    >>> reg = spreg.twosls_sp.BaseGM_Lag(y, X, w=w, w_lags=2, robust='white')
+    >>> reg.betas
+    array([[45.30170561],
+           [ 0.62088862],
+           [-0.48072345],
+           [ 0.02836221]])
+    >>> spreg.se_betas(reg)
+    array([20.47077481,  0.50613931,  0.20138425,  0.38028295])
+    >>> # instrument for HOVAL with DISCBD
+    >>> X = np.array(db.by_col("INC"))
+    >>> X = np.reshape(X, (49,1))
+    >>> yd = np.array(db.by_col("CRIME"))
+    >>> yd = np.reshape(yd, (49,1))
+    >>> q = np.array(db.by_col("DISCBD"))
+    >>> q = np.reshape(q, (49,1))
+    >>> X = np.hstack((np.ones(y.shape),X))
+    >>> reg = spreg.twosls_sp.BaseGM_Lag(y, X, w=w, yend=yd, q=q, w_lags=2)
+    >>> reg.betas
+    array([[100.79359082],
+           [ -0.50215501],
+           [ -1.14881711],
+           [ -0.38235022]])
+    >>> spreg.se_betas(reg)
+    array([53.0829123 ,  1.02511494,  0.57589064,  0.59891744])
+
+    """
+
+    def __init__(
+        self,
+        y,
+        x,
+        yend=None,
+        q=None,
+        w=None,
+        w_lags=1,
+        slx_lags=0,
+        lag_q=True,
+        robust=None,
+        gwk=None,
+        sig2n_k=False,
+    ):
+
+        if slx_lags > 0:
+            yend2, q2, wx = set_endog(y, x[:, 1:], w, yend, q, w_lags, lag_q, slx_lags)
+            x = np.hstack((x, wx))
+        else:
+            yend2, q2 = set_endog(y, x[:, 1:], w, yend, q, w_lags, lag_q)
+
+        TSLS.BaseTSLS.__init__(
+            self, y=y, x=x, yend=yend2, q=q2, robust=robust, gwk=gwk, sig2n_k=sig2n_k
+        )
+
+
+
[docs]class GM_Lag(BaseGM_Lag): + + """ + Spatial two stage least squares (S2SLS) with results and diagnostics; + Anselin (1988) :cite:`Anselin1988` + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x); cannot be + used in combination with h + w : pysal W object + Spatial weights object + w_lags : integer + Orders of W to include as instruments for the spatially + lagged dependent variable. For example, w_lags=1, then + instruments are WX; if w_lags=2, then WX, WWX; and so on. + lag_q : boolean + If True, then include spatial lags of the additional + instruments (q). + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the Spatial Durbin type. + robust : string + If 'white', then a White consistent estimator of the + variance-covariance matrix is given. If 'hac', then a + HAC consistent estimator of the variance-covariance + matrix is given. Default set to None. + gwk : pysal W object + Kernel spatial weights needed for HAC estimation. Note: + matrix must have ones along the main diagonal. + sig2n_k : boolean + If True, then use n-k to estimate sigma^2. If False, use n. + spat_diag : boolean + If True, then compute Anselin-Kelejian test + vm : boolean + If True, include variance-covariance matrix in summary + results + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_pred : array + nx1 array of residuals (using reduced form) + predy : array + nx1 array of predicted y values + predy_e : array + nx1 array of predicted y values (using reduced form) + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + kstar : integer + Number of endogenous variables. + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + z : array + nxk array of variables (combination of x and yend) + h : array + nxl array of instruments (combination of x and q) + robust : string + Adjustment for robust standard errors + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + utu : float + Sum of squared residuals + sig2 : float + Sigma squared used in computations + std_err : array + 1xk array of standard errors of the betas + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + ak_test : tuple + Anselin-Kelejian test; tuple contains the pair (statistic, + p-value) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + title : string + Name of the regression method used + sig2n : float + Sigma squared (computed with n in the denominator) + sig2n_k : float + Sigma squared (computed with n-k in the denominator) + hth : float + :math:`H'H` + hthi : float + :math:`(H'H)^{-1}` + varb : array + :math:`(Z'H (H'H)^{-1} H'Z)^{-1}` + zthhthi : array + :math:`Z'H(H'H)^{-1}` + pfora1a2 : array + n(zthhthi)'varb + + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. Since we will need some tests for our + model, we also import the diagnostics module. + + >>> import numpy as np + >>> import libpysal + >>> import spreg + + Open data on Columbus neighborhood crime (49 areas) using libpysal.io.open(). + This is the DBF associated with the Columbus shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"),'r') + + Extract the HOVAL column (home value) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y = np.array(db.by_col("HOVAL")) + >>> y = np.reshape(y, (49,1)) + + Extract INC (income) and CRIME (crime rates) vectors from the DBF to be used as + independent variables in the regression. Note that PySAL requires this to + be an nxj numpy array, where j is the number of independent variables (not + including a constant). By default this model adds a vector of ones to the + independent variables passed in, but this can be overridden by passing + constant=False. + + >>> X = [] + >>> X.append(db.by_col("INC")) + >>> X.append(db.by_col("CRIME")) + >>> X = np.array(X).T + + Since we want to run a spatial error model, we need to specify the spatial + weights matrix that includes the spatial configuration of the observations + into the error component of the model. To do that, we can open an already + existing gal file or create a new one. In this case, we will create one + from ``columbus.shp``. + + >>> w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + This class runs a lag model, which means that includes the spatial lag of + the dependent variable on the right-hand side of the equation. If we want + to have the names of the variables printed in the + output summary, we will have to pass them in as well, although this is + optional. The default most basic model to be run would be: + + >>> from spreg import GM_Lag + >>> np.set_printoptions(suppress=True) #prevent scientific format + >>> reg=GM_Lag(y, X, w=w, w_lags=2, name_x=['inc', 'crime'], name_y='hoval', name_ds='columbus') + >>> reg.betas + array([[45.30170561], + [ 0.62088862], + [-0.48072345], + [ 0.02836221]]) + + Once the model is run, we can obtain the standard error of the coefficient + estimates by calling the diagnostics module: + + >>> spreg.se_betas(reg) + array([17.91278862, 0.52486082, 0.1822815 , 0.31740089]) + + But we can also run models that incorporates corrected standard errors + following the White procedure. For that, we will have to include the + optional parameter ``robust='white'``: + + >>> reg=GM_Lag(y, X, w=w, w_lags=2, robust='white', name_x=['inc', 'crime'], name_y='hoval', name_ds='columbus') + >>> reg.betas + array([[45.30170561], + [ 0.62088862], + [-0.48072345], + [ 0.02836221]]) + + And we can access the standard errors from the model object: + + >>> reg.std_err + array([20.47077481, 0.50613931, 0.20138425, 0.38028295]) + + The class is flexible enough to accomodate a spatial lag model that, + besides the spatial lag of the dependent variable, includes other + non-spatial endogenous regressors. As an example, we will assume that + CRIME is actually endogenous and we decide to instrument for it with + DISCBD (distance to the CBD). We reload the X including INC only and + define CRIME as endogenous and DISCBD as instrument: + + >>> X = np.array(db.by_col("INC")) + >>> X = np.reshape(X, (49,1)) + >>> yd = np.array(db.by_col("CRIME")) + >>> yd = np.reshape(yd, (49,1)) + >>> q = np.array(db.by_col("DISCBD")) + >>> q = np.reshape(q, (49,1)) + + And we can run the model again: + + >>> reg=GM_Lag(y, X, w=w, yend=yd, q=q, w_lags=2, name_x=['inc'], name_y='hoval', name_yend=['crime'], name_q=['discbd'], name_ds='columbus') + >>> reg.betas + array([[100.79359082], + [ -0.50215501], + [ -1.14881711], + [ -0.38235022]]) + + Once the model is run, we can obtain the standard error of the coefficient + estimates by calling the diagnostics module: + + >>> spreg.se_betas(reg) + array([53.0829123 , 1.02511494, 0.57589064, 0.59891744]) + + """ + +
[docs] def __init__( + self, + y, + x, + yend=None, + q=None, + w=None, + w_lags=1, + lag_q=True, + slx_lags=0, + robust=None, + gwk=None, + sig2n_k=False, + spat_diag=False, + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_w=None, + name_gwk=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(x, yend, q) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + USER.check_robust(robust, gwk) + if robust == "hac" and spat_diag: + set_warn( + self, + "Spatial diagnostics are not available for HAC estimation. The spatial diagnostics have been disabled for this model.", + ) + spat_diag = False + x_constant, name_x, warn = USER.check_constant(x, name_x) + + if slx_lags > 0: + name_x += USER.set_name_spatial_lags(name_x, slx_lags) + + set_warn(self, warn) + BaseGM_Lag.__init__( + self, + y=y, + x=x_constant, + w=w, + yend=yend, + q=q, + w_lags=w_lags, + slx_lags=slx_lags, + robust=robust, + gwk=gwk, + lag_q=lag_q, + sig2n_k=sig2n_k, + ) + self.rho = self.betas[-1] + self.predy_e, self.e_pred, warn = sp_att( + w, self.y, self.predy, self.yend[:, -1].reshape(self.n, 1), self.rho + ) + set_warn(self, warn) + self.title = "SPATIAL TWO STAGE LEAST SQUARES" + if slx_lags > 0: + self.title += " WITH SLX (SPATIAL DURBIN MODEL)" + self.name_ds = USER.set_name_ds(name_ds) + self.name_y = USER.set_name_y(name_y) + self.name_x = USER.set_name_x(name_x, x_constant) # name_x contains SLX terms for slx_lags > 0 + self.name_yend = USER.set_name_yend(name_yend, yend) + self.name_yend.append(USER.set_name_yend_sp(self.name_y)) + self.name_z = self.name_x + self.name_yend + self.name_q = USER.set_name_q(name_q, q) + if slx_lags > 0: # need to remove all but last SLX variables from name_x + self.name_x0 = [] + self.name_x0.append(self.name_x[0]) # constant +# print(f"x0 first {self.name_x0}") + kx = int((self.k -self.kstar -1)/(slx_lags +1) ) # number of original exogenous vars + self.name_x0.extend(self.name_x[-kx:]) +# print(f"in here {self.name_x0}") + self.name_q.extend(USER.set_name_q_sp(self.name_x0, w_lags, self.name_q, lag_q)) + else: + self.name_q.extend(USER.set_name_q_sp(self.name_x, w_lags, self.name_q, lag_q)) + self.name_h = USER.set_name_h(self.name_x, self.name_q) + self.robust = USER.set_robust(robust) + self.name_w = USER.set_name_w(name_w, w) + self.name_gwk = USER.set_name_w(name_gwk, gwk) + self.output = pd.DataFrame(self.name_x + self.name_yend, columns=['var_names']) + self.output['var_type'] = ['x'] * len(self.name_x) + ['yend'] * (len(self.name_yend)-1) + ['rho'] + self.output['regime'], self.output['equation'] = (0, 0) + self.other_top = _spat_pseudo_r2(self) + if spat_diag: + diag_out = _spat_diag_out(self, w, 'yend') + else: + diag_out = None + output(reg=self, vm=vm, robust=robust, other_end=diag_out, latex=latex)
+ +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + + import numpy as np + import libpysal + + db = libpysal.io.open(libpysal.examples.get_path("columbus.dbf"), "r") + y_var = "CRIME" + y = np.array([db.by_col(y_var)]).reshape(49, 1) + x_var = ["INC"] + x = np.array([db.by_col(name) for name in x_var]).T + yd_var = ["HOVAL"] + yd = np.array([db.by_col(name) for name in yd_var]).T + q_var = ["DISCBD"] + q = np.array([db.by_col(name) for name in q_var]).T + w = libpysal.weights.Rook.from_shapefile(libpysal.examples.get_path("columbus.shp")) + w.transform = "r" + model = GM_Lag( + y, + x, + yd, + q, + w=w, + spat_diag=True, + name_y=y_var, + name_x=x_var, + name_yend=yd_var, + name_q=q_var, + name_ds="columbus", + name_w="columbus.gal", + ) + print(model.output) + print(model.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_modules/spreg/twosls_sp_regimes.html b/_modules/spreg/twosls_sp_regimes.html new file mode 100644 index 00000000..70c98cc3 --- /dev/null +++ b/_modules/spreg/twosls_sp_regimes.html @@ -0,0 +1,1134 @@ + + + + + + + spreg.twosls_sp_regimes — spreg v0.1.dev1+ge24dd97 Manual + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for spreg.twosls_sp_regimes

+"""
+Spatial Two Stages Least Squares with Regimes
+"""
+
+__author__ = "Luc Anselin luc.anselin@asu.edu, Pedro V. Amaral pedro.amaral@asu.edu, David C. Folch david.folch@asu.edu"
+
+import numpy as np
+from . import regimes as REGI
+from . import user_output as USER
+import multiprocessing as mp
+from .twosls_regimes import TSLS_Regimes, _optimal_weight
+from .twosls import BaseTSLS
+from .utils import set_endog, set_endog_sparse, sp_att, set_warn, sphstack, spdot
+from .robust import hac_multi
+import pandas as pd
+from .output import output, _spat_diag_out, _spat_pseudo_r2
+
+
+
[docs]class GM_Lag_Regimes(TSLS_Regimes, REGI.Regimes_Frame): + + """ + Spatial two stage least squares (S2SLS) with regimes; + :cite:`Anselin1988` + + Parameters + ---------- + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, excluding the constant + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + q : array + Two dimensional array with n rows and one column for each + external exogenous variable to use as instruments (note: + this should not contain any variables from x); cannot be + used in combination with h + constant_regi: string + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime (default). + cols2regi : list, 'all' + Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all' (default), all the variables vary by regime. + w : pysal W object + Spatial weights object + w_lags : integer + Orders of W to include as instruments for the spatially + lagged dependent variable. For example, w_lags=1, then + instruments are WX; if w_lags=2, then WX, WWX; and so on. + lag_q : boolean + If True, then include spatial lags of the additional + instruments (q). + slx_lags : integer + Number of spatial lags of X to include in the model specification. + If slx_lags>0, the specification becomes of the Spatial Durbin type. + regime_lag_sep: boolean + If True (default), the spatial parameter for spatial lag is also + computed according to different regimes. If False, + the spatial parameter is fixed accross regimes. + Option valid only when regime_err_sep=True + regime_err_sep: boolean + If True, a separate regression is run for each regime. + robust : string + If 'white', then a White consistent estimator of the + variance-covariance matrix is given. + If 'hac', then a HAC consistent estimator of the + variance-covariance matrix is given. + If 'ogmm', then Optimal GMM is used to estimate + betas and the variance-covariance matrix. + Default set to None. + gwk : pysal W object + Kernel spatial weights needed for HAC estimation. Note: + matrix must have ones along the main diagonal. + sig2n_k : boolean + If True, then use n-k to estimate sigma^2. If False, use n. + spat_diag : boolean + If True, then compute Anselin-Kelejian test + vm : boolean + If True, include variance-covariance matrix in summary + results + cores : boolean + Specifies if multiprocessing is to be used + Default: no multiprocessing, cores = False + Note: Multiprocessing may not work on all platforms. + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_q : list of strings + Names of instruments for use in output + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + latex : boolean + Specifies if summary is to be printed in latex format + + Attributes + ---------- + output : dataframe + regression results pandas dataframe + summary : string + Summary of regression results and diagnostics (note: use in + conjunction with the print command) + betas : array + kx1 array of estimated coefficients + u : array + nx1 array of residuals + e_pred : array + nx1 array of residuals (using reduced form) + predy : array + nx1 array of predicted y values + predy_e : array + nx1 array of predicted y values (using reduced form) + n : integer + Number of observations + k : integer + Number of variables for which coefficients are estimated + (including the constant) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + kstar : integer + Number of endogenous variables. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + y : array + nx1 array for dependent variable + x : array + Two dimensional array with n rows and one column for each + independent (exogenous) variable, including the constant + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + yend : array + Two dimensional array with n rows and one column for each + endogenous variable + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + q : array + Two dimensional array with n rows and one column for each + external exogenous variable used as instruments + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z : array + nxk array of variables (combination of x and yend) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + h : array + nxl array of instruments (combination of x and q) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + robust : string + Adjustment for robust standard errors + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + mean_y : float + Mean of dependent variable + std_y : float + Standard deviation of dependent variable + vm : array + Variance covariance matrix (kxk) + pr2 : float + Pseudo R squared (squared correlation between y and ypred) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + pr2_e : float + Pseudo R squared (squared correlation between y and ypred_e + (using reduced form)) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + utu : float + Sum of squared residuals + sig2 : float + Sigma squared used in computations + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + std_err : array + 1xk array of standard errors of the betas + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + z_stat : list of tuples + z statistic; each tuple contains the pair (statistic, + p-value), where each is a float + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + ak_test : tuple + Anselin-Kelejian test; tuple contains the pair (statistic, + p-value) + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + name_y : string + Name of dependent variable for use in output + name_x : list of strings + Names of independent variables for use in output + name_yend : list of strings + Names of endogenous variables for use in output + name_z : list of strings + Names of exogenous and endogenous variables for use in + output + name_q : list of strings + Names of external instruments + name_h : list of strings + Names of all instruments used in ouput + name_w : string + Name of weights matrix for use in output + name_gwk : string + Name of kernel weights matrix for use in output + name_ds : string + Name of dataset for use in output + name_regimes : string + Name of regimes variable for use in output + title : string + Name of the regression method used + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + sig2n : float + Sigma squared (computed with n in the denominator) + sig2n_k : float + Sigma squared (computed with n-k in the denominator) + hth : float + :math:`H'H`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + hthi : float + :math:`(H'H)^{-1}`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + varb : array + :math:`(Z'H (H'H)^{-1} H'Z)^{-1}`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + zthhthi : array + :math:`Z'H(H'H)^{-1}`. + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + pfora1a2 : array + n(zthhthi)'varb + Only available in dictionary 'multi' when multiple regressions + (see 'multi' below for details) + regimes : list + List of n values with the mapping of each + observation to a regime. Assumed to be aligned with 'x'. + constant_regi: string + Ignored if regimes=False. Constant option for regimes. + Switcher controlling the constant term setup. It may take + the following values: + + * 'one': a vector of ones is appended to x and held constant across regimes. + + * 'many': a vector of ones is appended to x and considered different per regime. + cols2regi : list, 'all' + Ignored if regimes=False. Argument indicating whether each + column of x should be considered as different per regime + or held constant across regimes (False). + If a list, k booleans indicating for each variable the + option (True if one per regime, False to be held constant). + If 'all', all the variables vary by regime. + regime_lag_sep: boolean + If True, the spatial parameter for spatial lag is also + computed according to different regimes. If False (default), + the spatial parameter is fixed accross regimes. + regime_err_sep: boolean + If True, a separate regression is run for each regime. + kr : int + Number of variables/columns to be "regimized" or subject + to change by regime. These will result in one parameter + estimate by regime for each variable (i.e. nr parameters per + variable) + kf : int + Number of variables/columns to be considered fixed or + global across regimes and hence only obtain one parameter + estimate + nr : int + Number of different regimes in the 'regimes' list + multi : dictionary + Only available when multiple regressions are estimated, + i.e. when regime_err_sep=True and no variable is fixed + across regimes. + Contains all attributes of each individual regression + + Examples + -------- + + We first need to import the needed modules, namely numpy to convert the + data we read into arrays that ``spreg`` understands and ``pysal`` to + perform all the analysis. + + >>> import numpy as np + >>> import libpysal + >>> from libpysal import examples + + Open data on NCOVR US County Homicides (3085 areas) using libpysal.io.open(). + This is the DBF associated with the NAT shapefile. Note that + libpysal.io.open() also reads data in CSV format; since the actual class + requires data to be passed in as numpy arrays, the user can read their + data in using any method. + + >>> db = libpysal.io.open(examples.get_path("NAT.dbf"),'r') + + Extract the HR90 column (homicide rates in 1990) from the DBF file and make it the + dependent variable for the regression. Note that PySAL requires this to be + an numpy array of shape (n, 1) as opposed to the also common shape of (n, ) + that other packages accept. + + >>> y_var = 'HR90' + >>> y = np.array([db.by_col(y_var)]).reshape(3085,1) + + Extract UE90 (unemployment rate) and PS90 (population structure) vectors from + the DBF to be used as independent variables in the regression. Other variables + can be inserted by adding their names to x_var, such as x_var = ['Var1','Var2','...] + Note that PySAL requires this to be an nxj numpy array, where j is the + number of independent variables (not including a constant). By default + this model adds a vector of ones to the independent variables passed in. + + >>> x_var = ['PS90','UE90'] + >>> x = np.array([db.by_col(name) for name in x_var]).T + + The different regimes in this data are given according to the North and + South dummy (SOUTH). + + >>> r_var = 'SOUTH' + >>> regimes = db.by_col(r_var) + + Since we want to run a spatial lag model, we need to specify + the spatial weights matrix that includes the spatial configuration of the + observations. To do that, we can open an already existing gal file or + create a new one. In this case, we will create one from ``NAT.shp``. + + >>> from libpysal import weights + >>> w = weights.Rook.from_shapefile(examples.get_path("NAT.shp")) + + Unless there is a good reason not to do it, the weights have to be + row-standardized so every row of the matrix sums to one. Among other + things, this allows to interpret the spatial lag of a variable as the + average value of the neighboring observations. In PySAL, this can be + easily performed in the following way: + + >>> w.transform = 'r' + + This class runs a lag model, which means that includes the spatial lag of + the dependent variable on the right-hand side of the equation. If we want + to have the names of the variables printed in the output summary, we will + have to pass them in as well, although this is optional. + + >>> from spreg import GM_Lag_Regimes + >>> model=GM_Lag_Regimes(y, x, regimes, w=w, regime_lag_sep=False, regime_err_sep=False, name_y=y_var, name_x=x_var, name_regimes=r_var, name_ds='NAT', name_w='NAT.shp') + >>> model.betas + array([[ 1.28897623], + [ 0.79777722], + [ 0.56366891], + [ 8.73327838], + [ 1.30433406], + [ 0.62418643], + [-0.39993716]]) + + Once the model is run, we can have a summary of the output by typing: + model.summary . Alternatively, we can obtain the standard error of + the coefficient estimates by calling: + + >>> model.std_err + array([0.44682888, 0.14358192, 0.05655124, 1.06044865, 0.20184548, + 0.06118262, 0.12387232]) + + In the example above, all coefficients but the spatial lag vary + according to the regime. It is also possible to have the spatial lag + varying according to the regime, which effective will result in an + independent spatial lag model estimated for each regime. To run these + models, the argument regime_lag_sep must be set to True: + + >>> model=GM_Lag_Regimes(y, x, regimes, w=w, regime_lag_sep=True, name_y=y_var, name_x=x_var, name_regimes=r_var, name_ds='NAT', name_w='NAT.shp') + >>> print(model.output) + var_names coefficients std_err zt_stat prob + 0 0_CONSTANT 1.365848 0.398547 3.427066 0.00061 + 1 0_PS90 0.808757 0.113249 7.141418 0.0 + 2 0_UE90 0.569468 0.046251 12.312591 0.0 + 3 0_W_HR90 -0.434244 0.133502 -3.252724 0.001143 + 4 1_CONSTANT 7.907311 1.636019 4.833264 0.000001 + 5 1_PS90 1.274657 0.247099 5.158493 0.0 + 6 1_UE90 0.601677 0.079933 7.527245 0.0 + 7 1_W_HR90 -0.296034 0.199345 -1.485036 0.137534 + + Alternatively, we can type: 'model.summary' to see the organized results output. + The class is flexible enough to accomodate a spatial lag model that, + besides the spatial lag of the dependent variable, includes other + non-spatial endogenous regressors. As an example, we will add the endogenous + variable RD90 (resource deprivation) and we decide to instrument for it with + FP89 (families below poverty): + + >>> yd_var = ['RD90'] + >>> yd = np.array([db.by_col(name) for name in yd_var]).T + >>> q_var = ['FP89'] + >>> q = np.array([db.by_col(name) for name in q_var]).T + + And we can run the model again: + + >>> model = GM_Lag_Regimes(y, x, regimes, yend=yd, q=q, w=w, regime_lag_sep=False, regime_err_sep=False, name_y=y_var, name_x=x_var, name_yend=yd_var, name_q=q_var, name_regimes=r_var, name_ds='NAT', name_w='NAT.shp') + >>> model.betas + array([[ 3.42195202], + [ 1.03311878], + [ 0.14308741], + [ 8.99740066], + [ 1.91877758], + [-0.32084816], + [ 2.38918212], + [ 3.67243761], + [ 0.06959139]]) + + Once the model is run, we can obtain the standard error of the coefficient + estimates. Alternatively, we can have a summary of the output by typing: + model.summary + + >>> model.std_err + array([0.49163311, 0.12237382, 0.05633464, 0.72555909, 0.17250521, + 0.06749131, 0.27370369, 0.25106224, 0.05804213]) + """ + +
[docs] def __init__( + self, + y, + x, + regimes, + yend=None, + q=None, + w=None, + w_lags=1, + slx_lags=0, + lag_q=True, + robust=None, + gwk=None, + sig2n_k=False, + spat_diag=False, + constant_regi="many", + cols2regi="all", + regime_lag_sep=True, + regime_err_sep=True, + cores=False, + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_regimes=None, + name_w=None, + name_gwk=None, + name_ds=None, + latex=False, + ): + + n = USER.check_arrays(y, x) + y = USER.check_y(y, n) + USER.check_weights(w, y, w_required=True) + USER.check_robust(robust, gwk) + if regime_lag_sep and not regime_err_sep: + set_warn(self, "regime_err_sep set to True when regime_lag_sep=True.") + regime_err_sep = True + if regime_err_sep and not regime_lag_sep: + set_warn(self, "Groupwise heteroskedasticity is not currently available for this method,\n so regime_err_sep has been set to False.") + regime_err_sep = False + if robust == "hac": + if regime_err_sep: + set_warn( + self, + "Error by regimes is not available for HAC estimation. The error by regimes has been disabled for this model.", + ) + regime_err_sep = False + if spat_diag: + set_warn( + self, + "Spatial diagnostics are not available for HAC estimation. The spatial diagnostics have been disabled for this model.", + ) + spat_diag = False + USER.check_spat_diag(spat_diag, w) + x_constant, name_x, warn = USER.check_constant(x, name_x, just_rem=True) + set_warn(self, warn) + name_x = USER.set_name_x(name_x, x_constant, constant=True) + name_y = USER.set_name_y(name_y) + name_yend = USER.set_name_yend(name_yend, yend) + name_q = USER.set_name_q(name_q, q) + self.name_regimes = USER.set_name_ds(name_regimes) + self.constant_regi = constant_regi + if slx_lags > 0: + yend2, q2, wx = set_endog(y, x_constant, w, yend, q, w_lags, lag_q, slx_lags) + x_constant = np.hstack((x_constant, wx)) + name_slx = USER.set_name_spatial_lags(name_x, slx_lags) + name_q.extend(USER.set_name_q_sp(name_slx[-len(name_x):], w_lags, name_q, lag_q, force_all=True)) + name_x += name_slx + else: + name_q.extend(USER.set_name_q_sp(name_x, w_lags, name_q, lag_q, force_all=True)) + yend2, q2 = yend, q + self.n = x_constant.shape[0] + cols2regi = REGI.check_cols2regi( + constant_regi, cols2regi, x_constant, yend=yend2, add_cons=False + ) + self.cols2regi = cols2regi + self.regimes_set = REGI._get_regimes_set(regimes) + self.regimes = regimes + USER.check_regimes(self.regimes_set, self.n, x_constant.shape[1]) + if regime_err_sep == True and robust == "hac": + set_warn( + self, + "Error by regimes is incompatible with HAC estimation for Spatial Lag models. Hence, error and lag by regimes have been disabled for this model.", + ) + regime_err_sep = False + regime_lag_sep = False + self.regime_err_sep = regime_err_sep + self.regime_lag_sep = regime_lag_sep + if regime_lag_sep == True: + cols2regi += [True] + w_i, regi_ids, warn = REGI.w_regimes( + w, + regimes, + self.regimes_set, + transform=True, + get_ids=True, + min_n=len(cols2regi) + 1, + ) + set_warn(self, warn) + + else: + cols2regi += [False] + + if ( + regime_err_sep == True + and set(cols2regi) == set([True]) + and constant_regi == "many" + ): + self.y = y + self.GM_Lag_Regimes_Multi( + y, + x_constant, + w_i, + w, + regi_ids, + yend=yend2, + q=q2, + w_lags=w_lags, + slx_lags=slx_lags, + lag_q=lag_q, + cores=cores, + robust=robust, + gwk=gwk, + sig2n_k=sig2n_k, + cols2regi=cols2regi, + spat_diag=spat_diag, + vm=vm, + name_y=name_y, + name_x=name_x, + name_yend=name_yend, + name_q=name_q, + name_regimes=self.name_regimes, + name_w=name_w, + name_gwk=name_gwk, + name_ds=name_ds, + latex=latex, + ) + else: + if regime_lag_sep == True: + w = REGI.w_regimes_union(w, w_i, self.regimes_set) + if slx_lags == 0: + yend2, q2 = set_endog(y, x_constant, w, yend2, q2, w_lags, lag_q) + name_yend.append(USER.set_name_yend_sp(name_y)) + TSLS_Regimes.__init__( + self, + y=y, + x=x_constant, + yend=yend2, + q=q2, + regimes=regimes, + w=w, + robust=robust, + gwk=gwk, + sig2n_k=sig2n_k, + spat_diag=spat_diag, + vm=vm, + constant_regi=constant_regi, + cols2regi=cols2regi, + regime_err_sep=regime_err_sep, + name_y=name_y, + name_x=name_x, + name_yend=name_yend, + name_q=name_q, + name_regimes=name_regimes, + name_w=name_w, + name_gwk=name_gwk, + name_ds=name_ds, + summ=False, + ) + + if regime_lag_sep: # not currently available. + self.sp_att_reg(w_i, regi_ids, yend2[:, -1].reshape(self.n, 1)) + else: + self.rho = self.betas[-1] + self.output.iat[-1, self.output.columns.get_loc('var_type')] = 'rho' + self.predy_e, self.e_pred, warn = sp_att( + w, self.y, self.predy, yend2[:, -1].reshape(self.n, 1), self.rho + ) + set_warn(self, warn) + self.regime_lag_sep = regime_lag_sep + self.title = "SPATIAL " + self.title + if slx_lags > 0: + self.title = " SPATIAL 2SLS WITH SLX (SPATIAL DURBIN MODEL) - REGIMES" + self.other_top = _spat_pseudo_r2(self) + if spat_diag: + diag_out = _spat_diag_out(self, w, 'yend') + else: + diag_out = None + output(reg=self, vm=vm, robust=robust, other_end=diag_out, latex=latex)
+ +
[docs] def GM_Lag_Regimes_Multi( + self, + y, + x, + w_i, + w, + regi_ids, + cores=False, + yend=None, + q=None, + w_lags=1, + slx_lags=0, + lag_q=True, + robust=None, + gwk=None, + sig2n_k=False, + cols2regi="all", + spat_diag=False, + vm=False, + name_y=None, + name_x=None, + name_yend=None, + name_q=None, + name_regimes=None, + name_w=None, + name_gwk=None, + name_ds=None, + latex=False, + ): + # pool = mp.Pool(cores) + self.name_ds = USER.set_name_ds(name_ds) + name_yend.append(USER.set_name_yend_sp(name_y)) + self.name_w = USER.set_name_w(name_w, w_i) + self.name_gwk = USER.set_name_w(name_gwk, gwk) + results_p = {} + """ + for r in self.regimes_set: + w_r = w_i[r].sparse + if system() == 'Windows': + is_win = True + results_p[r] = _work(*(y,x,regi_ids,r,yend,q,w_r,w_lags,lag_q,robust,sig2n_k,self.name_ds,name_y,name_x,name_yend,name_q,self.name_w,name_regimes)) + else: + results_p[r] = pool.apply_async(_work,args=(y,x,regi_ids,r,yend,q,w_r,w_lags,lag_q,robust,sig2n_k,self.name_ds,name_y,name_x,name_yend,name_q,self.name_w,name_regimes, )) + is_win = False + """ + x_constant, name_x = REGI.check_const_regi(self, x, name_x, regi_ids) + self.name_x_r = name_x + for r in self.regimes_set: + w_r = w_i[r].sparse + if cores: + pool = mp.Pool(None) + results_p[r] = pool.apply_async( + _work, + args=( + y, + x_constant, + regi_ids, + r, + yend, + q, + w_r, + w_lags, + slx_lags, + lag_q, + robust, + sig2n_k, + self.name_ds, + name_y, + name_x, + name_yend, + name_q, + self.name_w, + name_regimes, + ), + ) + else: + results_p[r] = _work( + *( + y, + x_constant, + regi_ids, + r, + yend, + q, + w_r, + w_lags, + slx_lags, + lag_q, + robust, + sig2n_k, + self.name_ds, + name_y, + name_x, + name_yend, + name_q, + self.name_w, + name_regimes, + ) + ) + + self.kryd = 0 + self.kr = len(cols2regi) + 1 + self.kf = 0 + self.nr = len(self.regimes_set) + self.name_x_r = name_x + name_yend + self.name_regimes = name_regimes + self.vm = np.zeros((self.nr * self.kr, self.nr * self.kr), float) + self.betas = np.zeros((self.nr * self.kr, 1), float) + self.u = np.zeros((self.n, 1), float) + self.predy = np.zeros((self.n, 1), float) + self.predy_e = np.zeros((self.n, 1), float) + self.e_pred = np.zeros((self.n, 1), float) + """ + if not is_win: + pool.close() + pool.join() + """ + if cores: + pool.close() + pool.join() + results = {} + ( + self.name_y, + self.name_x, + self.name_yend, + self.name_q, + self.name_z, + self.name_h, + ) = ([], [], [], [], [], []) + counter = 0 + self.output = pd.DataFrame(columns=['var_names', 'var_type', 'regime', 'equation']) + for r in self.regimes_set: + """ + if is_win: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + """ + if not cores: + results[r] = results_p[r] + else: + results[r] = results_p[r].get() + results[r].predy_e, results[r].e_pred, warn = sp_att( + w_i[r], + results[r].y, + results[r].predy, + results[r].yend[:, -1].reshape(results[r].n, 1), + results[r].rho, + ) + set_warn(results[r], warn) + results[r].w = w_i[r] + self.vm[ + (counter * self.kr) : ((counter + 1) * self.kr), + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].vm + self.betas[ + (counter * self.kr) : ((counter + 1) * self.kr), + ] = results[r].betas + self.u[ + regi_ids[r], + ] = results[r].u + self.predy[ + regi_ids[r], + ] = results[r].predy + self.predy_e[ + regi_ids[r], + ] = results[r].predy_e + self.e_pred[ + regi_ids[r], + ] = results[r].e_pred + self.name_y += results[r].name_y + self.name_x += results[r].name_x + self.name_yend += results[r].name_yend + self.name_q += results[r].name_q + self.name_z += results[r].name_z + self.name_h += results[r].name_h + if r == self.regimes_set[0]: + self.hac_var = np.zeros((self.n, results[r].h.shape[1]), float) + self.hac_var[ + regi_ids[r], + ] = results[r].h + results[r].other_top = _spat_pseudo_r2(results[r]) + results[r].other_mid = "" + if spat_diag: + results[r].other_mid += _spat_diag_out(results[r], results[r].w, 'yend') + self.output = pd.concat([self.output, pd.DataFrame({'var_names': results[r].name_x + results[r].name_yend, + 'var_type': ['x'] * len(results[r].name_x) + [ + 'yend'] * (len(results[r].name_yend)-1) + ['rho'], + 'regime': r, 'equation': r})], ignore_index=True) + counter += 1 + self.multi = results + if robust == "hac": + hac_multi(self, gwk, constant=True) + if robust == "ogmm": + set_warn( + self, + "Residuals treated as homoskedastic for the purpose of diagnostics.", + ) + self.chow = REGI.Chow(self) + if spat_diag: + # self._get_spat_diag_props(y, x, w, yend, q, w_lags, lag_q) + pass + output(reg=self, vm=vm, robust=robust, other_end=False, latex=latex)
+ +
[docs] def sp_att_reg(self, w_i, regi_ids, wy): + predy_e_r, e_pred_r = {}, {} + self.predy_e = np.zeros((self.n, 1), float) + self.e_pred = np.zeros((self.n, 1), float) + counter = 1 + for r in self.regimes_set: + self.rho = self.betas[ + (self.kr - self.kryd) * self.nr + + self.kf + - (self.yend.shape[1] - self.nr * self.kryd) + + self.kryd * counter + - 1 + ] + self.predy_e[regi_ids[r],], self.e_pred[regi_ids[r],], warn = sp_att( + w_i[r], + self.y[regi_ids[r]], + self.predy[regi_ids[r]], + wy[regi_ids[r]], + self.rho, + ) + counter += 1
+ + def _get_spat_diag_props(self, y, x, w, yend, q, w_lags, lag_q): + self._cache = {} + yend, q = set_endog(y, x[:, 1:], w, yend, q, w_lags, lag_q) + # x = USER.check_constant(x) + x = REGI.regimeX_setup(x, self.regimes, [True] * x.shape[1], self.regimes_set) + self.z = sphstack( + x, + REGI.regimeX_setup( + yend, + self.regimes, + [True] * (yend.shape[1] - 1) + [False], + self.regimes_set, + ), + ) + self.h = sphstack( + x, + REGI.regimeX_setup(q, self.regimes, [True] * q.shape[1], self.regimes_set), + ) + hthi = np.linalg.inv(spdot(self.h.T, self.h)) + zth = spdot(self.z.T, self.h) + self.varb = np.linalg.inv(spdot(spdot(zth, hthi), zth.T))
+ + +def _work( + y, + x, + regi_ids, + r, + yend, + q, + w_r, + w_lags, + slx_lags, + lag_q, + robust, + sig2n_k, + name_ds, + name_y, + name_x, + name_yend, + name_q, + name_w, + name_regimes, +): + y_r = y[regi_ids[r]] + x_r = x[regi_ids[r]] + if yend is not None: + yend_r = yend[regi_ids[r]] + else: + yend_r = yend + if q is not None: + q_r = q[regi_ids[r]] + else: + q_r = q + if slx_lags == 0: + yend_r, q_r = set_endog_sparse(y_r, x_r[:, 1:], w_r, yend_r, q_r, w_lags, lag_q) + title = "SPATIAL TWO STAGE LEAST SQUARES ESTIMATION - REGIME %s" % r + else: + title = "SPATIAL 2SLS WITH SLX (SPATIAL DURBIN MODEL) - REGIME %s" % r + # x_constant = USER.check_constant(x_r) + if robust == "hac" or robust == "ogmm": + robust2 = None + else: + robust2 = robust + model = BaseTSLS(y_r, x_r, yend_r, q_r, robust=robust2, sig2n_k=sig2n_k) + model.title = title + if robust == "ogmm": + _optimal_weight(model, sig2n_k, warn=False) + model.rho = model.betas[-1] + model.robust = USER.set_robust(robust) + model.name_ds = name_ds + model.name_y = "%s_%s" % (str(r), name_y) + model.name_x = ["%s_%s" % (str(r), i) for i in name_x] + model.name_yend = ["%s_%s" % (str(r), i) for i in name_yend] + model.name_z = model.name_x + model.name_yend + model.name_q = ["%s_%s" % (str(r), i) for i in name_q] + model.name_h = model.name_x + model.name_q + model.name_w = name_w + model.name_regimes = name_regimes + return model + + +def _test(): + import doctest + + start_suppress = np.get_printoptions()["suppress"] + np.set_printoptions(suppress=True) + doctest.testmod() + np.set_printoptions(suppress=start_suppress) + + +if __name__ == "__main__": + _test() + import numpy as np + import libpysal + from libpysal import examples + + db = libpysal.io.open(examples.get_path("columbus.dbf"), "r") + y_var = "CRIME" + y = np.array([db.by_col(y_var)]).reshape(49, 1) + x_var = ["INC"] + x = np.array([db.by_col(name) for name in x_var]).T + yd_var = ["HOVAL"] + yd = np.array([db.by_col(name) for name in yd_var]).T + q_var = ["DISCBD"] + q = np.array([db.by_col(name) for name in q_var]).T + r_var = "NSA" + regimes = db.by_col(r_var) + w = libpysal.weights.Queen.from_shapefile( + libpysal.examples.get_path("columbus.shp") + ) + w.transform = "r" + model = GM_Lag_Regimes( + y, + x, + regimes, + yend=yd, + q=q, + w=w, + constant_regi="many", + spat_diag=True, + sig2n_k=False, + lag_q=True, + name_y=y_var, + name_x=x_var, + name_yend=yd_var, + name_q=q_var, + name_regimes=r_var, + name_ds="columbus", + name_w="columbus.gal", + regime_err_sep=True, + regime_lag_sep = True, + robust="white", + ) + print(model.output) + print(model.summary) +
+ +
+ +
+
+
+
+

+ Back to top + +
+ + +

+

+ © Copyright 2018-, pysal developers.
+ Created using Sphinx 5.3.0.
+

+
+
+ + \ No newline at end of file diff --git a/_sources/api.rst.txt b/_sources/api.rst.txt new file mode 100644 index 00000000..abd4e60c --- /dev/null +++ b/_sources/api.rst.txt @@ -0,0 +1,130 @@ +.. _api_ref: + +.. currentmodule:: spreg + +API reference +============= + +.. _models_api: + +Spatial Regression Models +------------------------- + +These are the standard spatial regression models supported by the `spreg` package. Each of them contains a significant amount of detail in their docstring discussing how they're used, how they're fit, and how to interpret the results. + +.. autosummary:: + :toctree: generated/ + + spreg.OLS + spreg.ML_Lag + spreg.ML_Error + spreg.GM_Lag + spreg.GM_Error + spreg.GM_Error_Het + spreg.GM_Error_Hom + spreg.GM_Combo + spreg.GM_Combo_Het + spreg.GM_Combo_Hom + spreg.GM_Endog_Error + spreg.GM_Endog_Error_Het + spreg.GM_Endog_Error_Hom + spreg.TSLS + spreg.ThreeSLS + +Discrete Choice Models +---------------------- +.. autosummary:: + :toctree: generated/ + + spreg.Probit + +Regimes Models +--------------- + +Regimes models are variants of spatial regression models which allow for structural instability in parameters. That means that these models allow different coefficient values in distinct subsets of the data. + +.. autosummary:: + :toctree: generated/ + + spreg.OLS_Regimes + spreg.TSLS_Regimes + spreg.ML_Lag_Regimes + spreg.ML_Error_Regimes + spreg.GM_Lag_Regimes + spreg.GM_Error_Regimes + spreg.GM_Error_Het_Regimes + spreg.GM_Error_Hom_Regimes + spreg.GM_Combo_Regimes + spreg.GM_Combo_Hom_Regimes + spreg.GM_Combo_Het_Regimes + spreg.GM_Endog_Error_Regimes + spreg.GM_Endog_Error_Hom_Regimes + spreg.GM_Endog_Error_Het_Regimes + spreg.Skater_reg + +Seemingly-Unrelated Regressions +-------------------------------- + +Seemingly-unrelated regression models are a generalization of linear regression. These models (and their spatial generalizations) allow for correlation in the residual terms between groups that use the same model. In spatial Seeimingly-Unrelated Regressions, the error terms across groups are allowed to exhibit a structured type of correlation: spatial correlation. + +.. autosummary:: + :toctree: generated/ + + spreg.SUR + spreg.SURerrorGM + spreg.SURerrorML + spreg.SURlagIV + spreg.ThreeSLS + +Spatial Panel Models +-------------------- + +Spatial panel models allow for evaluating correlation in both spatial and time dimensions. + +.. autosummary:: + :toctree: generated/ + + spreg.Panel_FE_Lag + spreg.Panel_FE_Error + spreg.Panel_RE_Lag + spreg.Panel_RE_Error + spreg.GM_KKP + +Diagnostics +----------- + +Diagnostic tests are useful for identifying model fit, sufficiency, and specification correctness. + +.. autosummary:: + :toctree: generated/ + + spreg.f_stat + spreg.t_stat + spreg.r2 + spreg.ar2 + spreg.se_betas + spreg.log_likelihood + spreg.akaike + spreg.schwarz + spreg.condition_index + spreg.jarque_bera + spreg.breusch_pagan + spreg.white + spreg.koenker_bassett + spreg.vif + spreg.likratiotest + spreg.LMtests + spreg.MoranRes + spreg.AKtest + spreg.sur_setp + spreg.sur_lrtest + spreg.sur_lmtest + spreg.lam_setp + spreg.surLMe + spreg.surLMlag + spreg.constant_check + spreg.panel_LMlag + spreg.panel_LMerror + spreg.panel_rLMlag + spreg.panel_rLMerror + spreg.panel_Hausman diff --git a/_sources/generated/spreg.AKtest.rst.txt b/_sources/generated/spreg.AKtest.rst.txt new file mode 100644 index 00000000..c88779f4 --- /dev/null +++ b/_sources/generated/spreg.AKtest.rst.txt @@ -0,0 +1,22 @@ +ο»Ώspreg.AKtest +============ + +.. currentmodule:: spreg + +.. autoclass:: AKtest + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~AKtest.__init__ + + + + + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Combo.rst.txt b/_sources/generated/spreg.GM_Combo.rst.txt new file mode 100644 index 00000000..f13b9a47 --- /dev/null +++ b/_sources/generated/spreg.GM_Combo.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Combo +=============== + +.. currentmodule:: spreg + +.. autoclass:: GM_Combo + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Combo.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Combo.mean_y + ~GM_Combo.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Combo_Het.rst.txt b/_sources/generated/spreg.GM_Combo_Het.rst.txt new file mode 100644 index 00000000..48bf0149 --- /dev/null +++ b/_sources/generated/spreg.GM_Combo_Het.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Combo\_Het +==================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Combo_Het + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Combo_Het.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Combo_Het.mean_y + ~GM_Combo_Het.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Combo_Het_Regimes.rst.txt b/_sources/generated/spreg.GM_Combo_Het_Regimes.rst.txt new file mode 100644 index 00000000..574157d7 --- /dev/null +++ b/_sources/generated/spreg.GM_Combo_Het_Regimes.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Combo\_Het\_Regimes +============================= + +.. currentmodule:: spreg + +.. autoclass:: GM_Combo_Het_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Combo_Het_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Combo_Het_Regimes.mean_y + ~GM_Combo_Het_Regimes.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Combo_Hom.rst.txt b/_sources/generated/spreg.GM_Combo_Hom.rst.txt new file mode 100644 index 00000000..64e73a55 --- /dev/null +++ b/_sources/generated/spreg.GM_Combo_Hom.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Combo\_Hom +==================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Combo_Hom + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Combo_Hom.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Combo_Hom.mean_y + ~GM_Combo_Hom.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Combo_Hom_Regimes.rst.txt b/_sources/generated/spreg.GM_Combo_Hom_Regimes.rst.txt new file mode 100644 index 00000000..243e2d0a --- /dev/null +++ b/_sources/generated/spreg.GM_Combo_Hom_Regimes.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Combo\_Hom\_Regimes +============================= + +.. currentmodule:: spreg + +.. autoclass:: GM_Combo_Hom_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Combo_Hom_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Combo_Hom_Regimes.mean_y + ~GM_Combo_Hom_Regimes.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Combo_Regimes.rst.txt b/_sources/generated/spreg.GM_Combo_Regimes.rst.txt new file mode 100644 index 00000000..1104d6cd --- /dev/null +++ b/_sources/generated/spreg.GM_Combo_Regimes.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Combo\_Regimes +======================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Combo_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Combo_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Combo_Regimes.mean_y + ~GM_Combo_Regimes.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Endog_Error.rst.txt b/_sources/generated/spreg.GM_Endog_Error.rst.txt new file mode 100644 index 00000000..b67bcf4b --- /dev/null +++ b/_sources/generated/spreg.GM_Endog_Error.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Endog\_Error +====================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Endog_Error + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Endog_Error.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Endog_Error.mean_y + ~GM_Endog_Error.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Endog_Error_Het.rst.txt b/_sources/generated/spreg.GM_Endog_Error_Het.rst.txt new file mode 100644 index 00000000..dad1f183 --- /dev/null +++ b/_sources/generated/spreg.GM_Endog_Error_Het.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Endog\_Error\_Het +=========================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Endog_Error_Het + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Endog_Error_Het.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Endog_Error_Het.mean_y + ~GM_Endog_Error_Het.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Endog_Error_Het_Regimes.rst.txt b/_sources/generated/spreg.GM_Endog_Error_Het_Regimes.rst.txt new file mode 100644 index 00000000..182dfdf7 --- /dev/null +++ b/_sources/generated/spreg.GM_Endog_Error_Het_Regimes.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Endog\_Error\_Het\_Regimes +==================================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Endog_Error_Het_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Endog_Error_Het_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Endog_Error_Het_Regimes.mean_y + ~GM_Endog_Error_Het_Regimes.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Endog_Error_Hom.rst.txt b/_sources/generated/spreg.GM_Endog_Error_Hom.rst.txt new file mode 100644 index 00000000..13b66621 --- /dev/null +++ b/_sources/generated/spreg.GM_Endog_Error_Hom.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Endog\_Error\_Hom +=========================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Endog_Error_Hom + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Endog_Error_Hom.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Endog_Error_Hom.mean_y + ~GM_Endog_Error_Hom.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Endog_Error_Hom_Regimes.rst.txt b/_sources/generated/spreg.GM_Endog_Error_Hom_Regimes.rst.txt new file mode 100644 index 00000000..3ebc774d --- /dev/null +++ b/_sources/generated/spreg.GM_Endog_Error_Hom_Regimes.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Endog\_Error\_Hom\_Regimes +==================================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Endog_Error_Hom_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Endog_Error_Hom_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Endog_Error_Hom_Regimes.mean_y + ~GM_Endog_Error_Hom_Regimes.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Endog_Error_Regimes.rst.txt b/_sources/generated/spreg.GM_Endog_Error_Regimes.rst.txt new file mode 100644 index 00000000..ee89a29e --- /dev/null +++ b/_sources/generated/spreg.GM_Endog_Error_Regimes.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Endog\_Error\_Regimes +=============================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Endog_Error_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Endog_Error_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Endog_Error_Regimes.mean_y + ~GM_Endog_Error_Regimes.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Error.rst.txt b/_sources/generated/spreg.GM_Error.rst.txt new file mode 100644 index 00000000..2ece4eca --- /dev/null +++ b/_sources/generated/spreg.GM_Error.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Error +=============== + +.. currentmodule:: spreg + +.. autoclass:: GM_Error + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Error.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Error.mean_y + ~GM_Error.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Error_Het.rst.txt b/_sources/generated/spreg.GM_Error_Het.rst.txt new file mode 100644 index 00000000..9cc1360e --- /dev/null +++ b/_sources/generated/spreg.GM_Error_Het.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Error\_Het +==================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Error_Het + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Error_Het.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Error_Het.mean_y + ~GM_Error_Het.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Error_Het_Regimes.rst.txt b/_sources/generated/spreg.GM_Error_Het_Regimes.rst.txt new file mode 100644 index 00000000..6a3fafcb --- /dev/null +++ b/_sources/generated/spreg.GM_Error_Het_Regimes.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Error\_Het\_Regimes +============================= + +.. currentmodule:: spreg + +.. autoclass:: GM_Error_Het_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Error_Het_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Error_Het_Regimes.mean_y + ~GM_Error_Het_Regimes.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Error_Hom.rst.txt b/_sources/generated/spreg.GM_Error_Hom.rst.txt new file mode 100644 index 00000000..1a47ae25 --- /dev/null +++ b/_sources/generated/spreg.GM_Error_Hom.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Error\_Hom +==================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Error_Hom + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Error_Hom.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Error_Hom.mean_y + ~GM_Error_Hom.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Error_Hom_Regimes.rst.txt b/_sources/generated/spreg.GM_Error_Hom_Regimes.rst.txt new file mode 100644 index 00000000..1c3a9c30 --- /dev/null +++ b/_sources/generated/spreg.GM_Error_Hom_Regimes.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Error\_Hom\_Regimes +============================= + +.. currentmodule:: spreg + +.. autoclass:: GM_Error_Hom_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Error_Hom_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Error_Hom_Regimes.mean_y + ~GM_Error_Hom_Regimes.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Error_Regimes.rst.txt b/_sources/generated/spreg.GM_Error_Regimes.rst.txt new file mode 100644 index 00000000..ba5a00cc --- /dev/null +++ b/_sources/generated/spreg.GM_Error_Regimes.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_Error\_Regimes +======================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Error_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Error_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Error_Regimes.mean_y + ~GM_Error_Regimes.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_KKP.rst.txt b/_sources/generated/spreg.GM_KKP.rst.txt new file mode 100644 index 00000000..abeb8f31 --- /dev/null +++ b/_sources/generated/spreg.GM_KKP.rst.txt @@ -0,0 +1,29 @@ +ο»Ώspreg.GM\_KKP +============= + +.. currentmodule:: spreg + +.. autoclass:: GM_KKP + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_KKP.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_KKP.mean_y + ~GM_KKP.std_y + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Lag.rst.txt b/_sources/generated/spreg.GM_Lag.rst.txt new file mode 100644 index 00000000..cb8f7bbb --- /dev/null +++ b/_sources/generated/spreg.GM_Lag.rst.txt @@ -0,0 +1,34 @@ +ο»Ώspreg.GM\_Lag +============= + +.. currentmodule:: spreg + +.. autoclass:: GM_Lag + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Lag.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Lag.mean_y + ~GM_Lag.pfora1a2 + ~GM_Lag.sig2n + ~GM_Lag.sig2n_k + ~GM_Lag.std_y + ~GM_Lag.utu + ~GM_Lag.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.GM_Lag_Regimes.rst.txt b/_sources/generated/spreg.GM_Lag_Regimes.rst.txt new file mode 100644 index 00000000..964390e4 --- /dev/null +++ b/_sources/generated/spreg.GM_Lag_Regimes.rst.txt @@ -0,0 +1,36 @@ +ο»Ώspreg.GM\_Lag\_Regimes +====================== + +.. currentmodule:: spreg + +.. autoclass:: GM_Lag_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~GM_Lag_Regimes.GM_Lag_Regimes_Multi + ~GM_Lag_Regimes.__init__ + ~GM_Lag_Regimes.sp_att_reg + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~GM_Lag_Regimes.mean_y + ~GM_Lag_Regimes.pfora1a2 + ~GM_Lag_Regimes.sig2n + ~GM_Lag_Regimes.sig2n_k + ~GM_Lag_Regimes.std_y + ~GM_Lag_Regimes.utu + ~GM_Lag_Regimes.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.LMtests.rst.txt b/_sources/generated/spreg.LMtests.rst.txt new file mode 100644 index 00000000..8e52c18f --- /dev/null +++ b/_sources/generated/spreg.LMtests.rst.txt @@ -0,0 +1,22 @@ +ο»Ώspreg.LMtests +============= + +.. currentmodule:: spreg + +.. autoclass:: LMtests + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~LMtests.__init__ + + + + + + \ No newline at end of file diff --git a/_sources/generated/spreg.ML_Error.rst.txt b/_sources/generated/spreg.ML_Error.rst.txt new file mode 100644 index 00000000..94ba51ec --- /dev/null +++ b/_sources/generated/spreg.ML_Error.rst.txt @@ -0,0 +1,34 @@ +ο»Ώspreg.ML\_Error +=============== + +.. currentmodule:: spreg + +.. autoclass:: ML_Error + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~ML_Error.__init__ + ~ML_Error.get_x_lag + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~ML_Error.mean_y + ~ML_Error.sig2n + ~ML_Error.sig2n_k + ~ML_Error.std_y + ~ML_Error.utu + ~ML_Error.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.ML_Error_Regimes.rst.txt b/_sources/generated/spreg.ML_Error_Regimes.rst.txt new file mode 100644 index 00000000..65442bfa --- /dev/null +++ b/_sources/generated/spreg.ML_Error_Regimes.rst.txt @@ -0,0 +1,34 @@ +ο»Ώspreg.ML\_Error\_Regimes +======================== + +.. currentmodule:: spreg + +.. autoclass:: ML_Error_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~ML_Error_Regimes.__init__ + ~ML_Error_Regimes.get_x_lag + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~ML_Error_Regimes.mean_y + ~ML_Error_Regimes.sig2n + ~ML_Error_Regimes.sig2n_k + ~ML_Error_Regimes.std_y + ~ML_Error_Regimes.utu + ~ML_Error_Regimes.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.ML_Lag.rst.txt b/_sources/generated/spreg.ML_Lag.rst.txt new file mode 100644 index 00000000..c862afd9 --- /dev/null +++ b/_sources/generated/spreg.ML_Lag.rst.txt @@ -0,0 +1,33 @@ +ο»Ώspreg.ML\_Lag +============= + +.. currentmodule:: spreg + +.. autoclass:: ML_Lag + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~ML_Lag.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~ML_Lag.mean_y + ~ML_Lag.sig2n + ~ML_Lag.sig2n_k + ~ML_Lag.std_y + ~ML_Lag.utu + ~ML_Lag.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.ML_Lag_Regimes.rst.txt b/_sources/generated/spreg.ML_Lag_Regimes.rst.txt new file mode 100644 index 00000000..c025abe1 --- /dev/null +++ b/_sources/generated/spreg.ML_Lag_Regimes.rst.txt @@ -0,0 +1,34 @@ +ο»Ώspreg.ML\_Lag\_Regimes +====================== + +.. currentmodule:: spreg + +.. autoclass:: ML_Lag_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~ML_Lag_Regimes.ML_Lag_Regimes_Multi + ~ML_Lag_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~ML_Lag_Regimes.mean_y + ~ML_Lag_Regimes.sig2n + ~ML_Lag_Regimes.sig2n_k + ~ML_Lag_Regimes.std_y + ~ML_Lag_Regimes.utu + ~ML_Lag_Regimes.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.MoranRes.rst.txt b/_sources/generated/spreg.MoranRes.rst.txt new file mode 100644 index 00000000..ea1c616e --- /dev/null +++ b/_sources/generated/spreg.MoranRes.rst.txt @@ -0,0 +1,22 @@ +ο»Ώspreg.MoranRes +============== + +.. currentmodule:: spreg + +.. autoclass:: MoranRes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~MoranRes.__init__ + + + + + + \ No newline at end of file diff --git a/_sources/generated/spreg.OLS.rst.txt b/_sources/generated/spreg.OLS.rst.txt new file mode 100644 index 00000000..67fd5ef5 --- /dev/null +++ b/_sources/generated/spreg.OLS.rst.txt @@ -0,0 +1,33 @@ +ο»Ώspreg.OLS +========= + +.. currentmodule:: spreg + +.. autoclass:: OLS + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~OLS.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~OLS.mean_y + ~OLS.sig2n + ~OLS.sig2n_k + ~OLS.std_y + ~OLS.utu + ~OLS.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.OLS_Regimes.rst.txt b/_sources/generated/spreg.OLS_Regimes.rst.txt new file mode 100644 index 00000000..83a71f2e --- /dev/null +++ b/_sources/generated/spreg.OLS_Regimes.rst.txt @@ -0,0 +1,33 @@ +ο»Ώspreg.OLS\_Regimes +================== + +.. currentmodule:: spreg + +.. autoclass:: OLS_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~OLS_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~OLS_Regimes.mean_y + ~OLS_Regimes.sig2n + ~OLS_Regimes.sig2n_k + ~OLS_Regimes.std_y + ~OLS_Regimes.utu + ~OLS_Regimes.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.Panel_FE_Error.rst.txt b/_sources/generated/spreg.Panel_FE_Error.rst.txt new file mode 100644 index 00000000..a0d8ff66 --- /dev/null +++ b/_sources/generated/spreg.Panel_FE_Error.rst.txt @@ -0,0 +1,33 @@ +ο»Ώspreg.Panel\_FE\_Error +====================== + +.. currentmodule:: spreg + +.. autoclass:: Panel_FE_Error + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Panel_FE_Error.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Panel_FE_Error.mean_y + ~Panel_FE_Error.sig2n + ~Panel_FE_Error.sig2n_k + ~Panel_FE_Error.std_y + ~Panel_FE_Error.utu + ~Panel_FE_Error.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.Panel_FE_Lag.rst.txt b/_sources/generated/spreg.Panel_FE_Lag.rst.txt new file mode 100644 index 00000000..b7e82711 --- /dev/null +++ b/_sources/generated/spreg.Panel_FE_Lag.rst.txt @@ -0,0 +1,33 @@ +ο»Ώspreg.Panel\_FE\_Lag +==================== + +.. currentmodule:: spreg + +.. autoclass:: Panel_FE_Lag + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Panel_FE_Lag.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Panel_FE_Lag.mean_y + ~Panel_FE_Lag.sig2n + ~Panel_FE_Lag.sig2n_k + ~Panel_FE_Lag.std_y + ~Panel_FE_Lag.utu + ~Panel_FE_Lag.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.Panel_RE_Error.rst.txt b/_sources/generated/spreg.Panel_RE_Error.rst.txt new file mode 100644 index 00000000..4cf0cf96 --- /dev/null +++ b/_sources/generated/spreg.Panel_RE_Error.rst.txt @@ -0,0 +1,33 @@ +ο»Ώspreg.Panel\_RE\_Error +====================== + +.. currentmodule:: spreg + +.. autoclass:: Panel_RE_Error + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Panel_RE_Error.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Panel_RE_Error.mean_y + ~Panel_RE_Error.sig2n + ~Panel_RE_Error.sig2n_k + ~Panel_RE_Error.std_y + ~Panel_RE_Error.utu + ~Panel_RE_Error.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.Panel_RE_Lag.rst.txt b/_sources/generated/spreg.Panel_RE_Lag.rst.txt new file mode 100644 index 00000000..4fd33117 --- /dev/null +++ b/_sources/generated/spreg.Panel_RE_Lag.rst.txt @@ -0,0 +1,33 @@ +ο»Ώspreg.Panel\_RE\_Lag +==================== + +.. currentmodule:: spreg + +.. autoclass:: Panel_RE_Lag + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Panel_RE_Lag.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Panel_RE_Lag.mean_y + ~Panel_RE_Lag.sig2n + ~Panel_RE_Lag.sig2n_k + ~Panel_RE_Lag.std_y + ~Panel_RE_Lag.utu + ~Panel_RE_Lag.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.Probit.rst.txt b/_sources/generated/spreg.Probit.rst.txt new file mode 100644 index 00000000..29cc06ed --- /dev/null +++ b/_sources/generated/spreg.Probit.rst.txt @@ -0,0 +1,49 @@ +ο»Ώspreg.Probit +============ + +.. currentmodule:: spreg + +.. autoclass:: Probit + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Probit.__init__ + ~Probit.gradient + ~Probit.hessian + ~Probit.ll + ~Probit.par_est + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~Probit.KP_error + ~Probit.LR + ~Probit.PS_error + ~Probit.Pinkse_error + ~Probit.phiy + ~Probit.predpc + ~Probit.predy + ~Probit.scale + ~Probit.slopes + ~Probit.slopes_std_err + ~Probit.slopes_vm + ~Probit.slopes_z_stat + ~Probit.u_gen + ~Probit.u_naive + ~Probit.vm + ~Probit.xb + ~Probit.xmean + ~Probit.z_stat + + \ No newline at end of file diff --git a/_sources/generated/spreg.SUR.rst.txt b/_sources/generated/spreg.SUR.rst.txt new file mode 100644 index 00000000..4748b11f --- /dev/null +++ b/_sources/generated/spreg.SUR.rst.txt @@ -0,0 +1,22 @@ +ο»Ώspreg.SUR +========= + +.. currentmodule:: spreg + +.. autoclass:: SUR + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~SUR.__init__ + + + + + + \ No newline at end of file diff --git a/_sources/generated/spreg.SURerrorGM.rst.txt b/_sources/generated/spreg.SURerrorGM.rst.txt new file mode 100644 index 00000000..f9040480 --- /dev/null +++ b/_sources/generated/spreg.SURerrorGM.rst.txt @@ -0,0 +1,22 @@ +ο»Ώspreg.SURerrorGM +================ + +.. currentmodule:: spreg + +.. autoclass:: SURerrorGM + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~SURerrorGM.__init__ + + + + + + \ No newline at end of file diff --git a/_sources/generated/spreg.SURerrorML.rst.txt b/_sources/generated/spreg.SURerrorML.rst.txt new file mode 100644 index 00000000..66b8dc33 --- /dev/null +++ b/_sources/generated/spreg.SURerrorML.rst.txt @@ -0,0 +1,22 @@ +ο»Ώspreg.SURerrorML +================ + +.. currentmodule:: spreg + +.. autoclass:: SURerrorML + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~SURerrorML.__init__ + + + + + + \ No newline at end of file diff --git a/_sources/generated/spreg.SURlagIV.rst.txt b/_sources/generated/spreg.SURlagIV.rst.txt new file mode 100644 index 00000000..808666c6 --- /dev/null +++ b/_sources/generated/spreg.SURlagIV.rst.txt @@ -0,0 +1,22 @@ +ο»Ώspreg.SURlagIV +============== + +.. currentmodule:: spreg + +.. autoclass:: SURlagIV + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~SURlagIV.__init__ + + + + + + \ No newline at end of file diff --git a/_sources/generated/spreg.Skater_reg.rst.txt b/_sources/generated/spreg.Skater_reg.rst.txt new file mode 100644 index 00000000..20ba1961 --- /dev/null +++ b/_sources/generated/spreg.Skater_reg.rst.txt @@ -0,0 +1,26 @@ +ο»Ώspreg.Skater\_reg +================= + +.. currentmodule:: spreg + +.. autoclass:: Skater_reg + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~Skater_reg.__init__ + ~Skater_reg.find_cut + ~Skater_reg.fit + ~Skater_reg.score_spreg + ~Skater_reg.score_stats + + + + + + \ No newline at end of file diff --git a/_sources/generated/spreg.TSLS.rst.txt b/_sources/generated/spreg.TSLS.rst.txt new file mode 100644 index 00000000..695330ff --- /dev/null +++ b/_sources/generated/spreg.TSLS.rst.txt @@ -0,0 +1,34 @@ +ο»Ώspreg.TSLS +========== + +.. currentmodule:: spreg + +.. autoclass:: TSLS + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~TSLS.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~TSLS.mean_y + ~TSLS.pfora1a2 + ~TSLS.sig2n + ~TSLS.sig2n_k + ~TSLS.std_y + ~TSLS.utu + ~TSLS.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.TSLS_Regimes.rst.txt b/_sources/generated/spreg.TSLS_Regimes.rst.txt new file mode 100644 index 00000000..f6c01d86 --- /dev/null +++ b/_sources/generated/spreg.TSLS_Regimes.rst.txt @@ -0,0 +1,34 @@ +ο»Ώspreg.TSLS\_Regimes +=================== + +.. currentmodule:: spreg + +.. autoclass:: TSLS_Regimes + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~TSLS_Regimes.__init__ + + + + + + .. rubric:: Attributes + + .. autosummary:: + + ~TSLS_Regimes.mean_y + ~TSLS_Regimes.pfora1a2 + ~TSLS_Regimes.sig2n + ~TSLS_Regimes.sig2n_k + ~TSLS_Regimes.std_y + ~TSLS_Regimes.utu + ~TSLS_Regimes.vm + + \ No newline at end of file diff --git a/_sources/generated/spreg.ThreeSLS.rst.txt b/_sources/generated/spreg.ThreeSLS.rst.txt new file mode 100644 index 00000000..9ccd6065 --- /dev/null +++ b/_sources/generated/spreg.ThreeSLS.rst.txt @@ -0,0 +1,22 @@ +ο»Ώspreg.ThreeSLS +============== + +.. currentmodule:: spreg + +.. autoclass:: ThreeSLS + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~ThreeSLS.__init__ + + + + + + \ No newline at end of file diff --git a/_sources/generated/spreg.akaike.rst.txt b/_sources/generated/spreg.akaike.rst.txt new file mode 100644 index 00000000..721011c1 --- /dev/null +++ b/_sources/generated/spreg.akaike.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.akaike +============ + +.. currentmodule:: spreg + +.. autofunction:: akaike \ No newline at end of file diff --git a/_sources/generated/spreg.ar2.rst.txt b/_sources/generated/spreg.ar2.rst.txt new file mode 100644 index 00000000..13b026bb --- /dev/null +++ b/_sources/generated/spreg.ar2.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.ar2 +========= + +.. currentmodule:: spreg + +.. autofunction:: ar2 \ No newline at end of file diff --git a/_sources/generated/spreg.breusch_pagan.rst.txt b/_sources/generated/spreg.breusch_pagan.rst.txt new file mode 100644 index 00000000..e04ada15 --- /dev/null +++ b/_sources/generated/spreg.breusch_pagan.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.breusch\_pagan +==================== + +.. currentmodule:: spreg + +.. autofunction:: breusch_pagan \ No newline at end of file diff --git a/_sources/generated/spreg.condition_index.rst.txt b/_sources/generated/spreg.condition_index.rst.txt new file mode 100644 index 00000000..0c98e51b --- /dev/null +++ b/_sources/generated/spreg.condition_index.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.condition\_index +====================== + +.. currentmodule:: spreg + +.. autofunction:: condition_index \ No newline at end of file diff --git a/_sources/generated/spreg.constant_check.rst.txt b/_sources/generated/spreg.constant_check.rst.txt new file mode 100644 index 00000000..ad4fcdbf --- /dev/null +++ b/_sources/generated/spreg.constant_check.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.constant\_check +===================== + +.. currentmodule:: spreg + +.. autofunction:: constant_check \ No newline at end of file diff --git a/_sources/generated/spreg.f_stat.rst.txt b/_sources/generated/spreg.f_stat.rst.txt new file mode 100644 index 00000000..5ed721ac --- /dev/null +++ b/_sources/generated/spreg.f_stat.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.f\_stat +============= + +.. currentmodule:: spreg + +.. autofunction:: f_stat \ No newline at end of file diff --git a/_sources/generated/spreg.jarque_bera.rst.txt b/_sources/generated/spreg.jarque_bera.rst.txt new file mode 100644 index 00000000..9bca1990 --- /dev/null +++ b/_sources/generated/spreg.jarque_bera.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.jarque\_bera +================== + +.. currentmodule:: spreg + +.. autofunction:: jarque_bera \ No newline at end of file diff --git a/_sources/generated/spreg.koenker_bassett.rst.txt b/_sources/generated/spreg.koenker_bassett.rst.txt new file mode 100644 index 00000000..4b682575 --- /dev/null +++ b/_sources/generated/spreg.koenker_bassett.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.koenker\_bassett +====================== + +.. currentmodule:: spreg + +.. autofunction:: koenker_bassett \ No newline at end of file diff --git a/_sources/generated/spreg.lam_setp.rst.txt b/_sources/generated/spreg.lam_setp.rst.txt new file mode 100644 index 00000000..6ae82f98 --- /dev/null +++ b/_sources/generated/spreg.lam_setp.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.lam\_setp +=============== + +.. currentmodule:: spreg + +.. autofunction:: lam_setp \ No newline at end of file diff --git a/_sources/generated/spreg.likratiotest.rst.txt b/_sources/generated/spreg.likratiotest.rst.txt new file mode 100644 index 00000000..37937efd --- /dev/null +++ b/_sources/generated/spreg.likratiotest.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.likratiotest +================== + +.. currentmodule:: spreg + +.. autofunction:: likratiotest \ No newline at end of file diff --git a/_sources/generated/spreg.log_likelihood.rst.txt b/_sources/generated/spreg.log_likelihood.rst.txt new file mode 100644 index 00000000..94eaedd5 --- /dev/null +++ b/_sources/generated/spreg.log_likelihood.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.log\_likelihood +===================== + +.. currentmodule:: spreg + +.. autofunction:: log_likelihood \ No newline at end of file diff --git a/_sources/generated/spreg.panel_Hausman.rst.txt b/_sources/generated/spreg.panel_Hausman.rst.txt new file mode 100644 index 00000000..a89f25a7 --- /dev/null +++ b/_sources/generated/spreg.panel_Hausman.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.panel\_Hausman +==================== + +.. currentmodule:: spreg + +.. autofunction:: panel_Hausman \ No newline at end of file diff --git a/_sources/generated/spreg.panel_LMerror.rst.txt b/_sources/generated/spreg.panel_LMerror.rst.txt new file mode 100644 index 00000000..17ec1f8d --- /dev/null +++ b/_sources/generated/spreg.panel_LMerror.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.panel\_LMerror +==================== + +.. currentmodule:: spreg + +.. autofunction:: panel_LMerror \ No newline at end of file diff --git a/_sources/generated/spreg.panel_LMlag.rst.txt b/_sources/generated/spreg.panel_LMlag.rst.txt new file mode 100644 index 00000000..695c15bf --- /dev/null +++ b/_sources/generated/spreg.panel_LMlag.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.panel\_LMlag +================== + +.. currentmodule:: spreg + +.. autofunction:: panel_LMlag \ No newline at end of file diff --git a/_sources/generated/spreg.panel_rLMerror.rst.txt b/_sources/generated/spreg.panel_rLMerror.rst.txt new file mode 100644 index 00000000..c851a31a --- /dev/null +++ b/_sources/generated/spreg.panel_rLMerror.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.panel\_rLMerror +===================== + +.. currentmodule:: spreg + +.. autofunction:: panel_rLMerror \ No newline at end of file diff --git a/_sources/generated/spreg.panel_rLMlag.rst.txt b/_sources/generated/spreg.panel_rLMlag.rst.txt new file mode 100644 index 00000000..2a908232 --- /dev/null +++ b/_sources/generated/spreg.panel_rLMlag.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.panel\_rLMlag +=================== + +.. currentmodule:: spreg + +.. autofunction:: panel_rLMlag \ No newline at end of file diff --git a/_sources/generated/spreg.r2.rst.txt b/_sources/generated/spreg.r2.rst.txt new file mode 100644 index 00000000..1c2a0f12 --- /dev/null +++ b/_sources/generated/spreg.r2.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.r2 +======== + +.. currentmodule:: spreg + +.. autofunction:: r2 \ No newline at end of file diff --git a/_sources/generated/spreg.schwarz.rst.txt b/_sources/generated/spreg.schwarz.rst.txt new file mode 100644 index 00000000..c361c012 --- /dev/null +++ b/_sources/generated/spreg.schwarz.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.schwarz +============= + +.. currentmodule:: spreg + +.. autofunction:: schwarz \ No newline at end of file diff --git a/_sources/generated/spreg.se_betas.rst.txt b/_sources/generated/spreg.se_betas.rst.txt new file mode 100644 index 00000000..a1667a57 --- /dev/null +++ b/_sources/generated/spreg.se_betas.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.se\_betas +=============== + +.. currentmodule:: spreg + +.. autofunction:: se_betas \ No newline at end of file diff --git a/_sources/generated/spreg.surLMe.rst.txt b/_sources/generated/spreg.surLMe.rst.txt new file mode 100644 index 00000000..7cede27a --- /dev/null +++ b/_sources/generated/spreg.surLMe.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.surLMe +============ + +.. currentmodule:: spreg + +.. autofunction:: surLMe \ No newline at end of file diff --git a/_sources/generated/spreg.surLMlag.rst.txt b/_sources/generated/spreg.surLMlag.rst.txt new file mode 100644 index 00000000..48470bb7 --- /dev/null +++ b/_sources/generated/spreg.surLMlag.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.surLMlag +============== + +.. currentmodule:: spreg + +.. autofunction:: surLMlag \ No newline at end of file diff --git a/_sources/generated/spreg.sur_lmtest.rst.txt b/_sources/generated/spreg.sur_lmtest.rst.txt new file mode 100644 index 00000000..15aa811a --- /dev/null +++ b/_sources/generated/spreg.sur_lmtest.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.sur\_lmtest +================= + +.. currentmodule:: spreg + +.. autofunction:: sur_lmtest \ No newline at end of file diff --git a/_sources/generated/spreg.sur_lrtest.rst.txt b/_sources/generated/spreg.sur_lrtest.rst.txt new file mode 100644 index 00000000..3956ee6c --- /dev/null +++ b/_sources/generated/spreg.sur_lrtest.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.sur\_lrtest +================= + +.. currentmodule:: spreg + +.. autofunction:: sur_lrtest \ No newline at end of file diff --git a/_sources/generated/spreg.sur_setp.rst.txt b/_sources/generated/spreg.sur_setp.rst.txt new file mode 100644 index 00000000..0b55a797 --- /dev/null +++ b/_sources/generated/spreg.sur_setp.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.sur\_setp +=============== + +.. currentmodule:: spreg + +.. autofunction:: sur_setp \ No newline at end of file diff --git a/_sources/generated/spreg.t_stat.rst.txt b/_sources/generated/spreg.t_stat.rst.txt new file mode 100644 index 00000000..ff507b7b --- /dev/null +++ b/_sources/generated/spreg.t_stat.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.t\_stat +============= + +.. currentmodule:: spreg + +.. autofunction:: t_stat \ No newline at end of file diff --git a/_sources/generated/spreg.vif.rst.txt b/_sources/generated/spreg.vif.rst.txt new file mode 100644 index 00000000..3be42ae7 --- /dev/null +++ b/_sources/generated/spreg.vif.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.vif +========= + +.. currentmodule:: spreg + +.. autofunction:: vif \ No newline at end of file diff --git a/_sources/generated/spreg.white.rst.txt b/_sources/generated/spreg.white.rst.txt new file mode 100644 index 00000000..dd11eb7a --- /dev/null +++ b/_sources/generated/spreg.white.rst.txt @@ -0,0 +1,6 @@ +ο»Ώspreg.white +=========== + +.. currentmodule:: spreg + +.. autofunction:: white \ No newline at end of file diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt index 68ae8673..4da4604f 100644 --- a/_sources/index.rst.txt +++ b/_sources/index.rst.txt @@ -1,20 +1,27 @@ -.. No Errors Test Project documentation master file, created by - sphinx-quickstart on Fri Aug 30 17:07:56 2019. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +.. documentation master file -Welcome to No Errors Test Project's documentation! -================================================== +Spatial Regression Models (spreg) +================================= -.. toctree:: - :maxdepth: 2 - :caption: Hello World! +`spreg`, short for "spatial regression," is a python package to estimate simultaneous autoregressive spatial regression models. These models are useful when modeling processes where observations interact with one another. For more information on these models, consult the Spatial Regression short course by Luc Anselin (Spring, 2017), with the Center for Spatial Data Science at the University of Chicago: + +---- + +.. raw:: html +
+ +
+ +.. toctree:: + :hidden: + :maxdepth: 3 + :caption: Contents: + Installation + Tutorials + API + References -Indices and tables -================== -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +.. _PySAL: https://github.com/pysal/pysal diff --git a/_sources/installation.rst.txt b/_sources/installation.rst.txt new file mode 100644 index 00000000..854ee3fe --- /dev/null +++ b/_sources/installation.rst.txt @@ -0,0 +1,14 @@ +.. Installation + +Installation +============ + +spreg is installable using the Python Package Manager, `pip`. To install:: + + pip install spreg + +Further, all of the stable functionality is *also* available in PySAL, the +Python Spatial Analysis Library. PySAL can be installed using `pip` or `conda`:: + + pip install pysal #or + conda install pysal diff --git a/_sources/notebooks/GM_Lag_example.ipynb.txt b/_sources/notebooks/GM_Lag_example.ipynb.txt new file mode 100644 index 00000000..ada225b7 --- /dev/null +++ b/_sources/notebooks/GM_Lag_example.ipynb.txt @@ -0,0 +1,511 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---------------------------------------\n", + "\n", + "# Spatial 2SLS\n", + "\n", + "* **This notebook contains the PySAL/spreg code for Chapter 7 - Spatial 2SLS**\n", + " * *in: Modern Spatial Econometrics in Practice: A Guide to GeoDa, GeoDaSpace and PySAL.*\n", + " * *by: Luc Anselin and Sergio J. Rey.*" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-03T16:26:48.619651Z", + "start_time": "2021-01-03T16:26:48.586688Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Last updated: 2021-01-03T11:26:48.607797-05:00\n", + "\n", + "Python implementation: CPython\n", + "Python version : 3.8.6\n", + "IPython version : 7.19.0\n", + "\n", + "Compiler : Clang 11.0.0 \n", + "OS : Darwin\n", + "Release : 20.2.0\n", + "Machine : x86_64\n", + "Processor : i386\n", + "CPU cores : 8\n", + "Architecture: 64bit\n", + "\n" + ] + } + ], + "source": [ + "%load_ext watermark\n", + "%watermark" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-03T16:26:49.970828Z", + "start_time": "2021-01-03T16:26:48.621823Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Watermark: 2.1.0\n", + "\n", + "spreg : 1.2.0.post1\n", + "libpysal: 4.3.0\n", + "numpy : 1.19.4\n", + "\n" + ] + } + ], + "source": [ + "import numpy\n", + "import libpysal\n", + "import spreg\n", + "\n", + "%watermark -w\n", + "%watermark -iv" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Data" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-03T16:26:49.976860Z", + "start_time": "2021-01-03T16:26:49.973373Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "baltim\n", + "======\n", + "\n", + "Baltimore house sales prices and hedonics, 1978. \n", + "----------------------------------------------------------------\n", + "\n", + "* baltim.dbf: attribute data. (k=17)\n", + "* baltim.shp: Point shapefile. (n=211)\n", + "* baltim.shx: spatial index.\n", + "* baltim.tri.k12.kwt: kernel weights using a triangular kernel with 12 nearest neighbors in KWT format.\n", + "* baltim_k4.gwt: nearest neighbor weights (4nn) in GWT format.\n", + "* baltim_q.gal: queen contiguity weights in GAL format.\n", + "* baltimore.geojson: spatial weights in geojson format.\n", + "\n", + "Source: Dubin, Robin A. (1992). Spatial autocorrelation and neighborhood quality. Regional Science and Urban Economics 22(3), 433-452.\n" + ] + } + ], + "source": [ + "libpysal.examples.explain(\"baltim\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-03T16:26:49.991200Z", + "start_time": "2021-01-03T16:26:49.979155Z" + } + }, + "outputs": [], + "source": [ + "# Read Baltimore data\n", + "db = libpysal.io.open(libpysal.examples.get_path(\"baltim.dbf\"), \"r\")\n", + "ds_name = \"baltim.dbf\"\n", + "\n", + "# Read dependent variable\n", + "y_name = \"PRICE\"\n", + "y = numpy.array(db.by_col(y_name)).T\n", + "y = y[:, numpy.newaxis]\n", + "\n", + "# Read exogenous variables\n", + "x_names = [\"NROOM\", \"NBATH\", \"PATIO\", \"FIREPL\", \"AC\", \"GAR\", \"AGE\", \"LOTSZ\", \"SQFT\"]\n", + "x = numpy.array([db.by_col(var) for var in x_names]).T" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-03T16:26:50.062604Z", + "start_time": "2021-01-03T16:26:49.993233Z" + } + }, + "outputs": [], + "source": [ + "# Read spatial data\n", + "ww = libpysal.io.open(libpysal.examples.get_path(\"baltim_q.gal\"))\n", + "w = ww.read()\n", + "ww.close()\n", + "w_name = \"baltim_q.gal\"\n", + "w.transform = \"r\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic Spatial 2SLS\n", + "\n", + "The model to estimate is:\n", + "\n", + "$$ y = \\rho Wy + X \\beta + \\epsilon $$\n", + "\n", + "where you use $WX$ as instruments of $Wy$." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-03T16:26:50.074860Z", + "start_time": "2021-01-03T16:26:50.065491Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "REGRESSION\n", + "----------\n", + "SUMMARY OF OUTPUT: SPATIAL TWO STAGE LEAST SQUARES\n", + "--------------------------------------------------\n", + "Data set : baltim\n", + "Weights matrix : baltim_q\n", + "Dependent Variable : PRICE Number of Observations: 211\n", + "Mean dependent var : 44.3072 Number of Variables : 11\n", + "S.D. dependent var : 23.6061 Degrees of Freedom : 200\n", + "Pseudo R-squared : 0.7278\n", + "Spatial Pseudo R-squared: 0.6928\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error z-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " CONSTANT -2.5762742 5.5210355 -0.4666288 0.6407655\n", + " NROOM 0.9440746 1.0609697 0.8898224 0.3735612\n", + " NBATH 5.5981348 1.7376725 3.2216283 0.0012746\n", + " PATIO 5.8424768 2.7435166 2.1295577 0.0332081\n", + " FIREPL 6.4579185 2.4238370 2.6643369 0.0077140\n", + " AC 5.4871926 2.3450930 2.3398614 0.0192909\n", + " GAR 4.3565951 1.6955478 2.5694321 0.0101865\n", + " AGE -0.0730060 0.0523546 -1.3944510 0.1631814\n", + " LOTSZ 0.0579765 0.0149534 3.8771359 0.0001057\n", + " SQFT 0.0395330 0.1638055 0.2413409 0.8092909\n", + " W_PRICE 0.5823313 0.0721387 8.0723813 0.0000000\n", + "------------------------------------------------------------------------------------\n", + "Instrumented: W_PRICE\n", + "Instruments: W_AC, W_AGE, W_FIREPL, W_GAR, W_LOTSZ, W_NBATH, W_NROOM,\n", + " W_PATIO, W_SQFT\n", + "================================ END OF REPORT =====================================\n" + ] + } + ], + "source": [ + "model = spreg.GM_Lag(\n", + " y,\n", + " x,\n", + " w=w,\n", + " name_y=y_name,\n", + " name_x=x_names,\n", + " name_w=\"baltim_q\",\n", + " name_ds=\"baltim\"\n", + ")\n", + "print(model.summary)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Second order spatial lags\n", + "\n", + "You can also use $[WX, W^2X]$ as instruments of $Wy$." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-03T16:26:50.085089Z", + "start_time": "2021-01-03T16:26:50.076795Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "REGRESSION\n", + "----------\n", + "SUMMARY OF OUTPUT: SPATIAL TWO STAGE LEAST SQUARES\n", + "--------------------------------------------------\n", + "Data set : baltim\n", + "Weights matrix : baltim_q\n", + "Dependent Variable : PRICE Number of Observations: 211\n", + "Mean dependent var : 44.3072 Number of Variables : 11\n", + "S.D. dependent var : 23.6061 Degrees of Freedom : 200\n", + "Pseudo R-squared : 0.7276\n", + "Spatial Pseudo R-squared: 0.6915\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error z-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " CONSTANT -2.8867580 5.4563344 -0.5290654 0.5967601\n", + " NROOM 0.9527428 1.0613055 0.8977083 0.3693411\n", + " NBATH 5.5975309 1.7386698 3.2194330 0.0012844\n", + " PATIO 5.7884989 2.7409866 2.1118304 0.0347010\n", + " FIREPL 6.4012808 2.4201110 2.6450360 0.0081682\n", + " AC 5.4587589 2.3451078 2.3277220 0.0199269\n", + " GAR 4.3440361 1.6961624 2.5610969 0.0104342\n", + " AGE -0.0713188 0.0521742 -1.3669353 0.1716456\n", + " LOTSZ 0.0575329 0.0149111 3.8583943 0.0001141\n", + " SQFT 0.0377524 0.1638248 0.2304438 0.8177470\n", + " W_PRICE 0.5893267 0.0695101 8.4782886 0.0000000\n", + "------------------------------------------------------------------------------------\n", + "Instrumented: W_PRICE\n", + "Instruments: W2_AC, W2_AGE, W2_FIREPL, W2_GAR, W2_LOTSZ, W2_NBATH, W2_NROOM,\n", + " W2_PATIO, W2_SQFT, W_AC, W_AGE, W_FIREPL, W_GAR, W_LOTSZ,\n", + " W_NBATH, W_NROOM, W_PATIO, W_SQFT\n", + "================================ END OF REPORT =====================================\n" + ] + } + ], + "source": [ + "# using second order spatial lags for the instruments, set w_lags = 2\n", + "model2 = spreg.GM_Lag(\n", + " y,\n", + " x,\n", + " w=w,\n", + " w_lags=2,\n", + " name_y=y_name,\n", + " name_x=x_names,\n", + " name_w=\"baltim_q\",\n", + " name_ds=\"baltim\"\n", + ")\n", + "print(model2.summary)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Spatial Diagnostics" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-03T16:26:50.099577Z", + "start_time": "2021-01-03T16:26:50.088864Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "REGRESSION\n", + "----------\n", + "SUMMARY OF OUTPUT: SPATIAL TWO STAGE LEAST SQUARES\n", + "--------------------------------------------------\n", + "Data set : baltim\n", + "Weights matrix : baltim_q\n", + "Dependent Variable : PRICE Number of Observations: 211\n", + "Mean dependent var : 44.3072 Number of Variables : 11\n", + "S.D. dependent var : 23.6061 Degrees of Freedom : 200\n", + "Pseudo R-squared : 0.7278\n", + "Spatial Pseudo R-squared: 0.6928\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error z-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " CONSTANT -2.5762742 5.5210355 -0.4666288 0.6407655\n", + " NROOM 0.9440746 1.0609697 0.8898224 0.3735612\n", + " NBATH 5.5981348 1.7376725 3.2216283 0.0012746\n", + " PATIO 5.8424768 2.7435166 2.1295577 0.0332081\n", + " FIREPL 6.4579185 2.4238370 2.6643369 0.0077140\n", + " AC 5.4871926 2.3450930 2.3398614 0.0192909\n", + " GAR 4.3565951 1.6955478 2.5694321 0.0101865\n", + " AGE -0.0730060 0.0523546 -1.3944510 0.1631814\n", + " LOTSZ 0.0579765 0.0149534 3.8771359 0.0001057\n", + " SQFT 0.0395330 0.1638055 0.2413409 0.8092909\n", + " W_PRICE 0.5823313 0.0721387 8.0723813 0.0000000\n", + "------------------------------------------------------------------------------------\n", + "Instrumented: W_PRICE\n", + "Instruments: W_AC, W_AGE, W_FIREPL, W_GAR, W_LOTSZ, W_NBATH, W_NROOM,\n", + " W_PATIO, W_SQFT\n", + "\n", + "DIAGNOSTICS FOR SPATIAL DEPENDENCE\n", + "TEST MI/DF VALUE PROB\n", + "Anselin-Kelejian Test 1 5.234 0.0221\n", + "================================ END OF REPORT =====================================\n" + ] + } + ], + "source": [ + "model = spreg.GM_Lag(\n", + " y,\n", + " x,\n", + " w=w,\n", + " spat_diag=True,\n", + " name_y=y_name,\n", + " name_x=x_names,\n", + " name_w=\"baltim_q\",\n", + " name_ds=\"baltim\"\n", + ")\n", + "print(model.summary)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## White Standard Errors" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-03T16:26:50.112672Z", + "start_time": "2021-01-03T16:26:50.101959Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "REGRESSION\n", + "----------\n", + "SUMMARY OF OUTPUT: SPATIAL TWO STAGE LEAST SQUARES\n", + "--------------------------------------------------\n", + "Data set : baltim\n", + "Weights matrix : baltim_q\n", + "Dependent Variable : PRICE Number of Observations: 211\n", + "Mean dependent var : 44.3072 Number of Variables : 11\n", + "S.D. dependent var : 23.6061 Degrees of Freedom : 200\n", + "Pseudo R-squared : 0.7278\n", + "Spatial Pseudo R-squared: 0.6928\n", + "\n", + "White Standard Errors\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error z-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " CONSTANT -2.5762742 7.0147591 -0.3672648 0.7134215\n", + " NROOM 0.9440746 1.4002856 0.6742015 0.5001832\n", + " NBATH 5.5981348 2.1605285 2.5910951 0.0095671\n", + " PATIO 5.8424768 2.9445656 1.9841558 0.0472385\n", + " FIREPL 6.4579185 2.4500195 2.6358641 0.0083923\n", + " AC 5.4871926 2.6021469 2.1087175 0.0349690\n", + " GAR 4.3565951 2.2070747 1.9739228 0.0483905\n", + " AGE -0.0730060 0.0976079 -0.7479516 0.4544894\n", + " LOTSZ 0.0579765 0.0237454 2.4415887 0.0146228\n", + " SQFT 0.0395330 0.2355809 0.1678105 0.8667323\n", + " W_PRICE 0.5823313 0.1325884 4.3920220 0.0000112\n", + "------------------------------------------------------------------------------------\n", + "Instrumented: W_PRICE\n", + "Instruments: W_AC, W_AGE, W_FIREPL, W_GAR, W_LOTSZ, W_NBATH, W_NROOM,\n", + " W_PATIO, W_SQFT\n", + "\n", + "DIAGNOSTICS FOR SPATIAL DEPENDENCE\n", + "TEST MI/DF VALUE PROB\n", + "Anselin-Kelejian Test 1 5.234 0.0221\n", + "================================ END OF REPORT =====================================\n" + ] + } + ], + "source": [ + "model = spreg.GM_Lag(\n", + " y,\n", + " x,\n", + " w=w,\n", + " robust=\"white\",\n", + " spat_diag=True,\n", + " name_y=y_name,\n", + " name_x=x_names,\n", + " name_w=\"baltim_q\",\n", + " name_ds=\"baltim\"\n", + ")\n", + "print(model.summary)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "-----------------------------" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:py38_spreg]", + "language": "python", + "name": "conda-env-py38_spreg-py" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.6" + }, + "toc": { + "base_numbering": 1, + "nav_menu": { + "height": "103px", + "width": "212px" + }, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/_sources/notebooks/Panel_FE_example.ipynb.txt b/_sources/notebooks/Panel_FE_example.ipynb.txt new file mode 100644 index 00000000..1db9c440 --- /dev/null +++ b/_sources/notebooks/Panel_FE_example.ipynb.txt @@ -0,0 +1,367 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "------------\n", + "\n", + "# Spatial Panel Models with Fixed Effects\n", + "\n", + "* **This notebook uses the [Panel_FE_Lag](https://pysal.org/spreg/generated/spreg.Panel_FE_Lag.html#spreg.Panel_FE_Lag) and [Panel_FE_Error](https://pysal.org/spreg/generated/spreg.Panel_FE_Error.html#spreg.Panel_FE_Error) classes.**\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-04T16:36:53.158014Z", + "start_time": "2021-01-04T16:36:50.182287Z" + } + }, + "outputs": [], + "source": [ + "import numpy\n", + "import libpysal\n", + "import spreg" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Open data on NCOVR US County Homicides (3085 areas).**\n", + "\n", + "* First, extract the HR (homicide rates) data in the 70's, 80's and 90's as the dependent variable.\n", + "* Data can also be passed in the long format instead of wide format.\n", + " * i.e. a vector with $n \\times t$ rows and a single column for the dependent variable, and\n", + " * a matrix of dimension $n \\times (t \\ast k)$ for the independent variables\n", + "* Then, extract RD and PS as independent variables in the regression." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-04T16:36:53.489678Z", + "start_time": "2021-01-04T16:36:53.160457Z" + } + }, + "outputs": [], + "source": [ + "# Open data on NCOVR US County Homicides (3085 areas).\n", + "nat = libpysal.examples.load_example(\"NCOVR\")\n", + "db = libpysal.io.open(nat.get_path(\"NAT.dbf\"), \"r\")\n", + "\n", + "# Create spatial weight matrix\n", + "nat_shp = libpysal.examples.get_path(\"NAT.shp\")\n", + "w = libpysal.weights.Queen.from_shapefile(nat_shp)\n", + "w.transform = 'r'\n", + "\n", + "# Define dependent variable\n", + "name_y = [\"HR70\", \"HR80\", \"HR90\"]\n", + "y = numpy.array([db.by_col(name) for name in name_y]).T\n", + "\n", + "# Define independent variables\n", + "name_x = [\"RD70\", \"RD80\", \"RD90\", \"PS70\", \"PS80\", \"PS90\"]\n", + "x = numpy.array([db.by_col(name) for name in name_x]).T" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "--------------------\n", + "\n", + "## Spatial Lag model\n", + "\n", + "Let's estimate a spatial lag panel model with fixed effects:\n", + "\n", + "$$\n", + "y = \\rho Wy + X\\beta + \\mu_i + e\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-04T16:36:59.736302Z", + "start_time": "2021-01-04T16:36:53.492370Z" + } + }, + "outputs": [], + "source": [ + "fe_lag = spreg.Panel_FE_Lag(y, x, w, name_y=name_y, name_x=name_x, name_ds=\"NAT\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-04T16:36:59.741882Z", + "start_time": "2021-01-04T16:36:59.737965Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "REGRESSION\n", + "----------\n", + "SUMMARY OF OUTPUT: MAXIMUM LIKELIHOOD SPATIAL LAG PANEL - FIXED EFFECTS\n", + "-----------------------------------------------------------------------\n", + "Data set : NAT\n", + "Weights matrix : unknown\n", + "Dependent Variable : HR Number of Observations: 9255\n", + "Mean dependent var : 0.0000 Number of Variables : 3\n", + "S.D. dependent var : 3.9228 Degrees of Freedom : 9252\n", + "Pseudo R-squared : 0.0319\n", + "Spatial Pseudo R-squared: 0.0079\n", + "Sigma-square ML : 14.935 Log likelihood : -67936.533\n", + "S.E of regression : 3.865 Akaike info criterion : 135879.066\n", + " Schwarz criterion : 135900.465\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error z-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " RD 0.8005886 0.1614474 4.9588189 0.0000007\n", + " PS -2.6003523 0.4935486 -5.2686851 0.0000001\n", + " W_HR 0.1903043 0.0159991 11.8947008 0.0000000\n", + "------------------------------------------------------------------------------------\n", + "Warning: Assuming panel is in wide format.\n", + "y[:, 0] refers to T0, y[:, 1] refers to T1, etc.\n", + "x[:, 0:T] refers to T periods of k1, x[:, T+1:2T] refers to k2, etc.\n", + "================================ END OF REPORT =====================================\n" + ] + } + ], + "source": [ + "print(fe_lag.summary)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-04T16:36:59.753663Z", + "start_time": "2021-01-04T16:36:59.743818Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0.8006],\n", + " [-2.6004],\n", + " [ 0.1903]])" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numpy.around(fe_lag.betas, decimals=4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Data can also be in 'long' format:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "REGRESSION\n", + "----------\n", + "SUMMARY OF OUTPUT: MAXIMUM LIKELIHOOD SPATIAL LAG PANEL - FIXED EFFECTS\n", + "-----------------------------------------------------------------------\n", + "Data set : NAT\n", + "Weights matrix : unknown\n", + "Dependent Variable : HR Number of Observations: 9255\n", + "Mean dependent var : 0.0000 Number of Variables : 3\n", + "S.D. dependent var : 3.9228 Degrees of Freedom : 9252\n", + "Pseudo R-squared : 0.0319\n", + "Spatial Pseudo R-squared: 0.0079\n", + "Sigma-square ML : 14.935 Log likelihood : -67936.533\n", + "S.E of regression : 3.865 Akaike info criterion : 135879.066\n", + " Schwarz criterion : 135900.465\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error z-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " RD 0.8005886 0.1614474 4.9588189 0.0000007\n", + " PS -2.6003523 0.4935486 -5.2686851 0.0000001\n", + " W_HR 0.1903043 0.0159991 11.8947008 0.0000000\n", + "------------------------------------------------------------------------------------\n", + "Warning: Assuming panel is in long format.\n", + "y[0:N] refers to T0, y[N+1:2N] refers to T1, etc.\n", + "x[0:N] refers to T0, x[N+1:2N] refers to T1, etc.\n", + "================================ END OF REPORT =====================================\n" + ] + } + ], + "source": [ + "y_long = y.reshape((y.shape[0]*y.shape[1],1), order='F')\n", + "x_long = x.reshape((x.shape[0]*3,2), order='F')\n", + "\n", + "fe_lag_long = spreg.Panel_FE_Lag(y_long, x_long, w, name_y=name_y, name_x=name_x, name_ds=\"NAT\")\n", + "print(fe_lag_long.summary)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "------------------------\n", + "\n", + "## Spatial Error model\n", + "\n", + "Now, let's estimate a spatial error panel model with fixed effects:\n", + "\n", + "$$\n", + "y = X\\beta + \\mu_i + v\n", + "$$\n", + "\n", + "where\n", + "\n", + "$$\n", + "v = \\lambda W v + e\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-04T16:37:03.722913Z", + "start_time": "2021-01-04T16:36:59.755557Z" + } + }, + "outputs": [], + "source": [ + "fe_error = spreg.Panel_FE_Error(\n", + " y, x, w, name_y=name_y, name_x=name_x, name_ds=\"NAT\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-04T16:37:03.729503Z", + "start_time": "2021-01-04T16:37:03.726165Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "REGRESSION\n", + "----------\n", + "SUMMARY OF OUTPUT: MAXIMUM LIKELIHOOD SPATIAL ERROR PANEL - FIXED EFFECTS\n", + "-------------------------------------------------------------------------\n", + "Data set : NAT\n", + "Weights matrix : unknown\n", + "Dependent Variable : HR Number of Observations: 9255\n", + "Mean dependent var : 0.0000 Number of Variables : 2\n", + "S.D. dependent var : 3.9228 Degrees of Freedom : 9253\n", + "Pseudo R-squared : 0.0084\n", + "Sigma-square ML : 14.923 Log likelihood : -67934.005\n", + "S.E of regression : 3.863 Akaike info criterion : 135872.010\n", + " Schwarz criterion : 135886.276\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error z-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " RD 0.8697923 0.1718029 5.0627323 0.0000004\n", + " PS -2.9660674 0.5444783 -5.4475397 0.0000001\n", + " lambda 0.1943460 0.0160253 12.1274197 0.0000000\n", + "------------------------------------------------------------------------------------\n", + "Warning: Assuming panel is in wide format.\n", + "y[:, 0] refers to T0, y[:, 1] refers to T1, etc.\n", + "x[:, 0:T] refers to T periods of k1, x[:, T+1:2T] refers to k2, etc.\n", + "================================ END OF REPORT =====================================\n" + ] + } + ], + "source": [ + "print(fe_error.summary)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2021-01-04T16:37:03.735854Z", + "start_time": "2021-01-04T16:37:03.731739Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 0.8698],\n", + " [-2.9661],\n", + " [ 0.1943]])" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "numpy.around(fe_error.betas, decimals=4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "------------------" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:myenv] *", + "language": "python", + "name": "conda-env-myenv-py" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/_sources/notebooks/skater_reg.ipynb.txt b/_sources/notebooks/skater_reg.ipynb.txt new file mode 100644 index 00000000..bfbcf91c --- /dev/null +++ b/_sources/notebooks/skater_reg.ipynb.txt @@ -0,0 +1,716 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0a500c14", + "metadata": {}, + "source": [ + "# Skater Regression" + ] + }, + { + "cell_type": "markdown", + "id": "1847d3c6", + "metadata": {}, + "source": [ + "### This notebook shows the use of the Skater Regression funcion (Skater_reg), introduced by Anselin & Amaral (2021). For more information on the method, check:\n", + "https://www.researchgate.net/publication/353411566_Endogenous_Spatial_Regimes" + ] + }, + { + "cell_type": "markdown", + "id": "e4afc8e0", + "metadata": {}, + "source": [ + "In this example, in addition to the required packages, we will use geopandas to load the data and matplotlib to plot the results. Alternatively, PySAL's own IO could also be used to load the data." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a7a0de53", + "metadata": {}, + "outputs": [], + "source": [ + "# Required imports\n", + "import libpysal as ps\n", + "import numpy as np\n", + "import spreg\n", + "from spreg.skater_reg import Skater_reg\n", + "\n", + "# Optional imports\n", + "import matplotlib.pyplot as plt\n", + "import geopandas as gpd" + ] + }, + { + "cell_type": "markdown", + "id": "c01ad58d", + "metadata": {}, + "source": [ + "We use Messner et al. (2000) data on homicides and selected socio-economic characteristics for continental U.S. counties to exemplify the use of Skater_reg. It can be downloaded from PySAL's examples repository." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "52f82039", + "metadata": {}, + "outputs": [], + "source": [ + "# Load the example from PySAL\n", + "ps.examples.load_example(\"NCOVR\")\n", + "data = gpd.read_file(ps.examples.get_path('NAT.shp')).set_index('FIPS')\n", + "\n", + "# Set depedent and independent variables and the W matrix.\n", + "y = data['HR90'].to_numpy()\n", + "x = data[['RD90','PS90','UE90']].to_numpy()\n", + "w = ps.weights.Queen.from_dataframe(data, use_index=True)" + ] + }, + { + "cell_type": "markdown", + "id": "25be6fcf", + "metadata": {}, + "source": [ + "Skater_reg by default uses Euclidean distance to compute the Minimum Spanning Tree (MST). Therefore, we standardize the variables that will be used to compute the MST before calling the main Skater_reg function. Here, we use the X variables to compute the MST. Alternative specifications can be used.\n", + "\n", + "We set the number of clusters to 20 and minimum quorum to 100." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ae2bd006", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 1min 16s, sys: 31.6 s, total: 1min 48s\n", + "Wall time: 25.3 s\n" + ] + } + ], + "source": [ + "%%time\n", + "# Standardize the variables to be used to compute the minimum spanning tree (could add/remove any variable)\n", + "x_std = (x - np.mean(x,axis=0)) / np.std(x,axis=0)\n", + "\n", + "# Call the Skater_reg method based on OLS\n", + "results = Skater_reg().fit(20, w, x_std, {'reg':spreg.OLS,'y':y,'x':x}, quorum=100)" + ] + }, + { + "cell_type": "markdown", + "id": "53218349", + "metadata": {}, + "source": [ + "The intermediate steps are stored in the attibute \\_trace. We can use this information to plot the decrease in the total sum of squared residuals by number of clusters. This information can be helpful to select the number of desired clusters." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4e862e49", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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yEgMGzasQDHxPpMmTcL8+fPxxx9/ICkpCVOnTsW5c+cwfvx4hY+hr6+PKVOmYPLkyfj9999x/fp1JCQkYN26dYW2b9OmDSpXrozvvvsO//33H7Zs2YINGzaI21+9eoVx48YhNjYWt2/fxtGjR3Hq1CmxkLOxsUFmZiYOHjyIR48e4eXLl2jYsCEGDhyIr7/+Gjt27MDNmzdx6tQpzJ8/H3///XeRsd+8eRPTpk3D8ePHcfv2bURGRuLq1atKFY1EFQ2LJiL6YHPmzClwOalx48ZYtWoVVq5ciebNm+PkyZNF3ln2IYKCgjB//nw0b94ccXFx2L17N0xNTQEAlpaWOHr0KGQyGdzc3NC0aVOMHz8eRkZGcuOnFOHn54fAwEAEBgbCzs4OERER2LNnDxo0aKDUcaZPn47AwED8+OOPaNy4Mfr161dgnFY+ExMThIWF4e+//4adnR22bt0qN5WBVCrF48eP8fXXX6Nhw4bw8vJC165dMWvWLABAu3btMHr0aPTr1w81atTAggULALy5zPb1118jMDAQtra26NWrF06cOAFra+si465cuTL+/fdffPXVV2jYsCFGjhyJcePGYdSoUUrlT1SRSIR3/8cjIiIiogLY00RERESkABZNRERERApg0URERESkABZNRERERApg0URERESkABZNRERERApg0URERESkABZNRERERApg0URERESkABZNRERERApg0URERESkgP8HeW7RDjXuVoYAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "trace = [results._trace[i][1][2] for i in range(1,len(results._trace))]\n", + "fig, ax = plt.subplots()\n", + "ax.plot(list(range(2,len(trace)+2)), trace, '-o', color='black', linewidth=2)\n", + "\n", + "ax.set(xlabel='Number of clusters', ylabel='Total sum of squared residuals')\n", + "ax.grid()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "a3c6cf08", + "metadata": {}, + "source": [ + "Let's say we choose 12 clusters. We can plot the results using geopandas and matplotlib." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "ff616fb3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(-127.6195011138916, -64.0817699432373, 23.735178565979005, 50.59252300262451)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "data[\"cl_regions\"] = results._trace[11][0]\n", + "data.plot(column=\"cl_regions\", categorical=True, legend=True, cmap='Paired').axis(\"off\")" + ] + }, + { + "cell_type": "markdown", + "id": "9bef8f61", + "metadata": {}, + "source": [ + "With the cluster allocations and selected number of clusters, we can call the Regimes methods in Spreg to get the full regression results and Chow tests on the stability of the coefficients accross the 12 different clusters." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b13e7942", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "REGRESSION\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 0\n", + "---------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 0_['HR90'] Number of Observations: 604\n", + "Mean dependent var : 2.4577 Number of Variables : 4\n", + "S.D. dependent var : 3.9266 Degrees of Freedom : 600\n", + "R-squared : 0.3305\n", + "Adjusted R-squared : 0.3271\n", + "Sum squared residual: 6224.952 F-statistic : 98.7116\n", + "Sigma-square : 10.375 Prob(F-statistic) : 6.109e-52\n", + "S.E. of regression : 3.221 Log likelihood : -1561.528\n", + "Sigma-square ML : 10.306 Akaike info criterion : 3131.057\n", + "S.E of regression ML: 3.2103 Schwarz criterion : 3148.671\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 0_CONSTANT 4.0851876 0.4756999 8.5877407 0.0000000\n", + " 0_RD90 3.1288181 0.2856649 10.9527571 0.0000000\n", + " 0_PS90 1.4553321 0.1760078 8.2685645 0.0000000\n", + " 0_UE90 0.0530250 0.0612926 0.8651115 0.3873233\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 7.255\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 20184.603 0.0000\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 69.424 0.0000\n", + "Koenker-Bassett test 3 4.695 0.1956\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 1\n", + "---------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 1_['HR90'] Number of Observations: 180\n", + "Mean dependent var : 2.6269 Number of Variables : 4\n", + "S.D. dependent var : 4.5592 Degrees of Freedom : 176\n", + "R-squared : 0.1473\n", + "Adjusted R-squared : 0.1328\n", + "Sum squared residual: 3172.661 F-statistic : 10.1339\n", + "Sigma-square : 18.026 Prob(F-statistic) : 3.424e-06\n", + "S.E. of regression : 4.246 Log likelihood : -513.652\n", + "Sigma-square ML : 17.626 Akaike info criterion : 1035.304\n", + "S.E of regression ML: 4.1983 Schwarz criterion : 1048.076\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 1_CONSTANT 1.6802968 1.0041720 1.6733157 0.0960416\n", + " 1_RD90 0.9214816 0.7386502 1.2475210 0.2138639\n", + " 1_PS90 0.5520464 0.3817853 1.4459601 0.1499668\n", + " 1_UE90 0.3793060 0.1012117 3.7476508 0.0002418\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 6.525\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 4249.029 0.0000\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 6.927 0.0743\n", + "Koenker-Bassett test 3 0.565 0.9044\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 2\n", + "---------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 2_['HR90'] Number of Observations: 105\n", + "Mean dependent var : 5.4586 Number of Variables : 4\n", + "S.D. dependent var : 3.9328 Degrees of Freedom : 101\n", + "R-squared : 0.6004\n", + "Adjusted R-squared : 0.5885\n", + "Sum squared residual: 642.756 F-statistic : 50.5868\n", + "Sigma-square : 6.364 Prob(F-statistic) : 4.794e-20\n", + "S.E. of regression : 2.523 Log likelihood : -244.108\n", + "Sigma-square ML : 6.121 Akaike info criterion : 496.217\n", + "S.E of regression ML: 2.4742 Schwarz criterion : 506.832\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 2_CONSTANT 2.9279569 1.6500241 1.7744934 0.0789946\n", + " 2_RD90 3.8978472 0.8119511 4.8005936 0.0000055\n", + " 2_PS90 2.5952604 0.2458875 10.5546660 0.0000000\n", + " 2_UE90 0.3236171 0.1945793 1.6631633 0.0993799\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 15.160\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 6.807 0.0333\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 15.329 0.0016\n", + "Koenker-Bassett test 3 14.809 0.0020\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 3\n", + "---------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 3_['HR90'] Number of Observations: 157\n", + "Mean dependent var : 3.2521 Number of Variables : 4\n", + "S.D. dependent var : 3.4925 Degrees of Freedom : 153\n", + "R-squared : 0.3735\n", + "Adjusted R-squared : 0.3612\n", + "Sum squared residual: 1192.118 F-statistic : 30.4049\n", + "Sigma-square : 7.792 Prob(F-statistic) : 1.785e-15\n", + "S.E. of regression : 2.791 Log likelihood : -381.912\n", + "Sigma-square ML : 7.593 Akaike info criterion : 771.824\n", + "S.E of regression ML: 2.7556 Schwarz criterion : 784.049\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 3_CONSTANT 1.6648327 1.6499048 1.0090477 0.3145449\n", + " 3_RD90 2.5911850 0.5446873 4.7571975 0.0000045\n", + " 3_PS90 1.7951113 0.2645028 6.7867381 0.0000000\n", + " 3_UE90 0.2831519 0.1896309 1.4931734 0.1374511\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 17.037\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 700.804 0.0000\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 128.095 0.0000\n", + "Koenker-Bassett test 3 23.069 0.0000\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 4\n", + "---------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 4_['HR90'] Number of Observations: 157\n", + "Mean dependent var : 5.2565 Number of Variables : 4\n", + "S.D. dependent var : 7.5670 Degrees of Freedom : 153\n", + "R-squared : 0.0718\n", + "Adjusted R-squared : 0.0536\n", + "Sum squared residual: 8291.273 F-statistic : 3.9445\n", + "Sigma-square : 54.191 Prob(F-statistic) : 0.009592\n", + "S.E. of regression : 7.361 Log likelihood : -534.160\n", + "Sigma-square ML : 52.811 Akaike info criterion : 1076.321\n", + "S.E of regression ML: 7.2671 Schwarz criterion : 1088.546\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 4_CONSTANT 6.5333323 2.4673414 2.6479239 0.0089474\n", + " 4_RD90 2.7602351 1.0586310 2.6073627 0.0100275\n", + " 4_PS90 -0.6252142 0.6065058 -1.0308463 0.3042397\n", + " 4_UE90 -0.0983422 0.2825469 -0.3480561 0.7282764\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 9.215\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 10522.321 0.0000\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 397.444 0.0000\n", + "Koenker-Bassett test 3 19.450 0.0002\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 5\n", + "---------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 5_['HR90'] Number of Observations: 416\n", + "Mean dependent var : 3.5350 Number of Variables : 4\n", + "S.D. dependent var : 3.5289 Degrees of Freedom : 412\n", + "R-squared : 0.2384\n", + "Adjusted R-squared : 0.2328\n", + "Sum squared residual: 3936.025 F-statistic : 42.9870\n", + "Sigma-square : 9.553 Prob(F-statistic) : 3.458e-24\n", + "S.E. of regression : 3.091 Log likelihood : -1057.705\n", + "Sigma-square ML : 9.462 Akaike info criterion : 2123.409\n", + "S.E of regression ML: 3.0760 Schwarz criterion : 2139.532\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 5_CONSTANT 3.6580644 0.7883611 4.6400874 0.0000047\n", + " 5_RD90 2.1705064 0.3732128 5.8157339 0.0000000\n", + " 5_PS90 1.6485127 0.2143249 7.6916535 0.0000000\n", + " 5_UE90 -0.0049898 0.0843801 -0.0591343 0.9528738\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 11.124\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 2163.820 0.0000\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 295.778 0.0000\n", + "Koenker-Bassett test 3 48.598 0.0000\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 6\n", + "---------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 6_['HR90'] Number of Observations: 105\n", + "Mean dependent var : 6.9902 Number of Variables : 4\n", + "S.D. dependent var : 7.7137 Degrees of Freedom : 101\n", + "R-squared : 0.5133\n", + "Adjusted R-squared : 0.4989\n", + "Sum squared residual: 3011.570 F-statistic : 35.5107\n", + "Sigma-square : 29.818 Prob(F-statistic) : 9.373e-16\n", + "S.E. of regression : 5.461 Log likelihood : -325.192\n", + "Sigma-square ML : 28.682 Akaike info criterion : 658.384\n", + "S.E of regression ML: 5.3555 Schwarz criterion : 669.000\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 6_CONSTANT 12.6762323 2.3973782 5.2875396 0.0000007\n", + " 6_RD90 7.2357749 0.8959392 8.0761894 0.0000000\n", + " 6_PS90 3.0087836 0.5687185 5.2904618 0.0000007\n", + " 6_UE90 -0.9087647 0.4285148 -2.1207310 0.0363931\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 10.336\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 1082.543 0.0000\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 69.868 0.0000\n", + "Koenker-Bassett test 3 8.330 0.0397\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 7\n", + "---------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 7_['HR90'] Number of Observations: 212\n", + "Mean dependent var : 6.7045 Number of Variables : 4\n", + "S.D. dependent var : 7.5062 Degrees of Freedom : 208\n", + "R-squared : 0.6513\n", + "Adjusted R-squared : 0.6463\n", + "Sum squared residual: 4145.470 F-statistic : 129.5007\n", + "Sigma-square : 19.930 Prob(F-statistic) : 2.429e-47\n", + "S.E. of regression : 4.464 Log likelihood : -615.973\n", + "Sigma-square ML : 19.554 Akaike info criterion : 1239.945\n", + "S.E of regression ML: 4.4220 Schwarz criterion : 1253.372\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 7_CONSTANT 6.8749278 1.4815715 4.6402943 0.0000062\n", + " 7_RD90 5.0735729 0.4720012 10.7490683 0.0000000\n", + " 7_PS90 4.3257745 0.4290443 10.0823502 0.0000000\n", + " 7_UE90 -0.1901823 0.2136345 -0.8902227 0.3743748\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 10.840\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 23.086 0.0000\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 68.023 0.0000\n", + "Koenker-Bassett test 3 50.360 0.0000\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 8\n", + "---------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 8_['HR90'] Number of Observations: 142\n", + "Mean dependent var : 6.9674 Number of Variables : 4\n", + "S.D. dependent var : 7.7639 Degrees of Freedom : 138\n", + "R-squared : 0.0816\n", + "Adjusted R-squared : 0.0616\n", + "Sum squared residual: 7805.895 F-statistic : 4.0858\n", + "Sigma-square : 56.564 Prob(F-statistic) : 0.008156\n", + "S.E. of regression : 7.521 Log likelihood : -485.973\n", + "Sigma-square ML : 54.971 Akaike info criterion : 979.945\n", + "S.E of regression ML: 7.4142 Schwarz criterion : 991.769\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 8_CONSTANT 8.9134518 2.2205952 4.0139922 0.0000975\n", + " 8_RD90 3.1669956 1.0249618 3.0898670 0.0024224\n", + " 8_PS90 0.9219418 0.7333370 1.2571872 0.2108094\n", + " 8_UE90 -0.2902235 0.3083686 -0.9411576 0.3482687\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 7.818\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 211.413 0.0000\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 16.332 0.0010\n", + "Koenker-Bassett test 3 4.771 0.1893\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 9\n", + "---------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 9_['HR90'] Number of Observations: 494\n", + "Mean dependent var : 9.4357 Number of Variables : 4\n", + "S.D. dependent var : 6.1868 Degrees of Freedom : 490\n", + "R-squared : 0.3161\n", + "Adjusted R-squared : 0.3120\n", + "Sum squared residual: 12904.325 F-statistic : 75.5098\n", + "Sigma-square : 26.335 Prob(F-statistic) : 3.675e-40\n", + "S.E. of regression : 5.132 Log likelihood : -1506.863\n", + "Sigma-square ML : 26.122 Akaike info criterion : 3021.726\n", + "S.E of regression ML: 5.1110 Schwarz criterion : 3038.536\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 9_CONSTANT 10.2257744 0.7060239 14.4836089 0.0000000\n", + " 9_RD90 4.9173048 0.3601681 13.6528046 0.0000000\n", + " 9_PS90 2.7435413 0.3773269 7.2709932 0.0000000\n", + " 9_UE90 -0.5158999 0.1027098 -5.0228862 0.0000007\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 7.112\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 164.804 0.0000\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 93.891 0.0000\n", + "Koenker-Bassett test 3 45.305 0.0000\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 10\n", + "----------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 10_['HR90'] Number of Observations: 322\n", + "Mean dependent var : 10.9368 Number of Variables : 4\n", + "S.D. dependent var : 7.1069 Degrees of Freedom : 318\n", + "R-squared : 0.1980\n", + "Adjusted R-squared : 0.1904\n", + "Sum squared residual: 13003.178 F-statistic : 26.1676\n", + "Sigma-square : 40.890 Prob(F-statistic) : 3.738e-15\n", + "S.E. of regression : 6.395 Log likelihood : -1052.340\n", + "Sigma-square ML : 40.383 Akaike info criterion : 2112.680\n", + "S.E of regression ML: 6.3547 Schwarz criterion : 2127.779\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 10_CONSTANT 8.9613419 1.1548606 7.7596741 0.0000000\n", + " 10_RD90 3.1036861 0.4676112 6.6373221 0.0000000\n", + " 10_PS90 2.0054035 0.4775095 4.1997143 0.0000347\n", + " 10_UE90 -0.1659300 0.1618652 -1.0251118 0.3060896\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 8.728\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 805.242 0.0000\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 271.848 0.0000\n", + "Koenker-Bassett test 3 60.502 0.0000\n", + "----------\n", + "\n", + "SUMMARY OF OUTPUT: ORDINARY LEAST SQUARES ESTIMATION - REGIME 11\n", + "----------------------------------------------------------------\n", + "Data set : unknown\n", + "Weights matrix : unknown\n", + "Dependent Variable : 11_['HR90'] Number of Observations: 191\n", + "Mean dependent var : 12.6163 Number of Variables : 4\n", + "S.D. dependent var : 6.4910 Degrees of Freedom : 187\n", + "R-squared : 0.2010\n", + "Adjusted R-squared : 0.1882\n", + "Sum squared residual: 6396.303 F-statistic : 15.6792\n", + "Sigma-square : 34.205 Prob(F-statistic) : 3.882e-09\n", + "S.E. of regression : 5.848 Log likelihood : -606.337\n", + "Sigma-square ML : 33.488 Akaike info criterion : 1220.674\n", + "S.E of regression ML: 5.7869 Schwarz criterion : 1233.683\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Variable Coefficient Std.Error t-Statistic Probability\n", + "------------------------------------------------------------------------------------\n", + " 11_CONSTANT 10.6523809 1.8667675 5.7063244 0.0000000\n", + " 11_RD90 2.8884391 0.5972275 4.8364133 0.0000028\n", + " 11_PS90 0.2205890 0.5966193 0.3697316 0.7120008\n", + " 11_UE90 -0.0296635 0.3154386 -0.0940388 0.9251790\n", + "------------------------------------------------------------------------------------\n", + "Regimes variable: skater_reg\n", + "\n", + "REGRESSION DIAGNOSTICS\n", + "MULTICOLLINEARITY CONDITION NUMBER 10.444\n", + "\n", + "TEST ON NORMALITY OF ERRORS\n", + "TEST DF VALUE PROB\n", + "Jarque-Bera 2 16.443 0.0003\n", + "\n", + "DIAGNOSTICS FOR HETEROSKEDASTICITY\n", + "RANDOM COEFFICIENTS\n", + "TEST DF VALUE PROB\n", + "Breusch-Pagan test 3 18.499 0.0003\n", + "Koenker-Bassett test 3 11.542 0.0091\n", + "\n", + "REGIMES DIAGNOSTICS - CHOW TEST\n", + " VARIABLE DF VALUE PROB\n", + " CONSTANT 11 110.297 0.0000\n", + " PS90 11 95.473 0.0000\n", + " RD90 11 75.733 0.0000\n", + " UE90 11 52.373 0.0000\n", + " Global test 44 532.110 0.0000\n", + "================================ END OF REPORT =====================================\n" + ] + } + ], + "source": [ + "reg = spreg.OLS_Regimes(y,x,\n", + " regimes=results._trace[11][0], w=w, name_y=['HR90'], name_x=['RD90','PS90','UE90'], name_regimes='skater_reg')\n", + "print(reg.summary)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "887b4d0d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:myenv] *", + "language": "python", + "name": "conda-env-myenv-py" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.15" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/_sources/references.rst.txt b/_sources/references.rst.txt new file mode 100644 index 00000000..2f1b5306 --- /dev/null +++ b/_sources/references.rst.txt @@ -0,0 +1,7 @@ +.. reference for the docs + +References +========== + +.. bibliography:: _static/references.bib + :all: diff --git a/_sources/tutorials.rst.txt b/_sources/tutorials.rst.txt new file mode 100644 index 00000000..b3f6e1b1 --- /dev/null +++ b/_sources/tutorials.rst.txt @@ -0,0 +1,23 @@ +.. tutorials + + +Tutorials +========= + +.. toctree:: + :maxdepth: 1 + :caption: Spatial 2SLS + + notebooks/GM_Lag_example.ipynb + +.. toctree:: + :maxdepth: 1 + :caption: Spatial Panel Models with Fixed Effects + + notebooks/Panel_FE_example.ipynb + +.. toctree:: + :maxdepth: 1 + :caption: Skater_reg: Endogenous Spatial Regimes + + notebooks/skater_reg.ipynb diff --git a/_static/_sphinx_javascript_frameworks_compat.js b/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..8549469d --- /dev/null +++ b/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,134 @@ +/* + * _sphinx_javascript_frameworks_compat.js + * ~~~~~~~~~~ + * + * Compatability shim for jQuery and underscores.js. + * + * WILL BE REMOVED IN Sphinx 6.0 + * xref RemovedInSphinx60Warning + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_static/basic.css b/_static/basic.css index 01192852..4e9a9f1f 100644 --- a/_static/basic.css +++ b/_static/basic.css @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- basic theme. * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -15,6 +15,12 @@ div.clearer { clear: both; } +div.section::after { + display: block; + content: ''; + clear: left; +} + /* -- relbar ---------------------------------------------------------------- */ div.related { @@ -124,7 +130,7 @@ ul.search li a { font-weight: bold; } -ul.search li div.context { +ul.search li p.context { color: #888; margin: 2px 0 0 30px; text-align: left; @@ -216,7 +222,7 @@ table.modindextable td { /* -- general body styles --------------------------------------------------- */ div.body { - min-width: 450px; + min-width: 360px; max-width: 800px; } @@ -231,16 +237,6 @@ a.headerlink { visibility: hidden; } -a.brackets:before, -span.brackets > a:before{ - content: "["; -} - -a.brackets:after, -span.brackets > a:after { - content: "]"; -} - h1:hover > a.headerlink, h2:hover > a.headerlink, h3:hover > a.headerlink, @@ -271,25 +267,25 @@ p.rubric { font-weight: bold; } -img.align-left, .figure.align-left, object.align-left { +img.align-left, figure.align-left, .figure.align-left, object.align-left { clear: left; float: left; margin-right: 1em; } -img.align-right, .figure.align-right, object.align-right { +img.align-right, figure.align-right, .figure.align-right, object.align-right { clear: right; float: right; margin-left: 1em; } -img.align-center, .figure.align-center, object.align-center { +img.align-center, figure.align-center, .figure.align-center, object.align-center { display: block; margin-left: auto; margin-right: auto; } -img.align-default, .figure.align-default { +img.align-default, figure.align-default, .figure.align-default { display: block; margin-left: auto; margin-right: auto; @@ -313,24 +309,33 @@ img.align-default, .figure.align-default { /* -- sidebars -------------------------------------------------------------- */ -div.sidebar { +div.sidebar, +aside.sidebar { margin: 0 0 0.5em 1em; border: 1px solid #ddb; - padding: 7px 7px 0 7px; + padding: 7px; background-color: #ffe; width: 40%; float: right; + clear: right; + overflow-x: auto; } p.sidebar-title { font-weight: bold; } +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} /* -- topics ---------------------------------------------------------------- */ - +nav.contents, +aside.topic, div.topic { border: 1px solid #ccc; - padding: 7px 7px 0 7px; + padding: 7px; margin: 10px 0 10px 0; } @@ -352,10 +357,6 @@ div.admonition dt { font-weight: bold; } -div.admonition dl { - margin-bottom: 0; -} - p.admonition-title { margin: 0px 10px 5px 0px; font-weight: bold; @@ -366,9 +367,34 @@ div.body p.centered { margin-top: 25px; } +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + /* -- tables ---------------------------------------------------------------- */ table.docutils { + margin-top: 10px; + margin-bottom: 10px; border: 0; border-collapse: collapse; } @@ -398,10 +424,6 @@ table.docutils td, table.docutils th { border-bottom: 1px solid #aaa; } -table.footnote td, table.footnote th { - border: 0 !important; -} - th { text-align: left; padding-right: 5px; @@ -416,32 +438,34 @@ table.citation td { border-bottom: none; } -th > p:first-child, -td > p:first-child { +th > :first-child, +td > :first-child { margin-top: 0px; } -th > p:last-child, -td > p:last-child { +th > :last-child, +td > :last-child { margin-bottom: 0px; } /* -- figures --------------------------------------------------------------- */ -div.figure { +div.figure, figure { margin: 0.5em; padding: 0.5em; } -div.figure p.caption { +div.figure p.caption, figcaption { padding: 0.3em; } -div.figure p.caption span.caption-number { +div.figure p.caption span.caption-number, +figcaption span.caption-number { font-style: italic; } -div.figure p.caption span.caption-text { +div.figure p.caption span.caption-text, +figcaption span.caption-text { } /* -- field list styles ----------------------------------------------------- */ @@ -468,10 +492,71 @@ table.field-list td, table.field-list th { /* -- hlist styles ---------------------------------------------------------- */ +table.hlist { + margin: 1em 0; +} + table.hlist td { vertical-align: top; } +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + /* -- other body styles ----------------------------------------------------- */ @@ -495,26 +580,52 @@ ol.upperroman { list-style: upper-roman; } -li > p:first-child { +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { margin-top: 0px; } -li > p:last-child { +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { margin-bottom: 0px; } -dl.footnote > dt, -dl.citation > dt { - float: left; +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; } -dl.footnote > dd, -dl.citation > dd { - margin-bottom: 0em; +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; } -dl.footnote > dd:after, -dl.citation > dd:after { +ol.simple p, +ul.simple p { + margin-bottom: 0; +} +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { content: ""; clear: both; } @@ -531,10 +642,6 @@ dl.field-list > dt { padding-right: 5px; } -dl.field-list > dt:after { - content: ":"; -} - dl.field-list > dd { padding-left: 0.5em; margin-top: 0em; @@ -546,7 +653,7 @@ dl { margin-bottom: 15px; } -dd > p:first-child { +dd > :first-child { margin-top: 0px; } @@ -560,6 +667,11 @@ dd { margin-left: 30px; } +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + dt:target, span.highlighted { background-color: #fbe54e; } @@ -573,14 +685,6 @@ dl.glossary dt { font-size: 1.1em; } -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - .versionmodified { font-style: italic; } @@ -621,8 +725,9 @@ dl.glossary dt { .classifier:before { font-style: normal; - margin: 0.5em; + margin: 0 0.5em; content: ":"; + display: inline-block; } abbr, acronym { @@ -637,29 +742,69 @@ pre { overflow-y: hidden; /* fixes display issues on Chrome browsers */ } +pre, div[class*="highlight-"] { + clear: both; +} + span.pre { -moz-hyphens: none; -ms-hyphens: none; -webkit-hyphens: none; hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; } td.linenos pre { - padding: 5px 0px; border: 0; background-color: transparent; color: #aaa; } table.highlighttable { - margin-left: 0.5em; + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; } table.highlighttable td { - padding: 0 0.5em 0 0.5em; + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; } div.code-block-caption { + margin-top: 1em; padding: 2px 5px; font-size: small; } @@ -668,12 +813,14 @@ div.code-block-caption code { background-color: transparent; } -div.code-block-caption + div > div.highlight > pre { - margin-top: 0; -} - -div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ } div.code-block-caption span.caption-number { @@ -685,21 +832,7 @@ div.code-block-caption span.caption-text { } div.literal-block-wrapper { - padding: 1em 1em 0; -} - -div.literal-block-wrapper div.highlight { - margin: 0; -} - -code.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -code.descclassname { - background-color: transparent; + margin: 1em 0; } code.xref, a code { @@ -740,8 +873,7 @@ span.eqno { } span.eqno a.headerlink { - position: relative; - left: 0px; + position: absolute; z-index: 1; } diff --git a/_static/bootstrap-2.3.2/css/bootstrap-responsive.css b/_static/bootstrap-2.3.2/css/bootstrap-responsive.css new file mode 100644 index 00000000..09e88ce3 --- /dev/null +++ b/_static/bootstrap-2.3.2/css/bootstrap-responsive.css @@ -0,0 +1,1109 @@ +/*! + * Bootstrap Responsive v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +@-ms-viewport { + width: device-width; +} + +.hidden { + display: none; + visibility: hidden; +} + +.visible-phone { + display: none !important; +} + +.visible-tablet { + display: none !important; +} + +.hidden-desktop { + display: none !important; +} + +.visible-desktop { + display: inherit !important; +} + +@media (min-width: 768px) and (max-width: 979px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important ; + } + .visible-tablet { + display: inherit !important; + } + .hidden-tablet { + display: none !important; + } +} + +@media (max-width: 767px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important; + } + .visible-phone { + display: inherit !important; + } + .hidden-phone { + display: none !important; + } +} + +.visible-print { + display: none !important; +} + +@media print { + .visible-print { + display: inherit !important; + } + .hidden-print { + display: none !important; + } +} + +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + line-height: 0; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 30px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 1170px; + } + .span12 { + width: 1170px; + } + .span11 { + width: 1070px; + } + .span10 { + width: 970px; + } + .span9 { + width: 870px; + } + .span8 { + width: 770px; + } + .span7 { + width: 670px; + } + .span6 { + width: 570px; + } + .span5 { + width: 470px; + } + .span4 { + width: 370px; + } + .span3 { + width: 270px; + } + .span2 { + width: 170px; + } + .span1 { + width: 70px; + } + .offset12 { + margin-left: 1230px; + } + .offset11 { + margin-left: 1130px; + } + .offset10 { + margin-left: 1030px; + } + .offset9 { + margin-left: 930px; + } + .offset8 { + margin-left: 830px; + } + .offset7 { + margin-left: 730px; + } + .offset6 { + margin-left: 630px; + } + .offset5 { + margin-left: 530px; + } + .offset4 { + margin-left: 430px; + } + .offset3 { + margin-left: 330px; + } + .offset2 { + margin-left: 230px; + } + .offset1 { + margin-left: 130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + line-height: 0; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.564102564102564%; + *margin-left: 2.5109110747408616%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.564102564102564%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.45299145299145%; + *width: 91.39979996362975%; + } + .row-fluid .span10 { + width: 82.90598290598291%; + *width: 82.8527914166212%; + } + .row-fluid .span9 { + width: 74.35897435897436%; + *width: 74.30578286961266%; + } + .row-fluid .span8 { + width: 65.81196581196582%; + *width: 65.75877432260411%; + } + .row-fluid .span7 { + width: 57.26495726495726%; + *width: 57.21176577559556%; + } + .row-fluid .span6 { + width: 48.717948717948715%; + *width: 48.664757228587014%; + } + .row-fluid .span5 { + width: 40.17094017094017%; + *width: 40.11774868157847%; + } + .row-fluid .span4 { + width: 31.623931623931625%; + *width: 31.570740134569924%; + } + .row-fluid .span3 { + width: 23.076923076923077%; + *width: 23.023731587561375%; + } + .row-fluid .span2 { + width: 14.52991452991453%; + *width: 14.476723040552828%; + } + .row-fluid .span1 { + width: 5.982905982905983%; + *width: 5.929714493544281%; + } + .row-fluid .offset12 { + margin-left: 105.12820512820512%; + *margin-left: 105.02182214948171%; + } + .row-fluid .offset12:first-child { + margin-left: 102.56410256410257%; + *margin-left: 102.45771958537915%; + } + .row-fluid .offset11 { + margin-left: 96.58119658119658%; + *margin-left: 96.47481360247316%; + } + .row-fluid .offset11:first-child { + margin-left: 94.01709401709402%; + *margin-left: 93.91071103837061%; + } + .row-fluid .offset10 { + margin-left: 88.03418803418803%; + *margin-left: 87.92780505546462%; + } + .row-fluid .offset10:first-child { + margin-left: 85.47008547008548%; + *margin-left: 85.36370249136206%; + } + .row-fluid .offset9 { + margin-left: 79.48717948717949%; + *margin-left: 79.38079650845607%; + } + .row-fluid .offset9:first-child { + margin-left: 76.92307692307693%; + *margin-left: 76.81669394435352%; + } + .row-fluid .offset8 { + margin-left: 70.94017094017094%; + *margin-left: 70.83378796144753%; + } + .row-fluid .offset8:first-child { + margin-left: 68.37606837606839%; + *margin-left: 68.26968539734497%; + } + .row-fluid .offset7 { + margin-left: 62.393162393162385%; + *margin-left: 62.28677941443899%; + } + .row-fluid .offset7:first-child { + margin-left: 59.82905982905982%; + *margin-left: 59.72267685033642%; + } + .row-fluid .offset6 { + margin-left: 53.84615384615384%; + *margin-left: 53.739770867430444%; + } + .row-fluid .offset6:first-child { + margin-left: 51.28205128205128%; + *margin-left: 51.175668303327875%; + } + .row-fluid .offset5 { + margin-left: 45.299145299145295%; + *margin-left: 45.1927623204219%; + } + .row-fluid .offset5:first-child { + margin-left: 42.73504273504273%; + *margin-left: 42.62865975631933%; + } + .row-fluid .offset4 { + margin-left: 36.75213675213675%; + *margin-left: 36.645753773413354%; + } + .row-fluid .offset4:first-child { + margin-left: 34.18803418803419%; + *margin-left: 34.081651209310785%; + } + .row-fluid .offset3 { + margin-left: 28.205128205128204%; + *margin-left: 28.0987452264048%; + } + .row-fluid .offset3:first-child { + margin-left: 25.641025641025642%; + *margin-left: 25.53464266230224%; + } + .row-fluid .offset2 { + margin-left: 19.65811965811966%; + *margin-left: 19.551736679396257%; + } + .row-fluid .offset2:first-child { + margin-left: 17.094017094017094%; + *margin-left: 16.98763411529369%; + } + .row-fluid .offset1 { + margin-left: 11.11111111111111%; + *margin-left: 11.004728132387708%; + } + .row-fluid .offset1:first-child { + margin-left: 8.547008547008547%; + *margin-left: 8.440625568285142%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 30px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 1156px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 1056px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 956px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 856px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 756px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 656px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 556px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 456px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 356px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 256px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 156px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 56px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } + .row-fluid .thumbnails { + margin-left: 0; + } +} + +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + line-height: 0; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 724px; + } + .span12 { + width: 724px; + } + .span11 { + width: 662px; + } + .span10 { + width: 600px; + } + .span9 { + width: 538px; + } + .span8 { + width: 476px; + } + .span7 { + width: 414px; + } + .span6 { + width: 352px; + } + .span5 { + width: 290px; + } + .span4 { + width: 228px; + } + .span3 { + width: 166px; + } + .span2 { + width: 104px; + } + .span1 { + width: 42px; + } + .offset12 { + margin-left: 764px; + } + .offset11 { + margin-left: 702px; + } + .offset10 { + margin-left: 640px; + } + .offset9 { + margin-left: 578px; + } + .offset8 { + margin-left: 516px; + } + .offset7 { + margin-left: 454px; + } + .offset6 { + margin-left: 392px; + } + .offset5 { + margin-left: 330px; + } + .offset4 { + margin-left: 268px; + } + .offset3 { + margin-left: 206px; + } + .offset2 { + margin-left: 144px; + } + .offset1 { + margin-left: 82px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + line-height: 0; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.7624309392265194%; + *margin-left: 2.709239449864817%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.7624309392265194%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.43646408839778%; + *width: 91.38327259903608%; + } + .row-fluid .span10 { + width: 82.87292817679558%; + *width: 82.81973668743387%; + } + .row-fluid .span9 { + width: 74.30939226519337%; + *width: 74.25620077583166%; + } + .row-fluid .span8 { + width: 65.74585635359117%; + *width: 65.69266486422946%; + } + .row-fluid .span7 { + width: 57.18232044198895%; + *width: 57.12912895262725%; + } + .row-fluid .span6 { + width: 48.61878453038674%; + *width: 48.56559304102504%; + } + .row-fluid .span5 { + width: 40.05524861878453%; + *width: 40.00205712942283%; + } + .row-fluid .span4 { + width: 31.491712707182323%; + *width: 31.43852121782062%; + } + .row-fluid .span3 { + width: 22.92817679558011%; + *width: 22.87498530621841%; + } + .row-fluid .span2 { + width: 14.3646408839779%; + *width: 14.311449394616199%; + } + .row-fluid .span1 { + width: 5.801104972375691%; + *width: 5.747913483013988%; + } + .row-fluid .offset12 { + margin-left: 105.52486187845304%; + *margin-left: 105.41847889972962%; + } + .row-fluid .offset12:first-child { + margin-left: 102.76243093922652%; + *margin-left: 102.6560479605031%; + } + .row-fluid .offset11 { + margin-left: 96.96132596685082%; + *margin-left: 96.8549429881274%; + } + .row-fluid .offset11:first-child { + margin-left: 94.1988950276243%; + *margin-left: 94.09251204890089%; + } + .row-fluid .offset10 { + margin-left: 88.39779005524862%; + *margin-left: 88.2914070765252%; + } + .row-fluid .offset10:first-child { + margin-left: 85.6353591160221%; + *margin-left: 85.52897613729868%; + } + .row-fluid .offset9 { + margin-left: 79.8342541436464%; + *margin-left: 79.72787116492299%; + } + .row-fluid .offset9:first-child { + margin-left: 77.07182320441989%; + *margin-left: 76.96544022569647%; + } + .row-fluid .offset8 { + margin-left: 71.2707182320442%; + *margin-left: 71.16433525332079%; + } + .row-fluid .offset8:first-child { + margin-left: 68.50828729281768%; + *margin-left: 68.40190431409427%; + } + .row-fluid .offset7 { + margin-left: 62.70718232044199%; + *margin-left: 62.600799341718584%; + } + .row-fluid .offset7:first-child { + margin-left: 59.94475138121547%; + *margin-left: 59.838368402492065%; + } + .row-fluid .offset6 { + margin-left: 54.14364640883978%; + *margin-left: 54.037263430116376%; + } + .row-fluid .offset6:first-child { + margin-left: 51.38121546961326%; + *margin-left: 51.27483249088986%; + } + .row-fluid .offset5 { + margin-left: 45.58011049723757%; + *margin-left: 45.47372751851417%; + } + .row-fluid .offset5:first-child { + margin-left: 42.81767955801105%; + *margin-left: 42.71129657928765%; + } + .row-fluid .offset4 { + margin-left: 37.01657458563536%; + *margin-left: 36.91019160691196%; + } + .row-fluid .offset4:first-child { + margin-left: 34.25414364640884%; + *margin-left: 34.14776066768544%; + } + .row-fluid .offset3 { + margin-left: 28.45303867403315%; + *margin-left: 28.346655695309746%; + } + .row-fluid .offset3:first-child { + margin-left: 25.69060773480663%; + *margin-left: 25.584224756083227%; + } + .row-fluid .offset2 { + margin-left: 19.88950276243094%; + *margin-left: 19.783119783707537%; + } + .row-fluid .offset2:first-child { + margin-left: 17.12707182320442%; + *margin-left: 17.02068884448102%; + } + .row-fluid .offset1 { + margin-left: 11.32596685082873%; + *margin-left: 11.219583872105325%; + } + .row-fluid .offset1:first-child { + margin-left: 8.56353591160221%; + *margin-left: 8.457152932878806%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 710px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 648px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 586px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 524px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 462px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 400px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 338px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 276px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 214px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 152px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 90px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 28px; + } +} + +@media (max-width: 767px) { + body { + padding-right: 20px; + padding-left: 20px; + } + .navbar-fixed-top, + .navbar-fixed-bottom, + .navbar-static-top { + margin-right: -20px; + margin-left: -20px; + } + .container-fluid { + padding: 0; + } + .dl-horizontal dt { + float: none; + width: auto; + clear: none; + text-align: left; + } + .dl-horizontal dd { + margin-left: 0; + } + .container { + width: auto; + } + .row-fluid { + width: 100%; + } + .row, + .thumbnails { + margin-left: 0; + } + .thumbnails > li { + float: none; + margin-left: 0; + } + [class*="span"], + .uneditable-input[class*="span"], + .row-fluid [class*="span"] { + display: block; + float: none; + width: 100%; + margin-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .span12, + .row-fluid .span12 { + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="offset"]:first-child { + margin-left: 0; + } + .input-large, + .input-xlarge, + .input-xxlarge, + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .input-prepend input, + .input-append input, + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + display: inline-block; + width: auto; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 0; + } + .modal { + position: fixed; + top: 20px; + right: 20px; + left: 20px; + width: auto; + margin: 0; + } + .modal.fade { + top: -100px; + } + .modal.fade.in { + top: 20px; + } +} + +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 20px; + } + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-right: 10px; + padding-left: 10px; + } + .media .pull-left, + .media .pull-right { + display: block; + float: none; + margin-bottom: 10px; + } + .media-object { + margin-right: 0; + margin-left: 0; + } + .modal { + top: 10px; + right: 10px; + left: 10px; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} + +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top, + .navbar-fixed-bottom { + position: static; + } + .navbar-fixed-top { + margin-bottom: 20px; + } + .navbar-fixed-bottom { + margin-top: 20px; + } + .navbar-fixed-top .navbar-inner, + .navbar-fixed-bottom .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-right: 10px; + padding-left: 10px; + margin: 0 0 0 -5px; + } + .nav-collapse { + clear: both; + } + .nav-collapse .nav { + float: none; + margin: 0 0 10px; + } + .nav-collapse .nav > li { + float: none; + } + .nav-collapse .nav > li > a { + margin-bottom: 2px; + } + .nav-collapse .nav > .divider-vertical { + display: none; + } + .nav-collapse .nav .nav-header { + color: #777777; + text-shadow: none; + } + .nav-collapse .nav > li > a, + .nav-collapse .dropdown-menu a { + padding: 9px 15px; + font-weight: bold; + color: #777777; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .nav-collapse .btn { + padding: 4px 10px 4px; + font-weight: normal; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + } + .nav-collapse .dropdown-menu li + li a { + margin-bottom: 2px; + } + .nav-collapse .nav > li > a:hover, + .nav-collapse .nav > li > a:focus, + .nav-collapse .dropdown-menu a:hover, + .nav-collapse .dropdown-menu a:focus { + background-color: #f2f2f2; + } + .navbar-inverse .nav-collapse .nav > li > a, + .navbar-inverse .nav-collapse .dropdown-menu a { + color: #999999; + } + .navbar-inverse .nav-collapse .nav > li > a:hover, + .navbar-inverse .nav-collapse .nav > li > a:focus, + .navbar-inverse .nav-collapse .dropdown-menu a:hover, + .navbar-inverse .nav-collapse .dropdown-menu a:focus { + background-color: #111111; + } + .nav-collapse.in .btn-group { + padding: 0; + margin-top: 5px; + } + .nav-collapse .dropdown-menu { + position: static; + top: auto; + left: auto; + display: none; + float: none; + max-width: none; + padding: 0; + margin: 0 15px; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .nav-collapse .open > .dropdown-menu { + display: block; + } + .nav-collapse .dropdown-menu:before, + .nav-collapse .dropdown-menu:after { + display: none; + } + .nav-collapse .dropdown-menu .divider { + display: none; + } + .nav-collapse .nav > li > .dropdown-menu:before, + .nav-collapse .nav > li > .dropdown-menu:after { + display: none; + } + .nav-collapse .navbar-form, + .nav-collapse .navbar-search { + float: none; + padding: 10px 15px; + margin: 10px 0; + border-top: 1px solid #f2f2f2; + border-bottom: 1px solid #f2f2f2; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar-inverse .nav-collapse .navbar-form, + .navbar-inverse .nav-collapse .navbar-search { + border-top-color: #111111; + border-bottom-color: #111111; + } + .navbar .nav-collapse .nav.pull-right { + float: none; + margin-left: 0; + } + .nav-collapse, + .nav-collapse.collapse { + height: 0; + overflow: hidden; + } + .navbar .btn-navbar { + display: block; + } + .navbar-static .navbar-inner { + padding-right: 10px; + padding-left: 10px; + } +} + +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + } +} diff --git a/_static/bootstrap-2.3.2/css/bootstrap-responsive.min.css b/_static/bootstrap-2.3.2/css/bootstrap-responsive.min.css new file mode 100644 index 00000000..f4ede63f --- /dev/null +++ b/_static/bootstrap-2.3.2/css/bootstrap-responsive.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap Responsive v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} diff --git a/_static/bootstrap-2.3.2/css/bootstrap.css b/_static/bootstrap-2.3.2/css/bootstrap.css new file mode 100644 index 00000000..b725064a --- /dev/null +++ b/_static/bootstrap-2.3.2/css/bootstrap.css @@ -0,0 +1,6167 @@ +/*! + * Bootstrap v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +audio:not([controls]) { + display: none; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +a:hover, +a:active { + outline: 0; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + width: auto\9; + height: auto; + max-width: 100%; + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +#map_canvas img, +.google-maps img { + max-width: none; +} + +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} + +button, +input { + *overflow: visible; + line-height: normal; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +label, +select, +button, +input[type="button"], +input[type="reset"], +input[type="submit"], +input[type="radio"], +input[type="checkbox"] { + cursor: pointer; +} + +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 0.5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } +} + +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 20px; + color: #333333; + background-color: #ffffff; +} + +a { + color: #0088cc; + text-decoration: none; +} + +a:hover, +a:focus { + color: #005580; + text-decoration: underline; +} + +.img-rounded { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.img-polaroid { + padding: 4px; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.img-circle { + -webkit-border-radius: 500px; + -moz-border-radius: 500px; + border-radius: 500px; +} + +.row { + margin-left: -20px; + *zoom: 1; +} + +.row:before, +.row:after { + display: table; + line-height: 0; + content: ""; +} + +.row:after { + clear: both; +} + +[class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; +} + +.container, +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.span12 { + width: 940px; +} + +.span11 { + width: 860px; +} + +.span10 { + width: 780px; +} + +.span9 { + width: 700px; +} + +.span8 { + width: 620px; +} + +.span7 { + width: 540px; +} + +.span6 { + width: 460px; +} + +.span5 { + width: 380px; +} + +.span4 { + width: 300px; +} + +.span3 { + width: 220px; +} + +.span2 { + width: 140px; +} + +.span1 { + width: 60px; +} + +.offset12 { + margin-left: 980px; +} + +.offset11 { + margin-left: 900px; +} + +.offset10 { + margin-left: 820px; +} + +.offset9 { + margin-left: 740px; +} + +.offset8 { + margin-left: 660px; +} + +.offset7 { + margin-left: 580px; +} + +.offset6 { + margin-left: 500px; +} + +.offset5 { + margin-left: 420px; +} + +.offset4 { + margin-left: 340px; +} + +.offset3 { + margin-left: 260px; +} + +.offset2 { + margin-left: 180px; +} + +.offset1 { + margin-left: 100px; +} + +.row-fluid { + width: 100%; + *zoom: 1; +} + +.row-fluid:before, +.row-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.row-fluid:after { + clear: both; +} + +.row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.127659574468085%; + *margin-left: 2.074468085106383%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} + +.row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.127659574468085%; +} + +.row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; +} + +.row-fluid .span11 { + width: 91.48936170212765%; + *width: 91.43617021276594%; +} + +.row-fluid .span10 { + width: 82.97872340425532%; + *width: 82.92553191489361%; +} + +.row-fluid .span9 { + width: 74.46808510638297%; + *width: 74.41489361702126%; +} + +.row-fluid .span8 { + width: 65.95744680851064%; + *width: 65.90425531914893%; +} + +.row-fluid .span7 { + width: 57.44680851063829%; + *width: 57.39361702127659%; +} + +.row-fluid .span6 { + width: 48.93617021276595%; + *width: 48.88297872340425%; +} + +.row-fluid .span5 { + width: 40.42553191489362%; + *width: 40.37234042553192%; +} + +.row-fluid .span4 { + width: 31.914893617021278%; + *width: 31.861702127659576%; +} + +.row-fluid .span3 { + width: 23.404255319148934%; + *width: 23.351063829787233%; +} + +.row-fluid .span2 { + width: 14.893617021276595%; + *width: 14.840425531914894%; +} + +.row-fluid .span1 { + width: 6.382978723404255%; + *width: 6.329787234042553%; +} + +.row-fluid .offset12 { + margin-left: 104.25531914893617%; + *margin-left: 104.14893617021275%; +} + +.row-fluid .offset12:first-child { + margin-left: 102.12765957446808%; + *margin-left: 102.02127659574467%; +} + +.row-fluid .offset11 { + margin-left: 95.74468085106382%; + *margin-left: 95.6382978723404%; +} + +.row-fluid .offset11:first-child { + margin-left: 93.61702127659574%; + *margin-left: 93.51063829787232%; +} + +.row-fluid .offset10 { + margin-left: 87.23404255319149%; + *margin-left: 87.12765957446807%; +} + +.row-fluid .offset10:first-child { + margin-left: 85.1063829787234%; + *margin-left: 84.99999999999999%; +} + +.row-fluid .offset9 { + margin-left: 78.72340425531914%; + *margin-left: 78.61702127659572%; +} + +.row-fluid .offset9:first-child { + margin-left: 76.59574468085106%; + *margin-left: 76.48936170212764%; +} + +.row-fluid .offset8 { + margin-left: 70.2127659574468%; + *margin-left: 70.10638297872339%; +} + +.row-fluid .offset8:first-child { + margin-left: 68.08510638297872%; + *margin-left: 67.9787234042553%; +} + +.row-fluid .offset7 { + margin-left: 61.70212765957446%; + *margin-left: 61.59574468085106%; +} + +.row-fluid .offset7:first-child { + margin-left: 59.574468085106375%; + *margin-left: 59.46808510638297%; +} + +.row-fluid .offset6 { + margin-left: 53.191489361702125%; + *margin-left: 53.085106382978715%; +} + +.row-fluid .offset6:first-child { + margin-left: 51.063829787234035%; + *margin-left: 50.95744680851063%; +} + +.row-fluid .offset5 { + margin-left: 44.68085106382979%; + *margin-left: 44.57446808510638%; +} + +.row-fluid .offset5:first-child { + margin-left: 42.5531914893617%; + *margin-left: 42.4468085106383%; +} + +.row-fluid .offset4 { + margin-left: 36.170212765957444%; + *margin-left: 36.06382978723405%; +} + +.row-fluid .offset4:first-child { + margin-left: 34.04255319148936%; + *margin-left: 33.93617021276596%; +} + +.row-fluid .offset3 { + margin-left: 27.659574468085104%; + *margin-left: 27.5531914893617%; +} + +.row-fluid .offset3:first-child { + margin-left: 25.53191489361702%; + *margin-left: 25.425531914893618%; +} + +.row-fluid .offset2 { + margin-left: 19.148936170212764%; + *margin-left: 19.04255319148936%; +} + +.row-fluid .offset2:first-child { + margin-left: 17.02127659574468%; + *margin-left: 16.914893617021278%; +} + +.row-fluid .offset1 { + margin-left: 10.638297872340425%; + *margin-left: 10.53191489361702%; +} + +.row-fluid .offset1:first-child { + margin-left: 8.51063829787234%; + *margin-left: 8.404255319148938%; +} + +[class*="span"].hide, +.row-fluid [class*="span"].hide { + display: none; +} + +[class*="span"].pull-right, +.row-fluid [class*="span"].pull-right { + float: right; +} + +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} + +.container:before, +.container:after { + display: table; + line-height: 0; + content: ""; +} + +.container:after { + clear: both; +} + +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} + +.container-fluid:before, +.container-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.container-fluid:after { + clear: both; +} + +p { + margin: 0 0 10px; +} + +.lead { + margin-bottom: 20px; + font-size: 21px; + font-weight: 200; + line-height: 30px; +} + +small { + font-size: 85%; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +cite { + font-style: normal; +} + +.muted { + color: #999999; +} + +a.muted:hover, +a.muted:focus { + color: #808080; +} + +.text-warning { + color: #c09853; +} + +a.text-warning:hover, +a.text-warning:focus { + color: #a47e3c; +} + +.text-error { + color: #b94a48; +} + +a.text-error:hover, +a.text-error:focus { + color: #953b39; +} + +.text-info { + color: #3a87ad; +} + +a.text-info:hover, +a.text-info:focus { + color: #2d6987; +} + +.text-success { + color: #468847; +} + +a.text-success:hover, +a.text-success:focus { + color: #356635; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-center { + text-align: center; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 10px 0; + font-family: inherit; + font-weight: bold; + line-height: 20px; + color: inherit; + text-rendering: optimizelegibility; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + line-height: 1; + color: #999999; +} + +h1, +h2, +h3 { + line-height: 40px; +} + +h1 { + font-size: 38.5px; +} + +h2 { + font-size: 31.5px; +} + +h3 { + font-size: 24.5px; +} + +h4 { + font-size: 17.5px; +} + +h5 { + font-size: 14px; +} + +h6 { + font-size: 11.9px; +} + +h1 small { + font-size: 24.5px; +} + +h2 small { + font-size: 17.5px; +} + +h3 small { + font-size: 14px; +} + +h4 small { + font-size: 14px; +} + +.page-header { + padding-bottom: 9px; + margin: 20px 0 30px; + border-bottom: 1px solid #eeeeee; +} + +ul, +ol { + padding: 0; + margin: 0 0 10px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +li { + line-height: 20px; +} + +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +ul.inline, +ol.inline { + margin-left: 0; + list-style: none; +} + +ul.inline > li, +ol.inline > li { + display: inline-block; + *display: inline; + padding-right: 5px; + padding-left: 5px; + *zoom: 1; +} + +dl { + margin-bottom: 20px; +} + +dt, +dd { + line-height: 20px; +} + +dt { + font-weight: bold; +} + +dd { + margin-left: 10px; +} + +.dl-horizontal { + *zoom: 1; +} + +.dl-horizontal:before, +.dl-horizontal:after { + display: table; + line-height: 0; + content: ""; +} + +.dl-horizontal:after { + clear: both; +} + +.dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dl-horizontal dd { + margin-left: 180px; +} + +hr { + margin: 20px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} + +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 20px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + margin-bottom: 0; + font-size: 17.5px; + font-weight: 300; + line-height: 1.25; +} + +blockquote small { + display: block; + line-height: 20px; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +blockquote.pull-right small:before { + content: ''; +} + +blockquote.pull-right small:after { + content: '\00A0 \2014'; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 20px; + font-style: normal; + line-height: 20px; +} + +code, +pre { + padding: 0 3px 2px; + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +code { + padding: 2px 4px; + color: #d14; + white-space: nowrap; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} + +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 20px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +pre.prettyprint { + margin-bottom: 20px; +} + +pre code { + padding: 0; + color: inherit; + white-space: pre; + white-space: pre-wrap; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +form { + margin: 0 0 20px; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: 40px; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +legend small { + font-size: 15px; + color: #999999; +} + +label, +input, +button, +select, +textarea { + font-size: 14px; + font-weight: normal; + line-height: 20px; +} + +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +label { + display: block; + margin-bottom: 5px; +} + +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: 20px; + padding: 4px 6px; + margin-bottom: 10px; + font-size: 14px; + line-height: 20px; + color: #555555; + vertical-align: middle; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +input, +textarea, +.uneditable-input { + width: 206px; +} + +textarea { + height: auto; +} + +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: #ffffff; + border: 1px solid #cccccc; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} + +textarea:focus, +input[type="text"]:focus, +input[type="password"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="date"]:focus, +input[type="month"]:focus, +input[type="time"]:focus, +input[type="week"]:focus, +input[type="number"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="color"]:focus, +.uneditable-input:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); +} + +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + *margin-top: 0; + line-height: normal; +} + +input[type="file"], +input[type="image"], +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; +} + +select, +input[type="file"] { + height: 30px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 30px; +} + +select { + width: 220px; + background-color: #ffffff; + border: 1px solid #cccccc; +} + +select[multiple], +select[size] { + height: auto; +} + +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.uneditable-input, +.uneditable-textarea { + color: #999999; + cursor: not-allowed; + background-color: #fcfcfc; + border-color: #cccccc; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); +} + +.uneditable-input { + overflow: hidden; + white-space: nowrap; +} + +.uneditable-textarea { + width: auto; + height: auto; +} + +input:-moz-placeholder, +textarea:-moz-placeholder { + color: #999999; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #999999; +} + +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { + color: #999999; +} + +.radio, +.checkbox { + min-height: 20px; + padding-left: 20px; +} + +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -20px; +} + +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} + +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} + +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} + +.input-mini { + width: 60px; +} + +.input-small { + width: 90px; +} + +.input-medium { + width: 150px; +} + +.input-large { + width: 210px; +} + +.input-xlarge { + width: 270px; +} + +.input-xxlarge { + width: 530px; +} + +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} + +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} + +input, +textarea, +.uneditable-input { + margin-left: 0; +} + +.controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; +} + +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 926px; +} + +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 846px; +} + +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 766px; +} + +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 686px; +} + +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 606px; +} + +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 526px; +} + +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 446px; +} + +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 366px; +} + +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 286px; +} + +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 206px; +} + +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 126px; +} + +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 46px; +} + +.controls-row { + *zoom: 1; +} + +.controls-row:before, +.controls-row:after { + display: table; + line-height: 0; + content: ""; +} + +.controls-row:after { + clear: both; +} + +.controls-row [class*="span"], +.row-fluid .controls-row [class*="span"] { + float: left; +} + +.controls-row .checkbox[class*="span"], +.controls-row .radio[class*="span"] { + padding-top: 5px; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eeeeee; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + +.control-group.warning .control-label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} + +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; +} + +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + border-color: #c09853; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; +} + +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} + +.control-group.error .control-label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} + +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; +} + +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + border-color: #b94a48; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; +} + +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} + +.control-group.success .control-label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} + +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; +} + +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + border-color: #468847; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; +} + +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} + +.control-group.info .control-label, +.control-group.info .help-block, +.control-group.info .help-inline { + color: #3a87ad; +} + +.control-group.info .checkbox, +.control-group.info .radio, +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + color: #3a87ad; +} + +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + border-color: #3a87ad; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.info input:focus, +.control-group.info select:focus, +.control-group.info textarea:focus { + border-color: #2d6987; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; +} + +.control-group.info .input-prepend .add-on, +.control-group.info .input-append .add-on { + color: #3a87ad; + background-color: #d9edf7; + border-color: #3a87ad; +} + +input:focus:invalid, +textarea:focus:invalid, +select:focus:invalid { + color: #b94a48; + border-color: #ee5f5b; +} + +input:focus:invalid:focus, +textarea:focus:invalid:focus, +select:focus:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} + +.form-actions { + padding: 19px 20px 20px; + margin-top: 20px; + margin-bottom: 20px; + background-color: #f5f5f5; + border-top: 1px solid #e5e5e5; + *zoom: 1; +} + +.form-actions:before, +.form-actions:after { + display: table; + line-height: 0; + content: ""; +} + +.form-actions:after { + clear: both; +} + +.help-block, +.help-inline { + color: #595959; +} + +.help-block { + display: block; + margin-bottom: 10px; +} + +.help-inline { + display: inline-block; + *display: inline; + padding-left: 5px; + vertical-align: middle; + *zoom: 1; +} + +.input-append, +.input-prepend { + display: inline-block; + margin-bottom: 10px; + font-size: 0; + white-space: nowrap; + vertical-align: middle; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input, +.input-append .dropdown-menu, +.input-prepend .dropdown-menu, +.input-append .popover, +.input-prepend .popover { + font-size: 14px; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input { + position: relative; + margin-bottom: 0; + *margin-left: 0; + vertical-align: top; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-append input:focus, +.input-prepend input:focus, +.input-append select:focus, +.input-prepend select:focus, +.input-append .uneditable-input:focus, +.input-prepend .uneditable-input:focus { + z-index: 2; +} + +.input-append .add-on, +.input-prepend .add-on { + display: inline-block; + width: auto; + height: 20px; + min-width: 16px; + padding: 4px 5px; + font-size: 14px; + font-weight: normal; + line-height: 20px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #eeeeee; + border: 1px solid #ccc; +} + +.input-append .add-on, +.input-prepend .add-on, +.input-append .btn, +.input-prepend .btn, +.input-append .btn-group > .dropdown-toggle, +.input-prepend .btn-group > .dropdown-toggle { + vertical-align: top; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-append .active, +.input-prepend .active { + background-color: #a9dba9; + border-color: #46a546; +} + +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} + +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-append input + .btn-group .btn:last-child, +.input-append select + .btn-group .btn:last-child, +.input-append .uneditable-input + .btn-group .btn:last-child { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-append .add-on, +.input-append .btn, +.input-append .btn-group { + margin-left: -1px; +} + +.input-append .add-on:last-child, +.input-append .btn:last-child, +.input-append .btn-group:last-child > .dropdown-toggle { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend.input-append input + .btn-group .btn, +.input-prepend.input-append select + .btn-group .btn, +.input-prepend.input-append .uneditable-input + .btn-group .btn { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append .btn-group:first-child { + margin-left: 0; +} + +input.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +/* Allow for input prepend/append in search forms */ + +.form-search .input-append .search-query, +.form-search .input-prepend .search-query { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.form-search .input-append .search-query { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search .input-append .btn { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .search-query { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .btn { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + *display: inline; + margin-bottom: 0; + vertical-align: middle; + *zoom: 1; +} + +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} + +.form-search label, +.form-inline label, +.form-search .btn-group, +.form-inline .btn-group { + display: inline-block; +} + +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} + +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} + +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + +.control-group { + margin-bottom: 10px; +} + +legend + .control-group { + margin-top: 20px; + -webkit-margin-top-collapse: separate; +} + +.form-horizontal .control-group { + margin-bottom: 20px; + *zoom: 1; +} + +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + line-height: 0; + content: ""; +} + +.form-horizontal .control-group:after { + clear: both; +} + +.form-horizontal .control-label { + float: left; + width: 160px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 180px; + *margin-left: 0; +} + +.form-horizontal .controls:first-child { + *padding-left: 180px; +} + +.form-horizontal .help-block { + margin-bottom: 0; +} + +.form-horizontal input + .help-block, +.form-horizontal select + .help-block, +.form-horizontal textarea + .help-block, +.form-horizontal .uneditable-input + .help-block, +.form-horizontal .input-prepend + .help-block, +.form-horizontal .input-append + .help-block { + margin-top: 10px; +} + +.form-horizontal .form-actions { + padding-left: 180px; +} + +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +.table { + width: 100%; + margin-bottom: 20px; +} + +.table th, +.table td { + padding: 8px; + line-height: 20px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table th { + font-weight: bold; +} + +.table thead th { + vertical-align: bottom; +} + +.table caption + thead tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table .table { + background-color: #ffffff; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapse; + border-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} + +.table-bordered caption + thead tr:first-child th, +.table-bordered caption + tbody tr:first-child th, +.table-bordered caption + tbody tr:first-child td, +.table-bordered colgroup + thead tr:first-child th, +.table-bordered colgroup + tbody tr:first-child th, +.table-bordered colgroup + tbody tr:first-child td, +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} + +.table-bordered thead:first-child tr:first-child > th:first-child, +.table-bordered tbody:first-child tr:first-child > td:first-child, +.table-bordered tbody:first-child tr:first-child > th:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered thead:first-child tr:first-child > th:last-child, +.table-bordered tbody:first-child tr:first-child > td:last-child, +.table-bordered tbody:first-child tr:first-child > th:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-bordered thead:last-child tr:last-child > th:first-child, +.table-bordered tbody:last-child tr:last-child > td:first-child, +.table-bordered tbody:last-child tr:last-child > th:first-child, +.table-bordered tfoot:last-child tr:last-child > td:first-child, +.table-bordered tfoot:last-child tr:last-child > th:first-child { + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.table-bordered thead:last-child tr:last-child > th:last-child, +.table-bordered tbody:last-child tr:last-child > td:last-child, +.table-bordered tbody:last-child tr:last-child > th:last-child, +.table-bordered tfoot:last-child tr:last-child > td:last-child, +.table-bordered tfoot:last-child tr:last-child > th:last-child { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:first-child { + -webkit-border-bottom-left-radius: 0; + border-bottom-left-radius: 0; + -moz-border-radius-bottomleft: 0; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 0; + border-bottom-right-radius: 0; + -moz-border-radius-bottomright: 0; +} + +.table-bordered caption + thead tr:first-child th:first-child, +.table-bordered caption + tbody tr:first-child td:first-child, +.table-bordered colgroup + thead tr:first-child th:first-child, +.table-bordered colgroup + tbody tr:first-child td:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered caption + thead tr:first-child th:last-child, +.table-bordered caption + tbody tr:first-child td:last-child, +.table-bordered colgroup + thead tr:first-child th:last-child, +.table-bordered colgroup + tbody tr:first-child td:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-striped tbody > tr:nth-child(odd) > td, +.table-striped tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} + +.table-hover tbody tr:hover > td, +.table-hover tbody tr:hover > th { + background-color: #f5f5f5; +} + +table td[class*="span"], +table th[class*="span"], +.row-fluid table td[class*="span"], +.row-fluid table th[class*="span"] { + display: table-cell; + float: none; + margin-left: 0; +} + +.table td.span1, +.table th.span1 { + float: none; + width: 44px; + margin-left: 0; +} + +.table td.span2, +.table th.span2 { + float: none; + width: 124px; + margin-left: 0; +} + +.table td.span3, +.table th.span3 { + float: none; + width: 204px; + margin-left: 0; +} + +.table td.span4, +.table th.span4 { + float: none; + width: 284px; + margin-left: 0; +} + +.table td.span5, +.table th.span5 { + float: none; + width: 364px; + margin-left: 0; +} + +.table td.span6, +.table th.span6 { + float: none; + width: 444px; + margin-left: 0; +} + +.table td.span7, +.table th.span7 { + float: none; + width: 524px; + margin-left: 0; +} + +.table td.span8, +.table th.span8 { + float: none; + width: 604px; + margin-left: 0; +} + +.table td.span9, +.table th.span9 { + float: none; + width: 684px; + margin-left: 0; +} + +.table td.span10, +.table th.span10 { + float: none; + width: 764px; + margin-left: 0; +} + +.table td.span11, +.table th.span11 { + float: none; + width: 844px; + margin-left: 0; +} + +.table td.span12, +.table th.span12 { + float: none; + width: 924px; + margin-left: 0; +} + +.table tbody tr.success > td { + background-color: #dff0d8; +} + +.table tbody tr.error > td { + background-color: #f2dede; +} + +.table tbody tr.warning > td { + background-color: #fcf8e3; +} + +.table tbody tr.info > td { + background-color: #d9edf7; +} + +.table-hover tbody tr.success:hover > td { + background-color: #d0e9c6; +} + +.table-hover tbody tr.error:hover > td { + background-color: #ebcccc; +} + +.table-hover tbody tr.warning:hover > td { + background-color: #faf2cc; +} + +.table-hover tbody tr.info:hover > td { + background-color: #c4e3f3; +} + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + margin-top: 1px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +} + +/* White icons with optional class, or on hover/focus/active states of certain elements */ + +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:focus > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > li > a:focus > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:focus > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"], +.dropdown-submenu:focus > a > [class*=" icon-"] { + background-image: url("../img/glyphicons-halflings-white.png"); +} + +.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + width: 16px; + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + width: 16px; + background-position: -384px -120px; +} + +.icon-folder-open { + width: 16px; + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.icon-hdd { + background-position: 0 -144px; +} + +.icon-bullhorn { + background-position: -24px -144px; +} + +.icon-bell { + background-position: -48px -144px; +} + +.icon-certificate { + background-position: -72px -144px; +} + +.icon-thumbs-up { + background-position: -96px -144px; +} + +.icon-thumbs-down { + background-position: -120px -144px; +} + +.icon-hand-right { + background-position: -144px -144px; +} + +.icon-hand-left { + background-position: -168px -144px; +} + +.icon-hand-up { + background-position: -192px -144px; +} + +.icon-hand-down { + background-position: -216px -144px; +} + +.icon-circle-arrow-right { + background-position: -240px -144px; +} + +.icon-circle-arrow-left { + background-position: -264px -144px; +} + +.icon-circle-arrow-up { + background-position: -288px -144px; +} + +.icon-circle-arrow-down { + background-position: -312px -144px; +} + +.icon-globe { + background-position: -336px -144px; +} + +.icon-wrench { + background-position: -360px -144px; +} + +.icon-tasks { + background-position: -384px -144px; +} + +.icon-filter { + background-position: -408px -144px; +} + +.icon-briefcase { + background-position: -432px -144px; +} + +.icon-fullscreen { + background-position: -456px -144px; +} + +.dropup, +.dropdown { + position: relative; +} + +.dropdown-toggle { + *margin-bottom: -3px; +} + +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; +} + +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus, +.dropdown-submenu:hover > a, +.dropdown-submenu:focus > a { + color: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + outline: 0; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} + +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + cursor: default; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.open { + *z-index: 1000; +} + +.open > .dropdown-menu { + display: block; +} + +.dropdown-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 990; +} + +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: ""; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + -webkit-border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; +} + +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} + +.dropup .dropdown-submenu > .dropdown-menu { + top: auto; + bottom: 0; + margin-top: 0; + margin-bottom: -2px; + -webkit-border-radius: 5px 5px 5px 0; + -moz-border-radius: 5px 5px 5px 0; + border-radius: 5px 5px 5px 0; +} + +.dropdown-submenu > a:after { + display: block; + float: right; + width: 0; + height: 0; + margin-top: 5px; + margin-right: -10px; + border-color: transparent; + border-left-color: #cccccc; + border-style: solid; + border-width: 5px 0 5px 5px; + content: " "; +} + +.dropdown-submenu:hover > a:after { + border-left-color: #ffffff; +} + +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.dropdown .dropdown-menu .nav-header { + padding-right: 20px; + padding-left: 20px; +} + +.typeahead { + z-index: 1051; + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} + +.well-large { + padding: 24px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 20px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.btn { + display: inline-block; + *display: inline; + padding: 4px 12px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 14px; + line-height: 20px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #f5f5f5; + *background-color: #e6e6e6; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #cccccc; + *border: 0; + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-bottom-color: #b3b3b3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:hover, +.btn:focus, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + color: #333333; + background-color: #e6e6e6; + *background-color: #d9d9d9; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover, +.btn:focus { + color: #333333; + text-decoration: none; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-large { + padding: 11px 19px; + font-size: 17.5px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.btn-large [class^="icon-"], +.btn-large [class*=" icon-"] { + margin-top: 4px; +} + +.btn-small { + padding: 2px 10px; + font-size: 11.9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-small [class^="icon-"], +.btn-small [class*=" icon-"] { + margin-top: 0; +} + +.btn-mini [class^="icon-"], +.btn-mini [class*=" icon-"] { + margin-top: -1px; +} + +.btn-mini { + padding: 0 6px; + font-size: 10.5px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.btn-block + .btn-block { + margin-top: 5px; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn-primary { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #006dcc; + *background-color: #0044cc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); + background-repeat: repeat-x; + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + color: #ffffff; + background-color: #0044cc; + *background-color: #003bb3; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #003399 \9; +} + +.btn-warning { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #faa732; + *background-color: #f89406; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + color: #ffffff; + background-color: #f89406; + *background-color: #df8505; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #da4f49; + *background-color: #bd362f; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); + background-repeat: repeat-x; + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + color: #ffffff; + background-color: #bd362f; + *background-color: #a9302a; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #5bb75b; + *background-color: #51a351; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(to bottom, #62c462, #51a351); + background-repeat: repeat-x; + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + color: #ffffff; + background-color: #51a351; + *background-color: #499249; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #49afcd; + *background-color: #2f96b4; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); + background-repeat: repeat-x; + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + color: #ffffff; + background-color: #2f96b4; + *background-color: #2a85a0; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #363636; + *background-color: #222222; + background-image: -moz-linear-gradient(top, #444444, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); + background-image: -webkit-linear-gradient(top, #444444, #222222); + background-image: -o-linear-gradient(top, #444444, #222222); + background-image: linear-gradient(to bottom, #444444, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:focus, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + color: #ffffff; + background-color: #222222; + *background-color: #151515; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} + +button.btn, +input[type="submit"].btn { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +.btn-link, +.btn-link:active, +.btn-link[disabled] { + background-color: transparent; + background-image: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-link { + color: #0088cc; + cursor: pointer; + border-color: transparent; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-link:hover, +.btn-link:focus { + color: #005580; + text-decoration: underline; + background-color: transparent; +} + +.btn-link[disabled]:hover, +.btn-link[disabled]:focus { + color: #333333; + text-decoration: none; +} + +.btn-group { + position: relative; + display: inline-block; + *display: inline; + *margin-left: .3em; + font-size: 0; + white-space: nowrap; + vertical-align: middle; + *zoom: 1; +} + +.btn-group:first-child { + *margin-left: 0; +} + +.btn-group + .btn-group { + margin-left: 5px; +} + +.btn-toolbar { + margin-top: 10px; + margin-bottom: 10px; + font-size: 0; +} + +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group { + margin-left: 5px; +} + +.btn-group > .btn { + position: relative; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group > .btn + .btn { + margin-left: -1px; +} + +.btn-group > .btn, +.btn-group > .dropdown-menu, +.btn-group > .popover { + font-size: 14px; +} + +.btn-group > .btn-mini { + font-size: 10.5px; +} + +.btn-group > .btn-small { + font-size: 11.9px; +} + +.btn-group > .btn-large { + font-size: 17.5px; +} + +.btn-group > .btn:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.btn-group > .btn.large:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group > .btn + .dropdown-toggle { + *padding-top: 5px; + padding-right: 8px; + *padding-bottom: 5px; + padding-left: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group > .btn-mini + .dropdown-toggle { + *padding-top: 2px; + padding-right: 5px; + *padding-bottom: 2px; + padding-left: 5px; +} + +.btn-group > .btn-small + .dropdown-toggle { + *padding-top: 5px; + *padding-bottom: 4px; +} + +.btn-group > .btn-large + .dropdown-toggle { + *padding-top: 7px; + padding-right: 12px; + *padding-bottom: 7px; + padding-left: 12px; +} + +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group.open .btn.dropdown-toggle { + background-color: #e6e6e6; +} + +.btn-group.open .btn-primary.dropdown-toggle { + background-color: #0044cc; +} + +.btn-group.open .btn-warning.dropdown-toggle { + background-color: #f89406; +} + +.btn-group.open .btn-danger.dropdown-toggle { + background-color: #bd362f; +} + +.btn-group.open .btn-success.dropdown-toggle { + background-color: #51a351; +} + +.btn-group.open .btn-info.dropdown-toggle { + background-color: #2f96b4; +} + +.btn-group.open .btn-inverse.dropdown-toggle { + background-color: #222222; +} + +.btn .caret { + margin-top: 8px; + margin-left: 0; +} + +.btn-large .caret { + margin-top: 6px; +} + +.btn-large .caret { + border-top-width: 5px; + border-right-width: 5px; + border-left-width: 5px; +} + +.btn-mini .caret, +.btn-small .caret { + margin-top: 8px; +} + +.dropup .btn-large .caret { + border-bottom-width: 5px; +} + +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.btn-group-vertical { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-group-vertical > .btn { + display: block; + float: none; + max-width: 100%; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group-vertical > .btn + .btn { + margin-top: -1px; + margin-left: 0; +} + +.btn-group-vertical > .btn:first-child { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.btn-group-vertical > .btn:last-child { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.btn-group-vertical > .btn-large:first-child { + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; +} + +.btn-group-vertical > .btn-large:last-child { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 20px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.alert, +.alert h4 { + color: #c09853; +} + +.alert h4 { + margin: 0; +} + +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 20px; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-success h4 { + color: #468847; +} + +.alert-danger, +.alert-error { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-danger h4, +.alert-error h4 { + color: #b94a48; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-info h4 { + color: #3a87ad; +} + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} + +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} + +.alert-block p + p { + margin-top: 5px; +} + +.nav { + margin-bottom: 20px; + margin-left: 0; + list-style: none; +} + +.nav > li > a { + display: block; +} + +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} + +.nav > li > a > img { + max-width: none; +} + +.nav > .pull-right { + float: right; +} + +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 20px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} + +.nav li + .nav-header { + margin-top: 9px; +} + +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover, +.nav-list > .active > a:focus { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} + +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + margin-right: 2px; +} + +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.nav-tabs, +.nav-pills { + *zoom: 1; +} + +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + line-height: 0; + content: ""; +} + +.nav-tabs:after, +.nav-pills:after { + clear: both; +} + +.nav-tabs > li, +.nav-pills > li { + float: left; +} + +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} + +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +.nav-tabs > li { + margin-bottom: -1px; +} + +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 20px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover, +.nav-tabs > li > a:focus { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover, +.nav-tabs > .active > a:focus { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.nav-pills > .active > a, +.nav-pills > .active > a:hover, +.nav-pills > .active > a:focus { + color: #ffffff; + background-color: #0088cc; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li > a { + margin-right: 0; +} + +.nav-tabs.nav-stacked { + border-bottom: 0; +} + +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; +} + +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.nav-tabs.nav-stacked > li > a:hover, +.nav-tabs.nav-stacked > li > a:focus { + z-index: 2; + border-color: #ddd; +} + +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} + +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} + +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.nav-pills .dropdown-menu { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.nav .dropdown-toggle .caret { + margin-top: 6px; + border-top-color: #0088cc; + border-bottom-color: #0088cc; +} + +.nav .dropdown-toggle:hover .caret, +.nav .dropdown-toggle:focus .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} + +/* move down carets for tabs */ + +.nav-tabs .dropdown-toggle .caret { + margin-top: 8px; +} + +.nav .active .dropdown-toggle .caret { + border-top-color: #fff; + border-bottom-color: #fff; +} + +.nav-tabs .active .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.nav > .dropdown.active > a:hover, +.nav > .dropdown.active > a:focus { + cursor: pointer; +} + +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover, +.nav > li.dropdown.open.active > a:focus { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} + +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret, +.nav li.dropdown.open a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover, +.tabs-stacked .open > a:focus { + border-color: #999999; +} + +.tabbable { + *zoom: 1; +} + +.tabbable:before, +.tabbable:after { + display: table; + line-height: 0; + content: ""; +} + +.tabbable:after { + clear: both; +} + +.tab-content { + overflow: auto; +} + +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} + +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} + +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.tabs-below > .nav-tabs > li > a:hover, +.tabs-below > .nav-tabs > li > a:focus { + border-top-color: #ddd; + border-bottom-color: transparent; +} + +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover, +.tabs-below > .nav-tabs > .active > a:focus { + border-color: transparent #ddd #ddd #ddd; +} + +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} + +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} + +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.tabs-left > .nav-tabs > li > a:hover, +.tabs-left > .nav-tabs > li > a:focus { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} + +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover, +.tabs-left > .nav-tabs .active > a:focus { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} + +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} + +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.tabs-right > .nav-tabs > li > a:hover, +.tabs-right > .nav-tabs > li > a:focus { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} + +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover, +.tabs-right > .nav-tabs .active > a:focus { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} + +.nav > .disabled > a { + color: #999999; +} + +.nav > .disabled > a:hover, +.nav > .disabled > a:focus { + text-decoration: none; + cursor: default; + background-color: transparent; +} + +.navbar { + *position: relative; + *z-index: 2; + margin-bottom: 20px; + overflow: visible; +} + +.navbar-inner { + min-height: 40px; + padding-right: 20px; + padding-left: 20px; + background-color: #fafafa; + background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); + background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); + background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); + background-repeat: repeat-x; + border: 1px solid #d4d4d4; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); + *zoom: 1; + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); +} + +.navbar-inner:before, +.navbar-inner:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-inner:after { + clear: both; +} + +.navbar .container { + width: auto; +} + +.nav-collapse.collapse { + height: auto; + overflow: visible; +} + +.navbar .brand { + display: block; + float: left; + padding: 10px 20px 10px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + color: #777777; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .brand:hover, +.navbar .brand:focus { + text-decoration: none; +} + +.navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #777777; +} + +.navbar-link { + color: #777777; +} + +.navbar-link:hover, +.navbar-link:focus { + color: #333333; +} + +.navbar .divider-vertical { + height: 40px; + margin: 0 9px; + border-right: 1px solid #ffffff; + border-left: 1px solid #f2f2f2; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 5px; +} + +.navbar .btn-group .btn, +.navbar .input-prepend .btn, +.navbar .input-append .btn, +.navbar .input-prepend .btn-group, +.navbar .input-append .btn-group { + margin-top: 0; +} + +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} + +.navbar-form:before, +.navbar-form:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-form:after { + clear: both; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 5px; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .btn { + display: inline-block; + margin-bottom: 0; +} + +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} + +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 5px; + white-space: nowrap; +} + +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} + +.navbar-search { + position: relative; + float: left; + margin-top: 5px; + margin-bottom: 0; +} + +.navbar-search .search-query { + padding: 4px 14px; + margin-bottom: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.navbar-static-top { + position: static; + margin-bottom: 0; +} + +.navbar-static-top .navbar-inner { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + border-width: 0 0 1px; +} + +.navbar-fixed-bottom .navbar-inner { + border-width: 1px 0 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-right: 0; + padding-left: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.navbar-fixed-top { + top: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar-fixed-bottom { + bottom: 0; +} + +.navbar-fixed-bottom .navbar-inner { + -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} + +.navbar .nav.pull-right { + float: right; + margin-right: 0; +} + +.navbar .nav > li { + float: left; +} + +.navbar .nav > li > a { + float: none; + padding: 10px 15px 10px; + color: #777777; + text-decoration: none; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .nav .dropdown-toggle .caret { + margin-top: 8px; +} + +.navbar .nav > li > a:focus, +.navbar .nav > li > a:hover { + color: #333333; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + color: #555555; + text-decoration: none; + background-color: #e5e5e5; + -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); +} + +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-right: 5px; + margin-left: 5px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #ededed; + *background-color: #e5e5e5; + background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5)); + background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5); + background-repeat: repeat-x; + border-color: #e5e5e5 #e5e5e5 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} + +.navbar .btn-navbar:hover, +.navbar .btn-navbar:focus, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + color: #ffffff; + background-color: #e5e5e5; + *background-color: #d9d9d9; +} + +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #cccccc \9; +} + +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + +.navbar .nav > li > .dropdown-menu:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.navbar .nav > li > .dropdown-menu:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-left: 6px solid transparent; + content: ''; +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:before { + top: auto; + bottom: -7px; + border-top: 7px solid #ccc; + border-bottom: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:after { + top: auto; + bottom: -6px; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.navbar .nav li.dropdown > a:hover .caret, +.navbar .nav li.dropdown > a:focus .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + color: #555555; + background-color: #e5e5e5; +} + +.navbar .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #777777; + border-bottom-color: #777777; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.navbar .pull-right > li > .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:before, +.navbar .nav > li > .dropdown-menu.pull-right:before { + right: 12px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:after, +.navbar .nav > li > .dropdown-menu.pull-right:after { + right: 13px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu { + right: 100%; + left: auto; + margin-right: -1px; + margin-left: 0; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.navbar-inverse .navbar-inner { + background-color: #1b1b1b; + background-image: -moz-linear-gradient(top, #222222, #111111); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); + background-image: -webkit-linear-gradient(top, #222222, #111111); + background-image: -o-linear-gradient(top, #222222, #111111); + background-image: linear-gradient(to bottom, #222222, #111111); + background-repeat: repeat-x; + border-color: #252525; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); +} + +.navbar-inverse .brand, +.navbar-inverse .nav > li > a { + color: #999999; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar-inverse .brand:hover, +.navbar-inverse .nav > li > a:hover, +.navbar-inverse .brand:focus, +.navbar-inverse .nav > li > a:focus { + color: #ffffff; +} + +.navbar-inverse .brand { + color: #999999; +} + +.navbar-inverse .navbar-text { + color: #999999; +} + +.navbar-inverse .nav > li > a:focus, +.navbar-inverse .nav > li > a:hover { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .nav .active > a, +.navbar-inverse .nav .active > a:hover, +.navbar-inverse .nav .active > a:focus { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .navbar-link { + color: #999999; +} + +.navbar-inverse .navbar-link:hover, +.navbar-inverse .navbar-link:focus { + color: #ffffff; +} + +.navbar-inverse .divider-vertical { + border-right-color: #222222; + border-left-color: #111111; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .nav li.dropdown > a:hover .caret, +.navbar-inverse .nav li.dropdown > a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #999999; + border-bottom-color: #999999; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .navbar-search .search-query { + color: #ffffff; + background-color: #515151; + border-color: #111111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; +} + +.navbar-inverse .navbar-search .search-query:-moz-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:focus, +.navbar-inverse .navbar-search .search-query.focused { + padding: 5px 15px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + outline: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); +} + +.navbar-inverse .btn-navbar { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e0e0e; + *background-color: #040404; + background-image: -moz-linear-gradient(top, #151515, #040404); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404)); + background-image: -webkit-linear-gradient(top, #151515, #040404); + background-image: -o-linear-gradient(top, #151515, #040404); + background-image: linear-gradient(to bottom, #151515, #040404); + background-repeat: repeat-x; + border-color: #040404 #040404 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.navbar-inverse .btn-navbar:hover, +.navbar-inverse .btn-navbar:focus, +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active, +.navbar-inverse .btn-navbar.disabled, +.navbar-inverse .btn-navbar[disabled] { + color: #ffffff; + background-color: #040404; + *background-color: #000000; +} + +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active { + background-color: #000000 \9; +} + +.breadcrumb { + padding: 8px 15px; + margin: 0 0 20px; + list-style: none; + background-color: #f5f5f5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.breadcrumb > li { + display: inline-block; + *display: inline; + text-shadow: 0 1px 0 #ffffff; + *zoom: 1; +} + +.breadcrumb > li > .divider { + padding: 0 5px; + color: #ccc; +} + +.breadcrumb > .active { + color: #999999; +} + +.pagination { + margin: 20px 0; +} + +.pagination ul { + display: inline-block; + *display: inline; + margin-bottom: 0; + margin-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + *zoom: 1; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.pagination ul > li { + display: inline; +} + +.pagination ul > li > a, +.pagination ul > li > span { + float: left; + padding: 4px 12px; + line-height: 20px; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; + border-left-width: 0; +} + +.pagination ul > li > a:hover, +.pagination ul > li > a:focus, +.pagination ul > .active > a, +.pagination ul > .active > span { + background-color: #f5f5f5; +} + +.pagination ul > .active > a, +.pagination ul > .active > span { + color: #999999; + cursor: default; +} + +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover, +.pagination ul > .disabled > a:focus { + color: #999999; + cursor: default; + background-color: transparent; +} + +.pagination ul > li:first-child > a, +.pagination ul > li:first-child > span { + border-left-width: 1px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.pagination ul > li:last-child > a, +.pagination ul > li:last-child > span { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} + +.pagination-large ul > li > a, +.pagination-large ul > li > span { + padding: 11px 19px; + font-size: 17.5px; +} + +.pagination-large ul > li:first-child > a, +.pagination-large ul > li:first-child > span { + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.pagination-large ul > li:last-child > a, +.pagination-large ul > li:last-child > span { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.pagination-mini ul > li:first-child > a, +.pagination-small ul > li:first-child > a, +.pagination-mini ul > li:first-child > span, +.pagination-small ul > li:first-child > span { + -webkit-border-bottom-left-radius: 3px; + border-bottom-left-radius: 3px; + -webkit-border-top-left-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-topleft: 3px; +} + +.pagination-mini ul > li:last-child > a, +.pagination-small ul > li:last-child > a, +.pagination-mini ul > li:last-child > span, +.pagination-small ul > li:last-child > span { + -webkit-border-top-right-radius: 3px; + border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + border-bottom-right-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-bottomright: 3px; +} + +.pagination-small ul > li > a, +.pagination-small ul > li > span { + padding: 2px 10px; + font-size: 11.9px; +} + +.pagination-mini ul > li > a, +.pagination-mini ul > li > span { + padding: 0 6px; + font-size: 10.5px; +} + +.pager { + margin: 20px 0; + text-align: center; + list-style: none; + *zoom: 1; +} + +.pager:before, +.pager:after { + display: table; + line-height: 0; + content: ""; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #f5f5f5; +} + +.pager .next > a, +.pager .next > span { + float: right; +} + +.pager .previous > a, +.pager .previous > span { + float: left; +} + +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999999; + cursor: default; + background-color: #fff; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 10%; + left: 50%; + z-index: 1050; + width: 560px; + margin-left: -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + outline: none; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.modal.fade { + top: -25%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; +} + +.modal.fade.in { + top: 10%; +} + +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} + +.modal-header .close { + margin-top: 2px; +} + +.modal-header h3 { + margin: 0; + line-height: 30px; +} + +.modal-body { + position: relative; + max-height: 400px; + padding: 15px; + overflow-y: auto; +} + +.modal-form { + margin-bottom: 0; +} + +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + line-height: 0; + content: ""; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} + +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} + +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} + +.tooltip { + position: absolute; + z-index: 1030; + display: block; + font-size: 11px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.tooltip.top { + padding: 5px 0; + margin-top: -3px; +} + +.tooltip.right { + padding: 0 5px; + margin-left: 3px; +} + +.tooltip.bottom { + padding: 5px 0; + margin-top: 3px; +} + +.tooltip.left { + padding: 0 5px; + margin-left: -3px; +} + +.tooltip-inner { + max-width: 200px; + padding: 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #000000; + border-width: 5px 5px 5px 0; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #000000; + border-width: 5px 0 5px 5px; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + white-space: normal; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.popover.top { + margin-top: -10px; +} + +.popover.right { + margin-left: 10px; +} + +.popover.bottom { + margin-top: 10px; +} + +.popover.left { + margin-left: -10px; +} + +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} + +.popover-title:empty { + display: none; +} + +.popover-content { + padding: 9px 14px; +} + +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.popover .arrow { + border-width: 11px; +} + +.popover .arrow:after { + border-width: 10px; + content: ""; +} + +.popover.top .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, 0.25); + border-bottom-width: 0; +} + +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + border-top-color: #ffffff; + border-bottom-width: 0; +} + +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, 0.25); + border-left-width: 0; +} + +.popover.right .arrow:after { + bottom: -10px; + left: 1px; + border-right-color: #ffffff; + border-left-width: 0; +} + +.popover.bottom .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-top-width: 0; +} + +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + border-bottom-color: #ffffff; + border-top-width: 0; +} + +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, 0.25); + border-right-width: 0; +} + +.popover.left .arrow:after { + right: 1px; + bottom: -10px; + border-left-color: #ffffff; + border-right-width: 0; +} + +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} + +.thumbnails:before, +.thumbnails:after { + display: table; + line-height: 0; + content: ""; +} + +.thumbnails:after { + clear: both; +} + +.row-fluid .thumbnails { + margin-left: 0; +} + +.thumbnails > li { + float: left; + margin-bottom: 20px; + margin-left: 20px; +} + +.thumbnail { + display: block; + padding: 4px; + line-height: 20px; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +a.thumbnail:hover, +a.thumbnail:focus { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} + +.thumbnail > img { + display: block; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; + color: #555555; +} + +.media, +.media-body { + overflow: hidden; + *overflow: visible; + zoom: 1; +} + +.media, +.media .media { + margin-top: 15px; +} + +.media:first-child { + margin-top: 0; +} + +.media-object { + display: block; +} + +.media-heading { + margin: 0 0 5px; +} + +.media > .pull-left { + margin-right: 10px; +} + +.media > .pull-right { + margin-left: 10px; +} + +.media-list { + margin-left: 0; + list-style: none; +} + +.label, +.badge { + display: inline-block; + padding: 2px 4px; + font-size: 11.844px; + font-weight: bold; + line-height: 14px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; +} + +.label { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.badge { + padding-right: 9px; + padding-left: 9px; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} + +.label:empty, +.badge:empty { + display: none; +} + +a.label:hover, +a.label:focus, +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label-important, +.badge-important { + background-color: #b94a48; +} + +.label-important[href], +.badge-important[href] { + background-color: #953b39; +} + +.label-warning, +.badge-warning { + background-color: #f89406; +} + +.label-warning[href], +.badge-warning[href] { + background-color: #c67605; +} + +.label-success, +.badge-success { + background-color: #468847; +} + +.label-success[href], +.badge-success[href] { + background-color: #356635; +} + +.label-info, +.badge-info { + background-color: #3a87ad; +} + +.label-info[href], +.badge-info[href] { + background-color: #2d6987; +} + +.label-inverse, +.badge-inverse { + background-color: #333333; +} + +.label-inverse[href], +.badge-inverse[href] { + background-color: #1a1a1a; +} + +.btn .label, +.btn .badge { + position: relative; + top: -1px; +} + +.btn-mini .label, +.btn-mini .badge { + top: 0; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-ms-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress .bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + color: #ffffff; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(to bottom, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress .bar + .bar { + -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); +} + +.progress-striped .bar { + background-color: #149bdf; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} + +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-danger .bar, +.progress .bar-danger { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); +} + +.progress-danger.progress-striped .bar, +.progress-striped .bar-danger { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-success .bar, +.progress .bar-success { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(to bottom, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); +} + +.progress-success.progress-striped .bar, +.progress-striped .bar-success { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-info .bar, +.progress .bar-info { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(to bottom, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); +} + +.progress-info.progress-striped .bar, +.progress-striped .bar-info { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-warning .bar, +.progress .bar-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); +} + +.progress-warning.progress-striped .bar, +.progress-striped .bar-warning { + background-color: #fbb450; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.accordion { + margin-bottom: 20px; +} + +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.accordion-heading { + border-bottom: 0; +} + +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +.accordion-toggle { + cursor: pointer; +} + +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} + +.carousel { + position: relative; + margin-bottom: 20px; + line-height: 1; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + line-height: 1; +} + +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} + +.carousel-inner > .active { + left: 0; +} + +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} + +.carousel-inner > .next { + left: 100%; +} + +.carousel-inner > .prev { + left: -100%; +} + +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} + +.carousel-inner > .active.left { + left: -100%; +} + +.carousel-inner > .active.right { + left: 100%; +} + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover, +.carousel-control:focus { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-indicators { + position: absolute; + top: 15px; + right: 15px; + z-index: 5; + margin: 0; + list-style: none; +} + +.carousel-indicators li { + display: block; + float: left; + width: 10px; + height: 10px; + margin-left: 5px; + text-indent: -999px; + background-color: #ccc; + background-color: rgba(255, 255, 255, 0.25); + border-radius: 5px; +} + +.carousel-indicators .active { + background-color: #fff; +} + +.carousel-caption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + padding: 15px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + line-height: 20px; + color: #ffffff; +} + +.carousel-caption h4 { + margin: 0 0 5px; +} + +.carousel-caption p { + margin-bottom: 0; +} + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + font-size: 18px; + font-weight: 200; + line-height: 30px; + color: inherit; + background-color: #eeeeee; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; + color: inherit; +} + +.hero-unit li { + line-height: 30px; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} + +.affix { + position: fixed; +} diff --git a/_static/bootstrap-2.3.2/css/bootstrap.min.css b/_static/bootstrap-2.3.2/css/bootstrap.min.css new file mode 100644 index 00000000..b6428e69 --- /dev/null +++ b/_static/bootstrap-2.3.2/css/bootstrap.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed} diff --git a/_static/bootstrap-2.3.2/img/glyphicons-halflings-white.png b/_static/bootstrap-2.3.2/img/glyphicons-halflings-white.png new file mode 100644 index 0000000000000000000000000000000000000000..3bf6484a29d8da269f9bc874b25493a45fae3bae GIT binary patch literal 8777 zcmZvC1yGz#v+m*$LXcp=A$ZWB0fL7wNbp_U*$~{_gL`my3oP#L!5tQYy99Ta`+g_q zKlj|KJ2f@c)ARJx{q*bbkhN_!|Wn*Vos8{TEhUT@5e;_WJsIMMcG5%>DiS&dv_N`4@J0cnAQ-#>RjZ z00W5t&tJ^l-QC*ST1-p~00u^9XJ=AUl7oW-;2a+x2k__T=grN{+1c4XK0ZL~^z^i$ zp&>vEhr@4fZWb380S18T&!0cQ3IKpHF)?v=b_NIm0Q>vwY7D0baZ)n z31Fa5sELUQARIVaU0nqf0XzT+fB_63aA;@<$l~wse|mcA;^G1TmX?-)e)jkGPfkuA z92@|!<>h5S_4f8QP-JRq>d&7)^Yin8l7K8gED$&_FaV?gY+wLjpoW%~7NDe=nHfMG z5DO3j{R9kv5GbssrUpO)OyvVrlx>u0UKD0i;Dpm5S5dY16(DL5l{ixz|mhJU@&-OWCTb7_%}8-fE(P~+XIRO zJU|wp1|S>|J3KrLcz^+v1f&BDpd>&MAaibR4#5A_4(MucZwG9E1h4@u0P@C8;oo+g zIVj7kfJi{oV~E(NZ*h(@^-(Q(C`Psb3KZ{N;^GB(a8NE*Vwc715!9 zr-H4Ao|T_c6+VT_JH9H+P3>iXSt!a$F`>s`jn`w9GZ_~B!{0soaiV|O_c^R2aWa%}O3jUE)WO=pa zs~_Wz08z|ieY5A%$@FcBF9^!1a}m5ks@7gjn;67N>}S~Hrm`4sM5Hh`q7&5-N{|31 z6x1{ol7BnskoViZ0GqbLa#kW`Z)VCjt1MysKg|rT zi!?s##Ck>8c zpi|>$lGlw#@yMNi&V4`6OBGJ(H&7lqLlcTQ&1zWriG_fL>BnFcr~?;E93{M-xIozQ zO=EHQ#+?<}%@wbWWv23#!V70h9MOuUVaU>3kpTvYfc|LBw?&b*89~Gc9i&8tlT#kF ztpbZoAzkdB+UTy=tx%L3Z4)I{zY(Kb)eg{InobSJmNwPZt$14aS-uc4eKuY8h$dtfyxu^a%zA)>fYI&)@ZXky?^{5>xSC?;w4r&td6vBdi%vHm4=XJH!3yL3?Ep+T5aU_>i;yr_XGq zxZfCzUU@GvnoIk+_Nd`aky>S&H!b*{A%L>?*XPAgWL(Vf(k7qUS}>Zn=U(ZfcOc{B z3*tOHH@t5Ub5D~#N7!Fxx}P2)sy{vE_l(R7$aW&CX>c|&HY+7};vUIietK%}!phrCuh+;C@1usp;XLU<8Gq8P!rEI3ieg#W$!= zQcZr{hp>8sF?k&Yl0?B84OneiQxef-4TEFrq3O~JAZR}yEJHA|Xkqd49tR&8oq{zP zY@>J^HBV*(gJvJZc_0VFN7Sx?H7#75E3#?N8Z!C+_f53YU}pyggxx1?wQi5Yb-_`I`_V*SMx5+*P^b=ec5RON-k1cIlsBLk}(HiaJyab0`CI zo0{=1_LO$~oE2%Tl_}KURuX<`+mQN_sTdM&* zkFf!Xtl^e^gTy6ON=&gTn6)$JHQq2)33R@_!#9?BLNq-Wi{U|rVX7Vny$l6#+SZ@KvQt@VYb%<9JfapI^b9j=wa+Tqb4ei;8c5 z&1>Uz@lVFv6T4Z*YU$r4G`g=91lSeA<=GRZ!*KTWKDPR}NPUW%peCUj`Ix_LDq!8| zMH-V`Pv!a~QkTL||L@cqiTz)*G-0=ytr1KqTuFPan9y4gYD5>PleK`NZB$ev@W%t= zkp)_=lBUTLZJpAtZg;pjI;7r2y|26-N7&a(hX|`1YNM9N8{>8JAuv}hp1v`3JHT-=5lbXpbMq7X~2J5Kl zh7tyU`_AusMFZ{ej9D;Uyy;SQ!4nwgSnngsYBwdS&EO3NS*o04)*juAYl;57c2Ly0(DEZ8IY?zSph-kyxu+D`tt@oU{32J#I{vmy=#0ySPK zA+i(A3yl)qmTz*$dZi#y9FS;$;h%bY+;StNx{_R56Otq+?pGe^T^{5d7Gs&?`_r`8 zD&dzOA|j8@3A&FR5U3*eQNBf<4^4W_iS_()*8b4aaUzfk2 zzIcMWSEjm;EPZPk{j{1>oXd}pXAj!NaRm8{Sjz!D=~q3WJ@vmt6ND_?HI~|wUS1j5 z9!S1MKr7%nxoJ3k`GB^7yV~*{n~O~n6($~x5Bu{7s|JyXbAyKI4+tO(zZYMslK;Zc zzeHGVl{`iP@jfSKq>R;{+djJ9n%$%EL()Uw+sykjNQdflkJZSjqV_QDWivbZS~S{K zkE@T^Jcv)Dfm93!mf$XYnCT--_A$zo9MOkPB6&diM8MwOfV?+ApNv`moV@nqn>&lv zYbN1-M|jc~sG|yLN^1R2=`+1ih3jCshg`iP&mY$GMTcY^W^T`WOCX!{-KHmZ#GiRH zYl{|+KLn5!PCLtBy~9i}`#d^gCDDx$+GQb~uc;V#K3OgbbOG0j5{BRG-si%Bo{@lB zGIt+Ain8^C`!*S0d0OSWVO+Z89}}O8aFTZ>p&k}2gGCV zh#<$gswePFxWGT$4DC^8@84_e*^KT74?7n8!$8cg=sL$OlKr&HMh@Rr5%*Wr!xoOl zo7jItnj-xYgVTX)H1=A2bD(tleEH57#V{xAeW_ezISg5OC zg=k>hOLA^urTH_e6*vSYRqCm$J{xo}-x3@HH;bsHD1Z`Pzvsn}%cvfw%Q(}h`Dgtb z0_J^niUmoCM5$*f)6}}qi(u;cPgxfyeVaaVmOsG<)5`6tzU4wyhF;k|~|x>7-2hXpVBpc5k{L4M`Wbe6Q?tr^*B z`Y*>6*&R#~%JlBIitlZ^qGe3s21~h3U|&k%%jeMM;6!~UH|+0+<5V-_zDqZQN79?n?!Aj!Nj`YMO9?j>uqI9-Tex+nJD z%e0#Yca6(zqGUR|KITa?9x-#C0!JKJHO(+fy@1!B$%ZwJwncQW7vGYv?~!^`#L~Um zOL++>4qmqW`0Chc0T23G8|vO)tK=Z2`gvS4*qpqhIJCEv9i&&$09VO8YOz|oZ+ubd zNXVdLc&p=KsSgtmIPLN69P7xYkYQ1vJ?u1g)T!6Ru`k2wkdj*wDC)VryGu2=yb0?F z>q~~e>KZ0d_#7f3UgV%9MY1}vMgF{B8yfE{HL*pMyhYF)WDZ^^3vS8F zGlOhs%g_~pS3=WQ#494@jAXwOtr^Y|TnQ5zki>qRG)(oPY*f}U_=ip_{qB0!%w7~G zWE!P4p3khyW-JJnE>eECuYfI?^d366Shq!Wm#x&jAo>=HdCllE$>DPO0N;y#4G)D2y#B@5=N=+F%Xo2n{gKcPcK2!hP*^WSXl+ut; zyLvVoY>VL{H%Kd9^i~lsb8j4>$EllrparEOJNT?Ym>vJa$(P^tOG)5aVb_5w^*&M0 zYOJ`I`}9}UoSnYg#E(&yyK(tqr^@n}qU2H2DhkK-`2He% zgXr_4kpXoQHxAO9S`wEdmqGU4j=1JdG!OixdqB4PPP6RXA}>GM zumruUUH|ZG2$bBj)Qluj&uB=dRb)?^qomw?Z$X%#D+Q*O97eHrgVB2*mR$bFBU`*} zIem?dM)i}raTFDn@5^caxE^XFXVhBePmH9fqcTi`TLaXiueH=@06sl}>F%}h9H_e9 z>^O?LxM1EjX}NVppaO@NNQr=AtHcH-BU{yBT_vejJ#J)l^cl69Z7$sk`82Zyw7Wxt z=~J?hZm{f@W}|96FUJfy65Gk8?^{^yjhOahUMCNNpt5DJw}ZKH7b!bGiFY9y6OY&T z_N)?Jj(MuLTN36ZCJ6I5Xy7uVlrb$o*Z%=-)kPo9s?<^Yqz~!Z* z_mP8(unFq65XSi!$@YtieSQ!<7IEOaA9VkKI?lA`*(nURvfKL8cX}-+~uw9|_5)uC2`ZHcaeX7L8aG6Ghleg@F9aG%X$#g6^yP5apnB>YTz&EfS{q z9UVfSyEIczebC)qlVu5cOoMzS_jrC|)rQlAzK7sfiW0`M8mVIohazPE9Jzn*qPt%6 zZL8RELY@L09B83@Be;x5V-IHnn$}{RAT#<2JA%ttlk#^(%u}CGze|1JY5MPhbfnYG zIw%$XfBmA-<_pKLpGKwbRF$#P;@_)ech#>vj25sv25VM$ouo)?BXdRcO{)*OwTw)G zv43W~T6ekBMtUD%5Bm>`^Ltv!w4~65N!Ut5twl!Agrzyq4O2Fi3pUMtCU~>9gt_=h-f% z;1&OuSu?A_sJvIvQ+dZNo3?m1%b1+s&UAx?8sUHEe_sB7zkm4R%6)<@oYB_i5>3Ip zIA+?jVdX|zL{)?TGpx+=Ta>G80}0}Ax+722$XFNJsC1gcH56{8B)*)eU#r~HrC&}` z|EWW92&;6y;3}!L5zXa385@?-D%>dSvyK;?jqU2t_R3wvBW;$!j45uQ7tyEIQva;Db}r&bR3kqNSh)Q_$MJ#Uj3Gj1F;)sO|%6z#@<+ zi{pbYsYS#u`X$Nf($OS+lhw>xgjos1OnF^$-I$u;qhJswhH~p|ab*nO>zBrtb0ndn zxV0uh!LN`&xckTP+JW}gznSpU492)u+`f{9Yr)js`NmfYH#Wdtradc0TnKNz@Su!e zu$9}G_=ku;%4xk}eXl>)KgpuT>_<`Ud(A^a++K&pm3LbN;gI}ku@YVrA%FJBZ5$;m zobR8}OLtW4-i+qPPLS-(7<>M{)rhiPoi@?&vDeVq5%fmZk=mDdRV>Pb-l7pP1y6|J z8I>sF+TypKV=_^NwBU^>4JJq<*14GLfM2*XQzYdlqqjnE)gZsPW^E@mp&ww* zW9i>XL=uwLVZ9pO*8K>t>vdL~Ek_NUL$?LQi5sc#1Q-f6-ywKcIT8Kw?C(_3pbR`e|)%9S-({if|E+hR2W!&qfQ&UiF^I!|M#xhdWsenv^wpKCBiuxXbnp85`{i|;BM?Ba`lqTA zyRm=UWJl&E{8JzYDHFu>*Z10-?#A8D|5jW9Ho0*CAs0fAy~MqbwYuOq9jjt9*nuHI zbDwKvh)5Ir$r!fS5|;?Dt>V+@F*v8=TJJF)TdnC#Mk>+tGDGCw;A~^PC`gUt*<(|i zB{{g{`uFehu`$fm4)&k7`u{xIV)yvA(%5SxX9MS80p2EKnLtCZ>tlX>*Z6nd&6-Mv$5rHD*db;&IBK3KH&M<+ArlGXDRdX1VVO4)&R$f4NxXI>GBh zSv|h>5GDAI(4E`@F?EnW zS>#c&Gw6~_XL`qQG4bK`W*>hek4LX*efn6|_MY+rXkNyAuu?NxS%L7~9tD3cn7&p( zCtfqe6sjB&Q-Vs7BP5+%;#Gk};4xtwU!KY0XXbmkUy$kR9)!~?*v)qw00!+Yg^#H> zc#8*z6zZo>+(bud?K<*!QO4ehiTCK&PD4G&n)Tr9X_3r-we z?fI+}-G~Yn93gI6F{}Dw_SC*FLZ)5(85zp4%uubtD)J)UELLkvGk4#tw&Tussa)mTD$R2&O~{ zCI3>fr-!-b@EGRI%g0L8UU%%u_<;e9439JNV;4KSxd|78v+I+8^rmMf3f40Jb}wEszROD?xBZu>Ll3;sUIoNxDK3|j3*sam2tC@@e$ z^!;+AK>efeBJB%ALsQ{uFui)oDoq()2USi?n=6C3#eetz?wPswc={I<8x=(8lE4EIsUfyGNZ{|KYn1IR|=E==f z(;!A5(-2y^2xRFCSPqzHAZn5RCN_bp22T(KEtjA(rFZ%>a4@STrHZflxKoqe9Z4@^ zM*scx_y73?Q{vt6?~WEl?2q*;@8 z3M*&@%l)SQmXkcUm)d@GT2#JdzhfSAP9|n#C;$E8X|pwD!r#X?0P>0ZisQ~TNqupW z*lUY~+ikD`vQb?@SAWX#r*Y+;=_|oacL$2CL$^(mV}aKO77pg}O+-=T1oLBT5sL2i z42Qth2+0@C`c+*D0*5!qy26sis<9a7>LN2{z%Qj49t z=L@x`4$ALHb*3COHoT?5S_c(Hs}g!V>W^=6Q0}zaubkDn)(lTax0+!+%B}9Vqw6{H zvL|BRM`O<@;eVi1DzM!tXtBrA20Ce@^Jz|>%X-t`vi-%WweXCh_LhI#bUg2*pcP~R z*RuTUzBKLXO~~uMd&o$v3@d0shHfUjC6c539PE6rF&;Ufa(Rw@K1*m7?f5)t`MjH0 z)_V(cajV5Am>f!kWcI@5rE8t6$S>5M=k=aRZROH6fA^jJp~2NlR4;Q2>L$7F#RT#9 z>4@1RhWG`Khy>P2j1Yx^BBL{S`niMaxlSWV-JBU0-T9zZ%>7mR3l$~QV$({o0;jTI ze5=cN^!Bc2bT|BcojXp~K#2cM>OTe*cM{Kg-j*CkiW)EGQot^}s;cy8_1_@JA0Whq zlrNr+R;Efa+`6N)s5rH*|E)nYZ3uqkk2C(E7@A|3YI`ozP~9Lexx#*1(r8luq+YPk z{J}c$s` zPM35Fx(YWB3Z5IYnN+L_4|jaR(5iWJi2~l&xy}aU7kW?o-V*6Av2wyZTG!E2KSW2* zGRLQkQU;Oz##ie-Z4fI)WSRxn$(ZcD;TL+;^r=a4(G~H3ZhK$lSXZj?cvyY8%d9JM zzc3#pD^W_QnWy#rx#;c&N@sqHhrnHRmj#i;s%zLm6SE(n&BWpd&f7>XnjV}OlZntI70fq%8~9<7 zMYaw`E-rp49-oC1N_uZTo)Cu%RR2QWdHpzQIcNsoDp`3xfP+`gI?tVQZ4X={qU?(n zV>0ASES^Xuc;9JBji{)RnFL(Lez;8XbB1uWaMp@p?7xhXk6V#!6B@aP4Rz7-K%a>i z?fvf}va_DGUXlI#4--`A3qK7J?-HwnG7O~H2;zR~RLW)_^#La!=}+>KW#anZ{|^D3 B7G?kd literal 0 HcmV?d00001 diff --git a/_static/bootstrap-2.3.2/img/glyphicons-halflings.png b/_static/bootstrap-2.3.2/img/glyphicons-halflings.png new file mode 100644 index 0000000000000000000000000000000000000000..a9969993201f9cee63cf9f49217646347297b643 GIT binary patch literal 12799 zcma*OWmH^Ivn@*S;K3nSf_t!#;0f+&pm7Po8`nk}2q8f5;M%x$SdAkd9FAvlc$ zx660V9e3Ox@4WZ^?7jZ%QFGU-T~%||Ug4iK6bbQY@zBuF2$hxOw9wF=A)nUSxR_5@ zEX>HBryGrjyuOFFv$Y4<+|3H@gQfEqD<)+}a~mryD|1U9*I_FOG&F%+Ww{SJ-V2BR zjt<81Ek$}Yb*95D4RS0HCps|uLyovt;P05hchQb-u2bzLtmog&f2}1VlNhxXV);S9 zM2buBg~!q9PtF)&KGRgf3#z7B(hm5WlNClaCWFs!-P!4-u*u5+=+D|ZE9e`KvhTHT zJBnLwGM%!u&vlE%1ytJ=!xt~y_YkFLQb6bS!E+s8l7PiPGSt9xrmg?LV&&SL?J~cI zS(e9TF1?SGyh+M_p@o1dyWu7o7_6p;N6hO!;4~ z2B`I;y`;$ZdtBpvK5%oQ^p4eR2L)BH>B$FQeC*t)c`L71gXHPUa|vyu`Bnz)H$ZcXGve(}XvR!+*8a>BLV;+ryG1kt0=)ytl zNJxFUN{V7P?#|Cp85QTa@(*Q3%K-R(Pkv1N8YU*(d(Y}9?PQ(j;NzWoEVWRD-~H$=f>j9~PN^BM2okI(gY-&_&BCV6RP&I$FnSEM3d=0fCxbxA6~l>54-upTrw zYgX@%m>jsSGi`0cQt6b8cX~+02IghVlNblR7eI;0ps}mpWUcxty1yG56C5rh%ep(X z?)#2d?C<4t-KLc*EAn>>M8%HvC1TyBSoPNg(4id~H8JwO#I)Bf;N*y6ai6K9_bA`4 z_g9(-R;qyH&6I$`b42v|0V3Z8IXN*p*8g$gE98+JpXNY+jXxU0zsR^W$#V=KP z3AEFp@OL}WqwOfsV<)A^UTF4&HF1vQecz?LWE@p^Z2){=KEC_3Iopx_eS42>DeiDG zWMXGbYfG~W7C8s@@m<_?#Gqk;!&)_Key@^0xJxrJahv{B&{^!>TV7TEDZlP|$=ZCz zmX=ZWtt4QZKx**)lQQoW8y-XLiOQy#T`2t}p6l*S`68ojyH@UXJ-b~@tN`WpjF z%7%Yzv807gsO!v=!(2uR)16!&U5~VPrPHtGzUU?2w(b1Xchq}(5Ed^G|SD7IG+kvgyVksU) z(0R)SW1V(>&q2nM%Z!C9=;pTg!(8pPSc%H01urXmQI6Gi^dkYCYfu6b4^tW))b^U+ z$2K&iOgN_OU7n#GC2jgiXU{caO5hZt0(>k+c^(r><#m|#J^s?zA6pi;^#*rp&;aqL zRcZi0Q4HhVX3$ybclxo4FFJW*`IV`)Bj_L3rQe?5{wLJh168Ve1jZv+f1D}f0S$N= zm4i|9cEWz&C9~ZI3q*gwWH^<6sBWuphgy@S3Qy?MJiL>gwd|E<2h9-$3;gT9V~S6r z)cAcmE0KXOwDA5eJ02-75d~f?3;n7a9d_xPBJaO;Z)#@s7gk5$Qn(Fc^w@9c5W0zY z59is0?Mt^@Rolcn{4%)Ioat(kxQH6}hIykSA)zht=9F_W*D#<}N(k&&;k;&gKkWIL z0Of*sP=X(Uyu$Pw;?F@?j{}=>{aSHFcii#78FC^6JGrg-)!)MV4AKz>pXnhVgTgx8 z1&5Y=>|8RGA6++FrSy=__k_imx|z-EI@foKi>tK0Hq2LetjUotCgk2QFXaej!BWYL zJc{fv(&qA7UUJ|AXLc5z*_NW#yWzKtl(c8mEW{A>5Hj^gfZ^HC9lQNQ?RowXjmuCj4!!54Us1=hY z0{@-phvC}yls!PmA~_z>Y&n&IW9FQcj}9(OLO-t^NN$c0o}YksCUWt|DV(MJB%%Sr zdf}8!9ylU2TW!=T{?)g-ojAMKc>3pW;KiZ7f0;&g)k}K^#HBhE5ot)%oxq$*$W@b# zg4p<Ou`ME|Kd1WHK@8 zzLD+0(NHWa`B{em3Ye?@aVsEi>y#0XVZfaFuq#;X5C3{*ikRx7UY4FF{ZtNHNO?A_ z#Q?hwRv~D8fPEc%B5E-ZMI&TAmikl||EERumQCRh7p;)>fdZMxvKq;ky0}7IjhJph zW*uuu*(Y6)S;Od--8uR^R#sb$cmFCnPcj9PPCWhPN;n`i1Q#Qn>ii z{WR|0>8F`vf&#E(c2NsoH=I7Cd-FV|%(7a`i}gZw4N~QFFG2WtS^H%@c?%9UZ+kez z;PwGgg_r6V>Kn5n(nZ40P4qMyrCP3bDkJp@hp6&X3>gzC>=f@Hsen<%I~7W+x@}b> z0}Et*vx_50-q@PIV=(3&Tbm}}QRo*FP2@)A#XX-8jYspIhah`9ukPBr)$8>Tmtg&R z?JBoH17?+1@Y@r>anoKPQ}F8o9?vhcG79Cjv^V6ct709VOQwg{c0Q#rBSsSmK3Q;O zBpNihl3S0_IGVE)^`#94#j~$;7+u870yWiV$@={|GrBmuz4b)*bCOPkaN0{6$MvazOEBxFdKZDlbVvv{8_*kJ zfE6C`4&Kkz<5u%dEdStd85-5UHG5IOWbo8i9azgg#zw-(P1AA049hddAB*UdG3Vn0 zX`OgM+EM|<+KhJ<=k?z~WA5waVj?T9eBdfJGebVifBKS1u<$#vl^BvSg)xsnT5Aw_ZY#}v*LXO#htB>f}x3qDdDHoFeb zAq7;0CW;XJ`d&G*9V)@H&739DpfWYzdQt+Kx_E1K#Cg1EMtFa8eQRk_JuUdHD*2;W zR~XFnl!L2A?48O;_iqCVr1oxEXvOIiN_9CUVTZs3C~P+11}ebyTRLACiJuMIG#`xP zKlC|E(S@QvN+%pBc6vPiQS8KgQAUh75C0a2xcPQDD$}*bM&z~g8+=9ltmkT$;c;s z5_=8%i0H^fEAOQbHXf0;?DN5z-5+1 zDxj50yYkz4ox9p$HbZ|H?8ukAbLE^P$@h}L%i6QVcY>)i!w=hkv2zvrduut%!8>6b zcus3bh1w~L804EZ*s96?GB&F7c5?m?|t$-tp2rKMy>F*=4;w*jW}^;8v`st&8)c; z2Ct2{)?S(Z;@_mjAEjb8x=qAQvx=}S6l9?~H?PmP`-xu;ME*B8sm|!h@BX4>u(xg_ zIHmQzp4Tgf*J}Y=8STR5_s)GKcmgV!$JKTg@LO402{{Wrg>#D4-L%vjmtJ4r?p&$F!o-BOf7ej~ z6)BuK^^g1b#(E>$s`t3i13{6-mmSp7{;QkeG5v}GAN&lM2lQT$@(aQCcFP(%UyZbF z#$HLTqGT^@F#A29b0HqiJsRJAlh8kngU`BDI6 zJUE~&!cQ*&f95Ot$#mxU5+*^$qg_DWNdfu+1irglB7yDglzH()2!@#rpu)^3S8weW z_FE$=j^GTY*|5SH95O8o8W9FluYwB=2PwtbW|JG6kcV^dMVmX(wG+Otj;E$%gfu^K z!t~<3??8=()WQSycsBKy24>NjRtuZ>zxJIED;YXaUz$@0z4rl+TW zWxmvM$%4jYIpO>j5k1t1&}1VKM~s!eLsCVQ`TTjn3JRXZD~>GM z$-IT~(Y)flNqDkC%DfbxaV9?QuWCV&-U1yzrV@0jRhE;)ZO0=r-{s@W?HOFbRHDDV zq;eLo+wOW;nI|#mNf(J?RImB9{YSO2Y`9825Lz#u4(nk3)RGv3X8B(A$TsontJ8L! z9JP^eWxtKC?G8^xAZa1HECx*rp35s!^%;&@Jyk)NexVc)@U4$^X1Dag6`WKs|(HhZ#rzO2KEw3xh~-0<;|zcs0L>OcO#YYX{SN8m6`9pp+ zQG@q$I)T?aoe#AoR@%om_#z=c@ych!bj~lV13Qi-xg$i$hXEAB#l=t7QWENGbma4L zbBf*X*4oNYZUd_;1{Ln_ZeAwQv4z?n9$eoxJeI?lU9^!AB2Y~AwOSq67dT9ADZ)s@ zCRYS7W$Zpkdx$3T>7$I%3EI2ik~m!f7&$Djpt6kZqDWZJ-G{*_eXs*B8$1R4+I}Kf zqniwCI64r;>h2Lu{0c(#Atn)%E8&)=0S4BMhq9$`vu|Ct;^ur~gL`bD>J@l)P$q_A zO7b3HGOUG`vgH{}&&AgrFy%K^>? z>wf**coZ2vdSDcNYSm~dZ(vk6&m6bVKmVgrx-X<>{QzA!)2*L+HLTQz$e8UcB&Djq zl)-%s$ZtUN-R!4ZiG=L0#_P=BbUyH+YPmFl_ogkkQ$=s@T1v}rNnZ^eMaqJ|quc+6 z*ygceDOrldsL30w`H;rNu+IjlS+G~p&0SawXCA1+D zC%cZtjUkLNq%FadtHE?O(yQTP486A{1x<{krq#rpauNQaeyhM3*i0%tBpQHQo-u)x z{0{&KS`>}vf2_}b160XZO2$b)cyrHq7ZSeiSbRvaxnKUH{Q`-P(nL&^fcF2){vhN- zbX&WEjP7?b4A%0y6n_=m%l00uZ+}mCYO(!x?j$+O$*TqoD_Q5EoyDJ?w?^UIa491H zE}87(bR`X;@u#3Qy~9wWdWQIg1`cXrk$x9=ccR|RY1~%{fAJ@uq@J3e872x0v$hmv ze_KcL(wM|n0EOp;t{hKoohYyDmYO;!`7^Lx;0k=PWPGZpI>V5qYlzjSL_(%|mud50 z7#{p97s`U|Sn$WYF>-i{i4`kzlrV6a<}=72q2sAT7Zh{>P%*6B;Zl;~0xWymt10Mo zl5{bmR(wJefJpNGK=fSRP|mpCI-)Nf6?Pv==FcFmpSwF1%CTOucV{yqxSyx4Zws3O z8hr5Uyd%ezIO7?PnEO0T%af#KOiXD$e?V&OX-B|ZX-YsgSs%sv-6U+sLPuz{D4bq| zpd&|o5tNCmpT>(uIbRf?8c}d3IpOb3sn6>_dr*26R#ev<_~vi)wleW$PX|5)$_ z+_|=pi(0D(AB_sjQ;sQQSM&AWqzDO1@NHw;C9cPdXRKRI#@nUW)CgFxzQ1nyd!+h& zcjU!U=&u|>@}R(9D$%lu2TlV>@I2-n@fCr5PrZNVyKWR7hm zWjoy^p7v8m#$qN0K#8jT- zq`mSirDZDa1Jxm;Rg3rAPhC)LcI4@-RvKT+@9&KsR3b0_0zuM!Fg7u>oF>3bzOxZPU&$ab$Z9@ zY)f7pKh22I7ZykL{YsdjcqeN++=0a}elQM-4;Q)(`Ep3|VFHqnXOh14`!Bus& z9w%*EWK6AiAM{s$6~SEQS;A>ey$#`7)khZvamem{P?>k)5&7Sl&&NXKk}o!%vd;-! zpo2p-_h^b$DNBO>{h4JdGB=D>fvGIYN8v&XsfxU~VaefL?q} z3ekM?iOKkCzQHkBkhg=hD!@&(L}FcHKoa zbZ7)H1C|lHjwEb@tu=n^OvdHOo7o+W`0-y3KdP#bb~wM=Vr_gyoEq|#B?$&d$tals ziIs-&7isBpvS|CjC|7C&3I0SE?~`a%g~$PI%;au^cUp@ER3?mn-|vyu!$7MV6(uvt z+CcGuM(Ku2&G0tcRCo7#D$Dirfqef2qPOE5I)oCGzmR5G!o#Q~(k~)c=LpIfrhHQk zeAva6MilEifE7rgP1M7AyWmLOXK}i8?=z2;N=no)`IGm#y%aGE>-FN zyXCp0Sln{IsfOBuCdE*#@CQof%jzuU*jkR*Su3?5t}F(#g0BD0Zzu|1MDes8U7f9; z$JBg|mqTXt`muZ8=Z`3wx$uizZG_7>GI7tcfOHW`C2bKxNOR)XAwRkLOaHS4xwlH4 zDpU29#6wLXI;H?0Se`SRa&I_QmI{zo7p%uveBZ0KZKd9H6@U?YGArbfm)D*^5=&Rp z`k{35?Z5GbZnv>z@NmJ%+sx=1WanWg)8r}C_>EGR8mk(NR$pW<-l8OTU^_u3M@gwS z7}GGa1)`z5G|DZirw;FB@VhH7Dq*0qc=|9lLe{w2#`g+_nt>_%o<~9(VZe=zI*SSz4w43-_o>4E4`M@NPKTWZuQJs)?KXbWp1M zimd5F;?AP(LWcaI-^Sl{`~>tmxsQB9Y$Xi*{Zr#py_+I$vx7@NY`S?HFfS!hUiz$a z{>!&e1(16T!Om)m)&k1W#*d#GslD^4!TwiF2WjFBvi=Ms!ADT)ArEW6zfVuIXcXVk z>AHjPADW+mJzY`_Ieq(s?jbk4iD2Rb8*V3t6?I+E06(K8H!!xnDzO%GB;Z$N-{M|B zeT`jo%9)s%op*XZKDd6*)-^lWO{#RaIGFdBH+;XXjI(8RxpBc~azG1H^2v7c^bkFE zZCVPE+E*Q=FSe8Vm&6|^3ki{9~qafiMAf7i4APZg>b%&5>nT@pHH z%O*pOv(77?ZiT{W zBibx}Q12tRc7Py1NcZTp`Q4ey%T_nj@1WKg5Fz_Rjl4wlJQj)rtp8yL3r!Shy zvZvnmh!tH4T6Js-?vI0<-rzzl{mgT*S0d_7^AU_8gBg^03o-J=p(1o6kww2hx|!%T z-jqp}m^G*W?$!R#M%Ef?&2jYxmx+lXWZszpI4d$pUN`(S)|*c^CgdwY>Fa>> zgGBJhwe8y#Xd*q0=@SLEgPF>+Qe4?%E*v{a`||luZ~&dqMBrRfJ{SDMaJ!s_;cSJp zSqZHXIdc@@XteNySUZs^9SG7xK`8=NBNM)fRVOjw)D^)w%L2OPkTQ$Tel-J)GD3=YXy+F4in(ILy*A3m@3o73uv?JC}Q>f zrY&8SWmesiba0|3X-jmlMT3 z*ST|_U@O=i*sM_*48G)dgXqlwoFp5G6qSM3&%_f_*n!PiT>?cNI)fAUkA{qWnqdMi+aNK_yVQ&lx4UZknAc9FIzVk% zo6JmFH~c{_tK!gt4+o2>)zoP{sR}!!vfRjI=13!z5}ijMFQ4a4?QIg-BE4T6!#%?d&L;`j5=a`4is>U;%@Rd~ zXC~H7eGQhhYWhMPWf9znDbYIgwud(6$W3e>$W4$~d%qoJ z+JE`1g$qJ%>b|z*xCKenmpV$0pM=Gl-Y*LT8K+P)2X#;XYEFF4mRbc~jj?DM@(1e`nL=F4Syv)TKIePQUz)bZ?Bi3@G@HO$Aps1DvDGkYF50O$_welu^cL7;vPiMGho74$;4fDqKbE{U zd1h{;LfM#Fb|Z&uH~Rm_J)R~Vy4b;1?tW_A)Iz#S_=F|~pISaVkCnQ0&u%Yz%o#|! zS-TSg87LUfFSs{tTuM3$!06ZzH&MFtG)X-l7>3)V?Txuj2HyG*5u;EY2_5vU0ujA? zHXh5G%6e3y7v?AjhyX79pnRBVr}RmPmtrxoB7lkxEzChX^(vKd+sLh?SBic=Q)5nA zdz7Mw3_iA>;T^_Kl~?1|5t%GZ;ki_+i>Q~Q1EVdKZ)$Sh3LM@ea&D~{2HOG++7*wF zAC6jW4>fa~!Vp5+$Z{<)Qxb|{unMgCv2)@%3j=7)Zc%U<^i|SAF88s!A^+Xs!OASYT%7;Jx?olg_6NFP1475N z#0s<@E~FI}#LNQ{?B1;t+N$2k*`K$Hxb%#8tRQi*Z#No0J}Pl;HWb){l7{A8(pu#@ zfE-OTvEreoz1+p`9sUI%Y{e5L-oTP_^NkgpYhZjp&ykinnW;(fu1;ttpSsgYM8ABX4dHe_HxU+%M(D=~) zYM}XUJ5guZ;=_ZcOsC`_{CiU$zN3$+x&5C`vX-V3`8&RjlBs^rf00MNYZW+jCd~7N z%{jJuUUwY(M`8$`B>K&_48!Li682ZaRknMgQ3~dnlp8C?__!P2z@=Auv;T^$yrsNy zCARmaA@^Yo2sS%2$`031-+h9KMZsIHfB>s@}>Y(z988e!`%4=EDoAQ0kbk>+lCoK60Mx9P!~I zlq~wf7kcm_NFImt3ZYlE(b3O1K^QWiFb$V^a2Jlwvm(!XYx<`i@ZMS3UwFt{;x+-v zhx{m=m;4dgvkKp5{*lfSN3o^keSpp9{hlXj%=}e_7Ou{Yiw(J@NXuh*;pL6@$HsfB zh?v+r^cp@jQ4EspC#RqpwPY(}_SS$wZ{S959`C25777&sgtNh%XTCo9VHJC-G z;;wi9{-iv+ETiY;K9qvlEc04f;ZnUP>cUL_T*ms``EtGoP^B#Q>n2dSrbAg8a>*Lg zd0EJ^=tdW~7fbcLFsqryFEcy*-8!?;n%;F+8i{eZyCDaiYxghr z$8k>L|2&-!lhvuVdk!r-kpSFl`5F5d4DJr%M4-qOy3gdmQbqF1=aBtRM7)c_Ae?$b8 zQg4c8*KQ{XJmL)1c7#0Yn0#PTMEs4-IHPjkn0!=;JdhMXqzMLeh`yOylXROP- zl#z3+fwM9l3%VN(6R77ua*uI9%hO7l7{+Hcbr(peh;afUK?B4EC09J{-u{mv)+u#? zdKVBCPt`eU@IzL)OXA`Ebu`Xp?u0m%h&X41}FNfnJ*g1!1wcbbpo%F4x!-#R9ft!8{5`Ho}04?FI#Kg zL|k`tF1t_`ywdy8(wnTut>HND(qNnq%Sq=AvvZbXnLx|mJhi!*&lwG2g|edBdVgLy zjvVTKHAx(+&P;P#2Xobo7_RttUi)Nllc}}hX>|N?-u5g7VJ-NNdwYcaOG?NK=5)}` zMtOL;o|i0mSKm(UI_7BL_^6HnVOTkuPI6y@ZLR(H?c1cr-_ouSLp{5!bx^DiKd*Yb z{K78Ci&Twup zTKm)ioN|wcYy%Qnwb)IzbH>W!;Ah5Zdm_jRY`+VRJ2 zhkspZ9hbK3iQD91A$d!0*-1i#%x81|s+SPRmD}d~<1p6!A13(!vABP2kNgqEG z?AMgl^P+iRoIY(9@_I?n1829lGvAsRnHwS~|5vD2+Zi53j<5N4wNn0{q>>jF9*bI) zL$kMXM-awNOElF>{?Jr^tOz1glbwaD-M0OKOlTeW3C!1ZyxRbB>8JDof(O&R1bh%3x#>y2~<>OXO#IIedH0Q`(&&?eo-c~ z>*Ah#3~09unym~UC-UFqqI>{dmUD$Y4@evG#ORLI*{ZM)Jl=e1it!XzY($S3V zLG!Y6fCjE>x6r@5FG1n|8ompSZaJ>9)q6jqU;XxCQk9zV(?C9+i*>w z21+KYt1gXX&0`x3E)hS7I5}snbBzox9C@Xzcr|{B8Hw;SY1$}&BoYKXH^hpjW-RgJ z-Fb}tannKCv>y~^`r|(1Q9;+sZlYf3XPSX|^gR01UFtu$B*R;$sPZdIZShRr>|b@J z;#G{EdoY+O;REEjQ}X7_YzWLO+Ey3>a_KDe1CjSe| z6arqcEZ)CX!8r(si`dqbF$uu&pnf^Np{1f*TdJ`r2;@SaZ z#hb4xlaCA@Pwqj#LlUEe5L{I$k(Zj$d3(~)u(F%&xb8={N9hKxlZIO1ABsM{Mt|)2 zJ^t9Id;?%4PfR4&Ph9B9cFK~@tG3wlFW-0fXZS_L4U*EiAA%+`h%q2^6BCC;t0iO4V=s4Qug{M|iDV@s zC7|ef-dxiR7T&Mpre!%hiUhHM%3Qxi$Lzw6&(Tvlx9QA_7LhYq<(o~=Y>3ka-zrQa zhGpfFK@)#)rtfz61w35^sN1=IFw&Oc!Nah+8@qhJ0UEGr;JplaxOGI82OVqZHsqfX ze1}r{jy;G?&}Da}a7>SCDsFDuzuseeCKof|Dz2BPsP8? zY;a)Tkr2P~0^2BeO?wnzF_Ul-ekY=-w26VnU%U3f19Z-pj&2 z4J_a|o4Dci+MO)mPQIM>kdPG1xydiR9@#8m zh27D7GF{p|a{8({Q-Pr-;#jV{2zHR>lGoFtIfIpoMo?exuQyX_A;;l0AP4!)JEM$EwMInZkj+8*IHP4vKRd zKx_l-i*>A*C@{u%ct`y~s6MWAfO{@FPIX&sg8H{GMDc{4M3%$@c8&RAlw0-R<4DO3 trJqdc$mBpWeznn?E0M$F`|3v=`3%T2A17h;rxP7$%JLd=6(2u;`(N3pt&so# literal 0 HcmV?d00001 diff --git a/_static/bootstrap-2.3.2/js/bootstrap.js b/_static/bootstrap-2.3.2/js/bootstrap.js new file mode 100644 index 00000000..638bb187 --- /dev/null +++ b/_static/bootstrap-2.3.2/js/bootstrap.js @@ -0,0 +1,2287 @@ +/* =================================================== + * bootstrap-transition.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#transitions + * =================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) + * ======================================================= */ + + $(function () { + + $.support.transition = (function () { + + var transitionEnd = (function () { + + var el = document.createElement('bootstrap') + , transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + , name + + for (name in transEndEventNames){ + if (el.style[name] !== undefined) { + return transEndEventNames[name] + } + } + + }()) + + return transitionEnd && { + end: transitionEnd + } + + })() + + }) + +}(window.$jqTheme || window.jQuery); +/* ========================================================== + * bootstrap-alert.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent.trigger(e = $.Event('close')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT NO CONFLICT + * ================= */ + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + /* ALERT DATA-API + * ============== */ + + $(document).on('click.alert.data-api', dismiss, Alert.prototype.close) + +}(window.$jqTheme || window.jQuery); +/* ============================================================ + * bootstrap-button.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON NO CONFLICT + * ================== */ + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + /* BUTTON DATA-API + * =============== */ + + $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + +}(window.$jqTheme || window.jQuery); +/* ========================================================== + * bootstrap-carousel.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.prototype = { + + cycle: function (e) { + if (!e) this.paused = false + if (this.interval) clearInterval(this.interval); + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + return this + } + + , getActiveIndex: function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + return this.$items.index(this.$active) + } + + , to: function (pos) { + var activeIndex = this.getActiveIndex() + , that = this + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activeIndex == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + , pause: function (e) { + if (!e) this.paused = true + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.item.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + , e + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + e = $.Event('slide', { + relatedTarget: $next[0] + , direction: direction + }) + + if ($next.hasClass('active')) return + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) + , action = typeof option == 'string' ? option : options.slide + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + , pause: 'hover' + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL NO CONFLICT + * ==================== */ + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + /* CAROUSEL DATA-API + * ================= */ + + $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = $.extend({}, $target.data(), $this.data()) + , slideIndex + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('carousel').pause().to(slideIndex).cycle() + } + + e.preventDefault() + }) + +}(window.$jqTheme || window.jQuery); +/* ============================================================= + * bootstrap-collapse.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options.parent) { + this.$parent = $(this.options.parent) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension + , scroll + , actives + , hasData + + if (this.transitioning || this.$element.hasClass('in')) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + + if (actives && actives.length) { + hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', $.Event('show'), 'shown') + $.support.transition && this.$element[dimension](this.$element[0][scroll]) + } + + , hide: function () { + var dimension + if (this.transitioning || !this.$element.hasClass('in')) return + dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', $.Event('hide'), 'hidden') + this.$element[dimension](0) + } + + , reset: function (size) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') + + return this + } + + , transition: function (method, startEvent, completeEvent) { + var that = this + , complete = function () { + if (startEvent.type == 'show') that.reset() + that.transitioning = 0 + that.$element.trigger(completeEvent) + } + + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + + /* COLLAPSE PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSE NO CONFLICT + * ==================== */ + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + /* COLLAPSE DATA-API + * ================= */ + + $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + $(target).collapse(option) + }) + +}(window.$jqTheme || window.jQuery); +/* ============================================================ + * bootstrap-dropdown.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , isActive + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement) { + // if mobile we we use a backdrop because click events don't delegate + $('