API Reference¶
Common interface¶
recommender_systems.base ¶
The common interface shared by all recommenders.
Recommender ¶
Bases: ABC
Abstract base class for recommendation algorithms.
Concrete recommenders learn from interaction data in :meth:fit and produce a ranked
list of item ids in :meth:recommend. Sharing one interface lets algorithms be swapped
and evaluated interchangeably.
fit
abstractmethod
¶
Train on a ratings frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ratings
|
DataFrame
|
Interaction data with at least |
required |
Returns:
| Type | Description |
|---|---|
Recommender
|
The fitted instance, so calls can be chained. |
recommend
abstractmethod
¶
Return the top-n recommended item ids for user_id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
Hashable
|
The user to recommend for. |
required |
n
|
int
|
Maximum number of items to return. |
10
|
Returns:
| Type | Description |
|---|---|
list of Hashable
|
Item ids ordered from most to least recommended. |
Recommenders¶
Baselines¶
recommender_systems.baselines ¶
Non-personalized baseline recommenders.
MeanRating ¶
Bases: _RankingBaseline
Rank items by mean rating, requiring a minimum number of ratings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
min_ratings
|
int
|
Minimum number of ratings an item needs to be eligible. |
1
|
Neighborhood collaborative filtering¶
recommender_systems.neighborhood ¶
Neighborhood (k-NN) collaborative filtering on sparse matrices.
ItemKNN ¶
Bases: _SparseMatrixBackedRecommender
Score items by similarity to the items a user has already rated.
Builds a sparse item-item cosine similarity matrix, keeps the k largest
entries per row, and scores by S @ user_row. The full similarity is
materialized in CSR form, which is fine even for goodbooks-10k (10k by 10k
items would be 100M entries dense; in sparse form after the top-k trim
it's k * n_items = a few hundred thousand non-zeros).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
int
|
Number of nearest neighbors retained per item. |
20
|
UserKNN ¶
Bases: _SparseMatrixBackedRecommender
Score items by the ratings of a user's nearest neighbors.
Builds the neighborhood with :class:sklearn.neighbors.NearestNeighbors
(cosine metric on the sparse user-item matrix) rather than materializing
the full users-by-users similarity — that's n_users**2 and blows up
past a few thousand users. Per-user scoring weights the neighbors' rating
rows by their similarities.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
int
|
Number of nearest neighbors retained per user. |
20
|
Matrix factorization¶
recommender_systems.svd ¶
Matrix-factorization recommender via truncated SVD.
SVD ¶
Bases: _SparseMatrixBackedRecommender
Recommend from a low-rank reconstruction of the user-item matrix.
Operates on the sparse user-item matrix directly. TruncatedSVD accepts
CSR natively, so the dense (n_users, n_items) matrix never has to be
materialized — the win that opens the goodbooks-full corpus to SVD.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_factors
|
int
|
Number of latent factors. Clamped to the matrix rank when smaller. |
20
|
random_state
|
int | None
|
Seed for the SVD solver. |
None
|
Bayesian Personalized Ranking¶
recommender_systems.bpr ¶
Bayesian Personalized Ranking for implicit feedback.
BPR ¶
BPR(n_factors: int = 32, epochs: int = 20, learning_rate: float = 0.05, reg: float = 0.01, random_state: int | None = None)
Bases: _MatrixBackedRecommender
Bayesian Personalized Ranking — learns item embeddings from implicit feedback.
Every observed (user, item) interaction is treated as a positive signal; random unobserved items are sampled as negatives. The objective is to score each positive higher than its sampled negative — implemented as SGD on the sigmoid-margin loss with L2 regularization. The rating values themselves are ignored; only presence of an interaction matters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_factors
|
int
|
Dimensionality of the user and item embeddings. |
32
|
epochs
|
int
|
Number of full passes over the observed interactions. |
20
|
learning_rate
|
float
|
SGD step size. |
0.05
|
reg
|
float
|
L2 regularization strength applied to user and item factors. |
0.01
|
random_state
|
int | None
|
Seed for initialization and negative sampling. |
None
|
Alternating Least Squares¶
recommender_systems.als ¶
Alternating Least Squares for implicit-feedback matrix factorization.
ALS ¶
ALS(n_factors: int = 32, epochs: int = 15, regularization: float = 0.01, alpha: float = 40.0, random_state: int | None = None)
Bases: _PredictedScoreRecommender
Implicit-feedback matrix factorization via alternating least squares.
Follows Hu, Koren & Volinsky (2008): binary preferences p_ui = 1 if r_ui > 0
with confidence c_ui = 1 + alpha * r_ui, then alternate closed-form solves
for the user factors X and item factors Y of the regularized weighted
least-squares loss.
Same algorithm family as :class:recommender_systems.bpr.BPR but a different
optimization story — closed-form alternating solves instead of SGD on a sigmoid
margin — so it tends to converge in many fewer epochs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_factors
|
int
|
Latent factor dimensionality. |
32
|
epochs
|
int
|
Full passes over the (X, Y) update cycle. |
15
|
regularization
|
float
|
L2 regularization strength applied to the factor solves. |
0.01
|
alpha
|
float
|
Confidence scaling: a rating of |
40.0
|
random_state
|
int | None
|
Seed for factor initialization. |
None
|
Two-tower neural CF¶
recommender_systems.neural ¶
Two-tower neural collaborative filtering (PyTorch).
Optional — requires the neural extra:
pip install 'recommender-systems[neural]'
TwoTowerCF ¶
TwoTowerCF(n_factors: int = 32, epochs: int = 20, learning_rate: float = 0.01, batch_size: int = 256, random_state: int | None = None)
Bases: _PredictedScoreRecommender
Two-tower neural CF trained with a BPR-style ranking loss.
Each user and item is a learned embedding; the score for a (user, item) pair is
the dot product of their vectors. Training samples observed (positive) and random
unobserved (negative) items per user and maximizes the sigmoid margin between
them — the same objective as :class:recommender_systems.bpr.BPR, lifted onto
PyTorch for autograd, batched SGD, and easy extension (e.g. adding side
information into either tower).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_factors
|
int
|
Embedding dimensionality. |
32
|
epochs
|
int
|
Full passes over the observed interactions. |
20
|
learning_rate
|
float
|
Adam optimizer step size. |
0.01
|
batch_size
|
int
|
Triples per gradient step. |
256
|
random_state
|
int | None
|
Seed for embedding init and negative sampling. |
None
|
Content-based¶
recommender_systems.content ¶
Content-based recommendation by item-feature similarity.
ContentBased ¶
Bases: _PredictedScoreRecommender
Recommend items whose features resemble those a user has liked.
The user's profile is a ratings-weighted mean of the features of the items they rated; recommendations are ranked by cosine similarity between that profile and each candidate item.
Side information is passed at construction time rather than to fit. This
keeps fit(ratings) uniform across the library so algorithms stay interchangeable;
see CONTRIBUTING.md for the convention.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item_features
|
DataFrame
|
DataFrame indexed by item id with one numerical feature per column. Callers pre-compute features from raw inputs (TF-IDF over descriptions, embeddings, one-hot categoricals, etc.) before passing them in. |
required |
explain ¶
Return the top features driving item_id's score for user_id.
For each feature, the contribution to the user-item similarity is the
product of the user's profile weight and the item's feature weight.
The top non-zero features are returned as a comma-separated string —
e.g. "fantasy, magic, epic" for a fantasy-genre recommendation.
Returns "" if the user or item is unknown or the user has no profile.
recommend_with_reasons ¶
recommend_with_reasons(user_id: Hashable, n: int = 10, top_features: int = 3) -> list[tuple[Hashable, str]]
Top-n recommendations for user_id paired with their explanations.
Each entry is (item_id, reason) where reason is the output of
:meth:explain for that item — empty string if no features contribute.
Hybrid¶
recommender_systems.hybrid ¶
Combine several recommenders by weighted reciprocal-rank fusion.
HybridRecommender ¶
HybridRecommender(recommenders: Sequence[Recommender], weights: Sequence[float] | None = None, *, rank_constant: int = 60, pool: int = 100)
Bases: Recommender
Blend several recommenders via weighted reciprocal-rank fusion.
Each component produces its own ranked list; an item scores
sum_r weight_r / (rank_constant + rank_r), so items ranked highly by several
weighted components rise to the top. Because the components already exclude items
the user has rated, the fused list does too. Rank fusion needs only the public
recommend output, so any recommender can be combined.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
recommenders
|
Sequence[Recommender]
|
Component recommenders to combine. |
required |
weights
|
Sequence[float] | None
|
Per-component weights; defaults to equal weighting. |
None
|
rank_constant
|
int
|
Dampens the contribution of top ranks (the standard RRF constant). |
60
|
pool
|
int
|
How many items to pull from each component before fusing. |
100
|
Book-specific helpers¶
recommender_systems.books ¶
Book-specific helpers built on the goodbooks-10k loaders.
Drop-in pipelines for the book recommender — turn the tag table from
load_goodbooks_tags into a content-based recommender in one call, so callers
don't have to repeat the join + vectorize + ContentBased boilerplate.
tag_text_per_book ¶
Concatenate each book's tag names into a single space-separated string.
The schema matches what recommender_systems.datasets.load_goodbooks_tags
returns: columns book_id, tag_name, count. Books that share many
tags end up with overlapping vocabularies, which is what drives TF-IDF
similarity downstream.
build_tag_recommender ¶
Build a ContentBased recommender from goodbooks-style tag data.
Each book's tags are joined into one document; text_features runs TF-IDF
over the corpus to weigh rare-across-catalog tags higher than common ones.
The returned recommender follows the side-information convention — fit it on
the ratings frame (with item_id matching the book_id values used here)
and call recommend(user_id, n) as usual.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tags
|
DataFrame
|
DataFrame with columns |
required |
**vectorizer_kwargs
|
Any
|
Forwarded to |
{}
|
build_hybrid_book_recommender ¶
build_hybrid_book_recommender(tags: DataFrame, *, collaborative: Recommender | None = None, weights: tuple[float, float] = (3.0, 1.0), rank_constant: int = 60, **vectorizer_kwargs: Any) -> HybridRecommender
Blend a collaborative recommender with the tag-based content recommender.
Defaults to ItemKNN(k=20) on the collaborative side because item-item kNN
composes well with content signal (both rank items by similarity, just over
different spaces). Pass any other Recommender to swap that out.
The default weights=(3.0, 1.0) puts the collaborative signal in charge —
on benchmarked datasets the dense CF signal is much stronger than the
tag-only content one, so equal weighting dilutes accuracy. The content half
still contributes useful boosts for items both signals agree on, plus a
cold-start fallback for items the CF half has never seen.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tags
|
DataFrame
|
DataFrame with columns |
required |
collaborative
|
Recommender | None
|
Recommender to use on the collaborative side. |
None
|
weights
|
tuple[float, float]
|
|
(3.0, 1.0)
|
rank_constant
|
int
|
Forwarded to :class: |
60
|
**vectorizer_kwargs
|
Any
|
Forwarded to :func: |
{}
|
Data¶
Loading benchmarks¶
recommender_systems.datasets ¶
Dataset loaders for common recommender benchmarks.
load_movielens_100k ¶
Load the MovieLens 100k ratings, downloading and caching on first use.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_home
|
str | Path | None
|
Directory to cache the dataset in. Defaults to |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Ratings with columns |
load_goodbooks_10k ¶
Load the goodbooks-10k ratings, downloading and caching on first use.
For the open-source benchmark/demo only: the dataset derives from Goodreads and is not licensed for shipping in a commercial app (see the README).
Returns:
| Type | Description |
|---|---|
DataFrame
|
Ratings with columns |
load_goodbooks_books ¶
Load goodbooks-10k book metadata (title, authors, ids, average rating, ...).
load_goodbooks_tags ¶
Load goodbooks-10k tags joined to book_id and tag name.
Returns:
| Type | Description |
|---|---|
DataFrame
|
Columns |
Preparing interaction data¶
recommender_systems.data ¶
Utilities for preparing interaction data for recommenders.
build_user_item_matrix ¶
build_user_item_matrix(ratings: DataFrame, *, user_col: str = 'user_id', item_col: str = 'item_id', rating_col: str = 'rating', fill_value: float | None = None) -> pd.DataFrame
Pivot a long ratings frame into a user-by-item matrix.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ratings
|
DataFrame
|
Long-format interactions with one row per (user, item) rating. |
required |
user_col
|
str
|
Column names to read from |
'user_id'
|
item_col
|
str
|
Column names to read from |
'user_id'
|
rating_col
|
str
|
Column names to read from |
'user_id'
|
fill_value
|
float | None
|
Value for user-item pairs with no rating. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Rows indexed by user, columns by item, values the rating. Duplicate (user, item) pairs are averaged. |
split_ratings ¶
split_ratings(ratings: DataFrame, *, test_size: float = 0.2, random_state: int | None = None) -> tuple[pd.DataFrame, pd.DataFrame]
Split interactions into train and test sets by random row sampling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ratings
|
DataFrame
|
Interactions to split. |
required |
test_size
|
float
|
Fraction of rows to place in the test set, in the open interval (0, 1). |
0.2
|
random_state
|
int | None
|
Seed for reproducible splits. |
None
|
Returns:
| Type | Description |
|---|---|
tuple of pandas.DataFrame
|
|
densest_subset ¶
densest_subset(ratings: DataFrame, *, n_users: int = 1000, n_items: int = 1000, user_col: str = 'user_id', item_col: str = 'item_id') -> pd.DataFrame
Restrict ratings to the most active users and most popular items.
Lets dense-matrix algorithms run on large datasets (e.g. goodbooks-10k) without
materializing a full user-by-item matrix. Keeps the n_users users with the most
interactions and the n_items most-interacted items, then the rows in both.
Returns:
| Type | Description |
|---|---|
DataFrame
|
The filtered ratings. |
holdout_per_user ¶
holdout_per_user(ratings: DataFrame, *, test_size: float = 0.2, random_state: int | None = None, user_col: str = 'user_id') -> tuple[pd.DataFrame, pd.DataFrame]
Hold out a fraction of each user's interactions for testing.
Unlike :func:split_ratings (a global row split), this guarantees every user with at
least two interactions keeps training history — the standard protocol for top-N
recommender evaluation, so no user is left cold in the test set. Users with a single
interaction stay entirely in train.
Returns:
| Type | Description |
|---|---|
tuple of pandas.DataFrame
|
|
build_sparse_user_item_matrix ¶
build_sparse_user_item_matrix(ratings: DataFrame, *, user_col: str = 'user_id', item_col: str = 'item_id', rating_col: str = 'rating') -> tuple[sparse.csr_matrix, pd.Index, pd.Index]
Build a sparse user-item matrix plus its id-to-position index maps.
Scales to corpora where the dense :func:build_user_item_matrix would not fit in
memory (e.g. full goodbooks-10k). Duplicate (user, item) pairs are averaged, matching
the dense builder.
Returns:
| Type | Description |
|---|---|
tuple
|
|
Building feature matrices from text¶
recommender_systems.features ¶
Build item feature matrices from text, for use with ContentBased.
text_features ¶
text_features(item_text: Mapping[Hashable, str], *, method: str = 'tfidf', **vectorizer_kwargs: object) -> pd.DataFrame
Vectorize each item's text into a numerical feature matrix.
The result is indexed by item id with one column per term, ready to pass to
ContentBased(item_features=...). Item descriptions, concatenated tags, or any
per-item text all work.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item_text
|
Mapping[Hashable, str]
|
Mapping from item id to its text. |
required |
method
|
str
|
|
'tfidf'
|
**vectorizer_kwargs
|
object
|
Forwarded to the underlying scikit-learn vectorizer (e.g. |
{}
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Item-by-term feature matrix. |
Evaluation metrics¶
recommender_systems.metrics ¶
Metrics for top-N recommendation evaluation.
Accuracy metrics (precision, recall, MAP, NDCG) take parallel sequences of predicted ranked lists and held-out relevant item sets — one entry per user — and return a macro-averaged score across users that have at least one held-out item. Beyond-accuracy metrics (diversity, novelty, coverage, serendipity) capture different aspects of recommendation quality and are documented inline. Users with no relevant items are skipped from each mean so they don't drag the score toward zero.
precision_at_k ¶
precision_at_k(predicted: Sequence[Sequence[Hashable]], actual: Sequence[Collection[Hashable]], k: int) -> float
Macro-averaged precision@k across users.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
predicted
|
Sequence[Sequence[Hashable]]
|
For each user, an ordered iterable of recommended item ids (most relevant first). |
required |
actual
|
Sequence[Collection[Hashable]]
|
For each user, the items considered relevant in the holdout. |
required |
k
|
int
|
Cutoff; only the first |
required |
Returns:
| Type | Description |
|---|---|
float
|
Mean of |
recall_at_k ¶
recall_at_k(predicted: Sequence[Sequence[Hashable]], actual: Sequence[Collection[Hashable]], k: int) -> float
Macro-averaged recall@k across users.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
predicted
|
Sequence[Sequence[Hashable]]
|
Per-user ranked predictions. |
required |
actual
|
Sequence[Collection[Hashable]]
|
Per-user relevant items. |
required |
k
|
int
|
Cutoff applied to the predicted lists. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Mean of |
mean_average_precision ¶
mean_average_precision(predicted: Sequence[Sequence[Hashable]], actual: Sequence[Collection[Hashable]], k: int) -> float
Mean Average Precision at k.
For each user with at least one relevant item,
AP@k = (1 / min(|relevant|, k)) * sum_{i=1..k} rel(i) * precision_at_i,
where rel(i) is 1 if the i-th recommendation is relevant. The
min(|relevant|, k) denominator keeps the per-user score in [0, 1]
when |relevant| exceeds the cutoff.
ndcg_at_k ¶
ndcg_at_k(predicted: Sequence[Sequence[Hashable]], actual: Sequence[Collection[Hashable]], k: int) -> float
Normalized Discounted Cumulative Gain at k with binary relevance.
DCG = sum_{i=1..k} rel(i) / log2(i + 1); IDCG is the best
possible DCG for the user (all relevant items ranked first). Per-user
NDCG is DCG / IDCG (or 0 when no relevant items exist), averaged
across users with relevant items.
intra_list_diversity ¶
intra_list_diversity(predicted: Sequence[Sequence[Hashable]], similarity: Callable[[Hashable, Hashable], float], k: int) -> float
Macro-averaged intra-list dissimilarity across users.
For each user, dissimilarity averages 1 - similarity(a, b) over all
distinct pairs in the top-k recommendations. Users with fewer than two
recommendations are skipped — diversity is undefined for singletons.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
predicted
|
Sequence[Sequence[Hashable]]
|
Per-user ranked predictions. |
required |
similarity
|
Callable[[Hashable, Hashable], float]
|
Symmetric similarity in |
required |
k
|
int
|
Cutoff for the top of each prediction list. |
required |
novelty ¶
novelty(predicted: Sequence[Sequence[Hashable]], item_popularity: Mapping[Hashable, float], k: int) -> float
Mean self-information of recommended items, averaged across users.
Self-information of item i is -log2(p_i); popular items contribute
little novelty, rare ones contribute more. Items absent from
item_popularity are skipped within a user's list; users whose entire
top-k is unknown are skipped from the mean.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
predicted
|
Sequence[Sequence[Hashable]]
|
Per-user ranked predictions. |
required |
item_popularity
|
Mapping[Hashable, float]
|
Mapping from item id to its popularity in |
required |
k
|
int
|
Cutoff for the top of each prediction list. |
required |
catalog_coverage ¶
catalog_coverage(predicted: Sequence[Sequence[Hashable]], catalog: Collection[Hashable], k: int) -> float
Fraction of the catalog that appears in at least one user's top-k.
Items recommended outside catalog are ignored; recommending the same
item to many users still only counts it once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
predicted
|
Sequence[Sequence[Hashable]]
|
Per-user ranked predictions. |
required |
catalog
|
Collection[Hashable]
|
Items the recommender could have recommended. |
required |
k
|
int
|
Cutoff applied to each user's prediction list. |
required |
serendipity_at_k ¶
serendipity_at_k(predicted: Sequence[Sequence[Hashable]], actual: Sequence[Collection[Hashable]], expected: Sequence[Collection[Hashable]], k: int) -> float
Macro-averaged share of top-k that are both relevant and unexpected.
A recommendation counts as serendipitous when the user finds it relevant
(item in actual) and a baseline recommender would not have surfaced
it (item not in expected). The expected list per user is typically
drawn from a popularity or otherwise trivial recommender. Users with no
relevant items are skipped from the mean.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
predicted
|
Sequence[Sequence[Hashable]]
|
Per-user ranked predictions. |
required |
actual
|
Sequence[Collection[Hashable]]
|
Per-user relevant items. |
required |
expected
|
Sequence[Collection[Hashable]]
|
Per-user baseline recommendations; items already inside this set are not serendipitous even if relevant. |
required |
k
|
int
|
Cutoff applied to each user's prediction list. |
required |
Persistence¶
recommender_systems.persistence ¶
Save and load fitted recommenders.
save ¶
Persist a fitted recommender to path using pickle.
load ¶
Load a recommender previously saved with :func:save.
Only load files you trust: unpickling executes arbitrary code.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
TypeError
|
If the loaded object is not a :class: |
Command-line interface¶
recommender_systems.cli ¶
Command-line interface for the recommender_systems library.
Installed as the recsys console script via the project's [project.scripts]
entry point. Subcommands::
recsys recommend --algo item-knn --user 42 --n 10
recsys evaluate --algo svd
recsys list-algos
recommend and evaluate train on MovieLens 100k (downloaded and cached on
first use). --version prints the installed package version.