src.fairreckitlib.model.algorithms.base_recommender
This module contains the base class for recommenders.
Classes:
BaseRecommender: base class for recommenders.
Recommender: implements basic shared functionality.
This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course. © Copyright Utrecht University (Department of Information and Computing Sciences)
1"""This module contains the base class for recommenders. 2 3Classes: 4 5 BaseRecommender: base class for recommenders. 6 Recommender: implements basic shared functionality. 7 8This program has been developed by students from the bachelor Computer Science at 9Utrecht University within the Software Project course. 10© Copyright Utrecht University (Department of Information and Computing Sciences) 11""" 12 13from abc import ABCMeta, abstractmethod 14from typing import Any, Dict, List 15 16import numpy as np 17import pandas as pd 18 19from .base_algorithm import BaseAlgorithm 20 21 22class BaseRecommender(BaseAlgorithm, metaclass=ABCMeta): 23 """Base class for FairRecKit recommenders. 24 25 A recommender is used for recommender experiments. It computes a number of 26 item recommendations for any user that it was trained on. 27 Derived recommenders are expected to implement the abstract interface. 28 29 Abstract methods: 30 31 on_recommend 32 on_recommend_batch (optional) 33 34 Public methods: 35 36 has_rated_items_filter 37 recommend 38 recommend_batch 39 """ 40 41 def __init__(self, rated_items_filter: bool): 42 """Construct the recommender. 43 44 Args: 45 rated_items_filter: whether to filter already rated items when 46 producing item recommendations. 47 """ 48 BaseAlgorithm.__init__(self) 49 self.rated_items_filter = rated_items_filter 50 51 def has_rated_items_filter(self) -> bool: 52 """Get if the recommender filters already rated items when producing recommendations. 53 54 Returns: 55 whether the recommender filters already rated items. 56 """ 57 return self.rated_items_filter 58 59 def recommend(self, user: int, num_items: int=10) -> pd.DataFrame: 60 """Compute item recommendations for the specified user. 61 62 A recommendation is impossible when the user is not present in 63 the unique users it was trained on and will return an empty dataframe. 64 65 Args: 66 user: the user ID to compute recommendations for. 67 num_items: the number of item recommendations to produce. 68 69 Raises: 70 ArithmeticError: possibly raised by a recommender on testing. 71 MemoryError: possibly raised by a recommender on testing. 72 RuntimeError: when the recommender is not trained yet. 73 74 Returns: 75 a dataframe with the columns: 'item' and 'score'. 76 """ 77 if self.train_set is None: 78 raise RuntimeError('Recommender is not trained for item recommendations') 79 80 if not self.train_set.knows_user(user): 81 return pd.DataFrame(columns=['item', 'score']) 82 83 return self.on_recommend(user, num_items) 84 85 @abstractmethod 86 def on_recommend(self, user: int, num_items: int) -> pd.DataFrame: 87 """Compute item recommendations for the specified user. 88 89 The user is assumed to be present in the train set that the 90 recommender was trained on. 91 Derived implementations are expected to return a dataframe 92 with the 'score' column in descending order. 93 94 Args: 95 user: the user ID to compute recommendations for. 96 num_items: the number of item recommendations to produce. 97 98 Raises: 99 ArithmeticError: possibly raised by a recommender on testing. 100 MemoryError: possibly raised by a recommender on testing. 101 RuntimeError: when the recommender is not trained yet. 102 103 Returns: 104 a dataframe with the columns: 'item' and 'score'. 105 """ 106 raise NotImplementedError() 107 108 def recommend_batch(self, users: List[int], num_items: int=10) -> pd.DataFrame: 109 """Compute the items recommendations for each of the specified users. 110 111 All the users that are not present in the train set that the recommender 112 was trained on are filtered before recommendations are made. 113 114 Args: 115 users: the user ID's to compute recommendations for. 116 num_items: the number of item recommendations to produce. 117 118 Raises: 119 ArithmeticError: possibly raised by a recommender on testing. 120 MemoryError: possibly raised by a recommender on testing. 121 RuntimeError: when the recommender is not trained yet. 122 123 Returns: 124 a dataframe with the columns: 'rank', 'user', 'item', 'score'. 125 """ 126 if self.train_set is None: 127 raise RuntimeError('Recommender is not trained for item recommendations') 128 129 users = [u for u in users if self.train_set.knows_user(u)] 130 if len(users) == 0: 131 return pd.DataFrame(columns=['rank', 'user', 'item', 'score']) 132 133 return self.on_recommend_batch(users, num_items) 134 135 def on_recommend_batch(self, users: List[int], num_items: int) -> pd.DataFrame: 136 """Compute the items recommendations for each of the specified users. 137 138 All the users are assumed to be present in the train set that 139 the recommender was trained on. 140 A standard batch implementation is provided, but derived classes are 141 allowed to override batching with their own logic. 142 143 Args: 144 users: the user ID's to compute recommendations for. 145 num_items: the number of item recommendations to produce. 146 147 Raises: 148 ArithmeticError: possibly raised by a recommender on testing. 149 MemoryError: possibly raised by a recommender on testing. 150 RuntimeError: when the recommender is not trained yet. 151 152 Returns: 153 a dataframe with the columns: 'rank', 'user', 'item', 'score'. 154 """ 155 result = pd.DataFrame() 156 157 for user in users: 158 item_scores = self.recommend(user, num_items) 159 160 item_scores['rank'] = np.arange(1, 1 + num_items) 161 item_scores['user'] = np.full(num_items, user) 162 163 result = pd.concat( 164 [result, item_scores[['rank', 'user', 'item', 'score']]], 165 ignore_index=True 166 ) 167 168 return result 169 170 171class Recommender(BaseRecommender, metaclass=ABCMeta): 172 """Recommender that implements basic shared functionality.""" 173 174 def __init__(self, name: str, params: Dict[str, Any], num_threads: int, 175 rated_items_filter: bool): 176 """Construct the recommender. 177 178 Args: 179 name: the name of the recommender. 180 params: the parameters of the recommender. 181 num_threads: the max number of threads the recommender can use. 182 rated_items_filter: whether to filter already rated items when 183 producing item recommendations. 184 """ 185 BaseRecommender.__init__(self, rated_items_filter) 186 self.num_threads = num_threads 187 self.recommender_name = name 188 self.params = params 189 190 def get_name(self) -> str: 191 """Get the name of the recommender. 192 193 Returns: 194 the recommender name. 195 """ 196 return self.recommender_name 197 198 def get_num_threads(self) -> int: 199 """Get the max number of threads the recommender can use. 200 201 Returns: 202 the number of threads. 203 """ 204 return self.num_threads 205 206 def get_params(self) -> Dict[str, Any]: 207 """Get the parameters of the recommender. 208 209 Returns: 210 the recommender parameters. 211 """ 212 return dict(self.params)
23class BaseRecommender(BaseAlgorithm, metaclass=ABCMeta): 24 """Base class for FairRecKit recommenders. 25 26 A recommender is used for recommender experiments. It computes a number of 27 item recommendations for any user that it was trained on. 28 Derived recommenders are expected to implement the abstract interface. 29 30 Abstract methods: 31 32 on_recommend 33 on_recommend_batch (optional) 34 35 Public methods: 36 37 has_rated_items_filter 38 recommend 39 recommend_batch 40 """ 41 42 def __init__(self, rated_items_filter: bool): 43 """Construct the recommender. 44 45 Args: 46 rated_items_filter: whether to filter already rated items when 47 producing item recommendations. 48 """ 49 BaseAlgorithm.__init__(self) 50 self.rated_items_filter = rated_items_filter 51 52 def has_rated_items_filter(self) -> bool: 53 """Get if the recommender filters already rated items when producing recommendations. 54 55 Returns: 56 whether the recommender filters already rated items. 57 """ 58 return self.rated_items_filter 59 60 def recommend(self, user: int, num_items: int=10) -> pd.DataFrame: 61 """Compute item recommendations for the specified user. 62 63 A recommendation is impossible when the user is not present in 64 the unique users it was trained on and will return an empty dataframe. 65 66 Args: 67 user: the user ID to compute recommendations for. 68 num_items: the number of item recommendations to produce. 69 70 Raises: 71 ArithmeticError: possibly raised by a recommender on testing. 72 MemoryError: possibly raised by a recommender on testing. 73 RuntimeError: when the recommender is not trained yet. 74 75 Returns: 76 a dataframe with the columns: 'item' and 'score'. 77 """ 78 if self.train_set is None: 79 raise RuntimeError('Recommender is not trained for item recommendations') 80 81 if not self.train_set.knows_user(user): 82 return pd.DataFrame(columns=['item', 'score']) 83 84 return self.on_recommend(user, num_items) 85 86 @abstractmethod 87 def on_recommend(self, user: int, num_items: int) -> pd.DataFrame: 88 """Compute item recommendations for the specified user. 89 90 The user is assumed to be present in the train set that the 91 recommender was trained on. 92 Derived implementations are expected to return a dataframe 93 with the 'score' column in descending order. 94 95 Args: 96 user: the user ID to compute recommendations for. 97 num_items: the number of item recommendations to produce. 98 99 Raises: 100 ArithmeticError: possibly raised by a recommender on testing. 101 MemoryError: possibly raised by a recommender on testing. 102 RuntimeError: when the recommender is not trained yet. 103 104 Returns: 105 a dataframe with the columns: 'item' and 'score'. 106 """ 107 raise NotImplementedError() 108 109 def recommend_batch(self, users: List[int], num_items: int=10) -> pd.DataFrame: 110 """Compute the items recommendations for each of the specified users. 111 112 All the users that are not present in the train set that the recommender 113 was trained on are filtered before recommendations are made. 114 115 Args: 116 users: the user ID's to compute recommendations for. 117 num_items: the number of item recommendations to produce. 118 119 Raises: 120 ArithmeticError: possibly raised by a recommender on testing. 121 MemoryError: possibly raised by a recommender on testing. 122 RuntimeError: when the recommender is not trained yet. 123 124 Returns: 125 a dataframe with the columns: 'rank', 'user', 'item', 'score'. 126 """ 127 if self.train_set is None: 128 raise RuntimeError('Recommender is not trained for item recommendations') 129 130 users = [u for u in users if self.train_set.knows_user(u)] 131 if len(users) == 0: 132 return pd.DataFrame(columns=['rank', 'user', 'item', 'score']) 133 134 return self.on_recommend_batch(users, num_items) 135 136 def on_recommend_batch(self, users: List[int], num_items: int) -> pd.DataFrame: 137 """Compute the items recommendations for each of the specified users. 138 139 All the users are assumed to be present in the train set that 140 the recommender was trained on. 141 A standard batch implementation is provided, but derived classes are 142 allowed to override batching with their own logic. 143 144 Args: 145 users: the user ID's to compute recommendations for. 146 num_items: the number of item recommendations to produce. 147 148 Raises: 149 ArithmeticError: possibly raised by a recommender on testing. 150 MemoryError: possibly raised by a recommender on testing. 151 RuntimeError: when the recommender is not trained yet. 152 153 Returns: 154 a dataframe with the columns: 'rank', 'user', 'item', 'score'. 155 """ 156 result = pd.DataFrame() 157 158 for user in users: 159 item_scores = self.recommend(user, num_items) 160 161 item_scores['rank'] = np.arange(1, 1 + num_items) 162 item_scores['user'] = np.full(num_items, user) 163 164 result = pd.concat( 165 [result, item_scores[['rank', 'user', 'item', 'score']]], 166 ignore_index=True 167 ) 168 169 return result
Base class for FairRecKit recommenders.
A recommender is used for recommender experiments. It computes a number of item recommendations for any user that it was trained on. Derived recommenders are expected to implement the abstract interface.
Abstract methods:
on_recommend on_recommend_batch (optional)
Public methods:
has_rated_items_filter recommend recommend_batch
42 def __init__(self, rated_items_filter: bool): 43 """Construct the recommender. 44 45 Args: 46 rated_items_filter: whether to filter already rated items when 47 producing item recommendations. 48 """ 49 BaseAlgorithm.__init__(self) 50 self.rated_items_filter = rated_items_filter
Construct the recommender.
Args: rated_items_filter: whether to filter already rated items when producing item recommendations.
52 def has_rated_items_filter(self) -> bool: 53 """Get if the recommender filters already rated items when producing recommendations. 54 55 Returns: 56 whether the recommender filters already rated items. 57 """ 58 return self.rated_items_filter
Get if the recommender filters already rated items when producing recommendations.
Returns: whether the recommender filters already rated items.
60 def recommend(self, user: int, num_items: int=10) -> pd.DataFrame: 61 """Compute item recommendations for the specified user. 62 63 A recommendation is impossible when the user is not present in 64 the unique users it was trained on and will return an empty dataframe. 65 66 Args: 67 user: the user ID to compute recommendations for. 68 num_items: the number of item recommendations to produce. 69 70 Raises: 71 ArithmeticError: possibly raised by a recommender on testing. 72 MemoryError: possibly raised by a recommender on testing. 73 RuntimeError: when the recommender is not trained yet. 74 75 Returns: 76 a dataframe with the columns: 'item' and 'score'. 77 """ 78 if self.train_set is None: 79 raise RuntimeError('Recommender is not trained for item recommendations') 80 81 if not self.train_set.knows_user(user): 82 return pd.DataFrame(columns=['item', 'score']) 83 84 return self.on_recommend(user, num_items)
Compute item recommendations for the specified user.
A recommendation is impossible when the user is not present in the unique users it was trained on and will return an empty dataframe.
Args: user: the user ID to compute recommendations for. num_items: the number of item recommendations to produce.
Raises: ArithmeticError: possibly raised by a recommender on testing. MemoryError: possibly raised by a recommender on testing. RuntimeError: when the recommender is not trained yet.
Returns: a dataframe with the columns: 'item' and 'score'.
86 @abstractmethod 87 def on_recommend(self, user: int, num_items: int) -> pd.DataFrame: 88 """Compute item recommendations for the specified user. 89 90 The user is assumed to be present in the train set that the 91 recommender was trained on. 92 Derived implementations are expected to return a dataframe 93 with the 'score' column in descending order. 94 95 Args: 96 user: the user ID to compute recommendations for. 97 num_items: the number of item recommendations to produce. 98 99 Raises: 100 ArithmeticError: possibly raised by a recommender on testing. 101 MemoryError: possibly raised by a recommender on testing. 102 RuntimeError: when the recommender is not trained yet. 103 104 Returns: 105 a dataframe with the columns: 'item' and 'score'. 106 """ 107 raise NotImplementedError()
Compute item recommendations for the specified user.
The user is assumed to be present in the train set that the recommender was trained on. Derived implementations are expected to return a dataframe with the 'score' column in descending order.
Args: user: the user ID to compute recommendations for. num_items: the number of item recommendations to produce.
Raises: ArithmeticError: possibly raised by a recommender on testing. MemoryError: possibly raised by a recommender on testing. RuntimeError: when the recommender is not trained yet.
Returns: a dataframe with the columns: 'item' and 'score'.
109 def recommend_batch(self, users: List[int], num_items: int=10) -> pd.DataFrame: 110 """Compute the items recommendations for each of the specified users. 111 112 All the users that are not present in the train set that the recommender 113 was trained on are filtered before recommendations are made. 114 115 Args: 116 users: the user ID's to compute recommendations for. 117 num_items: the number of item recommendations to produce. 118 119 Raises: 120 ArithmeticError: possibly raised by a recommender on testing. 121 MemoryError: possibly raised by a recommender on testing. 122 RuntimeError: when the recommender is not trained yet. 123 124 Returns: 125 a dataframe with the columns: 'rank', 'user', 'item', 'score'. 126 """ 127 if self.train_set is None: 128 raise RuntimeError('Recommender is not trained for item recommendations') 129 130 users = [u for u in users if self.train_set.knows_user(u)] 131 if len(users) == 0: 132 return pd.DataFrame(columns=['rank', 'user', 'item', 'score']) 133 134 return self.on_recommend_batch(users, num_items)
Compute the items recommendations for each of the specified users.
All the users that are not present in the train set that the recommender was trained on are filtered before recommendations are made.
Args: users: the user ID's to compute recommendations for. num_items: the number of item recommendations to produce.
Raises: ArithmeticError: possibly raised by a recommender on testing. MemoryError: possibly raised by a recommender on testing. RuntimeError: when the recommender is not trained yet.
Returns: a dataframe with the columns: 'rank', 'user', 'item', 'score'.
136 def on_recommend_batch(self, users: List[int], num_items: int) -> pd.DataFrame: 137 """Compute the items recommendations for each of the specified users. 138 139 All the users are assumed to be present in the train set that 140 the recommender was trained on. 141 A standard batch implementation is provided, but derived classes are 142 allowed to override batching with their own logic. 143 144 Args: 145 users: the user ID's to compute recommendations for. 146 num_items: the number of item recommendations to produce. 147 148 Raises: 149 ArithmeticError: possibly raised by a recommender on testing. 150 MemoryError: possibly raised by a recommender on testing. 151 RuntimeError: when the recommender is not trained yet. 152 153 Returns: 154 a dataframe with the columns: 'rank', 'user', 'item', 'score'. 155 """ 156 result = pd.DataFrame() 157 158 for user in users: 159 item_scores = self.recommend(user, num_items) 160 161 item_scores['rank'] = np.arange(1, 1 + num_items) 162 item_scores['user'] = np.full(num_items, user) 163 164 result = pd.concat( 165 [result, item_scores[['rank', 'user', 'item', 'score']]], 166 ignore_index=True 167 ) 168 169 return result
Compute the items recommendations for each of the specified users.
All the users are assumed to be present in the train set that the recommender was trained on. A standard batch implementation is provided, but derived classes are allowed to override batching with their own logic.
Args: users: the user ID's to compute recommendations for. num_items: the number of item recommendations to produce.
Raises: ArithmeticError: possibly raised by a recommender on testing. MemoryError: possibly raised by a recommender on testing. RuntimeError: when the recommender is not trained yet.
Returns: a dataframe with the columns: 'rank', 'user', 'item', 'score'.
172class Recommender(BaseRecommender, metaclass=ABCMeta): 173 """Recommender that implements basic shared functionality.""" 174 175 def __init__(self, name: str, params: Dict[str, Any], num_threads: int, 176 rated_items_filter: bool): 177 """Construct the recommender. 178 179 Args: 180 name: the name of the recommender. 181 params: the parameters of the recommender. 182 num_threads: the max number of threads the recommender can use. 183 rated_items_filter: whether to filter already rated items when 184 producing item recommendations. 185 """ 186 BaseRecommender.__init__(self, rated_items_filter) 187 self.num_threads = num_threads 188 self.recommender_name = name 189 self.params = params 190 191 def get_name(self) -> str: 192 """Get the name of the recommender. 193 194 Returns: 195 the recommender name. 196 """ 197 return self.recommender_name 198 199 def get_num_threads(self) -> int: 200 """Get the max number of threads the recommender can use. 201 202 Returns: 203 the number of threads. 204 """ 205 return self.num_threads 206 207 def get_params(self) -> Dict[str, Any]: 208 """Get the parameters of the recommender. 209 210 Returns: 211 the recommender parameters. 212 """ 213 return dict(self.params)
Recommender that implements basic shared functionality.
175 def __init__(self, name: str, params: Dict[str, Any], num_threads: int, 176 rated_items_filter: bool): 177 """Construct the recommender. 178 179 Args: 180 name: the name of the recommender. 181 params: the parameters of the recommender. 182 num_threads: the max number of threads the recommender can use. 183 rated_items_filter: whether to filter already rated items when 184 producing item recommendations. 185 """ 186 BaseRecommender.__init__(self, rated_items_filter) 187 self.num_threads = num_threads 188 self.recommender_name = name 189 self.params = params
Construct the recommender.
Args: name: the name of the recommender. params: the parameters of the recommender. num_threads: the max number of threads the recommender can use. rated_items_filter: whether to filter already rated items when producing item recommendations.
191 def get_name(self) -> str: 192 """Get the name of the recommender. 193 194 Returns: 195 the recommender name. 196 """ 197 return self.recommender_name
Get the name of the recommender.
Returns: the recommender name.
199 def get_num_threads(self) -> int: 200 """Get the max number of threads the recommender can use. 201 202 Returns: 203 the number of threads. 204 """ 205 return self.num_threads
Get the max number of threads the recommender can use.
Returns: the number of threads.