Solingen

lab4.py

Apr 9th, 2026
42
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.72 KB | None | 0 0
  1. import math
  2.  
  3. # ============================================================
  4. # USER-BASED рекомендательная система
  5. # ============================================================
  6.  
  7. # Матрица предпочтений: ratings[товар][пользователь]
  8. # 0 = пользователь не оценил товар
  9.  
  10. products = ['P1', 'P2', 'P3', 'P4', 'P5']
  11. users    = ['U1', 'U2', 'U3', 'U4']
  12.  
  13. #          U1   U2   U3   U4
  14. ratings = [
  15.     [5,   5,   4,   5],   # P1
  16.     [5,   5,   3,   0],   # P2
  17.     [5,   5,   5,   5],   # P3
  18.     [5,   0,   2,   0],   # P4
  19.     [0,   5,   1,   0],   # P5
  20. ]
  21.  
  22. # Матрица косинусного подобия пользователей
  23. # sim[i][j] — подобие между users[i] и users[j]
  24. user_sim_raw = {
  25.     ('U1', 'U2'): 0.9,
  26.     ('U1', 'U3'): 0.7,
  27.     ('U1', 'U4'): 0.0,   # U4 исключён (мало оценок — все нули кроме P1, P3)
  28.     ('U2', 'U3'): 0.6,
  29.     ('U2', 'U4'): 0.0,
  30.     ('U3', 'U4'): 0.0,
  31. }
  32.  
  33. # ============================================================
  34. # Вспомогательные функции
  35. # ============================================================
  36.  
  37. def dot_product(a, b):
  38.     return sum(x * y for x, y in zip(a, b))
  39.  
  40. def norm(v):
  41.     return math.sqrt(sum(x ** 2 for x in v))
  42.  
  43. def cosine_similarity(a, b):
  44.     na, nb = norm(a), norm(b)
  45.     if na == 0 or nb == 0:
  46.         return 0.0
  47.     return dot_product(a, b) / (na * nb)
  48.  
  49. def get_user_vector(user_idx):
  50.     """Вектор оценок пользователя (по всем товарам)."""
  51.     return [ratings[i][user_idx] for i in range(len(products))]
  52.  
  53. def get_item_vector(item_idx):
  54.     """Вектор оценок товара (по всем пользователям)."""
  55.     return ratings[item_idx]
  56.  
  57. def get_sim(u1, u2):
  58.     """Косинусное подобие между двумя пользователями по имени."""
  59.     if u1 == u2:
  60.         return 1.0
  61.     key = (u1, u2) if (u1, u2) in user_sim_raw else (u2, u1)
  62.     return user_sim_raw.get(key, 0.0)
  63.  
  64. def avg_rating(user_idx):
  65.     """Средняя оценка пользователя по всем товарам, которые он оценил (> 0)."""
  66.     rated = [ratings[i][user_idx] for i in range(len(products)) if ratings[i][user_idx] > 0]
  67.     return sum(rated) / len(rated) if rated else 0.0
  68.  
  69. def is_new_user(user_idx):
  70.     """Новый пользователь — все оценки == 0."""
  71.     return all(ratings[i][user_idx] == 0 for i in range(len(products)))
  72.  
  73. def best_avg_product():
  74.     """Товар с наибольшим средним рейтингом (для новых пользователей)."""
  75.     best_p, best_avg = None, -1
  76.     for i, p in enumerate(products):
  77.         rated = [ratings[i][j] for j in range(len(users)) if ratings[i][j] > 0]
  78.         avg = sum(rated) / len(rated) if rated else 0.0
  79.         if avg > best_avg:
  80.             best_avg = avg
  81.             best_p = p
  82.     return best_p, best_avg
  83.  
  84. def predict(user_a_idx, item_i_idx, demo=True):
  85.     """Предсказывает оценку пользователя a для товара i."""
  86.     a_name = users[user_a_idx]
  87.     i_name = products[item_i_idx]
  88.  
  89.     # K — пользователи которые оценили товар i (кроме самого a)
  90.     K = []
  91.     for u_idx, u_name in enumerate(users):
  92.         if u_idx == user_a_idx:
  93.             continue
  94.         if ratings[item_i_idx][u_idx] > 0:
  95.             sim = get_sim(a_name, u_name)
  96.             if sim > 0:
  97.                 K.append(u_idx)
  98.  
  99.     if not K:
  100.         if demo:
  101.             print(f"    K пуст — нет похожих пользователей, оценивших {i_name}")
  102.         return None
  103.  
  104.     r_a = avg_rating(user_a_idx)
  105.  
  106.     numerator   = 0.0
  107.     denominator = 0.0
  108.  
  109.     if demo:
  110.         print(f"    r̄({a_name}) = {r_a:.4f}")
  111.         print(f"    K = {{ {', '.join(users[u] for u in K)} }}")
  112.  
  113.     for u_idx in K:
  114.         u_name  = users[u_idx]
  115.         r_ui    = ratings[item_i_idx][u_idx]
  116.         r_u     = avg_rating(u_idx)
  117.         cos_au  = get_sim(a_name, u_name)
  118.  
  119.         term    = (r_ui - r_u) * cos_au
  120.         numerator   += term
  121.         denominator += abs(cos_au)
  122.  
  123.         if demo:
  124.             print(f"      u={u_name}: r({u_name},{i_name})={r_ui}, "
  125.                   f"r̄({u_name})={r_u:.4f}, cos({a_name},{u_name})={cos_au:.4f} "
  126.                   f"→ ({r_ui} - {r_u:.4f}) × {cos_au:.4f} = {term:.4f}")
  127.  
  128.     if denominator == 0:
  129.         return None
  130.  
  131.     pr = r_a + numerator / denominator
  132.  
  133.     if demo:
  134.         print(f"    Pr({a_name},{i_name}) = {r_a:.4f} + {numerator:.4f} / {denominator:.4f} = {pr:.4f}")
  135.  
  136.     return pr
  137.  
  138. # ============================================================
  139. # Главная функция — рекомендация для каждого пользователя
  140. # ============================================================
  141.  
  142. def recommend_for_user(user_idx, demo=True):
  143.     a_name = users[user_idx]
  144.  
  145.     print(f"\n{'='*60}")
  146.     print(f"  Пользователь: {a_name}")
  147.     print(f"{'='*60}")
  148.  
  149.     # Новый пользователь?
  150.     if is_new_user(user_idx):
  151.         best_p, best_avg = best_avg_product()
  152.         print(f"  Новый пользователь (все оценки = 0).")
  153.         print(f"  Рекомендуем товар с наибольшим средним рейтингом: {best_p} (avg={best_avg:.4f})")
  154.         return best_p
  155.  
  156.     # Товары, которые пользователь НЕ оценил
  157.     unrated = [i for i in range(len(products)) if ratings[i][user_idx] == 0]
  158.  
  159.     if not unrated:
  160.         print(f"  {a_name} оценил все товары — нечего рекомендовать.")
  161.         return None
  162.  
  163.     print(f"  Неоцененные товары: {[products[i] for i in unrated]}")
  164.     print(f"  Считаем предсказанную оценку для каждого:\n")
  165.  
  166.     predictions = {}
  167.     for i_idx in unrated:
  168.         i_name = products[i_idx]
  169.         print(f"  → Pr({a_name}, {i_name}):")
  170.         pr = predict(user_idx, i_idx, demo=demo)
  171.         if pr is not None:
  172.             predictions[i_name] = pr
  173.             print(f"    Результат: {pr:.4f}")
  174.         else:
  175.             print(f"    Нет данных для предсказания.")
  176.         print()
  177.  
  178.     if not predictions:
  179.         print(f"  Не удалось предсказать оценки.")
  180.         return None
  181.  
  182.     best = max(predictions, key=lambda x: predictions[x])
  183.     print(f"  Все предсказания: { {k: round(v,4) for k,v in predictions.items()} }")
  184.     print(f"  ✓ Рекомендуем {a_name}: товар {best} (Pr = {predictions[best]:.4f})")
  185.     return best
  186.  
  187. # ============================================================
  188. # Вывод исходных данных
  189. # ============================================================
  190.  
  191. print("=" * 60)
  192. print("  USER-BASED РЕКОМЕНДАТЕЛЬНАЯ СИСТЕМА")
  193. print("=" * 60)
  194.  
  195. # Матрица предпочтений
  196. col_w = 6
  197. print("\n  Матрица предпочтений:")
  198. print("  " + " " * 4 + "".join(f"{u:>{col_w}}" for u in users))
  199. print("  " + "-" * (4 + col_w * len(users)))
  200. for i, p in enumerate(products):
  201.     row = f"  {p:<4}" + "".join(f"{ratings[i][j]:>{col_w}}" for j in range(len(users)))
  202.     print(row)
  203.  
  204. # Средние оценки
  205. print("\n  Средние оценки пользователей (по оцененным товарам):")
  206. for j, u in enumerate(users):
  207.     print(f"    r̄({u}) = {avg_rating(j):.4f}")
  208.  
  209. # Матрица подобия
  210. print("\n  Матрица косинусного подобия пользователей:")
  211. print("  " + " " * 4 + "".join(f"{u:>{col_w}}" for u in users))
  212. print("  " + "-" * (4 + col_w * len(users)))
  213. for i, u1 in enumerate(users):
  214.     row = f"  {u1:<4}"
  215.     for j, u2 in enumerate(users):
  216.         row += f"{get_sim(u1,u2):>{col_w}.2f}"
  217.     print(row)
  218.  
  219. # ============================================================
  220. # Рекомендации для всех пользователей
  221. # ============================================================
  222. print("\n\n" + "=" * 60)
  223. print("  РАСЧЁТ РЕКОМЕНДАЦИЙ")
  224. print("=" * 60)
  225.  
  226. results = {}
  227. for j in range(len(users)):
  228.     rec = recommend_for_user(j, demo=True)
  229.     results[users[j]] = rec
  230.  
  231. print("\n" + "=" * 60)
  232. print("  ИТОГОВЫЕ РЕКОМЕНДАЦИИ")
  233. print("=" * 60)
  234. for u, rec in results.items():
  235.     if rec:
  236.         print(f"  {u} → рекомендовать {rec}")
  237.     else:
  238.         print(f"  {u} → нечего рекомендовать")
Advertisement
Add Comment
Please, Sign In to add comment