segstats 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- segstats-0.1.0/CHANGELOG.md +24 -0
- segstats-0.1.0/CITATION.cff +21 -0
- segstats-0.1.0/LICENSE +21 -0
- segstats-0.1.0/MANIFEST.in +9 -0
- segstats-0.1.0/PKG-INFO +282 -0
- segstats-0.1.0/README.md +244 -0
- segstats-0.1.0/examples/quickstart.py +69 -0
- segstats-0.1.0/pyproject.toml +116 -0
- segstats-0.1.0/setup.cfg +4 -0
- segstats-0.1.0/src/segstats/__init__.py +124 -0
- segstats-0.1.0/src/segstats/__main__.py +7 -0
- segstats-0.1.0/src/segstats/_arrays.py +84 -0
- segstats-0.1.0/src/segstats/_version.py +1 -0
- segstats-0.1.0/src/segstats/aspatial.py +203 -0
- segstats-0.1.0/src/segstats/cli.py +220 -0
- segstats-0.1.0/src/segstats/data.py +233 -0
- segstats-0.1.0/src/segstats/geometry.py +354 -0
- segstats-0.1.0/src/segstats/indices.py +327 -0
- segstats-0.1.0/src/segstats/inference.py +329 -0
- segstats-0.1.0/src/segstats/local.py +65 -0
- segstats-0.1.0/src/segstats/py.typed +0 -0
- segstats-0.1.0/src/segstats/spatial.py +375 -0
- segstats-0.1.0/src/segstats/weights.py +79 -0
- segstats-0.1.0/src/segstats.egg-info/PKG-INFO +282 -0
- segstats-0.1.0/src/segstats.egg-info/SOURCES.txt +36 -0
- segstats-0.1.0/src/segstats.egg-info/dependency_links.txt +1 -0
- segstats-0.1.0/src/segstats.egg-info/entry_points.txt +2 -0
- segstats-0.1.0/src/segstats.egg-info/requires.txt +10 -0
- segstats-0.1.0/src/segstats.egg-info/top_level.txt +1 -0
- segstats-0.1.0/tests/conftest.py +51 -0
- segstats-0.1.0/tests/test_aspatial.py +138 -0
- segstats-0.1.0/tests/test_cli.py +83 -0
- segstats-0.1.0/tests/test_data_local.py +122 -0
- segstats-0.1.0/tests/test_geometry.py +137 -0
- segstats-0.1.0/tests/test_indices.py +112 -0
- segstats-0.1.0/tests/test_inference.py +115 -0
- segstats-0.1.0/tests/test_reference_pysal.py +87 -0
- segstats-0.1.0/tests/test_spatial.py +164 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.1.0] - 2026-11-09
|
|
8
|
+
### Added
|
|
9
|
+
- Evenness: dissimilarity D, Gini, entropy (Theil H), Atkinson; multigroup D and H.
|
|
10
|
+
- Exposure: isolation xPx, interaction xPy, correlation ratio (eta squared), exposure matrix.
|
|
11
|
+
- Concentration: delta, absolute and relative concentration.
|
|
12
|
+
- Centralization: absolute and relative centralization (ties in distance grouped).
|
|
13
|
+
- Clustering: absolute clustering, relative clustering, spatial proximity, negative
|
|
14
|
+
exponential proximity matrix.
|
|
15
|
+
- Spatial evenness: Morrill D(adj), Wong D(w) and D(s), Reardon & O'Sullivan spatial
|
|
16
|
+
dissimilarity and spatial information theory index with kernel or contiguity
|
|
17
|
+
neighbourhoods.
|
|
18
|
+
- Local measures: location quotients, local entropy, local spatial entropy, per-zone
|
|
19
|
+
contributions to D.
|
|
20
|
+
- Pure-Python GeoJSON geometry: areas, perimeters, centroids, queen/rook contiguity and
|
|
21
|
+
shared boundary lengths (T-junctions handled), on-the-fly lon/lat projection.
|
|
22
|
+
- Index registry (`compute`, `profile`, `statistic`), random-allocation and zone-shuffle
|
|
23
|
+
permutation tests, multinomial and zone bootstrap confidence intervals.
|
|
24
|
+
- CSV / GeoJSON / pandas input and the `segstats` command-line tool.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it as below."
|
|
3
|
+
authors:
|
|
4
|
+
- family-names: "Eminoğlu"
|
|
5
|
+
given-names: "Yusuf"
|
|
6
|
+
email: "geospacephilo@gmail.com"
|
|
7
|
+
orcid: "https://orcid.org/0009-0005-6000-2934"
|
|
8
|
+
title: "segstats"
|
|
9
|
+
version: "0.1.0"
|
|
10
|
+
date-released: "2026-11-09"
|
|
11
|
+
license: "MIT"
|
|
12
|
+
repository-code: "https://gitlab.com/geophilo1/segstats_sdk"
|
|
13
|
+
url: "https://pypi.org/project/segstats/"
|
|
14
|
+
abstract: "Residential segregation and diversity indices for urban analysis: the five Massey-Denton dimensions (evenness, exposure, concentration, centralization, clustering), multigroup indices, spatial evenness measures (Morrill, Wong, Reardon-O'Sullivan), local diversity measures, random-allocation permutation tests and bootstrap confidence intervals."
|
|
15
|
+
keywords:
|
|
16
|
+
- segregation
|
|
17
|
+
- residential segregation
|
|
18
|
+
- dissimilarity index
|
|
19
|
+
- entropy
|
|
20
|
+
- urban analysis
|
|
21
|
+
- spatial statistics
|
segstats-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yusuf Eminoğlu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
segstats-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: segstats
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Residential segregation and diversity indices for urban analysis: the five Massey-Denton dimensions, multigroup and spatial indices (Reardon-O'Sullivan, Wong, Morrill), local measures, permutation tests and bootstrap CIs.
|
|
5
|
+
Author-email: Yusuf Eminoğlu <geospacephilo@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://gitlab.com/geophilo1/segstats_sdk
|
|
8
|
+
Project-URL: Repository, https://gitlab.com/geophilo1/segstats_sdk
|
|
9
|
+
Project-URL: Issues, https://gitlab.com/geophilo1/segstats_sdk/-/work_items
|
|
10
|
+
Project-URL: Changelog, https://gitlab.com/geophilo1/segstats_sdk/-/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: segregation,residential-segregation,dissimilarity-index,entropy,diversity,massey-denton,spatial-statistics,urban-analysis,urban-planning,census,geojson,gis
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Environment :: Console
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
22
|
+
Classifier: Topic :: Sociology
|
|
23
|
+
Classifier: Intended Audience :: Science/Research
|
|
24
|
+
Classifier: Intended Audience :: Developers
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.9
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: numpy>=1.22
|
|
30
|
+
Provides-Extra: pandas
|
|
31
|
+
Requires-Dist: pandas>=1.3.0; extra == "pandas"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
36
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# segstats
|
|
40
|
+
|
|
41
|
+
[](https://pypi.org/project/segstats/)
|
|
42
|
+
[](https://pypi.org/project/segstats/)
|
|
43
|
+
[](https://gitlab.com/geophilo1/segstats_sdk/-/pipelines)
|
|
44
|
+
[](LICENSE)
|
|
45
|
+
|
|
46
|
+
**Residential segregation and diversity indices for urban analysis.**
|
|
47
|
+
|
|
48
|
+
`segstats` computes the classic segregation indices from a table of population
|
|
49
|
+
counts by zone (census tracts, neighbourhoods, *mahalle*) and, when zone polygons are
|
|
50
|
+
available, their spatial counterparts. It covers the five dimensions of Massey &
|
|
51
|
+
Denton (1988), multigroup indices, spatially adjusted measures, local indices per
|
|
52
|
+
zone, and Monte Carlo inference. It needs only NumPy. Geometry comes from plain
|
|
53
|
+
GeoJSON; shapely and GDAL are not required.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install segstats # numpy only
|
|
57
|
+
pip install "segstats[pandas]" # + DataFrame input
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Requires Python 3.9 or newer.
|
|
61
|
+
|
|
62
|
+
> **Looking for more?** The PySAL
|
|
63
|
+
> [`segregation`](https://github.com/pysal/segregation) package is a fuller
|
|
64
|
+
> alternative. It adds many more indices, decomposition, network distances,
|
|
65
|
+
> multiscalar profiles and comparative inference, but needs the full geospatial
|
|
66
|
+
> stack. `segstats` is a small, dependency-light toolkit whose numbers are checked
|
|
67
|
+
> against hand calculations and PySAL (see *Validation*).
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Quickstart
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import segstats as ss
|
|
75
|
+
|
|
76
|
+
# counts only: CSV with columns tract, black, total
|
|
77
|
+
data = ss.read_csv("tracts.csv", id_column="tract", groups=["black"], total_column="total")
|
|
78
|
+
x, t = data.two_group("black") # group counts and zone totals
|
|
79
|
+
ss.dissimilarity(x, t) # 0 = even, 1 = complete segregation
|
|
80
|
+
ss.profile(data, group="black") # every aspatial index at once
|
|
81
|
+
|
|
82
|
+
# counts + polygons (GeoJSON in lon/lat is projected to metres on the fly)
|
|
83
|
+
data = ss.read_geojson("tracts.geojson", id_property="GEOID", counts=data)
|
|
84
|
+
ss.profile(data, group="black", center=(28.98, 41.01), bandwidth=1000)
|
|
85
|
+
|
|
86
|
+
# Is D higher than random allocation would give?
|
|
87
|
+
res = ss.permutation_test(data, "D", group="black", n_permutations=999, seed=1)
|
|
88
|
+
res.statistic, res.null_mean, res.p_value
|
|
89
|
+
|
|
90
|
+
# 95% bootstrap CI of the spatial information theory index (1 km Gaussian kernel)
|
|
91
|
+
ci = ss.bootstrap_ci(data, "SH", bandwidth=1000, seed=1)
|
|
92
|
+
ci.ci_low, ci.ci_high
|
|
93
|
+
|
|
94
|
+
# local measures
|
|
95
|
+
ss.location_quotient(data.counts) # zones x groups
|
|
96
|
+
ss.local_entropy(data.counts) # normalised diversity per zone
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
See [`examples/quickstart.py`](examples/quickstart.py) for a runnable synthetic city.
|
|
100
|
+
|
|
101
|
+
### Command line
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
segstats list # all indices and their inputs
|
|
105
|
+
segstats indices tracts.csv --id tract --groups black --total total --group black
|
|
106
|
+
segstats indices tracts.csv --id tract --groups black --total total \
|
|
107
|
+
--geojson tracts.geojson --geo-id GEOID --group black \
|
|
108
|
+
--center 28.98,41.01 --bandwidth 1000 --permutations 999 --bootstrap 999 --seed 1
|
|
109
|
+
segstats local tracts.geojson --id GEOID --groups black,white,asian -o local.csv
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`--format table|json|csv` controls the output. A GeoJSON file can hold the counts in
|
|
113
|
+
its feature properties, or a CSV table can be joined to polygons with `--geojson`.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Indices
|
|
118
|
+
|
|
119
|
+
Two-group indices compare a group of interest (*x*) with everyone else
|
|
120
|
+
(*y = t - x*). Multigroup indices use all count columns.
|
|
121
|
+
|
|
122
|
+
| Name | Index | Dimension | Inputs | Source |
|
|
123
|
+
|---|---|---|---|---|
|
|
124
|
+
| `D` | Dissimilarity | evenness | counts | Duncan & Duncan 1955 |
|
|
125
|
+
| `G` | Gini | evenness | counts | Massey & Denton 1988 |
|
|
126
|
+
| `H` | Entropy / Theil H | evenness | counts | Theil & Finizza 1971 |
|
|
127
|
+
| `A` | Atkinson (shape *b*) | evenness | counts | Atkinson 1970 |
|
|
128
|
+
| `MD`, `MH` | Multigroup D and H | evenness | counts | Reardon & Firebaugh 2002 |
|
|
129
|
+
| `xPx` | Isolation | exposure | counts | Bell 1954; M&D 1988 |
|
|
130
|
+
| `xPy` | Interaction | exposure | counts | M&D 1988 |
|
|
131
|
+
| `V` | Correlation ratio (eta squared) | exposure | counts | Bell 1954; White 1986 |
|
|
132
|
+
| `DEL` | Delta | concentration | area | Duncan, Cuzzort & Duncan 1961 |
|
|
133
|
+
| `ACO`, `RCO` | Absolute / relative concentration | concentration | area | M&D 1988 |
|
|
134
|
+
| `ACE`, `RCE` | Absolute / relative centralization | centralization | centre | M&D 1988 |
|
|
135
|
+
| `ACL`, `RCL` | Absolute / relative clustering | clustering | distances | M&D 1988 |
|
|
136
|
+
| `SP` | Spatial proximity | clustering | distances | White 1983 |
|
|
137
|
+
| `D_adj` | Adjusted D (contiguity) | spatial evenness | contiguity | Morrill 1991 |
|
|
138
|
+
| `D_w`, `D_s` | Boundary-weighted and shape-adjusted D | spatial evenness | boundaries | Wong 1993 |
|
|
139
|
+
| `SD`, `SH` | Spatial dissimilarity and information theory index | spatial evenness | neighbourhood | Reardon & O'Sullivan 2004 |
|
|
140
|
+
|
|
141
|
+
Local indices: `location_quotient`, `local_entropy`, `local_spatial_entropy`
|
|
142
|
+
(entropy of each zone's kernel-weighted local environment), and
|
|
143
|
+
`local_dissimilarity_contribution`.
|
|
144
|
+
|
|
145
|
+
### API overview
|
|
146
|
+
|
|
147
|
+
| Area | Functions |
|
|
148
|
+
|---|---|
|
|
149
|
+
| Plain arrays | `dissimilarity(x, t)`, `gini`, `entropy`, `atkinson(x, t, b)`, `isolation`, `interaction`, `correlation_ratio`, `multigroup_dissimilarity(counts)`, `multigroup_entropy`, `exposure_matrix`, `delta(x, t, area)`, `absolute_concentration`, `relative_concentration`, `absolute_centralization(x, area, dist)`, `relative_centralization(x, t, dist)`, `absolute_clustering(x, t, c)`, `relative_clustering`, `spatial_proximity`, `proximity_matrix(d, area, scale)`, `morrill_dissimilarity(x, t, C)`, `wong_dissimilarity_w(x, t, B)`, `wong_dissimilarity_s(x, t, B, perimeter, area)`, `local_environment(counts, W)`, `spatial_dissimilarity(counts, W)`, `spatial_entropy(counts, W)` |
|
|
150
|
+
| Data | `ZoneData`, `read_csv`, `read_geojson`, `from_dataframe`, `ZoneGeometry` (`area`, `perimeter`, `centroids`, `contiguity("queen"/"rook")`, `boundary_lengths()`, `distances()`) |
|
|
151
|
+
| Weights | `distance_matrix`, `kernel_weights(d, bandwidth, kernel)`, `with_self`, `row_standardize` |
|
|
152
|
+
| By name | `compute(data, "D", group)`, `profile(data, group)`, `statistic(...)`, `INDICES`, `IndexOptions` |
|
|
153
|
+
| Inference | `permutation_test(data, index, group, null="labels"/"zones")`, `bootstrap_ci(data, index, group, method="multinomial"/"zones")`, `random_allocation` |
|
|
154
|
+
|
|
155
|
+
`IndexOptions` holds the options shared by the registry: Atkinson `b`, `center` or
|
|
156
|
+
`center_distance`, `decay_scale` (distance unit of `exp(-d)`, default 1000 for km
|
|
157
|
+
when coordinates are metres), `clustering` (`"proximity"` or `"contiguity"` matrix for
|
|
158
|
+
ACL), `bandwidth` and `kernel` (`gaussian`, `exponential`, `biweight`, `box`) for the
|
|
159
|
+
Reardon & O'Sullivan neighbourhood (default: the zone plus its contiguous
|
|
160
|
+
neighbours), and `contiguity` (`queen`/`rook`).
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Method and sources
|
|
165
|
+
|
|
166
|
+
Notation: *x_i*, *y_i*, *t_i* are the group, rest-of-population and total counts of
|
|
167
|
+
zone *i*; capitals are city totals; *p_i = x_i / t_i*, *P = X / T*; *a_i* is the zone
|
|
168
|
+
area.
|
|
169
|
+
|
|
170
|
+
- **D** = ½ Σ |x_i/X − y_i/Y|. **G** = ΣΣ t_i t_j |p_i − p_j| / (2T²P(1−P)), computed
|
|
171
|
+
in O(n log n) from sorted proportions. **H** = Σ t_i (E − E_i) / (E T) with Shannon
|
|
172
|
+
entropies E, E_i (natural log). **A** = 1 − P/(1−P) · |Σ (1−p_i)^(1−b) p_i^b t_i /
|
|
173
|
+
(P T)|^(1/(1−b)). (Massey & Denton 1988, eqs. 1–4.)
|
|
174
|
+
- **xPx** = Σ (x_i/X)(x_i/t_i), **xPy** = Σ (x_i/X)(y_i/t_i), **V** = (xPx − P)/(1 − P).
|
|
175
|
+
- **Multigroup** D = Σ_m Σ_i t_i |π_im − π_m| / (2 T I), with I = Σ π_m(1 − π_m), and
|
|
176
|
+
Theil's H (Reardon & Firebaugh 2002).
|
|
177
|
+
- **DEL** = ½ Σ |x_i/X − a_i/A|. **ACO** and **RCO** compare the group's
|
|
178
|
+
area-weighted mean zone size with that of the n₁ smallest and the n₂ largest zones
|
|
179
|
+
holding X people (Massey & Denton 1988, eqs. 10–11; same convention for n₁ and n₂
|
|
180
|
+
as PySAL).
|
|
181
|
+
- **ACE** = Σ X_{i−1}A_i − Σ X_i A_{i−1} and **RCE** = Σ X_{i−1}Y_i − Σ X_i Y_{i−1} over
|
|
182
|
+
zones sorted by distance to the centre (cumulative shares). Zones at equal distance
|
|
183
|
+
form one step, so the result does not depend on input order.
|
|
184
|
+
- **SP** = (X Pxx + Y Pyy)/(T Ptt), **RCL** = Pxx/Pyy − 1, with Pxx = ΣΣ x_i x_j c_ij /
|
|
185
|
+
X² and c_ij = exp(−d_ij / scale), d_ii = (0.6 a_i)^0.5 (Massey & Denton 1988; White
|
|
186
|
+
1983). **ACL** follows Massey & Denton eq. 14 with the chosen c matrix.
|
|
187
|
+
- **D(adj)** = D − ΣΣ c_ij |p_i − p_j| / ΣΣ c_ij (binary contiguity; Morrill 1991).
|
|
188
|
+
**D(w)** = D − ΣΣ w_ij |p_i − p_j| with w_ij = b_ij / ΣΣ b_kl, the normalised
|
|
189
|
+
shared-boundary length. **D(s)** additionally multiplies each term by
|
|
190
|
+
½(PA_i + PA_j)/max(PA), PA = perimeter/area (Wong 1993). The normalisation follows
|
|
191
|
+
the R package `seg` (Hong, O'Sullivan & Sadahiro 2014). Zones with no population are
|
|
192
|
+
left out of the adjustment term.
|
|
193
|
+
- **Spatial D and H** (Reardon & O'Sullivan 2004): each zone's local environment
|
|
194
|
+
is π̃_im = Σ_j w_ij x_jm / Σ_j w_ij t_j, with kernel weights that include the
|
|
195
|
+
zone itself. Then H̃ = 1 − Σ t_i Ẽ_i / (T E) and D̃ = Σ_m Σ_i t_i |π̃_im − π_m| /
|
|
196
|
+
(2 T I). Identity weights reproduce the aspatial indices.
|
|
197
|
+
- **Inference.** `null="labels"` is random allocation: individuals' group labels are
|
|
198
|
+
shuffled while zone sizes and group totals stay fixed (exact multivariate
|
|
199
|
+
hypergeometric draws). `null="zones"` shuffles whole zone compositions among
|
|
200
|
+
locations, which tests the spatial arrangement only. p = (1 + #{sim ≥ obs})/(1 + R).
|
|
201
|
+
The bootstrap redraws each zone from a multinomial with its observed shares
|
|
202
|
+
(geometry fixed) and reports percentile intervals.
|
|
203
|
+
|
|
204
|
+
### Validation
|
|
205
|
+
|
|
206
|
+
The tests check every index against values worked out by hand: complete segregation
|
|
207
|
+
gives 1, an even distribution gives 0, and a four-zone city has exact fractions
|
|
208
|
+
(D = 5/9, ACO = 14/15, RCO = 77/92, ACE = 79/120, ...). Thirteen two-group indices
|
|
209
|
+
and the multigroup D and H also match PySAL `segregation` 2.6.0 to 1e-9 on an
|
|
210
|
+
irregular eight-zone layout. Wong's D(w) matches PySAL when given PySAL's boundary
|
|
211
|
+
matrix. On polygons that meet at T-junctions, PySAL's vertex-based contiguity misses
|
|
212
|
+
some neighbours, while `segstats` measures collinear edge overlap directly.
|
|
213
|
+
|
|
214
|
+
### References
|
|
215
|
+
|
|
216
|
+
- Massey, D. S. & Denton, N. A. (1988). The dimensions of residential segregation. *Social Forces* 67(2), 281–315. https://doi.org/10.2307/2579183
|
|
217
|
+
- Bell, W. (1954). A probability model for the measurement of ecological segregation. *Social Forces* 32(4), 357–364.
|
|
218
|
+
- Duncan, O. D. & Duncan, B. (1955). A methodological analysis of segregation indexes. *American Sociological Review* 20(2), 210–217.
|
|
219
|
+
- Atkinson, A. B. (1970). On the measurement of inequality. *Journal of Economic Theory* 2(3), 244–263.
|
|
220
|
+
- White, M. J. (1983). The measurement of spatial segregation. *American Journal of Sociology* 88(5), 1008–1018.
|
|
221
|
+
- White, M. J. (1986). Segregation and diversity measures in population distribution. *Population Index* 52(2), 198–221.
|
|
222
|
+
- Morrill, R. L. (1991). On the measure of geographic segregation. *Geography Research Forum* 11, 25–36.
|
|
223
|
+
- Wong, D. W. S. (1993). Spatial indices of segregation. *Urban Studies* 30(3), 559–572.
|
|
224
|
+
- Reardon, S. F. & Firebaugh, G. (2002). Measures of multigroup segregation. *Sociological Methodology* 32, 33–67.
|
|
225
|
+
- Reardon, S. F. & O'Sullivan, D. (2004). Measures of spatial segregation. *Sociological Methodology* 34, 121–162.
|
|
226
|
+
- Hong, S.-Y., O'Sullivan, D. & Sadahiro, Y. (2014). Implementing spatial segregation measures in R. *PLoS ONE* 9(11), e113767.
|
|
227
|
+
- Allen, R., Burgess, S., Davidson, R. & Windmeijer, F. (2015). More reliable inference for the dissimilarity index of segregation. *The Econometrics Journal* 18(1), 40–66.
|
|
228
|
+
- Cortese, C. F., Falk, R. F. & Cohen, J. K. (1976). Further considerations on the methodological analysis of segregation indices. *American Sociological Review* 41(4), 630–637.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Limitations
|
|
233
|
+
|
|
234
|
+
- **Distance units.** The `exp(-d)` proximity behind SP, RCL and ACL depends on
|
|
235
|
+
the distance unit. `decay_scale` defaults to 1000 (km for metric coordinates).
|
|
236
|
+
Massey & Denton do not fix a unit, so report the scale you use.
|
|
237
|
+
- **Geometry.** Polygons are planar. Lon/lat GeoJSON is projected with a local
|
|
238
|
+
equirectangular approximation, which is fine at city scale. Reproject large regions
|
|
239
|
+
beforehand. Contiguity needs clean topology: gaps wider than the tolerance (1e-9 of
|
|
240
|
+
the extent) break adjacency. Distances are measured between area-weighted centroids.
|
|
241
|
+
- **Ties.** ACO and RCO sort zones by area. When several zones have exactly the same
|
|
242
|
+
area, the core set follows input order (as in PySAL, whose tie order is arbitrary).
|
|
243
|
+
- **Small-unit bias.** D, H and the other indices are biased upward in small zones.
|
|
244
|
+
Use the permutation null mean (`res.excess`) to judge it. The percentile bootstrap
|
|
245
|
+
does not correct this bias.
|
|
246
|
+
- **Integer counts.** The permutation tests and the multinomial bootstrap need
|
|
247
|
+
whole-number counts. Weighted or estimated (e.g. ACS) counts must be rounded, and
|
|
248
|
+
their sampling error is not modelled.
|
|
249
|
+
- **Not included:** network distances, multiscalar profiles, decomposition,
|
|
250
|
+
comparative (two-city) tests and the distance-decay exposure indices. PySAL
|
|
251
|
+
`segregation` covers these.
|
|
252
|
+
- `D_s` follows Wong (1993) with the full zone perimeter. The R package `seg`
|
|
253
|
+
uses only the shared part of the perimeter, which you can pass explicitly.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Development
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
pip install -e ".[dev,pandas]"
|
|
261
|
+
pytest --cov=segstats
|
|
262
|
+
ruff check . && ruff format --check src tests && mypy src
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## License
|
|
266
|
+
|
|
267
|
+
MIT © 2026 Yusuf Eminoğlu. See [LICENSE](LICENSE). To cite segstats, see
|
|
268
|
+
[CITATION.cff](CITATION.cff).
|
|
269
|
+
|
|
270
|
+
## Academic citation
|
|
271
|
+
|
|
272
|
+
```bibtex
|
|
273
|
+
@software{eminoglu_segstats,
|
|
274
|
+
author = {Eminoğlu, Yusuf},
|
|
275
|
+
title = {segstats},
|
|
276
|
+
year = {2026},
|
|
277
|
+
version = {0.1.0},
|
|
278
|
+
url = {https://gitlab.com/geophilo1/segstats_sdk}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
See also `CITATION.cff`.
|
segstats-0.1.0/README.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# segstats
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/segstats/)
|
|
4
|
+
[](https://pypi.org/project/segstats/)
|
|
5
|
+
[](https://gitlab.com/geophilo1/segstats_sdk/-/pipelines)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
**Residential segregation and diversity indices for urban analysis.**
|
|
9
|
+
|
|
10
|
+
`segstats` computes the classic segregation indices from a table of population
|
|
11
|
+
counts by zone (census tracts, neighbourhoods, *mahalle*) and, when zone polygons are
|
|
12
|
+
available, their spatial counterparts. It covers the five dimensions of Massey &
|
|
13
|
+
Denton (1988), multigroup indices, spatially adjusted measures, local indices per
|
|
14
|
+
zone, and Monte Carlo inference. It needs only NumPy. Geometry comes from plain
|
|
15
|
+
GeoJSON; shapely and GDAL are not required.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install segstats # numpy only
|
|
19
|
+
pip install "segstats[pandas]" # + DataFrame input
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Requires Python 3.9 or newer.
|
|
23
|
+
|
|
24
|
+
> **Looking for more?** The PySAL
|
|
25
|
+
> [`segregation`](https://github.com/pysal/segregation) package is a fuller
|
|
26
|
+
> alternative. It adds many more indices, decomposition, network distances,
|
|
27
|
+
> multiscalar profiles and comparative inference, but needs the full geospatial
|
|
28
|
+
> stack. `segstats` is a small, dependency-light toolkit whose numbers are checked
|
|
29
|
+
> against hand calculations and PySAL (see *Validation*).
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Quickstart
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
import segstats as ss
|
|
37
|
+
|
|
38
|
+
# counts only: CSV with columns tract, black, total
|
|
39
|
+
data = ss.read_csv("tracts.csv", id_column="tract", groups=["black"], total_column="total")
|
|
40
|
+
x, t = data.two_group("black") # group counts and zone totals
|
|
41
|
+
ss.dissimilarity(x, t) # 0 = even, 1 = complete segregation
|
|
42
|
+
ss.profile(data, group="black") # every aspatial index at once
|
|
43
|
+
|
|
44
|
+
# counts + polygons (GeoJSON in lon/lat is projected to metres on the fly)
|
|
45
|
+
data = ss.read_geojson("tracts.geojson", id_property="GEOID", counts=data)
|
|
46
|
+
ss.profile(data, group="black", center=(28.98, 41.01), bandwidth=1000)
|
|
47
|
+
|
|
48
|
+
# Is D higher than random allocation would give?
|
|
49
|
+
res = ss.permutation_test(data, "D", group="black", n_permutations=999, seed=1)
|
|
50
|
+
res.statistic, res.null_mean, res.p_value
|
|
51
|
+
|
|
52
|
+
# 95% bootstrap CI of the spatial information theory index (1 km Gaussian kernel)
|
|
53
|
+
ci = ss.bootstrap_ci(data, "SH", bandwidth=1000, seed=1)
|
|
54
|
+
ci.ci_low, ci.ci_high
|
|
55
|
+
|
|
56
|
+
# local measures
|
|
57
|
+
ss.location_quotient(data.counts) # zones x groups
|
|
58
|
+
ss.local_entropy(data.counts) # normalised diversity per zone
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
See [`examples/quickstart.py`](examples/quickstart.py) for a runnable synthetic city.
|
|
62
|
+
|
|
63
|
+
### Command line
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
segstats list # all indices and their inputs
|
|
67
|
+
segstats indices tracts.csv --id tract --groups black --total total --group black
|
|
68
|
+
segstats indices tracts.csv --id tract --groups black --total total \
|
|
69
|
+
--geojson tracts.geojson --geo-id GEOID --group black \
|
|
70
|
+
--center 28.98,41.01 --bandwidth 1000 --permutations 999 --bootstrap 999 --seed 1
|
|
71
|
+
segstats local tracts.geojson --id GEOID --groups black,white,asian -o local.csv
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`--format table|json|csv` controls the output. A GeoJSON file can hold the counts in
|
|
75
|
+
its feature properties, or a CSV table can be joined to polygons with `--geojson`.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Indices
|
|
80
|
+
|
|
81
|
+
Two-group indices compare a group of interest (*x*) with everyone else
|
|
82
|
+
(*y = t - x*). Multigroup indices use all count columns.
|
|
83
|
+
|
|
84
|
+
| Name | Index | Dimension | Inputs | Source |
|
|
85
|
+
|---|---|---|---|---|
|
|
86
|
+
| `D` | Dissimilarity | evenness | counts | Duncan & Duncan 1955 |
|
|
87
|
+
| `G` | Gini | evenness | counts | Massey & Denton 1988 |
|
|
88
|
+
| `H` | Entropy / Theil H | evenness | counts | Theil & Finizza 1971 |
|
|
89
|
+
| `A` | Atkinson (shape *b*) | evenness | counts | Atkinson 1970 |
|
|
90
|
+
| `MD`, `MH` | Multigroup D and H | evenness | counts | Reardon & Firebaugh 2002 |
|
|
91
|
+
| `xPx` | Isolation | exposure | counts | Bell 1954; M&D 1988 |
|
|
92
|
+
| `xPy` | Interaction | exposure | counts | M&D 1988 |
|
|
93
|
+
| `V` | Correlation ratio (eta squared) | exposure | counts | Bell 1954; White 1986 |
|
|
94
|
+
| `DEL` | Delta | concentration | area | Duncan, Cuzzort & Duncan 1961 |
|
|
95
|
+
| `ACO`, `RCO` | Absolute / relative concentration | concentration | area | M&D 1988 |
|
|
96
|
+
| `ACE`, `RCE` | Absolute / relative centralization | centralization | centre | M&D 1988 |
|
|
97
|
+
| `ACL`, `RCL` | Absolute / relative clustering | clustering | distances | M&D 1988 |
|
|
98
|
+
| `SP` | Spatial proximity | clustering | distances | White 1983 |
|
|
99
|
+
| `D_adj` | Adjusted D (contiguity) | spatial evenness | contiguity | Morrill 1991 |
|
|
100
|
+
| `D_w`, `D_s` | Boundary-weighted and shape-adjusted D | spatial evenness | boundaries | Wong 1993 |
|
|
101
|
+
| `SD`, `SH` | Spatial dissimilarity and information theory index | spatial evenness | neighbourhood | Reardon & O'Sullivan 2004 |
|
|
102
|
+
|
|
103
|
+
Local indices: `location_quotient`, `local_entropy`, `local_spatial_entropy`
|
|
104
|
+
(entropy of each zone's kernel-weighted local environment), and
|
|
105
|
+
`local_dissimilarity_contribution`.
|
|
106
|
+
|
|
107
|
+
### API overview
|
|
108
|
+
|
|
109
|
+
| Area | Functions |
|
|
110
|
+
|---|---|
|
|
111
|
+
| Plain arrays | `dissimilarity(x, t)`, `gini`, `entropy`, `atkinson(x, t, b)`, `isolation`, `interaction`, `correlation_ratio`, `multigroup_dissimilarity(counts)`, `multigroup_entropy`, `exposure_matrix`, `delta(x, t, area)`, `absolute_concentration`, `relative_concentration`, `absolute_centralization(x, area, dist)`, `relative_centralization(x, t, dist)`, `absolute_clustering(x, t, c)`, `relative_clustering`, `spatial_proximity`, `proximity_matrix(d, area, scale)`, `morrill_dissimilarity(x, t, C)`, `wong_dissimilarity_w(x, t, B)`, `wong_dissimilarity_s(x, t, B, perimeter, area)`, `local_environment(counts, W)`, `spatial_dissimilarity(counts, W)`, `spatial_entropy(counts, W)` |
|
|
112
|
+
| Data | `ZoneData`, `read_csv`, `read_geojson`, `from_dataframe`, `ZoneGeometry` (`area`, `perimeter`, `centroids`, `contiguity("queen"/"rook")`, `boundary_lengths()`, `distances()`) |
|
|
113
|
+
| Weights | `distance_matrix`, `kernel_weights(d, bandwidth, kernel)`, `with_self`, `row_standardize` |
|
|
114
|
+
| By name | `compute(data, "D", group)`, `profile(data, group)`, `statistic(...)`, `INDICES`, `IndexOptions` |
|
|
115
|
+
| Inference | `permutation_test(data, index, group, null="labels"/"zones")`, `bootstrap_ci(data, index, group, method="multinomial"/"zones")`, `random_allocation` |
|
|
116
|
+
|
|
117
|
+
`IndexOptions` holds the options shared by the registry: Atkinson `b`, `center` or
|
|
118
|
+
`center_distance`, `decay_scale` (distance unit of `exp(-d)`, default 1000 for km
|
|
119
|
+
when coordinates are metres), `clustering` (`"proximity"` or `"contiguity"` matrix for
|
|
120
|
+
ACL), `bandwidth` and `kernel` (`gaussian`, `exponential`, `biweight`, `box`) for the
|
|
121
|
+
Reardon & O'Sullivan neighbourhood (default: the zone plus its contiguous
|
|
122
|
+
neighbours), and `contiguity` (`queen`/`rook`).
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Method and sources
|
|
127
|
+
|
|
128
|
+
Notation: *x_i*, *y_i*, *t_i* are the group, rest-of-population and total counts of
|
|
129
|
+
zone *i*; capitals are city totals; *p_i = x_i / t_i*, *P = X / T*; *a_i* is the zone
|
|
130
|
+
area.
|
|
131
|
+
|
|
132
|
+
- **D** = ½ Σ |x_i/X − y_i/Y|. **G** = ΣΣ t_i t_j |p_i − p_j| / (2T²P(1−P)), computed
|
|
133
|
+
in O(n log n) from sorted proportions. **H** = Σ t_i (E − E_i) / (E T) with Shannon
|
|
134
|
+
entropies E, E_i (natural log). **A** = 1 − P/(1−P) · |Σ (1−p_i)^(1−b) p_i^b t_i /
|
|
135
|
+
(P T)|^(1/(1−b)). (Massey & Denton 1988, eqs. 1–4.)
|
|
136
|
+
- **xPx** = Σ (x_i/X)(x_i/t_i), **xPy** = Σ (x_i/X)(y_i/t_i), **V** = (xPx − P)/(1 − P).
|
|
137
|
+
- **Multigroup** D = Σ_m Σ_i t_i |π_im − π_m| / (2 T I), with I = Σ π_m(1 − π_m), and
|
|
138
|
+
Theil's H (Reardon & Firebaugh 2002).
|
|
139
|
+
- **DEL** = ½ Σ |x_i/X − a_i/A|. **ACO** and **RCO** compare the group's
|
|
140
|
+
area-weighted mean zone size with that of the n₁ smallest and the n₂ largest zones
|
|
141
|
+
holding X people (Massey & Denton 1988, eqs. 10–11; same convention for n₁ and n₂
|
|
142
|
+
as PySAL).
|
|
143
|
+
- **ACE** = Σ X_{i−1}A_i − Σ X_i A_{i−1} and **RCE** = Σ X_{i−1}Y_i − Σ X_i Y_{i−1} over
|
|
144
|
+
zones sorted by distance to the centre (cumulative shares). Zones at equal distance
|
|
145
|
+
form one step, so the result does not depend on input order.
|
|
146
|
+
- **SP** = (X Pxx + Y Pyy)/(T Ptt), **RCL** = Pxx/Pyy − 1, with Pxx = ΣΣ x_i x_j c_ij /
|
|
147
|
+
X² and c_ij = exp(−d_ij / scale), d_ii = (0.6 a_i)^0.5 (Massey & Denton 1988; White
|
|
148
|
+
1983). **ACL** follows Massey & Denton eq. 14 with the chosen c matrix.
|
|
149
|
+
- **D(adj)** = D − ΣΣ c_ij |p_i − p_j| / ΣΣ c_ij (binary contiguity; Morrill 1991).
|
|
150
|
+
**D(w)** = D − ΣΣ w_ij |p_i − p_j| with w_ij = b_ij / ΣΣ b_kl, the normalised
|
|
151
|
+
shared-boundary length. **D(s)** additionally multiplies each term by
|
|
152
|
+
½(PA_i + PA_j)/max(PA), PA = perimeter/area (Wong 1993). The normalisation follows
|
|
153
|
+
the R package `seg` (Hong, O'Sullivan & Sadahiro 2014). Zones with no population are
|
|
154
|
+
left out of the adjustment term.
|
|
155
|
+
- **Spatial D and H** (Reardon & O'Sullivan 2004): each zone's local environment
|
|
156
|
+
is π̃_im = Σ_j w_ij x_jm / Σ_j w_ij t_j, with kernel weights that include the
|
|
157
|
+
zone itself. Then H̃ = 1 − Σ t_i Ẽ_i / (T E) and D̃ = Σ_m Σ_i t_i |π̃_im − π_m| /
|
|
158
|
+
(2 T I). Identity weights reproduce the aspatial indices.
|
|
159
|
+
- **Inference.** `null="labels"` is random allocation: individuals' group labels are
|
|
160
|
+
shuffled while zone sizes and group totals stay fixed (exact multivariate
|
|
161
|
+
hypergeometric draws). `null="zones"` shuffles whole zone compositions among
|
|
162
|
+
locations, which tests the spatial arrangement only. p = (1 + #{sim ≥ obs})/(1 + R).
|
|
163
|
+
The bootstrap redraws each zone from a multinomial with its observed shares
|
|
164
|
+
(geometry fixed) and reports percentile intervals.
|
|
165
|
+
|
|
166
|
+
### Validation
|
|
167
|
+
|
|
168
|
+
The tests check every index against values worked out by hand: complete segregation
|
|
169
|
+
gives 1, an even distribution gives 0, and a four-zone city has exact fractions
|
|
170
|
+
(D = 5/9, ACO = 14/15, RCO = 77/92, ACE = 79/120, ...). Thirteen two-group indices
|
|
171
|
+
and the multigroup D and H also match PySAL `segregation` 2.6.0 to 1e-9 on an
|
|
172
|
+
irregular eight-zone layout. Wong's D(w) matches PySAL when given PySAL's boundary
|
|
173
|
+
matrix. On polygons that meet at T-junctions, PySAL's vertex-based contiguity misses
|
|
174
|
+
some neighbours, while `segstats` measures collinear edge overlap directly.
|
|
175
|
+
|
|
176
|
+
### References
|
|
177
|
+
|
|
178
|
+
- Massey, D. S. & Denton, N. A. (1988). The dimensions of residential segregation. *Social Forces* 67(2), 281–315. https://doi.org/10.2307/2579183
|
|
179
|
+
- Bell, W. (1954). A probability model for the measurement of ecological segregation. *Social Forces* 32(4), 357–364.
|
|
180
|
+
- Duncan, O. D. & Duncan, B. (1955). A methodological analysis of segregation indexes. *American Sociological Review* 20(2), 210–217.
|
|
181
|
+
- Atkinson, A. B. (1970). On the measurement of inequality. *Journal of Economic Theory* 2(3), 244–263.
|
|
182
|
+
- White, M. J. (1983). The measurement of spatial segregation. *American Journal of Sociology* 88(5), 1008–1018.
|
|
183
|
+
- White, M. J. (1986). Segregation and diversity measures in population distribution. *Population Index* 52(2), 198–221.
|
|
184
|
+
- Morrill, R. L. (1991). On the measure of geographic segregation. *Geography Research Forum* 11, 25–36.
|
|
185
|
+
- Wong, D. W. S. (1993). Spatial indices of segregation. *Urban Studies* 30(3), 559–572.
|
|
186
|
+
- Reardon, S. F. & Firebaugh, G. (2002). Measures of multigroup segregation. *Sociological Methodology* 32, 33–67.
|
|
187
|
+
- Reardon, S. F. & O'Sullivan, D. (2004). Measures of spatial segregation. *Sociological Methodology* 34, 121–162.
|
|
188
|
+
- Hong, S.-Y., O'Sullivan, D. & Sadahiro, Y. (2014). Implementing spatial segregation measures in R. *PLoS ONE* 9(11), e113767.
|
|
189
|
+
- Allen, R., Burgess, S., Davidson, R. & Windmeijer, F. (2015). More reliable inference for the dissimilarity index of segregation. *The Econometrics Journal* 18(1), 40–66.
|
|
190
|
+
- Cortese, C. F., Falk, R. F. & Cohen, J. K. (1976). Further considerations on the methodological analysis of segregation indices. *American Sociological Review* 41(4), 630–637.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Limitations
|
|
195
|
+
|
|
196
|
+
- **Distance units.** The `exp(-d)` proximity behind SP, RCL and ACL depends on
|
|
197
|
+
the distance unit. `decay_scale` defaults to 1000 (km for metric coordinates).
|
|
198
|
+
Massey & Denton do not fix a unit, so report the scale you use.
|
|
199
|
+
- **Geometry.** Polygons are planar. Lon/lat GeoJSON is projected with a local
|
|
200
|
+
equirectangular approximation, which is fine at city scale. Reproject large regions
|
|
201
|
+
beforehand. Contiguity needs clean topology: gaps wider than the tolerance (1e-9 of
|
|
202
|
+
the extent) break adjacency. Distances are measured between area-weighted centroids.
|
|
203
|
+
- **Ties.** ACO and RCO sort zones by area. When several zones have exactly the same
|
|
204
|
+
area, the core set follows input order (as in PySAL, whose tie order is arbitrary).
|
|
205
|
+
- **Small-unit bias.** D, H and the other indices are biased upward in small zones.
|
|
206
|
+
Use the permutation null mean (`res.excess`) to judge it. The percentile bootstrap
|
|
207
|
+
does not correct this bias.
|
|
208
|
+
- **Integer counts.** The permutation tests and the multinomial bootstrap need
|
|
209
|
+
whole-number counts. Weighted or estimated (e.g. ACS) counts must be rounded, and
|
|
210
|
+
their sampling error is not modelled.
|
|
211
|
+
- **Not included:** network distances, multiscalar profiles, decomposition,
|
|
212
|
+
comparative (two-city) tests and the distance-decay exposure indices. PySAL
|
|
213
|
+
`segregation` covers these.
|
|
214
|
+
- `D_s` follows Wong (1993) with the full zone perimeter. The R package `seg`
|
|
215
|
+
uses only the shared part of the perimeter, which you can pass explicitly.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Development
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
pip install -e ".[dev,pandas]"
|
|
223
|
+
pytest --cov=segstats
|
|
224
|
+
ruff check . && ruff format --check src tests && mypy src
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
MIT © 2026 Yusuf Eminoğlu. See [LICENSE](LICENSE). To cite segstats, see
|
|
230
|
+
[CITATION.cff](CITATION.cff).
|
|
231
|
+
|
|
232
|
+
## Academic citation
|
|
233
|
+
|
|
234
|
+
```bibtex
|
|
235
|
+
@software{eminoglu_segstats,
|
|
236
|
+
author = {Eminoğlu, Yusuf},
|
|
237
|
+
title = {segstats},
|
|
238
|
+
year = {2026},
|
|
239
|
+
version = {0.1.0},
|
|
240
|
+
url = {https://gitlab.com/geophilo1/segstats_sdk}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
See also `CITATION.cff`.
|