Spaces:
Running
Running
| import numpy as np | |
| from sklearn.base import BaseEstimator | |
| class BayesianRecommender(BaseEstimator): | |
| def __init__(self, | |
| item_embeddings: np.ndarray, | |
| lambda_reg: float = 1.0, | |
| sigma2: float = 1.0, | |
| z: float = -1.1645, # -1.645=<10% LCB | |
| mask_value: float = -np.inf): | |
| self.item_embeddings = np.asarray(item_embeddings, dtype=np.float64) | |
| self.N_, self.d_ = self.item_embeddings.shape | |
| self.lambda_reg = float(lambda_reg) | |
| self.sigma2 = float(sigma2) | |
| self.z = float(z) | |
| self.mask_value = mask_value | |
| self.X_items = self.item_embeddings | |
| self.XT_items = self.item_embeddings.T | |
| def fit(self, X=None, y=None): | |
| return self | |
| def _user_posterior_and_scores(self, y_vec: np.ndarray): | |
| seen_mask = y_vec != 0 | |
| X_obs = self.X_items[seen_mask] | |
| y_obs = y_vec[seen_mask].astype(np.float64) | |
| A = self.lambda_reg * np.eye(self.d_, dtype=np.float64) + (X_obs.T @ X_obs) / self.sigma2 | |
| invA = np.linalg.inv(A) | |
| mu = invA @ (X_obs.T @ y_obs) / self.sigma2 | |
| m = self.X_items @ mu | |
| XinvA = self.X_items @ invA | |
| s2 = np.einsum('ij,ij->i', XinvA, self.X_items) | |
| s = np.sqrt(np.clip(s2, 0.0, None)) | |
| scores = m + self.z * s | |
| scores[seen_mask] = self.mask_value | |
| return scores | |
| def transform(self, X): | |
| X = np.asarray(X, dtype=np.float64) | |
| if X.ndim == 1: | |
| X = X[None, :] | |
| B, N = X.shape | |
| if N != self.N_: | |
| raise ValueError(f"Input width {N} != number of items {self.N_}.") | |
| out = np.empty((B, N), dtype=np.float64) | |
| for b in range(B): | |
| out[b] = self._user_posterior_and_scores(X[b]) | |
| return out | |