REMFlow: relational event modeling in Python
REMFlow implements relational event models (REMs) for ordered sender-receiver interactions. For each observed event, it constructs the set of events that could have occurred and evaluates time-varying network statistics for the observed and alternative events.
The package fits conditional event-choice models for ordinal data and intensity models for exact or duration data. It supports tie-oriented and actor-oriented specifications, model diagnostics, and next-event prediction. The general high-level facade supports untyped and typed tie-oriented events. A dedicated misinformation subclass adds descriptive actor-role and group-similarity measures and evaluates actor removal in the conditional next-event distribution.
Installation
REMFlow requires Python 3.11 or newer. Install the released package from PyPI:
python -m pip install remflow
Only for development from a source checkout, use an editable install:
python -m pip install -e .
For development and documentation work:
python -m pip install -e ".[dev,docs]"
JAX support is optional:
python -m pip install "remflow[gpu]"
Readable result tables require no extra dependency. Basic graphical output is not installed by default. Enable it with the optional Matplotlib extra:
python -m pip install "remflow[plot]"
When running examples from a source checkout, use
python -m pip install -e ".[plot]" instead.
The classroom example generates a
two-panel figure with --plot.
For GPU use, install the JAX build appropriate for the local CUDA setup. An
explicit backend="jax:gpu" request fails with BackendUnavailable if JAX
cannot see a GPU; it does not fall back to the CPU.
The optional CuPy dependency is used only by the CUDA comparison benchmarks:
python -m pip install "remflow[benchmark-cuda]"
A small example
The following example fits an exact-time model with inertia, reciprocity, and outgoing two-path statistics:
import pandas as pd
from remflow import (
coefficient_table,
diagnostic_table,
diagnostics,
remify,
remstats,
remstimate,
)
events = pd.DataFrame(
{
"time": [1.0, 2.0, 3.0, 4.0, 5.0],
"sender": ["A", "B", "A", "C", "B"],
"receiver": ["B", "A", "C", "A", "C"],
}
)
history = remify(events, actors=["A", "B", "C"], ordinal=False)
statistics = remstats(
history,
tie_effects="~ inertia() + reciprocity() + otp()",
first=2,
)
fit = remstimate(history, statistics, backend="numpy")
report = diagnostics(fit, history, statistics)
print(coefficient_table(fit).to_string(index=False))
print(diagnostic_table(report).to_string(index=False))
After installing the optional plot extra, generate Matplotlib figures:
from remflow import plot_coefficients, plot_diagnostics
coefficient_figure, _ = plot_coefficients(fit)
diagnostic_figure, _ = plot_diagnostics(report)
Set ordinal=True to fit a conditional event-choice model instead. Public
actor, dyad, type, and event identifiers are 1-based; the input labels remain
available in the history dictionaries.
The formula language is intentionally restricted and never calls eval or
exec. The same effects can also be assembled with the Python builder API.
What is implemented
Event histories may be directed or undirected and may use exact, ordinal, or
duration time. The preprocessing code handles simultaneous and typed events,
weights, actor and dyad attributes, manual opportunity sets, and sampled tie
risk sets. For larger datasets, remify(..., ncores=2) can build risk sets
concurrently without changing their order.
The statistics module includes inertia, reciprocity, degree effects, shared partners, participation shifts, recency, rank, active-state effects, and user covariates. Both string formulas and typed effect objects preserve term order.
The main estimation paths are:
- tie-oriented and actor-oriented ordinal or exact-time MLE;
- HMC for supported tie and actor models;
- interval and ordinal duration MLE;
- sampled tie likelihoods;
- frequentist penalties, random effects, finite mixtures, and moving windows;
- Bayesian shrinkage in its documented NumPy paths.
Fits retain coefficient order, covariance information, convergence status, backend metadata, fitted probabilities, and the data needed by the available diagnostics. AIC, BIC, AICC, and WAIC are provided where their required inputs exist.
The general RelationalEventModel facade works with untyped or typed events.
MisinformationModel extends it with action and stance conventions,
descriptive actor-role scores, source ranking, echo-chamber metrics, and a
conditional next-event intervention. The intervention is not a full cascade
simulator or a causal estimator.
Current limitations
Several combinations are rejected explicitly because their statistical or backend implementation is not complete:
- bipartite/two-mode risk sets and polyadic relational hyperevents;
- type-expanded actor risk sets and actor case-control sampling;
- Bayesian frailty/random-effects models and general Bayesian duration models;
- WAIC for mixture, random-effects, and duration fits;
- non-constant concomitant formulas in mixture models;
- JAX execution for mixtures, random effects, penalties, and shrinkage;
- duration attribution with
remtribute.
Text embeddings and stance labels are not generated by REMFlow. Supply them as covariates if an analysis needs them.
The public names remify, remstats, and remstimate follow the established
three-stage terminology used by R REM packages. They are functions inside the
remflow Python namespace, not drop-in replacements for those packages.
Backends
Use backend="numpy", "jax", "jax:cpu", or "jax:gpu". The default
numpy backend runs on the CPU. For model families with a JAX implementation,
jax:cpu and jax:gpu place the likelihood and derivative calculations on the
requested device. Both implementations use float64, and the test suite checks
their numerical agreement. Fit metadata records the selected backend,
platform, device, precision, JAX version, and compilation state.
engine="auto" currently selects SciPy. The optimizer engine and array backend
are separate choices: selecting SciPy does not prevent supported objective or
gradient work from running through JAX.
GPU benchmark
The hardware-gated suite was run using an NVIDIA GeForce RTX 4070 Laptop GPU (8 GiB), Python 3.12.3, JAX/JAXLIB 0.7.2, CUDA 12, and float64. All 11 GPU tests passed without CPU fallback.
The measurements below are means from 10 likelihood-and-gradient evaluations after JAX compilation. They measure the numerical kernel, not event preprocessing or total fitting time.
| Actors | Events | Risk set | NumPy | JAX GPU | Speedup | Maximum gradient error |
|---|---|---|---|---|---|---|
| 50 | 1,000 | 2,450 | 176.330 ms | 5.734 ms | 30.75x | 2.13e-14 |
| 100 | 1,000 | 9,900 | 419.867 ms | 11.055 ms | 37.98x | 2.49e-14 |
Warm-up took 3.208 seconds for 50 actors and 11.220 seconds for 100 actors. Measured peak GPU memory was 165.42 MiB and 512.00 MiB, respectively. To rerun the checks and benchmark:
REMFLOW_REQUIRE_GPU=1 JAX_ENABLE_X64=true python -m pytest -q tests/gpu
python benchmarks/run_gpu_study.py --repeats 10 --include-large
Small problems may be faster with NumPy because JAX compilation and device transfer overhead dominate the computation.
Development checks
uv run python -m pytest
uv run python -m ruff check .
uv run python -m mypy src
uv run python -m sphinx -W --keep-going -b html docs docs/_build/html
The physical-GPU tests run only when compatible hardware is available and
REMFLOW_REQUIRE_GPU=1 is set.
Documentation
- Source repository
- Read the Docs: Quick start
- Introduction
- Quick start
- Usage guide
- API reference
- Performance evaluation
- Classroom event study
License
REMFlow is released under the MIT License. The classroom dataset in
data/classroom_events/ keeps its upstream CC BY-NC-ND 4.0 license and is not
covered by the project license. Provenance and reuse terms are recorded with
the data.
Metadata
Release files for remflow 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| remflow-0.1.2.tar.gz | 115.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| remflow-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 236.8 kB
Release files / remflow-0.1.2.tar.gz
| Download URL | remflow-0.1.2.tar.gz |
|---|---|
| Size | 115.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b9c94b355f6177260d5b5eb741a9e360b08f9691949e3661b48448fb8132a33d
|
|
BLAKE2b-256 checksum How to use checksums |
c9570579c14dfe7db12437177972f05ae2fd2e82596adc41cb1353d3682b68ec
|
| 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 Oct 7, 2026.
Transparency logRelease files / remflow-0.1.2-py3-none-any.whl
| Download URL | remflow-0.1.2-py3-none-any.whl |
|---|---|
| Size | 121.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9ed25792ae40c725e3d253f89bc1374eae1960936376cbb1df26bc011cb5390a
|
|
BLAKE2b-256 checksum How to use checksums |
f96b12eff27808b3d3f7cf58442e6776f50571ef5196f55aa38ef398c2d92791
|
| 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 Oct 7, 2026.
Transparency log