Group recommendations that are fair over time. If a member loses out this session, LTP prioritizes them next session — keeping result-level proportionality across a sequence of sessions while preserving group utility.
Group recommender systems must balance conflicting member preferences, and within
a single recommendation it's often impossible to be fair to everyone. But group
decisions usually happen over several sessions — so fairness can be balanced
across them. LTP (Long-Term Proportionality) does exactly that: it carries
per-member fairness state between sessions and selects proportionally, so no member
is consistently overlooked.
Algorithm: Patrik Dokoupil & Ladislav Peska (KAIS '26, see Citing). This implementation: Patrik Dokoupil — a standalone, packaged reimplementation.
pip install ltp-rsCreate one LTP per group; call recommend once per session — the fairness state
carries across calls.
import numpy as np
from ltp import LTP
agg = LTP(gamma=1.0, beta=0.0) # one aggregator per group
for session in range(n_sessions):
# ratings[m, i] = predicted rating of item i for group member m, this session
ratings = your_model.predict(group, session) # shape (n_members, n_items)
recommendation = agg.recommend(ratings, k=10) # -> item indices
agg.reset() # start a fresh groupItems recommended in earlier sessions are not repeated (toggle with
avoid_repeats=False).
gamma— memory of past sessions (1.0 = full; < 1.0 gradually forgets).beta— in-list position discount; item at positionpupdates state with weightexp(-beta·p)(0.0 = all positions equal).tie_breaking— fairness nudge when items score near-equally.member_weights— relative importance of members (the paper's user weightsw; default uniform).normalize— per-member scaling each session:None,"minmax","standard","robust","quantile".
Each session, LTP runs RLProp's mandate-allocation step over the group members (members play the role of "objectives"), but seeded with each member's accumulated gains from previous sessions, averaged by the number of sessions. A member who has been under-served carries a larger unfilled mandate and is favored until balance is restored. See the paper for the algorithm, the simulated-choice evaluation, and the fairness/utility trade-off.
python examples/quickstart.py shows cumulative per-member utility staying far more
balanced under LTP than under a per-session additive baseline.
LTP is the sequential, group generalization of
RLProp: a single session of LTP with
gamma=1, beta=0 is exactly RLProp over the group members. This package reuses
RLProp's allocation kernel (rlprop.core.rlprop_step) and normalizers, so the two
stay numerically consistent (a test asserts the single-session equivalence).
If you use this software, please cite the paper (GitHub's "Cite this repository"
button reads CITATION.cff):
@article{dokoupil2026ltp,
author = {Dokoupil, Patrik and Peska, Ladislav},
title = {Long-term fairness in sequential group recommendations},
journal = {Knowledge and Information Systems},
volume = {68},
number = {1},
year = {2026},
doi = {10.1007/s10115-025-02642-9}
}MIT — see LICENSE.