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
58 changes: 58 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: CI

on:
push:
branches: [master]
pull_request:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
lint:
name: Lint (ruff)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: python -m pip install ruff
- run: ruff check src tests
- run: ruff format --check src tests

test:
name: Test (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
- name: Install
run: python -m pip install -e ".[dev,contour]"
- name: Test
run: pytest --cov --cov-report=term-missing

build:
name: Build distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: python -m pip install build twine
- run: python -m build
- run: twine check dist/*
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
47 changes: 47 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Publish to PyPI

# Publishes when a version tag (v1.2.3) is pushed. Uses PyPI "trusted
# publishing" (OpenID Connect), so no API token is stored in the repository:
# register this workflow once at https://pypi.org/manage/account/publishing/
# (owner: adaj, repository: predspot, workflow: publish.yml, environment: pypi).

on:
push:
tags: ["v[0-9]+.[0-9]+.[0-9]+*"]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Check that the tag matches the package version
run: |
python -m pip install -e .
PKG_VERSION="v$(python -c 'import predspot; print(predspot.__version__)')"
echo "tag=${GITHUB_REF_NAME} package=${PKG_VERSION}"
test "${GITHUB_REF_NAME}" = "${PKG_VERSION}"
- run: python -m pip install build twine
- run: python -m build
- run: twine check dist/*
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

publish:
needs: build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/predspot
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@release/v1
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@
build/
dist/
*.egg-info/
.coverage
htmlcov/
.ruff_cache/
49 changes: 49 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Changelog

All notable changes to Predspot are documented here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
[Semantic Versioning](https://semver.org/).

## [Unreleased]

## [0.2.0] - 2026-09

Revival release: the code base now targets Python 3.10+ with current
versions of pandas (>= 2.2), GeoPandas (>= 1.0), scikit-learn and statsmodels.

### Added
- `QuadratCount` mapping (event counts per cell) as a first-class alternative
to `KDE`, usable with hexagonal (`create_gridhexagonal`) and square
(`create_gridsquares`) grids inside `PredictionPipeline`.
- `pipeline.build_default_pipeline` and reproducible
`pipeline.generate_testdata(..., seed=...)`.
- `PredictionPipeline.features`, `.next_time` and `random_state`.
- Test suite (pytest) and continuous integration for Python 3.10-3.13.
- `pyproject.toml` packaging (src layout) and automated PyPI publishing.

### Changed
- `tfreq` is optional in the feature classes (inferred from the series).
- Debug `print`s replaced with the `logging` module (`predspot` logger); the
`debug=` arguments were removed.
- Wrapper estimators expose their inner estimator as `.estimator`
(previously `._estimator`).
- `Dataset` no longer modifies the input DataFrame and requires the study
area to have a CRS.
- Grid centroids are computed in a projected CRS; grids accept study areas in
any CRS.
- `geojsoncontour` is an optional dependency (`pip install predspot[contour]`).

### Removed
- `QuadratCount2`, `KGrid` and the hard dependencies on `descartes`,
`contextily` and `rtree`.

### Fixed
- Compatibility with pandas 2/3 (`'ME'` offsets, `DataFrame.append`,
positional `Series` indexing), GeoPandas 1.x (`sjoin(predicate=)`, CRS
strings, `gpd.datasets`) and scikit-learn 1.x (`FeatureUnion` internals).
- `Seasonality`/`Trend` never called `STL(...).fit()`.
- `FeatureScaling` had no `fit`, so scalers inside a `Pipeline` were never fitted.

## [0.1.3] - 2020

Original master's thesis release.
29 changes: 29 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Contributing

Thanks for your interest in Predspot! Issues and pull requests are welcome.

## Development setup

```bash
git clone https://github.com/adaj/predspot.git
cd predspot
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,contour]"
```

## Checks

```bash
ruff check src tests # lint
ruff format src tests # format
pytest # tests (~10 s)
```

CI runs the same checks on Python 3.10 to 3.13 for every pull request.

## Releasing

1. Bump `__version__` in `src/predspot/__init__.py` and update `CHANGELOG.md`.
2. Merge to `master`, then tag and push: `git tag v0.2.0 && git push origin v0.2.0`.
3. The `Publish to PyPI` workflow builds the distribution and uploads it via
PyPI trusted publishing.
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include LICENSE README.md CHANGELOG.md CONTRIBUTING.md
recursive-include tests *.py
prune docs
24 changes: 19 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Predspot

[![CI](https://github.com/adaj/predspot/actions/workflows/ci.yml/badge.svg)](https://github.com/adaj/predspot/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/predspot.svg)](https://pypi.org/project/predspot/)
[![Python](https://img.shields.io/pypi/pyversions/predspot.svg)](https://pypi.org/project/predspot/)
[![License: BSD-3](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](LICENSE)

## Overview 📖

Predspot is a Python library for spatio-temporal crime prediction and hotspot detection. It combines machine learning techniques with spatial analysis to help predict and visualize crime patterns across time and space.
Expand Down Expand Up @@ -89,23 +94,32 @@ Predspot has four main modules:

Predspot requires Python 3.10 or newer.

```bash
pip install predspot # from PyPI
pip install "predspot[contour]" # + GeoJSON contour export (geojsoncontour)
```

From source, for development:

```bash
git clone https://github.com/adaj/predspot.git
cd predspot
pip install .
pip install -e ".[dev,contour]"
```

Core dependencies (installed automatically): pandas, geopandas, shapely,
numpy, scipy, scikit-learn, statsmodels and matplotlib. The optional
`geojsoncontour` package enables `predspot.utilities.contour_geojson`.
numpy, scipy, scikit-learn, statsmodels and matplotlib.

### Tests 🧪

```bash
pip install pytest
pytest
ruff check src tests # lint
pytest # ~10 s
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for the release process and
[CHANGELOG.md](CHANGELOG.md) for what changed between versions.

### Input Data Format 📊

The crime data should be a pandas DataFrame with the following required columns:
Expand Down
6 changes: 0 additions & 6 deletions install.md

This file was deleted.

28 changes: 0 additions & 28 deletions predspot/__init__.py

This file was deleted.

95 changes: 95 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "predspot"
dynamic = ["version"]
description = "Predicting crime hotspots with machine learning"
readme = "README.md"
license = "BSD-3-Clause"
license-files = ["LICENSE"]
requires-python = ">=3.10"
authors = [
{ name = "Adelson Araujo", email = "adelson.dias@gmail.com" },
]
keywords = [
"crime", "hotspots", "spatio-temporal", "kernel density estimation",
"geopandas", "scikit-learn", "forecasting", "criminology",
]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Science/Research",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: GIS",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
]
dependencies = [
"numpy>=1.24",
"pandas>=2.2",
"geopandas>=1.0",
"shapely>=2.0",
"scipy>=1.10",
"scikit-learn>=1.3",
"statsmodels>=0.14",
"matplotlib>=3.7",
]

[project.optional-dependencies]
contour = ["geojsoncontour>=0.4"]
dev = [
"pytest>=8",
"pytest-cov>=5",
"ruff>=0.6",
"build>=1.2",
"twine>=5",
]

[project.urls]
Homepage = "https://github.com/adaj/predspot"
Documentation = "https://adaj.github.io/predspot/"
Repository = "https://github.com/adaj/predspot"
Issues = "https://github.com/adaj/predspot/issues"
Changelog = "https://github.com/adaj/predspot/blob/master/CHANGELOG.md"

[tool.setuptools]
package-dir = { "" = "src" }

[tool.setuptools.packages.find]
where = ["src"]

[tool.setuptools.dynamic]
version = { attr = "predspot.__version__" }

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-ra"
filterwarnings = [
"error::DeprecationWarning:predspot",
"error::FutureWarning:predspot",
]

[tool.coverage.run]
source = ["predspot"]
branch = true

[tool.ruff]
line-length = 100
target-version = "py310"
src = ["src", "tests"]

[tool.ruff.lint]
select = ["E", "F", "W", "I", "B", "UP", "NPY", "PD"]
ignore = [
"PD011", # .values is used deliberately for numpy interop
]

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["B011"]
8 changes: 0 additions & 8 deletions requirements.txt

This file was deleted.

Loading
Loading