Skip to main content

stsckm

Continuous integration PyPI version Python versions

stsckm is a Python framework for graph-regularized K-means clustering. It supports general feature matrices, multi-view representations, layered sparse graphs, and a dedicated spatio-temporal estimator for point-event data.

GraphRegularizedKMeans separates the variables used to define centroids from the representation used to construct the neighborhood graph. STSCKM remains the backward-compatible specialization that applies separate spatial and temporal distance weights. Both estimators use one shared optimization engine and a soft label-disagreement penalty.

The method was introduced in:

Idris, M. A., Aidi, M. N., and Djuraidah, A. (2026). Performance Evaluation of ST-DBSCAN and Spatio-Temporal Spatially Constrained K-Means (ST-SCKM) for Wildfire Risk Zoning and Resilience Analysis. Journal of Safety Science and Resilience. https://doi.org/10.1016/j.jnlssr.2026.100357

The package generalizes the reference implementation into reusable graph, diagnostic, selection, and multi-view components. Version 2.1.0 includes reproducible wildfire and earthquake illustrations; the estimators themselves are not tied to either domain.

What the package provides

  • a scikit-learn-style GraphRegularizedKMeans estimator for arbitrary numeric feature matrices;
  • a backward-compatible STSCKM estimator for aligned spatial and temporal matrices;
  • separate centroid features and graph-construction features;
  • directed, union, or mutual K-nearest-neighbor graphs and radius graphs;
  • caller-supplied dense or SciPy sparse weighted adjacency matrices;
  • weighted multi-layer graph composition with optional per-layer normalization;
  • sequential or synchronous label-update schemes;
  • graph disagreement, connected-component, and fragmentation diagnostics;
  • deterministic parameter-grid summaries and repeated-fit stability checks;
  • conventional silhouette, Calinski-Harabasz, and Davies-Bouldin indices;
  • explicit separation between clustering variables and post hoc profile variables; and
  • a synthetic wildfire dataset, an archived USGS earthquake catalog, tests, documentation, examples, and a complete replication archive.

The graph penalty is soft. It encourages neighboring observations to share a label but does not guarantee that every cluster is connected. Use a strict regionalization method when connected regions are mandatory.

Installation

Install the published package from PyPI:

python -m pip install stsckm

Optional plotting support is available with:

python -m pip install "stsckm[plot]"

For an editable development installation from the repository root:

python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements-dev.txt

On Windows, use .venv\Scripts\activate.

General graph-regularized estimator

import numpy as np

from stsckm import GraphRegularizedKMeans

# X defines centroid fit. graph_features can be a different representation.
X = np.array(
    [
        [0.0, 0.1, 1.0],
        [0.1, 0.0, 0.9],
        [0.2, 0.1, 1.1],
        [4.0, 4.1, 8.0],
        [4.1, 4.0, 8.2],
        [4.2, 4.1, 7.9],
    ]
)
graph_features = X[:, :2]
model = GraphRegularizedKMeans(
    n_clusters=2,
    graph_penalty=1.0,
    feature_weights=[1.0, 1.0, 0.5],
    n_neighbors=2,
    graph_symmetrize="union",
    random_state=42,
).fit(X, graph_features=graph_features)

print(model.graph_diagnostics_)

The general estimator implements fit, fit_predict, transform, and predict. Its predict method uses centroid distances only because no graph for new observations is implied by the fitted sample.

Spatio-temporal specialization

import numpy as np

from stsckm import (
    STSCKM,
    add_default_features,
    evaluate_labels,
    load_sample_wildfire,
    standardize_features,
)

events = add_default_features(load_sample_wildfire())
X_spatial, spatial_scaler = standardize_features(
    events, ["x_proj", "y_proj"]
)
X_temporal, temporal_scaler = standardize_features(events, ["time_days"])

model = STSCKM(
    n_clusters=4,
    spatial_weight=0.5,
    temporal_weight=1.5,
    lambda_spatial=1.0,
    graph_type="knn",
    n_neighbors=5,
    graph_symmetrize="union",
    random_state=42,
).fit(X_spatial, X_temporal)

metrics = evaluate_labels(
    np.column_stack([X_spatial, X_temporal]), model.labels_
)
print(metrics)
print(model.graph_diagnostics_)

The fitted object stores labels_, separate spatial and temporal centroids, the original sparse adjacency_, the symmetric regularization_adjacency_, an objective history, and graph diagnostics. transform() returns unregularized weighted distances to the fitted centroids. The package deliberately does not define out-of-sample predict() because prediction requires an explicit rule for connecting new observations to the fitted graph.

Radius, custom, and layered graphs

from stsckm import STSCKM, spatial_graph

radius_model = STSCKM(
    n_clusters=4,
    graph_type="radius",
    radius=0.20,
    lambda_spatial=1.0,
    random_state=42,
).fit(X_spatial, X_temporal)

