N-Kibria commited on
Commit
5ef8c66
·
verified ·
1 Parent(s): a84da0d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -68
app.py CHANGED
@@ -8,43 +8,36 @@ import os
8
  from scipy.sparse import csr_matrix
9
 
10
  class ItemBasedCF:
11
- def __init__(self):
 
 
12
  self.user_item_matrix = None
13
- self.similarity_matrix = None
14
-
15
- def predict(self, user_idx, movie_idx):
16
- if self.user_item_matrix is None or self.similarity_matrix is None:
17
- return 3.0
18
 
 
19
  user_ratings = self.user_item_matrix[user_idx].toarray().flatten()
20
- rated_items = np.where(user_ratings > 0)[0]
21
 
22
- if len(rated_items) == 0:
23
- return 3.0
24
 
25
- similarities = self.similarity_matrix[movie_idx, rated_items].toarray().flatten()
26
- ratings = user_ratings[rated_items]
27
 
28
- if similarities.sum() == 0:
29
- return 3.0
 
30
 
31
- prediction = np.dot(similarities, ratings) / similarities.sum()
32
  return np.clip(prediction, 1, 5)
33
 
34
 
35
  class SVDRecommender:
36
- def __init__(self):
 
37
  self.user_factors = None
38
  self.item_factors = None
39
  self.global_mean = 3.5
40
 
41
  def predict(self, user_idx, movie_idx):
42
- if self.user_factors is None or self.item_factors is None:
43
- return self.global_mean
44
-
45
- if user_idx >= len(self.user_factors) or movie_idx >= len(self.item_factors):
46
- return self.global_mean
47
-
48
  prediction = self.global_mean + np.dot(self.user_factors[user_idx], self.item_factors[movie_idx])
49
  return np.clip(prediction, 1, 5)
50
 
@@ -82,71 +75,71 @@ class NeuralCF(nn.Module):
82
 
83
 
84
  class HybridRecommender:
85
- def __init__(self):
 
 
86
  self.item_cf = None
87
  self.svd = None
88
  self.ncf = None
89
- self.weights = [0.33, 0.33, 0.34]
90
- self.device = 'cpu'
 
 
 
91
 
92
  def predict(self, user_idx, movie_idx):
93
- predictions = []
94
-
95
- if self.item_cf is not None:
96
- predictions.append(self.item_cf.predict(user_idx, movie_idx))
97
-
98
- if self.svd is not None:
99
- predictions.append(self.svd.predict(user_idx, movie_idx))
100
-
101
- if self.ncf is not None:
102
- predictions.append(self.ncf.predict(user_idx, movie_idx, self.device))
103
-
104
- if not predictions:
105
- return 3.5
106
-
107
- weights = self.weights[:len(predictions)]
108
- weight_sum = sum(weights)
109
- weighted_pred = sum(p * w for p, w in zip(predictions, weights)) / weight_sum
110
 
111
- return np.clip(weighted_pred, 1, 5)
112
 
113
- def recommend_movies(self, user_id, N, user_id_map, reverse_movie_map, movies_df):
114
- if user_id not in user_id_map:
115
- return []
116
-
117
- user_idx = user_id_map[user_id]
118
-
119
- if self.item_cf is None or self.item_cf.user_item_matrix is None:
120
- return []
121
 
122
- user_ratings = self.item_cf.user_item_matrix[user_idx].toarray().flatten()
123
- unrated_indices = np.where(user_ratings == 0)[0]
124
 
125
- if len(unrated_indices) == 0:
126
- return []
 
 
 
127
 
128
- predictions = []
129
- for movie_idx in unrated_indices:
130
- pred_rating = self.predict(user_idx, movie_idx)
131
- predictions.append((movie_idx, pred_rating))
132
-
133
- predictions.sort(key=lambda x: x[1], reverse=True)
134
- top_predictions = predictions[:N]
135
 
136
  recommendations = []
137
- for movie_idx, pred_rating in top_predictions:
138
- original_movie_id = reverse_movie_map[movie_idx]
139
- movie_info = movies_df[movies_df['movie_id'] == original_movie_id]
 
 
 
 
 
 
 
140
 
141
- if not movie_info.empty:
142
- title = movie_info['title'].values[0]
143
- recommendations.append((original_movie_id, title, pred_rating))
144
 
145
  return recommendations
146
 
147
 
148
  class MovieLensDataLoader:
