Spaces:
Sleeping
Sleeping
| import numpy as np | |
| from datetime import datetime | |
| from typing import List, Dict, Optional | |
| class EngineRecommandationGroupe: | |
| def __init__( | |
| self, | |
| t_half: float = 365.0, | |
| lambda_r: float = 1.0, | |
| alpha: float = 0.65, | |
| omega_hist: float = 0.4, | |
| omega_mood: float = 0.6, | |
| omega_pen: float = 0.3, | |
| delta: float = 0.7, | |
| gamma_pop: float = 0.15, | |
| ): | |
| self.t_half = t_half | |
| self.lambda_r = lambda_r | |
| self.alpha = alpha | |
| self.omega_hist = omega_hist | |
| self.omega_mood = omega_mood | |
| self.omega_pen = omega_pen | |
| self.delta = delta | |
| self.gamma_pop = gamma_pop | |
| def calcul_profil_utilisateur( | |
| self, | |
| history: List[Dict], | |
| embeddings_catalogue: Dict[str, np.ndarray], | |
| date_reference: Optional[datetime] = None, | |
| ) -> np.ndarray: | |
| if not date_reference: | |
| date_reference = datetime.now() | |
| valid_records = [r for r in history if r["key"] in embeddings_catalogue] | |
| if not valid_records: | |
| dim = next(iter(embeddings_catalogue.values())).shape | |
| return np.zeros(dim, dtype=np.float64) | |
| ratings = [r["rating"] for r in valid_records] | |
| user_mean = np.mean(ratings) if len(ratings) >= 5 else 3.0 | |
| sample = next(iter(embeddings_catalogue.values())) | |
| p_u = np.zeros(sample.shape, dtype=np.float64) | |
| for record in valid_records: | |
| v_m = embeddings_catalogue[record["key"]] | |
| w_r = np.exp((record["rating"] - user_mean) / self.lambda_r) - 1.0 | |
| delta_t = (date_reference - record["date_viewed"]).days | |
| decay = 2.0 ** (-max(0.0, delta_t) / self.t_half) | |
| p_u += (w_r * decay) * v_m | |
| norm = np.linalg.norm(p_u) | |
| if norm > 1e-9: | |
| p_u = p_u / norm | |
| return p_u | |
| def _cosinus_normalise(self, vec_a: np.ndarray, vec_b: np.ndarray) -> float: | |
| na, nb = np.linalg.norm(vec_a), np.linalg.norm(vec_b) | |
| if na < 1e-9 or nb < 1e-9: | |
| return 0.5 | |
| return float(0.5 * (np.dot(vec_a, vec_b) / (na * nb) + 1.0)) | |
| def scoring_film_candidat( | |
| self, | |
| v_m: np.ndarray, | |
| genres_m: List[str], | |
| pop_m: float, | |
| profils_groupe: List[np.ndarray], | |
| v_mood: np.ndarray, | |
| genres_mood: List[str], | |
| ) -> float: | |
| N = len(profils_groupe) | |
| if N == 0: | |
| raise ValueError("Groupe vide.") | |
| prefs = np.array([self._cosinus_normalise(p, v_m) for p in profils_groupe]) | |
| if N == 1: | |
| r_hybrid = float(prefs[0]) | |
| sigma_p = 0.0 | |
| else: | |
| r_hybrid = self.alpha * np.mean(prefs) + (1.0 - self.alpha) * np.min(prefs) | |
| sigma_p = float(np.std(prefs)) | |
| sim_sem = self._cosinus_normalise(v_m, v_mood) | |
| if genres_mood: | |
| sim_genre = len(set(genres_m) & set(genres_mood)) / len(genres_mood) | |
| else: | |
| sim_genre = 1.0 | |
| sim_mood = self.delta * sim_sem + (1.0 - self.delta) * sim_genre | |
| score = self.omega_hist * r_hybrid + self.omega_mood * sim_mood - self.omega_pen * sigma_p | |
| facteur_pop = 1.0 / (np.log(10 + pop_m) ** self.gamma_pop) | |
| return float(score * facteur_pop) | |