Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
PYGW_TEST_DATA="{project}/tests/londonhp100.csv"
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: >
python "${{ github.workspace }}/tools/repair_windows_wheel.py" {wheel} {dest_dir}
CIBW_TEST_COMMAND: "pytest {project}/tests -v --ignore={project}/tests/test_gwss.py"
CIBW_TEST_COMMAND: "pytest {project}/tests -v"
CIBW_TEST_REQUIRES: pytest

- name: Upload wheels
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
CMAKE_ARGS: "-DWITH_TESTS=OFF"

- name: Run tests
run: python -m pytest test/ -v --ignore=test/test_gwss.py
run: python -m pytest test/ -v
env:
PYGW_TEST_DATA: test/londonhp100.csv

Expand Down Expand Up @@ -116,6 +116,6 @@ jobs:
pip install $wheel

- name: Run tests
run: python -m pytest test/ -v --ignore=test/test_gwss.py
run: python -m pytest test/ -v
env:
PYGW_TEST_DATA: test/londonhp100.csv
3 changes: 2 additions & 1 deletion doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Implemented Models
* **GWRBasic** — Basic Geographically Weighted Regression with a single bandwidth.
* **GWRMultiscale** — Multiscale GWR (MGWR) with per-variable bandwidths and
backfitting algorithm.
* **GWSS** — Geographically Weighted Summary Statistics (averages and correlations).
* **GWAverage** — Geographically Weighted Summary Statistics (mean, std dev, etc.).
* **GWCorrelation** — Geographically Weighted Correlation coefficients.

Quick Start
-----------
Expand Down
1 change: 1 addition & 0 deletions doc/models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ Regression Models

models/gwr
models/gwr_multiscale
models/gwss
68 changes: 42 additions & 26 deletions doc/models/gwss.rst
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
Geographically Weighted Summary Statistics (GWSS)
=================================================
Geographically Weighted Summary Statistics (GWAverage / GWCorrelation)
======================================================================

.. _gwss-overview:

Model Overview
--------------

Geographically Weighted Summary Statistics (GWSS) performs locally weighted
Geographically Weighted Summary Statistics performs locally weighted
descriptive statistics on multivariate data, revealing spatial heterogeneity
in the statistical characteristics of variables.

GWSS supports two modes:
Two classes are provided:

- Average mode — computes local mean, standard deviation, variance, skewness,
coefficient of variation, and optionally local median, interquartile range,
and quantile imbalance.
- Correlation mode — computes local Pearson correlation coefficients and
Spearman rank correlation coefficients.
- :class:`~pygwmodel.gwss.GWAverage` — computes local mean, standard deviation,
variance, skewness, coefficient of variation, and optionally local median,
interquartile range, and quantile imbalance.
- :class:`~pygwmodel.gwss.GWCorrelation` — computes local Pearson correlation
coefficients and Spearman rank correlation coefficients for every pair of
variables.

.. _gwss-modes:
.. _gwss-average:

Two Modes
GWAverage
---------

Average Mode
~~~~~~~~~~~~

For each variable, the following local statistics are computed:

.. list-table::
Expand Down Expand Up @@ -67,8 +65,10 @@ When ``quantile=True``:
- ``qi``
- ``{variable}_QI``

Correlation Mode
~~~~~~~~~~~~~~~~
.. _gwss-correlation:

GWCorrelation
-------------

For each pair of variables :math:`(X_i, X_j)`, the following are computed:

Expand All @@ -83,35 +83,51 @@ Column name format: ``{var1}.{var2}_Corr`` and ``{var1}.{var2}_SCorr``.
Code Examples
-------------

Average Mode
~~~~~~~~~~~~
GWAverage
~~~~~~~~~

.. code-block:: python

from pygwmodel import GWSS, BandwidthWeight
from pygwmodel import GWAverage, BandwidthWeight

vars = ["PURCHASE", "FLOORSZ", "UNEMPLOY", "PROF"]