149
- def __init__(self):
 
 
150
  self.user_id_map = {}
151
  self.movie_id_map = {}
152
  self.reverse_user_map = {}
 
8
  from scipy.sparse import csr_matrix
9
 
10
  class ItemBasedCF:
11
+ def __init__(self, n_neighbors=20):
12
+ self.n_neighbors = n_neighbors
13
+ self.item_similarity = None
14
  self.user_item_matrix = None
 
 
 
 
 
15
 
16
+ def predict(self, user_idx, movie_idx):
17
  user_ratings = self.user_item_matrix[user_idx].toarray().flatten()
18
+ rated_mask = user_ratings > 0
19
 
20
+ if not rated_mask.any():
21
+ return 2.5
22
 
23
+ similarities = self.item_similarity[movie_idx].toarray().flatten()
 
24
 
25
+ weights = similarities * rated_mask
26
+ if weights.sum() == 0:
27
+ return 2.5
28
 
29
+ prediction = (weights * user_ratings).sum() / weights.sum()
30
  return np.clip(prediction, 1, 5)
31
 
32
 
33
  class SVDRecommender:
34
+ def __init__(self, n_factors=50):
35
+ self.n_factors = n_factors
36
  self.user_factors = None
37
  self.item_factors = None
38
  self.global_mean = 3.5
39
 
40
  def predict(self, user_idx, movie_idx):
 
 
 
 
 
 
41
  prediction = self.global_mean + np.dot(self.user_factors[user_idx], self.item_factors[movie_idx])
42
  return np.clip(prediction, 1, 5)
43
 
 
75
 
76
 
77
  class HybridRecommender:
78
+ def __init__(self, n_users, n_movies):
79
+ self.n_users = n_users
80
+ self.n_movies = n_movies
81
  self.item_cf = None
82
  self.svd = None
83
  self.ncf = None
84
+ self.weights = {
85
+ 'item_cf': 0.3,
86
+ 'svd': 0.4,
87
+ 'ncf': 0.3
88
+ }
89
 
90
  def predict(self, user_idx, movie_idx):
91
+ cf_pred = self.item_cf.predict(user_idx, movie_idx)
92
+ svd_pred = self.svd.predict(user_idx, movie_idx)
93
+ ncf_pred = self.ncf.predict(user_idx, movie_idx)
94
+
95
+ prediction = (
96
+ self.weights['item_cf'] * cf_pred +
97
+ self.weights['svd'] * svd_pred +
98
+ self.weights['ncf'] * ncf_pred
99
+ )
 
 
 
 
 
 
 
 
100
 
101
+ return np.clip(prediction, 1, 5)
102
 
103
+ def recommend_movies(self, user_id, N=10, user_id_map=None, reverse_movie_map=None, movies_df=None):
104
+ if user_id_map is not None:
105
+ if user_id not in user_id_map:
106
+ return []
107
+ user_idx = user_id_map[user_id]
108
+ else:
109
+ user_idx = user_id
 
110
 
111
+ rated_movies = set(np.where(self.item_cf.user_item_matrix[user_idx].toarray().flatten() > 0)[0])
 
112
 
113
+ scores = []
114
+ for movie_idx in range(self.n_movies):
115
+ if movie_idx not in rated_movies:
116
+ score = self.predict(user_idx, movie_idx)
117
+ scores.append((movie_idx, score))
118
 
119
+ scores.sort(key=lambda x: x[1], reverse=True)
120
+ top_recommendations = scores[:N]
 
 
 
 
 
121
 
122
  recommendations = []
123
+ for movie_idx, score in top_recommendations:
124
+ if reverse_movie_map is not None:
125
+ original_movie_id = reverse_movie_map[movie_idx]
126
+ else:
127
+ original_movie_id = movie_idx
128
+
129
+ if movies_df is not None:
130
+ title = movies_df[movies_df['movie_id'] == original_movie_id]['title'].values[0]
131
+ else:
132
+ title = f"Movie {original_movie_id}"
133
 
134
+ recommendations.append((original_movie_id, title, score))
 
 
135
 
136
  return recommendations
137
 
138
 
139
  class MovieLensDataLoader:
140
+ def __init__(self, ratings_path=None, movies_path=None):
141
+ self.ratings_path = ratings_path
142
+ self.movies_path = movies_path
143
  self.user_id_map = {}
144
  self.movie_id_map = {}
145
  self.reverse_user_map = {}