可在thinkphp6.x中基于用户历史行为实现轻量级协同过滤推荐:构建用户-物品矩阵、用皮尔逊系数计算相似度、筛选邻居、加权预测未交互物品评分,最后封装为可注入的服务类。

如果您希望在 ThinkPHP6.x 框架中实现一个轻量级的推荐功能,且仅依赖用户历史行为数据(如浏览、收藏、评分),则可采用基于用户的简单协同过滤算法。以下是该算法在 ThinkPHP6.x 环境下的具体实现步骤:
一、构建用户-物品行为矩阵
协同过滤的基础是量化用户与物品之间的交互关系,需将原始行为日志转化为稀疏矩阵形式,其中行代表用户ID,列代表物品ID,单元格值为显式评分或隐式行为权重(如点击次数、停留时长归一化值)。ThinkPHP6.x 中可通过数据库查询与 Collection 类配合完成结构化组装。
1、在 app/model/BehaviorLog.php 中定义模型,关联 user_id、item_id、behavior_type(如 view/collection/rate)、score(若存在)字段。
2、使用 Db::table('behavior_log')->select() 查询全量有效行为记录,并过滤掉 score = 0 或 behavior_type 不在预设列表中的条目。
3、调用 collect($records)->groupBy('user_id') 将数据按用户聚合,再对每个用户组内 item_id 去重并加权统计:view 计 1 分,collection 计 2 分,rate 按实际值计入,最终生成 $userItemMatrix 数组,格式为 ['user1' => ['item_a' => 3.5, 'item_b' => 1.0], ...]。
二、计算用户相似度
采用皮尔逊相关系数(Pearson Correlation Coefficient)衡量用户间兴趣相似性,该方法能缓解用户评分尺度差异问题,适用于评分稀疏场景。相似度计算需基于共同交互过的物品集合,避免空交集导致除零异常。
1、遍历 $userItemMatrix 中所有用户对 (u, v),提取二者共现的 item_id 列表 $commonItems。
2、若 count($commonItems) 阈值 3 可防止偶然共现引发的虚假高相似。
3、分别计算 u 和 v 在 $commonItems 上的评分均值 $meanU、$meanV,再代入公式:∑[(r_ui − meanU)(r_vi − meanV)] / √[∑(r_ui − meanU)² × ∑(r_vi − meanV)²],结果存入二维数组 $similarityMatrix['u']['v']。
三、生成目标用户的近邻集合
为提升推荐效率与精度,需为目标用户筛选出最相似的 K 个邻居,K 值建议设为 5–15,过大易引入噪声,过小则覆盖不足。相似度排序应排除自身及未产生任何行为的用户。
1、从 $similarityMatrix 中提取目标用户 $targetId 对应的所有非零相似度项,构成临时数组 $candidates。
2、使用 array_filter($candidates, function($s) { return $s > 0.1; }) 过滤低相似度用户,0.1 是经验性下限,低于该值视为无实质兴趣重叠。
3、调用 arsort($candidates) 降序排列,取前 K 个键名,存入 $neighbors 数组,作为后续预测依据。
四、预测未交互物品评分并排序
对目标用户未接触过的每个物品,利用其邻居在该物品上的评分加权平均进行预测。权重即邻居与目标用户的相似度,确保高相似用户影响更大,同时抑制冷门物品的误推荐。
1、获取全量 item_id 列表 $allItems,再通过 array_keys($userItemMatrix[$targetId] ?? []) 获取目标用户已交互物品,两者取差集得 $unseenItems。
2、对每个 $item ∈ $unseenItems,初始化 $sumScore = 0、$sumWeight = 0;遍历 $neighbors,若该 neighbor 在 $userItemMatrix 中存在 $item 键,则执行:$sumScore += $similarityMatrix[$targetId][$neighbor] * $userItemMatrix[$neighbor][$item];$sumWeight += abs($similarityMatrix[$targetId][$neighbor])。
3、若 $sumWeight > 0,则预测评分为 $sumScore / $sumWeight,否则跳过该物品;将有效预测结果存入 $predictions 关联数组,键为 item_id,值为浮点评分。
五、封装为服务类并注入控制器
将上述逻辑抽象为独立服务类,便于复用与测试,符合 ThinkPHP6.x 的依赖注入规范。该类应实现接口契约,支持运行时传入用户ID与推荐数量参数,返回标准化的物品ID数组。
1、在 app/service/RecommendService.php 中定义类,构造函数接收 Db 查询实例与缓存实例(如 Cache::store('redis'))。
2、添加 public function getRecommendations(string $userId, int $limit = 10): array 方法,内部依次调用前述五个步骤对应私有方法,并在最后对 $predictions 按值降序排列,取 key_slice(array_keys($sorted), 0, $limit) 返回。
3、在控制器中通过 app()->make(RecommendService::class)->getRecommendations($uid, 8) 调用,每次请求必须校验 $userId 是否为合法整数字符串,防止 SQL 注入与空指针异常。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











