当前位置: 首页 > news >正文

个性化题目推荐引擎:协同过滤与知识图谱的混合推荐策略

个性化题目推荐引擎:协同过滤与知识图谱的混合推荐策略

一、用户刷题卡壳了,推荐什么

一个算法初学者刚刚刷过"两数之和",但在"三数之和"上卡了 30 分钟。此时系统应该建议他先去刷一道双指针的基础题,还是直接给他另一道哈希表的题目?

推荐引擎的核心是在正确的时间,推荐正确的题目。这需要融合三种信息:用户的能力画像(已刷题、正确率、用时)、题目的知识图谱关系(前置知识点、相似题型、难度梯度)、其他用户的协同行为(相似用户还刷了什么)。

flowchart TB A[用户能力画像] --> D[混合推荐引擎] B[题目知识图谱] --> D C[协同过滤矩阵] --> D D --> E[协同过滤分数] D --> F[知识图谱分数] D --> G[难度适配分数] E --> H[加权融合层] F --> H G --> H H --> I[候选题目排序] I --> J[去重 & 多样性过滤] J --> K[Top-N 推荐列表] style D fill:#ccf style H fill:#ffc

二、混合推荐的三层机制

协同过滤层:基于用户-题目的交互矩阵(刷题次数/正确率),找到相似用户喜欢的题目。核心公式是余弦相似度:

similarity(u, v) = (R_u · R_v) / (|R_u| * |R_v|)

其中 R_u 是用户 u 的题目评分向量。

知识图谱层:基于知识点的前置关系和难度梯度,推荐"跳一跳够得着"的题目。图结构中的路径权重由知识点关联强度决定。

难度适配层:根据用户当前的能力水平(正确率和平均用时),筛选适当难度的题目。难度阈值 = 当前能力 + 0.1(稍微挑战)。

三、混合推荐引擎的完整实现

