Source code for recbole.model.general_recommender.slimelastic

r"""
SLIMElastic
################################################
Reference:
    Xia Ning et al. "SLIM: Sparse Linear Methods for Top-N Recommender Systems." in ICDM 2011.
Reference code:
    https://github.com/KarypisLab/SLIM
    https://github.com/MaurizioFD/RecSys2019_DeepLearning_Evaluation/blob/master/SLIM_ElasticNet/SLIMElasticNetRecommender.py
"""

import torch
import warnings
import numpy as np
import scipy.sparse as sp

from sklearn.linear_model import ElasticNet
from sklearn.exceptions import ConvergenceWarning

from recbole.utils import InputType, ModelType
from recbole.model.abstract_recommender import GeneralRecommender


[docs]class SLIMElastic(GeneralRecommender): r"""SLIMElastic is a sparse linear method for top-K recommendation, which learns a sparse aggregation coefficient matrix by solving an L1-norm and L2-norm regularized optimization problem. """ input_type = InputType.POINTWISE type = ModelType.TRADITIONAL def __init__(self, config, dataset): super().__init__(config, dataset) # load parameters info self.hide_item = config["hide_item"] self.alpha = config["alpha"] self.l1_ratio = config["l1_ratio"] self.positive_only = config["positive_only"] # need at least one param self.dummy_param = torch.nn.Parameter(torch.zeros(1)) X = dataset.inter_matrix(form="csr").astype(np.float32) X = X.tolil() self.interaction_matrix = X model = ElasticNet( alpha=self.alpha, l1_ratio=self.l1_ratio, positive=self.positive_only, fit_intercept=False, copy_X=False, precompute=True, selection="random", max_iter=100, tol=1e-4, ) item_coeffs = [] # ignore ConvergenceWarnings with warnings.catch_warnings(): warnings.simplefilter("ignore", category=ConvergenceWarning) for j in range(X.shape[1]): # target column r = X[:, j] if self.hide_item: # set item column to 0 X[:, j] = 0 # fit the model model.fit(X, r.todense().getA1()) # store the coefficients coeffs = model.sparse_coef_ item_coeffs.append(coeffs) if self.hide_item: # reattach column if removed X[:, j] = r self.item_similarity = sp.vstack(item_coeffs).T self.other_parameter_name = ["interaction_matrix", "item_similarity"]
[docs] def forward(self): pass
[docs] def calculate_loss(self, interaction): return torch.nn.Parameter(torch.zeros(1))
[docs] def predict(self, interaction): user = interaction[self.USER_ID].cpu().numpy() item = interaction[self.ITEM_ID].cpu().numpy() r = torch.from_numpy( (self.interaction_matrix[user, :].multiply(self.item_similarity[:, item].T)) .sum(axis=1) .getA1() ) return r
[docs] def full_sort_predict(self, interaction): user = interaction[self.USER_ID].cpu().numpy() r = self.interaction_matrix[user, :] @ self.item_similarity r = torch.from_numpy(r.todense().getA1()) return r