1. 项目背景与核心价值
最近在做一个电影推荐小程序时,发现单纯按热度或分类推荐效果很一般。用户反馈"推荐的片子都差不多"、"根本不是我喜欢的类型"。这让我开始研究如何用协同过滤算法实现个性化推荐。经过两个月的开发和调优,最终上线的推荐模块点击率提升了47%,用户停留时长增加32%。今天就把这套经过实战验证的方案拆解给大家。
协同过滤(Collaborative Filtering)是推荐系统的经典算法,核心思想是"物以类聚,人以群分"。它不需要复杂的特征工程,仅通过用户历史行为数据就能挖掘出"相似用户"和"相似物品"。在微信小程序这种轻量级场景下尤其适用——不需要用户填写繁琐的偏好问卷,看完几部电影后系统就能自动推荐符合口味的影片。
2. 系统架构设计
2.1 技术选型考量
微信小程序端采用MINA框架开发,推荐服务端用Python搭建主要基于以下考量:
- 计算密集型任务放在服务端(Python的NumPy/SciPy生态完善)
- 小程序与云开发天然集成(使用云函数调用推荐服务)
- 实时性要求不高(每日离线更新推荐结果即可)
数据流设计特别注意了微信生态的特点:
- 用户在小程序端的评分/观看记录通过云数据库收集
- 每晚定时云函数触发Spark计算任务
- 计算结果写回云数据库供小程序读取
- 推荐结果缓存到本地提升加载速度
2.2 算法选型对比
测试了三种协同过滤方案:
| 算法类型 | 准确率 | 计算复杂度 | 冷启动问题 |
|---|---|---|---|
| 用户基础(UserCF) | 68% | O(M^2) | 严重 |
| 物品基础(ItemCF) | 72% | O(N^2) | 中等 |
| 矩阵分解(MF) | 85% | O(K*(M+N)) | 较轻 |
最终选择ItemCF作为基础算法,因为:
- 电影数量(N)相对稳定,而用户量(M)增长快
- 电影相似度矩阵可以预先计算
- 适合微信小程序用户"浏览-点击"的行为模式
3. 核心实现细节
3.1 数据预处理关键步骤
原始行为数据需要经过多层过滤:
python复制# 去噪:过滤观看时长不足5分钟的记录
df = df[df['watch_time'] > 300]
# 降噪:同一用户对同一电影的多次观看取均值
df = df.groupby(['user_id','movie_id'])['rating'].mean().reset_index()
# 稀疏处理:只保留有20个以上行为的用户
user_counts = df['user_id'].value_counts()
valid_users = user_counts[user_counts > 20].index
df = df[df['user_id'].isin(valid_users)]
3.2 相似度计算优化
传统余弦相似度在稀疏数据下效果不佳,改用改进的加权相似度:
code复制sim(i,j) =
N(i)∩N(j) / sqrt(N(i)*N(j))
* log(1 + |N(i)∩N(j)|)
* 1/(1 + |avg_rating(i) - avg_rating(j)|)
其中:
- N(i)是对物品i有过行为的用户集合
- 第二项惩罚热门物品
- 第三项考虑评分差异
3.3 实时推荐策略
虽然主要采用离线计算,但小程序端需要实时响应。解决方案:
- 预计算TOP100相似电影存入Redis
- 用户最近观看的3部电影作为实时输入
- 加权融合相似电影列表:
- 每部电影贡献度 = 观看时长 * 相似度
- 去除用户已观看过的
- 按融合得分取TOP10
4. 工程化落地经验
4.1 微信小程序特殊处理
-
冷启动方案:
- 新用户展示"大家都在看"(全局热门)
- 看过3部电影后启用混合推荐
- 超过10部后完全个性化推荐
-
性能优化:
- 相似度矩阵压缩存储(CSR格式)
- 分片加载推荐结果(先加载5条)
- 利用storage API缓存昨日推荐
-
交互设计技巧:
- 添加"不感兴趣"按钮收集负反馈
- 长按电影封面可查看推荐理由
- 滑动到推荐列表底部自动加载
4.2 效果监控体系
搭建了完整的AB测试框架:
javascript复制// 在小程序端埋点
wx.reportAnalytics('rec_show', {
scene: rec_scene,
position: item_index,
algorithm: algo_version
});
wx.reportAnalytics('rec_click', {
movie_id: item_id,
dwell_time: dwellTime
});
关键指标监控看板包含:
- 推荐点击率(分算法版本)
- 推荐转化率(观看超30分钟)
- 负反馈率
- 列表曝光深度
5. 典型问题解决方案
5.1 常见bad case分析
问题1:推荐重复类型电影
- 原因:相似度计算未考虑类型多样性
- 解法:在排序公式加入类型惩罚项:
code复制score = base_score * (1 - 0.2*同类型计数)
问题2:老用户推荐新颖度低
- 原因:过度依赖历史行为
- 解法:混合10%的探索流量(新上映/小众电影)
问题3:节假日推荐不合时宜
- 原因:未考虑时间上下文
- 解法:建立节日特征库,在圣诞等节日加权相关电影
5.2 性能调优记录
场景:相似度计算超时
- 原始方案:全量计算耗时4.2小时
- 优化1:改用Spark分布式计算 → 1.5小时
- 优化2:只计算周增量数据 → 20分钟
- 优化3:相似度剪枝(只保留TOP50相似) → 8分钟
内存优化技巧:
- 将相似度矩阵从JSON改为二进制存储
- 使用protobuf压缩传输数据
- 相似度值用int8存储(0-100映射到-128~127)
6. 扩展优化方向
当前系统在三个方向还有提升空间:
-
多模态特征融合:
- 结合电影海报的CNN特征
- 抽取影评文本的LDA主题
- 融合社交网络好友偏好
-
实时反馈利用:
- 用户实时滑动行为(快速跳过/反复观看)
- 页面停留时长动态调整权重
- 建立短期兴趣模型
-
跨平台迁移学习:
- 同步用户在其他视频平台的行为
- 通过联邦学习更新模型
- 使用知识蒸馏压缩模型
这套系统上线半年后,日均推荐点击量达到23万次,证明了协同过滤在微信生态的可行性。最大的收获是:推荐系统不是算法越复杂越好,关键要匹配业务场景的数据特点和用户预期。