moveq-core
Pure NumPy algorithms for measuring transport equity.
This is the calculation engine of the moveq
stack. It has no I/O: you pass NumPy arrays (or, with the optional
frames extra, a pandas DataFrame) and get numbers and small result objects
back. There is no database, GIS library, or network client.
Most applications should install the umbrella package
moveq, which re-exports this API.
Install moveq-core directly only when you want the metrics without the
catalogue registry.
What each metric is for
Transport analysis usually has a service variable per area (trips, departures, coverage) and a population weight. Sometimes there is also a socioeconomic rank (deprivation index, income band).
Population-weighted Gini
Gini answers: how unevenly is this service spread across people?
Areas are sorted from lowest to highest service. Cumulative population share
is plotted against cumulative service share (a Lorenz curve). Gini is 1
minus twice the area under that curve, using trapezoidal integration.
0— every person faces the same service level (including the all-zero convention: nothing to distribute)- toward
1— almost all service sits with a small share of the population
Gini does not know whether the poorly served people are deprived. It is a statement about the service distribution only.
Palma ratio
Palma answers: how does the best-served tenth compare with the worst-served two-fifths?
It is the population-weighted mean service of the top 10% divided by that of
the bottom 40% (areas on the boundary of those shares are split
proportionally). Equal service, including all-zero service, gives 1. If
the bottom 40% have zero service while the top 10% do not, the function
returns inf rather than dividing by zero.
Palma is more sensitive to the tails than Gini, which is why the two are reported together.
Wagstaff Concentration Index
The concentration index answers: does service rise or fall as deprivation falls?
Areas are ordered by rank (1 = most deprived by convention in this
library). Units that tie on rank share the group's midpoint fractional
rank, so the answer does not depend on input order. Unpopulated units are
ignored. A population-weighted covariance between service and fractional
rank is scaled by the mean service. For non-negative service the result is
in [-1, 1]:
| Sign | Meaning |
|---|---|
CI > 0 |
service concentrated in less deprived areas (pro-rich) |
CI < 0 |
service concentrated in more deprived areas (pro-poor) |
CI = 0 |
no systematic gradient with rank |
This is the metric to use when the policy question is about socioeconomic targeting, not only about overall unevenness.
Composite score with missing-term renormalisation
compute_score builds a 0–100 weighted index from named terms in [0, 1].
The important behaviour is what happens when a term is None:
- that term is dropped, not treated as zero
- remaining design weights are renormalised to sum to 1
- the result records
weight_usedvsdesign_weight, the dropped ids, and anote
If every term is missing, score is None. Design weights must be finite
and strictly positive; non-finite term values are rejected rather than
clipped. Callers keep control of which indicators exist; the library
refuses to invent a zero.
Optional DataFrame helpers (moveq_core.frames)
With pip install "moveq-core[frames]" (or "moveq[frames]"):
- vulnerability index — min-max scale several deprivation-like columns to 0–100 and take the row-wise mean
- multiply deprived — flag areas that sit in the worst tertile on at least k factors at once
These are convenience summaries, not a substitute for a national IMD.
Formulae: methodology.
Installation
Requires Python 3.10+. Runtime dependency: numpy>=1.24.
pip install moveq-core
pip install "moveq-core[frames]" # pandas helpers
Quickstart
import numpy as np
from moveq_core import (
compute_gini,
compute_palma_ratio,
compute_concentration_index,
compute_score,
)
service = np.array([10.0, 20.0, 5.0, 50.0, 8.0])
population = np.array([1000, 800, 1200, 300, 900])
deprivation_rank = np.array([1, 3, 2, 5, 4]) # 1 = most deprived
gini = compute_gini(service, population)
palma = compute_palma_ratio(service, population)
ci = compute_concentration_index(service, deprivation_rank, population)
score_res = compute_score(
terms={"coverage": 0.75, "evening": 0.50, "night": None},
weights={"coverage": 0.50, "evening": 0.30, "night": 0.20},
)
print(score_res.score, score_res.dropped, score_res.note)
Documentation
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file moveq_core-0.1.2.tar.gz.
File metadata
- Download URL: moveq_core-0.1.2.tar.gz
- Upload date:
- Size: 15.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b565c0e155967c136be06af9a5c5e6f24af84c627b1c72b95c0d47d77cbd77c
|
|
| MD5 |
d2a80a66fe2a7ba2f1bebef84daddbcf
|
|
| BLAKE2b-256 |
e11ed5d792e990102056403dcd0ed3796b71e7c2bd92c7dc5a7740caa86e17f3
|
Provenance
The following attestation bundles were made for moveq_core-0.1.2.tar.gz:
Publisher:
publish.yml on SVamseekar/moveq
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
moveq_core-0.1.2.tar.gz -
Subject digest:
0b565c0e155967c136be06af9a5c5e6f24af84c627b1c72b95c0d47d77cbd77c - Sigstore transparency entry: 2583180376
- Sigstore integration time:
-
Permalink:
SVamseekar/moveq@a7329283135199248491ca348939e9dfe3fcbaec -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/SVamseekar
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a7329283135199248491ca348939e9dfe3fcbaec -
Trigger Event:
push
-
Statement type:
File details
Details for the file moveq_core-0.1.2-py3-none-any.whl.
File metadata
- Download URL: moveq_core-0.1.2-py3-none-any.whl
- Upload date:
- Size: 10.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5a7ffa4c5122b225af30cbc7ae768af9abac33fd71d4605dfd832b95ab715e80
|
|
| MD5 |
722cc4abb4ade05ab8154dc1bb0a29ef
|
|
| BLAKE2b-256 |
c236518ad7b535847f5461bfedd42fd1cc8ed80d0c395623079890038723ef6c
|
Provenance
The following attestation bundles were made for moveq_core-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on SVamseekar/moveq
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
moveq_core-0.1.2-py3-none-any.whl -
Subject digest:
5a7ffa4c5122b225af30cbc7ae768af9abac33fd71d4605dfd832b95ab715e80 - Sigstore transparency entry: 2583180385
- Sigstore integration time:
-
Permalink:
SVamseekar/moveq@a7329283135199248491ca348939e9dfe3fcbaec -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/SVamseekar
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a7329283135199248491ca348939e9dfe3fcbaec -
Trigger Event:
push
-
Statement type: