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 (HGNN), AlignGroup
(InfoNCE member/group alignment) — each reviewed against its original repo. They plug
into benchmark(..., level="sampled") and share the same coupled leaderboard as
results-aggregators. Reproduced on CAMRa2011 (HR@5): GroupIM 0.62, ConsRec 0.62,
AGREE/AlignGroup/HyperGroup ~0.59, EASE+GFAR 0.58.
There's also a profile-first path (ProfileGroupRecommender):
aggregate-then-recommend — merge member profiles (average/union/sum) into a
pseudo-user, query the base RS once.
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-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, leaderboard & the rift
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"
scripts/run_leaderboard.py regenerates a CSV + a static HTML page (GitHub-Pages
hostable) + an accumulating LeaderboardStore. A live Streamlit browser is in
examples/leaderboard_app.py (pip install grouprec[demo]). Plot the
relevance–fairness trade-off with gr.bench.viz.plot_pareto(...).
Explore a group recommendation end-to-end in the
interactive inspector
— every ranking is a real grouprec call (how it's built;
regenerate with grouprec-build-inspector, needs [torch]).
scripts/build_showcase.py produces the headline two-panel board
(docs/leaderboard.html, refreshed by CI): (A) deep models vs
EASE+GFAR/EASE+AVG under coupled sampled HR/NDCG on CAMRa2011 + Mafengwo; (B)
aggregators decoupled on MovieLens, where LTP/RLProp lead the fairness–utility
trade-off (ndcg.min 0.27 vs AVG 0.22; AVG wins raw utility).
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 three levels — per-member (ndcg/recall/hr/ar/…×mean/min/minmax/jain/zero), per-list (novelty,list_coverage,register_list_metric), per-run (carbon viagr.track_emissions). Long-term fairness:dMAE,groupSatO,groupDisO. - 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
with gr.track_emissions() as em: ... # carbon cost of a run
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.
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.1.tar.gz.
File metadata
- Download URL: grouprec-0.0.1.tar.gz
- Upload date:
- Size: 727.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ae249785189728752dc6ff9d1a1b9f25078f508d02977ecda480c0dd16ec442
|
|
| MD5 |
6d79402fd8040143661d04afa731482d
|
|
| BLAKE2b-256 |
e6fdd87bc99e4d2d10a9c7d0705efcdf4da21ae75506b259237a71edd959ea4a
|
File details
Details for the file grouprec-0.0.1-py3-none-any.whl.
File metadata
- Download URL: grouprec-0.0.1-py3-none-any.whl
- Upload date:
- Size: 125.5 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 |
1bdcf2b7ee6ca5fa769712fa913ad9abc21e36e69b8a8a25f4ed7dd4a7f43b57
|
|
| MD5 |
7842da1824105fc97e4cb919dbae0369
|
|
| BLAKE2b-256 |
db696b4cc46cd72a802aa3216acf088041f9bddd0ca34abfbe956c3b9a59509f
|