Group recommender systems for Python: results aggregation and profile aggregation as first-class citizens behind one API. Preference aggregation, group recommendation, fairness.
Project description
grouprec
Group recommender systems for Python — results aggregation and profile aggregation as first-class citizens behind one API.
Keywords: group recommendation · group recommender systems · preference aggregation · collaborative filtering · fairness · Python.
Why this exists
One library for both kinds of group recommender — deep-learning SOTA models (AGREE, GroupIM, ConsRec, …) and classic, fairness-oriented aggregators (GFAR, EP-FuzzDA, RLProp/LTP, …) — behind one API, so you compare them head-to-head on the same data, splits, and metrics.
Group recommendation has split into two communities that rarely compare against each
other (Peska et al., Bridging the Rift, UMAP 2025); general-purpose toolkits (LensKit,
RecBole, Cornac, …) are single-user. grouprec bridges that — swap a results-aggregator
for a deep model, score the same recommender under coupled vs decoupled, and
put both in one leaderboard. See the design & the rift.
Install
pip install -e ".[full]"
Quickstart
import grouprec as gr
from grouprec import GroupRecommender, evaluate
from grouprec.backends import EASE # or implicit_als(), Popularity(), lenskit(...)
data = gr.make_blobs_dataset(seed=0) # or gr.datasets.load("ml-1m") / your own Dataset
groups = gr.groups.synthetic(data, kind="similar", size=4, n=1000, metric="pearson")
folds = gr.split.crossval(data, k=5, seed=0)
rec = GroupRecommender(EASE(), gr.aggregators.get("GFAR"), normalize="minmax")
report = evaluate(rec, data, groups, folds,
protocol=["coupled", "decoupled"], # score both at once
metrics=["ndcg@10", "recall@10"],
group_aggregations=["mean", "min", "minmax"]) # the fairness lens
print(report.pivot())
Aggregators are plain numpy and usable standalone on a (n_members, n_items) matrix:
import numpy as np
from grouprec.aggregators import get
get("LTP").aggregate(np.array([[5., 3., 1.], [2., 3., 4.]]), k=2)
Bring your own recommender (wide algorithm coverage via adapters)
We don't reimplement single-user recommenders — we wrap the established
frameworks so you inherit their entire model zoos, plus a few dependency-free
built-ins. Any object with fit(dataset) + score(users, items=None) is a backend.
| Backend | How | Algorithms |
|---|---|---|
| Built-in (no extra deps) | Popularity, EASE, ItemKNN, Random |
popularity, EASE^R, item-kNN |
implicit [implicit] |
gr.backends.implicit_als(factors=64), implicit_bpr(...) |
ALS, BPR |
LensKit [lenskit] |
gr.backends.lenskit(ImplicitMFScorer(...)) |
ImplicitMF, BiasedMF, ItemKNN, UserKNN, EASE, SLIM, … |
RecBole [recbole] |
gr.backends.recbole(model, dataset) (experimental) |
the full RecBole zoo |
Deep group models ([torch])
Lazily imported, so import grouprec never pulls torch:
from grouprec.models import AGREE, GroupIM, ConsRec, make_synthetic_group_data
gd = make_synthetic_group_data(seed=0)
model = ConsRec(gd.groups, gd.group_interactions).fit(gd.dataset)
model.recommend(gd.groups[0], k=10) # paradigm="profile" -> coupled group-level
Model zoo: NCFGroup, AGREE, GroupIM (InfoMax SSL), ConsRec
(overlap/hypergraph/LightGCN consensus), HyperGroup (hierarchical hyperedge
embedding), HHGR (double-scale self-supervised hypergraph), AlignGroup
(InfoNCE member/group alignment) — each reviewed against its original repo. They plug
into benchmark(..., level="sampled") and share the same coupled protocol as
results-aggregators, so both families compare side by side.
Datasets (license-aware)
data = gr.datasets.load("ml-1m") # auto-fetched, cached, parsed
data = gr.datasets.k_core(data, k=5) # k-core / binarize / min-count preprocessing
print(gr.datasets.info("kgrec").license) # every entry carries license + citation
gd = gr.datasets.load_consrec("path/CAMRa2011") # explicit-group benchmark
gd = gr.datasets.load_yin(gr.datasets.fetch_yin(accept_license=True), "yelp")
| Policy | Datasets | Behavior |
|---|---|---|
auto |
MovieLens 100K/1M/25M/32M/latest/latest-small | fetched for your own use (GroupLens permits research download; redistribution terms differ by release — 100K/1M forbid it, 25M/latest allow it under same terms) |
auto_nc |
KGRec, Last.fm, Yelp-LA, Douban-SH | non-commercial — fetched only after accept_license=True, citations surfaced |
manual |
CAMRa2011, Mafengwo, Weeplaces | redistribution unclear — load prints where to download |
Licensing: The library code is released under MIT. Datasets are not relicensed by the library and remain subject to their upstream terms.
The library does not bundle dataset files; for datasets with access restrictions or non-commercial terms, loading is enabled only when the user accepts the dataset-specific license or follows the upstream download instructions. Plus
from_huggingface(...) / from_path(...) for anything else.
Benchmark & the rift
Score the same recommender under coupled vs decoupled and put both families on one board:
res = gr.benchmark(recs, tasks, protocols=["coupled", "decoupled"], metrics=["ndcg@10"])
res.to_csv("leaderboard.csv") # tidy long-format
res.leaderboard("ndcg", k=10, protocol="coupled") # ranking flips vs "decoupled"
Explore a group recommendation end-to-end in the
interactive inspector
— built on the 20-core of MovieLens ml-latest (204,257 users / 23,290 items / 32.2M
ratings); every ranking is a real grouprec call
(how it's built; regenerate with
grouprec-build-inspector, needs [torch] — add --small for a quick, much smaller
page off ml-latest-small).
What's inside
- Aggregators (numpy core):
ADD AVG LMS MUL MPL AVGNM BDC FAI,GFAR GreedyLM PAR SPGreedy EPFuzzDA(fairness),RLProp LTP PeriodicFAI EPFuzzDAWeighted SDAA SIAA(sequential). - Group formation:
gr.groups.synthetic(kind="random|similar|divergent|outlier"). - Evaluation:
coupled/decoupled/sampledprotocols; metrics at the per-member (ndcg/recall/hr/ar/…×mean/min/minmax/jain/zero) and per-list (novelty,list_coverage,register_list_metric) levels. - Reproducibility:
gr.Experiment(seed + env + git SHA/dirty/diff + citations),gr.set_seed,gr.cite("ConsRec").
Extras at a glance
gr.cite("ConsRec") # BibTeX for any implemented method
gr.collect_citations(rec, dataset) # auto-collect cites for what a run used
with gr.Experiment("run1", seed=42, cite=[rec, dataset]) as exp: # cites auto-resolved
... # writes runs/run1-<ts>/ on exit
gr.eval.register_metric("coverage", fn) # custom per-member metric
gr.eval.register_list_metric("ild", fn) # custom per-list metric
Contributing — researchers especially welcome
Published a group-rec method? Add it (small PR — CONTRIBUTING.md
has copy-paste recipes for an aggregator / deep model / dataset / metric), or just
link your repo in a port-request issue and we'll port it. Every method
ships with its citation, so your work is credited wherever the library is used.
Students & practitioners welcome too (good-first-issue).
Citation
If you use grouprec, please cite it (CITATION.cff) and the relevant method
(gr.cite(...)). Docs: https://pdokoupil.github.io/grouprec.
A demo-track paper describing this toolkit is under review at RecSys 2026:
Patrik Dokoupil, Ludovico Boratto, and Ladislav Peska. GroupRec: A Unified Toolkit for Reproducible and Inspectable Group Recommendation Research.
License
MIT. Datasets retain their own licenses (see Datasets above).
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 grouprec-0.0.2.tar.gz.
File metadata
- Download URL: grouprec-0.0.2.tar.gz
- Upload date:
- Size: 762.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7008b8eefdd6a2743af0d5f1533a7cdbee53a66398eea5cde7daeee2b163cfe9
|
|
| MD5 |
a6e074e725f5f9ca6799f88ff7b18b51
|
|
| BLAKE2b-256 |
4124e95f2cc6af43c6700fe07f91f7c7699a50080c6010b3ce54cac6de5f1b54
|
File details
Details for the file grouprec-0.0.2-py3-none-any.whl.
File metadata
- Download URL: grouprec-0.0.2-py3-none-any.whl
- Upload date:
- Size: 143.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
660bb01e01c1735a10d82c95cabd9db11b2a08487b27c2f786cec61635edfe66
|
|
| MD5 |
a5a173ea69592dd07b7a45f236fa9f76
|
|
| BLAKE2b-256 |
d106dd0d5d79873b743fb64d6e990a6e3d9854cbc7a3db99ff59ab8327fde266
|