""" 个性化题目推荐引擎 三层融合:协同过滤 + 知识图谱 + 难度适配 """ import math import numpy as np from typing import List, Dict, Tuple, Optional from dataclasses import dataclass from collections import defaultdict @dataclass class Problem: """题目定义""" problem_id: int title: str difficulty: float # 0-1 难度值 knowledge_points: List[str] # 知识点列表 prerequisites: List[int] # 前置题目 ID class CollaborativeFilter: """协同过滤推荐""" def __init__(self): self.user_ratings: Dict[int, Dict[int, float]] = {} def add_rating(self, user_id: int, problem_id: int, rating: float): """添加用户对题目的评分""" if user_id not in self.user_ratings: self.user_ratings[user_id] = {} self.user_ratings[user_id][problem_id] = rating def find_similar_users(self, target_user: int, top_k: int = 10) -> List[Tuple[int, float]]: """找到最相似的 K 个用户""" if target_user not in self.user_ratings: return [] target_vec = self.user_ratings[target_user] similarities = [] for uid, ratings in self.user_ratings.items(): if uid == target_user: continue # 余弦相似度 common = set(target_vec.keys()) & set(ratings.keys()) if len(common) < 3: continue dot = sum(target_vec[p] * ratings[p] for p in common) norm_a = math.sqrt(sum(v ** 2 for v in target_vec.values())) norm_b = math.sqrt(sum(v ** 2 for v in ratings.values())) sim = dot / (norm_a * norm_b) if norm_a and norm_b else 0 similarities.append((uid, sim)) similarities.sort(key=lambda x: x[1], reverse=True) return similarities[:top_k] def predict_rating(self, user_id: int, problem_id: int) -> float: """预测用户对题目的评分""" similar_users = self.find_similar_users(user_id) if not similar_users: return 0.0 weighted_sum = 0.0 sim_sum = 0.0 for uid, sim in similar_users: if problem_id in self.user_ratings.get(uid, {}): weighted_sum += sim * self.user_ratings[uid][problem_id] sim_sum += abs(sim) return weighted_sum / sim_sum if sim_sum > 0 else 0.0 class KnowledgeGraphRecommender: """基于知识图谱的推荐""" def __init__(self): self.problems: Dict[int, Problem] = {} self.kg_edges: Dict[str, float] = {} # "kp_a→kp_b": weight def add_problem(self, problem: Problem): """添加题目到知识图谱""" self.problems[problem.problem_id] = problem def add_kg_edge(self, kp_a: str, kp_b: str, weight: float = 1.0): """添加知识点之间的关联边""" self.kg_edges[f"{kp_a}→{kp_b}"] = weight def get_related_problems(self, problem_id: int, max_distance: int = 2, top_k: int = 10) -> List[Tuple[int, float]]: """获取与题目相关的其他题目""" if problem_id not in self.problems: return [] src_kps = set(self.problems[problem_id].knowledge_points) scores = defaultdict(float) for pid, problem in self.problems.items(): if pid == problem_id: continue dst_kps = set(problem.knowledge_points) # 计算知识点重叠与距离 overlap = len(src_kps & dst_kps) if overlap > 0: scores[pid] = overlap * 0.5 + ( 1.0 / (abs(problem.difficulty - self.problems[problem_id].difficulty) + 0.1) ) * 0.3 sorted_scores = sorted( scores.items(), key=lambda x: x[1], reverse=True ) return sorted_scores[:top_k] class DifficultyAdapter: """难度适配器""" def __init__(self, target_success_rate: float = 0.7): self.target_success_rate = target_success_rate self.user_skill: Dict[int, float] = {} def update_skill(self, user_id: int, correct: bool, problem_difficulty: float, learning_rate: float = 0.1): """更新用户能力估计(基于 Elo 评分思想)""" if user_id not in self.user_skill: self.user_skill[user_id] = 0.3 # 初始能力 expected = 1.0 / (1.0 + math.exp( -(self.user_skill[user_id] - problem_difficulty) * 5 )) actual = 1.0 if correct else 0.0 self.user_skill[user_id] += learning_rate * (actual - expected) def score(self, user_id: int, problem_difficulty: float) -> float: """根据难度适配程度打分(越接近最近发展区越高)""" skill = self.user_skill.get(user_id, 0.3) # 最优难度 = 当前能力 + 0.1(稍微挑战) optimal = skill + 0.1 diff = abs(problem_difficulty - optimal) return math.exp(-diff * 5) # 高斯核 class HybridRecommender: """混合推荐引擎""" def __init__(self): self.cf = CollaborativeFilter() self.kg = KnowledgeGraphRecommender() self.da = DifficultyAdapter() # 三路权重 self.weights = {"cf": 0.4, "kg": 0.35, "da": 0.25} def recommend(self, user_id: int, current_problem_id: Optional[int] = None, top_n: int = 5) -> List[int]: """综合推荐""" all_scores = defaultdict(float) # 1. 协同过滤分数 for pid in list(self.kg.problems.keys())[:20]: cf_score = self.cf.predict_rating(user_id, pid) all_scores[pid] += cf_score * self.weights["cf"] # 2. 知识图谱分数 if current_problem_id: kg_recs = self.kg.get_related_problems(current_problem_id) for pid, kg_score in kg_recs: all_scores[pid] += kg_score * self.weights["kg"] # 3. 难度适配分数 for pid in list(self.kg.problems.keys())[:20]: diff = self.kg.problems.get(pid) if diff: da_score = self.da.score(user_id, diff.difficulty) all_scores[pid] += da_score * self.weights["da"] # 排序去重 sorted_items = sorted( all_scores.items(), key=lambda x: x[1], reverse=True ) return [pid for pid, _ in sorted_items[:top_n]] if __name__ == "__main__": engine = HybridRecommender() for i in range(20): engine.kg.add_problem(Problem( i, f"Problem {i}", difficulty=0.1 + i * 0.04, knowledge_points=[f"kp_{i % 5}"], prerequisites=[max(0, i - 1)], )) engine.cf.add_rating(1, 0, 1.0) engine.cf.add_rating(1, 1, 0.8) engine.cf.add_rating(2, 0, 0.9) engine.cf.add_rating(2, 2, 1.0) recs = engine.recommend(1, current_problem_id=0) print(f"推荐题目: {recs}")

四、冷启动与多样性问题

新用户冷启动:新用户没有任何行为数据时,协同过滤失效。解决:初始用知识图谱推荐(按知识点拓扑排序),随着交互增多逐渐增加协同过滤权重。

