Skip to main content

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.

Python versions License: MIT GitHub stars CI codecov docs code style: ruff

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 / sampled protocols; 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 via gr.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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

grouprec-0.0.1.tar.gz (727.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

grouprec-0.0.1-py3-none-any.whl (125.5 kB view details)

Uploaded Python 3

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

Hashes for grouprec-0.0.1.tar.gz
Algorithm Hash digest
SHA256 2ae249785189728752dc6ff9d1a1b9f25078f508d02977ecda480c0dd16ec442
MD5 6d79402fd8040143661d04afa731482d
BLAKE2b-256 e6fdd87bc99e4d2d10a9c7d0705efcdf4da21ae75506b259237a71edd959ea4a

See more details on using hashes here.

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

Hashes for grouprec-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1bdcf2b7ee6ca5fa769712fa913ad9abc21e36e69b8a8a25f4ed7dd4a7f43b57
MD5 7842da1824105fc97e4cb919dbae0369
BLAKE2b-256 db696b4cc46cd72a802aa3216acf088041f9bddd0ca34abfbe956c3b9a59509f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page