gwss = GWSS(
gwa = GWAverage(
data, vars,
weight=BandwidthWeight(36.0, adaptive=True),
mode=GWSS.Mode.Average,
quantile=False
).run()

result = gwss.result_layer
result = gwa.result_layer
print(result.columns)
# PURCHASE_Mean, PURCHASE_SDev, PURCHASE_Skew, PURCHASE_CV,
# FLOORSZ_Mean, ...

Correlation Mode
~~~~~~~~~~~~~~~~
GWCorrelation
~~~~~~~~~~~~~

.. code-block:: python

gwss = GWSS(data, vars, weight=BandwidthWeight(36.0, adaptive=True))
result = gwss.run(mode=GWSS.Mode.Correlation).result_layer
from pygwmodel import GWCorrelation, BandwidthWeight

gwc = GWCorrelation(data, vars, weight=BandwidthWeight(36.0, adaptive=True))
result = gwc.run().result_layer

print(result.columns)
# PURCHASE.FLOORSZ_Corr, PURCHASE.FLOORSZ_SCorr,
# PURCHASE.UNEMPLOY_Corr, ...

Parallel Execution
~~~~~~~~~~~~~~~~~~

Both classes support OpenMP multi-threading:

.. code-block:: python

from pygwmodel import GWAverage, GWCorrelation, ParallelType

gwa = GWAverage(data, vars, weight=...)
gwa.enable_parallel(ParallelType.OpenMP, threads=4).run()

gwc = GWCorrelation(data, vars, weight=...)
gwc.enable_parallel(ParallelType.OpenMP, threads=4).run()
12 changes: 6 additions & 6 deletions doc/pygwmodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ pygwmodel.gwr_multiscale module
:undoc-members:
:show-inheritance:

.. pygwmodel.gwss module (disabled — _analysis module needs _GWSS binding update)
.. ---------------------
pygwmodel.gwss module
---------------------

.. .. automodule:: pygwmodel.gwss
.. :members:
.. :undoc-members:
.. :show-inheritance:
.. automodule:: pygwmodel.gwss
:members:
:undoc-members:
:show-inheritance:

pygwmodel.parallel module
-------------------------
Expand Down
3 changes: 2 additions & 1 deletion doc/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Currently implemented models:

- **Geographically Weighted Regression (GWR)** — :class:`~pygwmodel.gwr_basic.GWRBasic`
- **Multiscale GWR (MGWR)** — :class:`~pygwmodel.gwr_multiscale.GWRMultiscale`
- **Geographically Weighted Summary Statistics (GWSS)** — :class:`~pygwmodel.gwss.GWSS`
- **GW Average** — :class:`~pygwmodel.gwss.GWAverage`
- **GW Correlation** — :class:`~pygwmodel.gwss.GWCorrelation`

All algorithms use a C++17 core, exposed to Python via
`nanobind <https://github.com/wjakob/nanobind>`_, with support for
Expand Down
5 changes: 3 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ target_link_libraries(_spatial_weight PRIVATE gwmodel)
nanobind_add_module(_regression STABLE_ABI common.hpp parallel.hpp base.cpp gwr_basic.cpp gwr_multiscale.cpp regression.cpp)
target_link_libraries(_regression PRIVATE gwmodel)

# nanobind_add_module(_analysis STABLE_ABI common.hpp base.cpp parallel.hpp analysis.cpp gwss.cpp)
# target_link_libraries(_analysis PRIVATE gwmodel)
nanobind_add_module(_analysis STABLE_ABI common.hpp base.cpp parallel.hpp analysis.cpp gwss.cpp)
target_link_libraries(_analysis PRIVATE gwmodel)

install(TARGETS
_regression
_spatial_weight
_parallel
_analysis
LIBRARY DESTINATION pygwmodel)
77 changes: 49 additions & 28 deletions src/gwss.cpp
Original file line number Diff line number Diff line change
@@ -1,42 +1,63 @@
#include <nanobind/nanobind.h>
#include <GWSS.h>
#include <nanobind/stl/vector.h>
#include <GWAverage.h>
#include <GWCorrelation.h>
#include "common.hpp"
#include "parallel.hpp"

namespace nb = nanobind;

void init_gwss(nb::module_& m)
{
nb::class_<gwm::GWSS, gwm::SpatialMonoscaleAlgorithm> _GWSS(m, "_GWSS");
nb::class_<gwm::GWAverage, gwm::SpatialMonoscaleAlgorithm> _GWAverage(m, "_GWAverage");
_GWAverage
.def(nb::init<>())
.def_prop_rw("variables", &gwm::GWAverage::variables, &gwm::GWAverage::setVariables, nb::rv_policy::move)
.def_prop_rw("quantile", &gwm::GWAverage::quantile, &gwm::GWAverage::setQuantile)
.def("run", &gwm::GWAverage::run)
.def_prop_ro("local_mean", &gwm::GWAverage::localMean, nb::rv_policy::move)
.def_prop_ro("local_sdev", &gwm::GWAverage::localSDev, nb::rv_policy::move)
.def_prop_ro("local_skewness", &gwm::GWAverage::localSkewness, nb::rv_policy::move)
.def_prop_ro("local_cv", &gwm::GWAverage::localCV, nb::rv_policy::move)
.def_prop_ro("local_var", &gwm::GWAverage::localVar, nb::rv_policy::move)
.def_prop_ro("local_median", &gwm::GWAverage::localMedian, nb::rv_policy::move)
.def_prop_ro("iqr", &gwm::GWAverage::iqr, nb::rv_policy::move)
.def_prop_ro("qi", &gwm::GWAverage::qi, nb::rv_policy::move)
;
def_parallel_info(_GWAverage);
def_parallel_openmp(_GWAverage);

nb::class_<gwm::GWCorrelation, gwm::SpatialMultiscaleAlgorithm> _GWCorrelation(m, "_GWCorrelation");

nb::enum_<gwm::GWCorrelation::BandwidthInitilizeType>(_GWCorrelation, "BandwidthInitilizeType")
.value("Null", gwm::GWCorrelation::BandwidthInitilizeType::Null)
.value("Initial", gwm::GWCorrelation::BandwidthInitilizeType::Initial)
.value("Specified", gwm::GWCorrelation::BandwidthInitilizeType::Specified)
.export_values()
;

nb::enum_<gwm::GWSS::GWSSMode>(_GWSS, "Mode")
.value("Average", gwm::GWSS::GWSSMode::Average)
.value("Correlation", gwm::GWSS::GWSSMode::Correlation)
nb::enum_<gwm::GWCorrelation::BandwidthSelectionCriterionType>(_GWCorrelation, "BandwidthSelectionCriterionType")
.value("CV", gwm::GWCorrelation::BandwidthSelectionCriterionType::CV)
.value("AIC", gwm::GWCorrelation::BandwidthSelectionCriterionType::AIC)
.export_values()
;

_GWSS
_GWCorrelation
.def(nb::init<>())
.def("set_mode", [](gwm::GWSS &instance, int mode)
{
instance.setGWSSMode(gwm::GWSS::GWSSMode(mode));
})
.def_prop_rw("variables", &gwm::GWSS::variables, &gwm::GWSS::setVariables, nb::rv_policy::move)
.def_prop_rw("quantile", &gwm::GWSS::quantile, &gwm::GWSS::setQuantile)
.def_prop_rw("corr_with_first", &gwm::GWSS::isCorrWithFirstOnly, &gwm::GWSS::setIsCorrWithFirstOnly)
.def("run", &gwm::GWSS::run)
.def_prop_ro("local_mean", &gwm::GWSS::localMean, nb::rv_policy::move)
.def_prop_ro("local_sdev", &gwm::GWSS::localSDev, nb::rv_policy::move)
.def_prop_ro("local_skewness", &gwm::GWSS::localSkewness, nb::rv_policy::move)
.def_prop_ro("local_cv", &gwm::GWSS::localCV, nb::rv_policy::move)
.def_prop_ro("local_var", &gwm::GWSS::localVar, nb::rv_policy::move)
.def_prop_ro("local_median", &gwm::GWSS::localMedian, nb::rv_policy::move)
.def_prop_ro("iqr", &gwm::GWSS::iqr, nb::rv_policy::move)
.def_prop_ro("qi", &gwm::GWSS::qi, nb::rv_policy::move)
.def_prop_ro("local_cov", &gwm::GWSS::localCov, nb::rv_policy::move)
.def_prop_ro("local_corr", &gwm::GWSS::localCorr, nb::rv_policy::move)
.def_prop_ro("local_s_corr", &gwm::GWSS::localSCorr, nb::rv_policy::move)
.def_prop_rw("variables1", &gwm::GWCorrelation::variables1, &gwm::GWCorrelation::setVariables1, nb::rv_policy::move)
.def_prop_rw("variables2", &gwm::GWCorrelation::variables2, &gwm::GWCorrelation::setVariables2, nb::rv_policy::move)
.def_prop_rw("bandwidth_initilize", &gwm::GWCorrelation::bandwidthInitilize, &gwm::GWCorrelation::setBandwidthInitilize)
.def_prop_rw("bandwidth_selection_approach", &gwm::GWCorrelation::bandwidthSelectionApproach, &gwm::GWCorrelation::setBandwidthSelectionApproach)
.def("run", &gwm::GWCorrelation::run)
.def_prop_ro("local_mean", &gwm::GWCorrelation::localMean, nb::rv_policy::move)
.def_prop_ro("local_sdev", &gwm::GWCorrelation::localSDev, nb::rv_policy::move)
.def_prop_ro("local_skewness", &gwm::GWCorrelation::localSkewness, nb::rv_policy::move)
.def_prop_ro("local_cv", &gwm::GWCorrelation::localCV, nb::rv_policy::move)
.def_prop_ro("local_var", &gwm::GWCorrelation::localVar, nb::rv_policy::move)
.def_prop_ro("local_cov", &gwm::GWCorrelation::localCov, nb::rv_policy::move)
.def_prop_ro("local_corr", &gwm::GWCorrelation::localCorr, nb::rv_policy::move)
.def_prop_ro("local_s_corr", &gwm::GWCorrelation::localSCorr, nb::rv_policy::move)
;

def_parallel_info(_GWSS);
def_parallel_openmp(_GWSS);
def_parallel_info(_GWCorrelation);
def_parallel_openmp(_GWCorrelation);
}
1 change: 1 addition & 0 deletions src/pygwmodel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def _add_windows_dll_directories():
from .gwr_basic import GWRBasic, ParallelType
from .gwr_multiscale import GWRMultiscale
from .spatial_weight import SpatialWeight, BandwidthWeight, CRSDistance
from .gwss import GWAverage, GWCorrelation

if __name__ == "__main__":
print("PyGWmodel Package.")
Loading
Loading