内容多样性:如果只推荐分数最高的题目,可能连续推荐 5 道"双指针"题。加入 MMR(最大边缘相关性)算法,平衡相关性和多样性。

探索-利用平衡:总是推荐"最可能喜欢"的题目会导致信息茧房。定期以 10-15% 的概率随机推荐"探索性题目",帮助用户发现新的知识点。

五、总结

  1. 协同过滤负责"你也可能喜欢":冷启动弱但长期效果好。
  2. 知识图谱负责"学习路径":确保推荐遵循知识点前置关系。
  3. 难度适配负责"跳一跳够得着":70% 成功率的目标对学习最有利。
  4. 混合策略权重可动态调整:初期知识图谱权重高,中后期协同过滤权重高。

本文实现了融合协同过滤、知识图谱和难度适配的三层混合推荐引擎,核心的评分融合逻辑和动态权重机制可直接用于个性化学习推荐。

http://www.jsqmd.com/news/1196502/

相关文章:

  • 2026年Q3电池模拟器行业技术生态与供应能力评估 - 企业推荐官【官方】
  • 情感陪伴应用的长期记忆架构:从会话缓存到持久化记忆网络
  • 容器化部署下Java外卖API服务的JVM内存调优:G1垃圾回收器参数实战
  • AI 智能窗帘电机智能功率 覆盖H桥驱动 精准选型方案
  • 一次性保鲜膜套定制常见问题解答(2026专家版) - 全域品牌推荐
  • 用ChatGPT做科技事实核查:消费电子参数验证实战指南
  • 【学习笔记】多模态部署:VLM、语音、视频理解(29/35)
  • 正交性悖论:当空间不再天然垂直,工程建模如何应对度规畸变
  • 北京卖老酒不用跑门店!6 家支持京津上门收酒的实体老店,综合实力测评 - 深鉴新闻
  • 宁波本地企业GEO流量增长工具怎么选?高性价比工具推荐与2026年选型七维解析 - 小随科技
  • 2026年7月最新泉州芝柏官方售后维修服务网点地址与客服电话 - 亨得利官方服务中心
  • 基于下一层信息反馈的模型结构化裁剪策略:Lookahead 剪枝比例分配算法的原理推导与实验验证
  • 2026年专业保鲜膜套源头厂家推荐 保鲜膜套选型指南 - 全域品牌推荐
  • 2026年Java面试的风向彻底变了!
  • 多线程并发模型:Actor模型在ArkTS中的应用(172)
  • 2026年07月工业阀门行业关键性能指标与纽顺阀门集团有限公司全品类选型参考 - 企业推荐官【官方】
  • C++写的RSA文件加密小工具,支持TXT和JPG/PNG等图片直接加解密
  • OpenClaw 集成 SearXNG 实战:从踩坑到成功部署(macOS + Docker)
  • Java 23 种设计模式:从踩坑到精通 | 番外:适配器 vs 装饰器 —— 一个改接口,一个不改接口
  • 伯爵中国官方售后服务中心|服务热线及详细地址权威信息公示(2026年7月最新) - 亨得利钟表维修中心
  • Patran中可直接运行的圆柱体参数化建模全套PCL脚本(含菜单、材料、网格、载荷与结果提取)
  • 2026深圳靠谱搬家公司推荐|10家本地大型正规直营搬家公司排名,本土老牌无外包、无隐形消费、合规避坑全指南 - 厚道搬家
  • AI 应用的技术债务管理:从 Prompt 碎片到架构腐化的系统性治理
  • 深圳本地企业GEO流量增长工具怎么选?高性价比工具推荐 - 小随科技
  • 2026 年新发布:宝丰热门的热浸塑排水管道供应厂家深度剖析,别再用传统管道了!热浸塑技术如何彻底改变排水难题 - 行业推荐【认证官】
  • 故障自愈与自动恢复机制:从手动重启到无人值守
  • 大模型配置优化实战:从参数调优到生产部署完整指南
  • Jetson TK1系统检查全指南:L4T版本、Ubuntu兼容性与硬件诊断
  • 稳健回归实战指南:应对异常值的5种Python方法与选型策略
  • 使用 Docker 安装