Solingen

lab5.py

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