Download model.py from tasdid25/DataSynthis_ML_JobTask: direct link, hf CLI and curl.
- Browser
- Download file 9.42 kB
-
https://huggingface.co/tasdid25/DataSynthis_ML_JobTask/resolve/main/model.py
- Command line
-
hf download hf://tasdid25/DataSynthis_ML_JobTask/model.py
-
curl -L -o model.py https://huggingface.co/tasdid25/DataSynthis_ML_JobTask/resolve/main/model.py
9.42 kB
| """ | |
| DataSynthis_ML_JobTask - Movie Recommendation Model | |
| A movie recommendation system using collaborative filtering and matrix factorization. | |
| """ | |
| import pandas as pd | |
| import numpy as np | |
| from sklearn.metrics.pairwise import cosine_similarity | |
| from sklearn.decomposition import TruncatedSVD | |
| import os | |
| import urllib.request | |
| import zipfile | |
| import pickle | |
| from typing import List, Dict, Optional, Union | |
| class MovieRecommender: | |
| """ | |
| Movie Recommendation Model using collaborative filtering and SVD. | |
| """ | |
| def __init__(self): | |
| self.ratings = None | |
| self.movies = None | |
| self.user_item_matrix = None | |
| self.item_similarity = None | |
| self.item_similarity_df = None | |
| self.svd_model = None | |
| self.pred_svd_df = None | |
| self.is_trained = False | |
| def load_data(self): | |
| """Load MovieLens 100k dataset.""" | |
| dataset_url = "http://files.grouplens.org/datasets/movielens/ml-100k.zip" | |
| dataset_path = "ml-100k" | |
| if not os.path.exists(dataset_path): | |
| if os.path.exists("ml-100k.zip"): | |
| print("Extracting existing MovieLens 100k dataset...") | |
| with zipfile.ZipFile("ml-100k.zip", "r") as zip_ref: | |
| zip_ref.extractall(".") | |
| print("Extraction complete.") | |
| else: | |
| print("Downloading MovieLens 100k dataset...") | |
| try: | |
| urllib.request.urlretrieve(dataset_url, "ml-100k.zip") | |
| with zipfile.ZipFile("ml-100k.zip", "r") as zip_ref: | |
| zip_ref.extractall(".") | |
| print("Download complete.") | |
| except Exception as e: | |
| print(f"Download failed: {e}") | |
| raise Exception("Could not download dataset") | |
| # Load ratings | |
| self.ratings = pd.read_csv( | |
| "ml-100k/u.data", | |
| sep="\t", | |
| names=["user_id", "movie_id", "rating", "timestamp"] | |
| ) | |
| # Load movies | |
| self.movies = pd.read_csv( | |
| "ml-100k/u.item", | |
| sep="|", | |
| encoding="ISO-8859-1", | |
| names=["movie_id", "title", "release_date", "video_release_date", "IMDb_URL", | |
| "unknown", "Action", "Adventure", "Animation", "Children", "Comedy", | |
| "Crime", "Documentary", "Drama", "Fantasy", "Film-Noir", "Horror", | |
| "Musical", "Mystery", "Romance", "Sci-Fi", "Thriller", "War", "Western"] | |
| ) | |
| # Remove timestamp column | |
| self.ratings.drop("timestamp", axis=1, inplace=True) | |
| print(f"Loaded {len(self.ratings)} ratings from {len(self.ratings['user_id'].unique())} users") | |
| print(f"Loaded {len(self.movies)} movies") | |
| def train(self): | |
| """Train the recommendation models.""" | |
| if self.ratings is None: | |
| self.load_data() | |
| # Create user-item matrix | |
| self.user_item_matrix = self.ratings.pivot( | |
| index='user_id', columns='movie_id', values='rating' | |
| ) | |
| # Collaborative Filtering - Item-based similarity | |
| self.item_similarity = cosine_similarity(self.user_item_matrix.T.fillna(0)) | |
| self.item_similarity_df = pd.DataFrame( | |
| self.item_similarity, | |
| index=self.user_item_matrix.columns, | |
| columns=self.user_item_matrix.columns | |
| ) | |
| # SVD - Matrix Factorization | |
| R = self.user_item_matrix.fillna(0) | |
| self.svd_model = TruncatedSVD(n_components=20, random_state=42) | |
| U = self.svd_model.fit_transform(R) | |
| Sigma = np.diag(self.svd_model.singular_values_) | |
| Vt = self.svd_model.components_ | |
| pred_svd = np.dot(np.dot(U, Sigma), Vt) | |
| self.pred_svd_df = pd.DataFrame(pred_svd, index=R.index, columns=R.columns) | |
| self.is_trained = True | |
| print("Model training completed!") | |
| def predict_ratings_cf(self, user_id: int) -> pd.Series: | |
| """Predict ratings using collaborative filtering.""" | |
| if not self.is_trained: | |
| raise ValueError("Model must be trained first") | |
| if user_id not in self.user_item_matrix.index: | |
| raise ValueError(f"User {user_id} not found in dataset") | |
| user_ratings = self.user_item_matrix.loc[user_id] | |
| weighted_sum = self.item_similarity_df.dot(user_ratings.fillna(0)) | |
| sim_sum = np.abs(self.item_similarity_df).dot(user_ratings.notna().astype(int)) | |
| pred = weighted_sum / np.maximum(sim_sum, 1e-9) | |
| return pred | |
| def recommend_movies(self, user_id: int, n_recommendations: int = 10, | |
| method: str = "svd") -> List[Dict]: | |
| """ | |
| Get movie recommendations for a user. | |
| Args: | |
| user_id: User ID to get recommendations for | |
| n_recommendations: Number of recommendations to return | |
| method: "svd" or "cf" (collaborative filtering) | |
| Returns: | |
| List of dictionaries with movie recommendations | |
| """ | |
| if not self.is_trained: | |
| self.train() | |
| # Check if user exists | |
| if user_id not in self.user_item_matrix.index: | |
| available_users = sorted(self.user_item_matrix.index.tolist()) | |
| return [{ | |
| "error": f"User {user_id} not found", | |
| "available_users": f"Available user IDs: {available_users[:10]}... (showing first 10)" | |
| }] | |
| # Get predictions | |
| if method == "svd": | |
| preds = self.pred_svd_df.loc[user_id] | |
| else: # collaborative filtering | |
| preds = self.predict_ratings_cf(user_id) | |
| # Remove already watched movies | |
| watched = self.ratings[self.ratings.user_id == user_id].movie_id.values | |
| preds = preds.drop(watched, errors='ignore') | |
| # Get top recommendations | |
| top_movies = preds.sort_values(ascending=False).head(n_recommendations).index | |
| recommendations = self.movies[self.movies.movie_id.isin(top_movies)][["movie_id", "title"]] | |
| # Convert to list of dictionaries | |
| result = [] | |
| for _, row in recommendations.iterrows(): | |
| result.append({ | |
| "movie_id": int(row["movie_id"]), | |
| "title": row["title"], | |
| "predicted_rating": float(preds[row["movie_id"]]) | |
| }) | |
| return result | |
| def get_user_stats(self, user_id: int) -> Dict: | |
| """Get statistics for a user.""" | |
| if not self.is_trained: | |
| self.train() | |
| if user_id not in self.user_item_matrix.index: | |
| return {"error": f"User {user_id} not found"} | |
| user_ratings = self.ratings[self.ratings.user_id == user_id] | |
| return { | |
| "user_id": user_id, | |
| "total_ratings": len(user_ratings), | |
| "average_rating": float(user_ratings["rating"].mean()), | |
| "rating_distribution": user_ratings["rating"].value_counts().to_dict() | |
| } | |
| def get_available_users(self) -> List[int]: | |
| """Get list of available user IDs.""" | |
| if not self.is_trained: | |
| self.train() | |
| return sorted(self.user_item_matrix.index.tolist()) | |
| def save_model(self, path: str): | |
| """Save the trained model.""" | |
| if not self.is_trained: | |
| raise ValueError("Model must be trained first") | |
| model_data = { | |
| 'ratings': self.ratings, | |
| 'movies': self.movies, | |
| 'user_item_matrix': self.user_item_matrix, | |
| 'item_similarity_df': self.item_similarity_df, | |
| 'svd_model': self.svd_model, | |
| 'pred_svd_df': self.pred_svd_df, | |
| 'is_trained': self.is_trained | |
| } | |
| with open(path, 'wb') as f: | |
| pickle.dump(model_data, f) | |
| print(f"Model saved to {path}") | |
| def load_model(self, path: str): | |
| """Load a trained model.""" | |
| with open(path, 'rb') as f: | |
| model_data = pickle.load(f) | |
| self.ratings = model_data['ratings'] | |
| self.movies = model_data['movies'] | |
| self.user_item_matrix = model_data['user_item_matrix'] | |
| self.item_similarity_df = model_data['item_similarity_df'] | |
| self.svd_model = model_data['svd_model'] | |
| self.pred_svd_df = model_data['pred_svd_df'] | |
| self.is_trained = model_data['is_trained'] | |
| print(f"Model loaded from {path}") | |
| # Create a global model instance for inference | |
| model = MovieRecommender() | |
| def predict(user_id: int, n_recommendations: int = 10, method: str = "svd") -> List[Dict]: | |
| """ | |
| Inference function for Hugging Face model. | |
| Args: | |
| user_id: User ID to get recommendations for | |
| n_recommendations: Number of recommendations (default: 10) | |
| method: Recommendation method - "svd" or "cf" (default: "svd") | |
| Returns: | |
| List of movie recommendations | |
| """ | |
| return model.recommend_movies(user_id, n_recommendations, method) |