Domain-agnostic LOOPR ranking engine library
Project description
LOOPR
loopr is a domain-agnostic ranking library for event-based competition data.
It is built for the common real-world case where outcomes are recorded for
groups or teams, but the thing you actually want to rank is individuals. Give
it event results plus who belonged to or appeared for each group, and it
decomposes that team-shaped evidence into entity-level rankings.
The stable public API is:
rank_entities(...)for the one-shot ranking pathprepare_rank_inputs(...)for validating neutral input tablesLOOPREnginewhen you want engine state, diagnostics, or LOO analysisExposureLogOddsConfigwhen you need to override defaults
LOOPREngine is currently an alias for ExposureLogOddsEngine.
Installation
PyPI distribution name:
pip install loopr-ranking
Import path remains:
import loopr
For local development:
pip install -e .
pip install -e .[dev]
If you use uv:
uv sync --extra dev
Requires Python 3.10+.
Docker Build
The wheel and sdist release path is also available through the multi-stage
Dockerfile.
Run tests and quickstart smoke inside Docker:
docker build --target test .
Build distributable artifacts into a local directory:
docker buildx build --target artifacts --output type=local,dest=dist .
Quick Start
Command line:
loopr rank \
--matches examples/quickstart/matches.csv \
--participants examples/quickstart/participants.csv \
--appearances examples/quickstart/appearances.csv \
--output rankings.csv
If the package is installed and you prefer the module entrypoint:
python -m loopr rank \
--matches examples/quickstart/matches.csv \
--participants examples/quickstart/participants.csv \
--appearances examples/quickstart/appearances.csv \
--output rankings.csv
Python:
import polars as pl
from loopr import rank_entities
matches = pl.read_csv("examples/quickstart/matches.csv")
participants = pl.read_csv("examples/quickstart/participants.csv")
appearances = pl.read_csv("examples/quickstart/appearances.csv")
entities = pl.read_csv("examples/quickstart/entities.csv")
rankings = rank_entities(
matches,
participants,
appearances=appearances,
)
print(
rankings.join(entities, on="entity_id")
.select(["entity_id", "entity_name", "score", "exposure"])
.head(10)
)
If your spreadsheets look like this, you are on the happy path.
matches.csv
| event_id | match_id | winner_id | loser_id | completed_at |
|---|---|---|---|---|
| 1 | 10 | 100 | 200 | 1700000000 |
| 1 | 11 | 100 | 300 | 1700003600 |
| 1 | 12 | 300 | 200 | 1700007200 |
participants.csv
| event_id | group_id | entity_id |
|---|---|---|
| 1 | 100 | 1 |
| 1 | 100 | 2 |
| 1 | 200 | 3 |
| 1 | 200 | 4 |
| 1 | 300 | 5 |
| 1 | 300 | 6 |
appearances.csv (optional)
| event_id | match_id | entity_id | group_id |
|---|---|---|---|
| 1 | 10 | 1 | 100 |
| 1 | 10 | 2 | 100 |
| 1 | 10 | 3 | 200 |
| 1 | 10 | 4 | 200 |
If you omit appearances, loopr assumes the full event-level group roster
participated in each result.
The example files shown above live in the repository under
examples/quickstart/. They are not installed with the wheel. After
installing the package, you can regenerate them with:
python -m loopr.example_data --output-dir examples/quickstart
Recommended Defaults
For most users, the right starting point is:
rank_entities(...)- default configuration
appearancesincluded whenever available
Treat the output as a ranking signal, not a calibrated probability-like score.
Tune only after you have an external validation target or a clear operational
reason. The deeper guidance lives in the repository docs under
docs/defaults-and-recipes.md and docs/validation-harness.md.
Public Input Shape
The main public path expects binary group-result inputs and returns individual/entity rankings.
Matches
Required columns:
event_idmatch_idwinner_idloser_id
Optional columns:
completed_atcreated_atwalkover
Participants
Required columns:
event_idgroup_identity_id
Appearances
Optional per-match participation data:
event_idmatch_identity_id- optional
group_id
If appearances are present, loopr uses them to determine who actually
played in a result instead of assuming the full roster participated.
Stable API
For published usage, prefer these as the supported surface:
rank_entities(...)loopr rankprepare_rank_inputs(...)LOOPREngineExposureLogOddsConfig
The public API is neutral-schema-only. Inputs using the older
tournament / team / user naming are not part of the supported public
surface.
Engine Summary
LOOPREngine / ExposureLogOddsEngine
The recommended default. It is volume-neutral, exposure-based, supports time decay and inactivity decay, and includes exact leave-one-match-out analysis.
TickTockEngine
An iterative tournament-influence engine that alternates between entity rating updates and tournament-strength updates.
TTLEngine
A hybrid flow that uses tick-tock tournament influence updates with a rating backend such as the log-odds backend.
Documentation
README is the general entrypoint. The advanced docs live in the repository
under docs/, including:
docs/README.md: advanced docs indexdocs/input-patterns.md: schema guidance and normalizationdocs/how-loopr-works.md: technical walkthroughdocs/mathematical-machinery.md: equations and intuitiondocs/engines-and-configuration.md: engine comparison and configurationdocs/defaults-and-recipes.md: starting setup and baseline recipesdocs/validation-and-benchmarks.md: evaluation guidancedocs/validation-harness.md: reusable validation contractdocs/ablations.md: ingredient-level comparison designdocs/case-studies/README.md: applied examplesdocs/analysis-and-diagnostics.md: diagnostics and LOO analysis
Common Next Steps
- Use
prepare_rank_inputs(...)when you want schema validation before ranking or when debugging normalized inputs. - Pass
appearanceswhen match-level participation differs from the stored roster. - Start with
rank_entities(...)and the default config, then validate before tuning; seedocs/defaults-and-recipes.mdin the repository.
Development
Run the test suite with:
pytest -q
The codebase uses Polars, NumPy, and SciPy for the main compute path.
License
Apache-2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
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 loopr_ranking-0.0.1.tar.gz.
File metadata
- Download URL: loopr_ranking-0.0.1.tar.gz
- Upload date:
- Size: 78.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fac0acf353edbfc1f76055cd53b1a0db8856039d0ed2514434f6ada30e91ec71
|
|
| MD5 |
6e85dbbaf26120a12e483f92c2f6a73b
|
|
| BLAKE2b-256 |
b5ad5cca250744c9795afdcf43bf0e0490f21ee699fa1966c28e42b9021cec25
|
File details
Details for the file loopr_ranking-0.0.1-py3-none-any.whl.
File metadata
- Download URL: loopr_ranking-0.0.1-py3-none-any.whl
- Upload date:
- Size: 71.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ae7570b78dc0693653530ca08e72be4022ee86a737f265ef070164693127284
|
|
| MD5 |
a6bd777a8d854e64e8400621f472c97b
|
|
| BLAKE2b-256 |
d1638513736c24fdab9d5b030977ac25e1d3c103fde5d2844989cf99ab5ff6eb
|