adjacency = spatial_graph(
    X_spatial,
    graph_type="knn",
    n_neighbors=8,
    symmetrize="mutual",
)
custom_model = STSCKM(n_clusters=4, random_state=42).fit(
    X_spatial,
    X_temporal,
    adjacency=adjacency,
)

Multiple relationship layers can be combined before fitting:

from stsckm import combine_adjacencies

layered_graph = combine_adjacencies(
    [spatial_layer, temporal_layer],
    weights=[0.8, 0.2],
    normalize="max",
    symmetrize="union",
)

Non-negative edge weights in a custom graph enter the disagreement penalty. Diagonal entries are removed during validation. A complete asymmetric six-observation example is available in examples/custom_weighted_graph.py.

Non-wildfire example

examples/earthquake_catalog.py applies GraphRegularizedKMeans to an archived 924-event USGS California earthquake catalog. Centroid fit uses magnitude, depth, and event time, while a layered graph combines geographic and temporal neighborhoods. The query, retrieval date, and SHA-256 digest are recorded in data/README.md. This example demonstrates the software interface and is not a seismic-hazard analysis.

python examples/earthquake_catalog.py

Parameter selection and stability

from stsckm import STSCKM, fit_stability, parameter_search

search = parameter_search(
    X_spatial,
    X_temporal,
    {
        "n_clusters": [3, 4],
        "lambda_spatial": [0.0, 0.5, 1.0, 2.0],
        "graph_symmetrize": ["union"],
    },
    estimator=STSCKM(n_neighbors=5, random_state=42),
)

stability = fit_stability(
    STSCKM(n_clusters=4, graph_symmetrize="union"),
    X_spatial,
    X_temporal,
    seeds=(0, 1, 2, 3, 4),
)
print(search)
print(stability.mean_adjusted_rand)

Internal separation and graph coherence quantify different properties. A parameter choice should therefore consider both, together with domain checks when available.

The package does not replace all spatial clustering tools:

Software or method Main mechanism Prefer it when
scikit-learn K-means Unconstrained centroid clustering No graph preference is required
scikit-learn connectivity-constrained Ward Only connected clusters may merge A hierarchical partition under a connectivity graph is appropriate
st-dbscan Spatial and temporal density thresholds Noise detection and an unknown cluster count are central
PySAL spopt Strict regionalization algorithms Areal units must form connected regions
R ClustGeo Feature and geographic dissimilarities A Ward-like hierarchy with soft geographic dissimilarity is preferred
R adespatial::constr.hclust Contiguity-constrained agglomeration Spatial or chronological contiguity must restrict each merge
stsckm Soft graph disagreement plus general or space-time centroids Fixed-K feature or event data need tunable graph coherence and explicit graph inspection

The JSS manuscript gives full citations, a feature comparison, limitations, and shared-input empirical illustrations in two application domains.

Reproducing the manuscript

The review archive is self-contained. After installing its submitted source distribution, run all commands from the replication folder:

cd replication
python -m pip install -r requirements.txt
python run_all.py

run_all.py executes the manuscript listings, runs the independently callable examples/run_example.py, recreates all numerical tables and data-driven figures, records dependency versions, and checks platform-invariant results against the archived CSVs in expected/. It also regenerates a small scaling benchmark and the earthquake comparison without comparing wall times for exact equality. See replication/README.md for the exact reviewer workflow and output map.

For a single end-to-end script that prepares the bundled data, fits the model, writes diagnostics, screens a transparent parameter grid, and saves auditable outputs, run python replication/worked_analysis.py from the replication folder.

Tests, documentation, and build

python -m pytest
python -m ruff check src tests replication
python -m sphinx -W -b html docs docs/_build/html
python -m build
python -m twine check dist/*

License and author

stsckm is released under the MIT license, which is GPL-compatible.

Muh Akbar Idris, IPB University
ORCID: https://orcid.org/0009-0000-2995-1975

Metadata

Release files for stsckm 2.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for stsckm 2.1.0
File Size Uploaded
stsckm-2.1.0.tar.gz 174.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for stsckm 2.1.0
File Interpreter ABI Platform
stsckm-2.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 322.1 kB

Release files / stsckm-2.1.0.tar.gz

Download URL stsckm-2.1.0.tar.gz
Size 174.5 kB
Tags Source
SHA-256 checksum
How to use checksums
3571b5673f8c84b868a3e615efc37c2b513906595da03105d02aa7f575791233
BLAKE2b-256 checksum
How to use checksums
f6be655aac41b087fe400e3667f840bbc4f423cc07fc9155f6372a84ac37ae05
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release files / stsckm-2.1.0-py3-none-any.whl

Download URL stsckm-2.1.0-py3-none-any.whl
Size 147.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ffa0ad28e792c8a7ddd7b9ea5cecb44745769ed973aee8b30d38ed00c22e81d9
BLAKE2b-256 checksum
How to use checksums
96bc420f6788d4d1fdce8479a3675022e6eebadfa9e3265c21e881717e056f82
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2.1.0 This release

2 release files

2.0.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page