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

MovieLens个性化推荐系统实战(一):数据洞察与特征工程(数据清洗、特征构建)

1. MovieLens数据集初探

第一次接触MovieLens数据集时,我被它的完整性惊艳到了。这个由GroupLens实验室维护的经典数据集,包含了真实用户对电影的真实评分记录,就像一座未经开采的金矿。我使用的ml-1m版本包含6000名用户对4000部电影的100万条评分,足够丰富又不会让初学者望而生畏。

数据集主要包含三个文件:

  • users.dat:用户 demographic 信息(性别、年龄、职业、邮编)
  • movies.dat:电影元数据(片名、类型)
  • ratings.dat:用户-电影评分矩阵(用户ID、电影ID、评分、时间戳)

用pandas加载这些数据时有个小坑需要注意:原始文件使用"::"作为分隔符,这在CSV中并不常见。我第一次读取时直接用了默认逗号分隔,结果所有数据都挤在第一列。正确的打开方式是这样的:

import pandas as pd # 用户数据 user_cols = ['user_id', 'gender', 'age', 'occupation', 'zip'] users = pd.read_csv('users.dat', sep='::', names=user_cols, engine='python') # 电影数据 movie_cols = ['movie_id', 'title', 'genres'] movies = pd.read_csv('movies.dat', sep='::', names=movie_cols, engine='python', encoding='ISO-8859-1') # 评分数据 rating_cols = ['user_id', 'movie_id', 'rating', 'timestamp'] ratings = pd.read_csv('ratings.dat', sep='::', names=rating_cols, engine='python')

数据集中的年龄和职业字段都是编码后的数值,刚开始看可能有点懵。年龄分段从1开始编码,比如1代表"Under 18",18代表"18-24";职业编码更丰富,0代表"other",12是"programmer",15是"scientist"等。理解这些编码对后续构建用户画像至关重要。

2. 数据质量诊断与清洗

2.1 缺失值处理

拿到数据后我做的第一件事就是检查完整性。意外的是,这个数据集出奇的干净,用isnull().sum()检查三张表都没有缺失值。这在真实业务场景中几乎是不可能的——通常用户数据会有大量缺失,特别是demographic信息。MovieLens可能已经做过预处理,但我们在实际项目中一定要做好缺失值应对方案。

2.2 异常值检测

评分数据的异常值检查特别重要。理论上评分应该是1-5的整数,但实际业务中可能有极端值。我用describe()快速查看了评分分布:

ratings['rating'].describe()

输出显示最小值1,最大值5,完全符合预期。为了更直观,我还画了箱线图确认没有离群点:

import seaborn as sns sns.boxplot(x=ratings['rating'])

2.3 重复记录处理

重复记录会严重影响推荐效果。检查重复时我发现一个细节:单纯用duplicated()检查评分表会漏掉用户对同一电影多次评分的情况(可能发生在不同时间)。正确的做法是检查user_id和movie_id的组合是否唯一:

print(f"重复评分记录: {ratings.duplicated(subset=['user_id','movie_id']).sum()}")

结果显示为零,说明数据集在这方面也很干净。不过在实际业务中,这种情况很常见,通常需要保留最新评分或计算平均分。

3. 特征工程实战

3.1 电影特征构建

原始数据中的电影类型是个宝藏字段,但存储格式是"Action|Adventure|Sci-Fi"这样的管道分隔字符串。我把它展开成多列二元特征:

# 类型独热编码 genres = movies['genres'].str.get_dummies(sep='|') movies = pd.concat([movies, genres], axis=1)

这样每部电影就有了18维的类型特征向量。比如《星球大战》对应的Sci-Fi列就是1,而Romance列是0。

另一个重要特征是电影热度。我通过计算每部电影的评分次数来体现:

movie_stats = ratings.groupby('movie_id')['rating'].agg(['count','mean']) movies = movies.merge(movie_stats, left_on='movie_id', right_index=True)

这里有个实用技巧:为了避免热门电影主导推荐,我对评分次数做了对数变换:

import numpy as np movies['log_count'] = np.log1p(movies['count'])

3.2 用户特征工程

用户行为特征对推荐系统至关重要。我构建了几个关键特征:

活跃度特征

user_activity = ratings.groupby('user_id').agg({ 'rating': ['count','mean'], 'movie_id': 'nunique' }) user_activity.columns = ['rating_count', 'avg_rating', 'unique_movies'] users = users.merge(user_activity, left_on='user_id', right_index=True)

类型偏好特征: 通过合并评分和电影类型数据,可以计算用户对各类电影的偏好程度:

# 合并用户评分和电影类型 merged = ratings.merge(movies, on='movie_id') # 计算用户对各类电影的评分均值 genre_cols = movies.columns[-18:-2] # 18个类型列 user_genre_pref = merged.groupby('user_id')[genre_cols].mean() users = users.merge(user_genre_pref, left_on='user_id', right_index=True)

人口统计特征: 原始的用户年龄和职业字段需要适当编码。年龄可以直接使用原始数值,也可以分段one-hot编码;职业字段我采用了embedding技术,这在后续模型中可以学习到更丰富的语义关系。

4. 时间特征与冷启动处理

4.1 时间特征提取

时间戳字段包含宝贵信息。我将其转换为多个时间维度:

ratings['date'] = pd.to_datetime(ratings['timestamp'], unit='s') ratings['day_of_week'] = ratings['date'].dt.dayofweek ratings['month'] = ratings['date'].dt.month ratings['hour'] = ratings['date'].dt.hour

这些时间特征可以揭示用户行为模式,比如周末看电影更多,晚上评分更高等。

4.2 冷启动问题缓解

新用户和新电影缺乏历史数据是个老大难问题。我准备了几个解决方案:

对于新用户:

  • 利用注册时收集的基本信息(性别、年龄等)
  • 实施基于内容的推荐,直到积累足够行为数据
  • 设计引导流程快速收集偏好

对于新电影:

  • 使用元数据(类型、导演、演员等)计算内容相似度
  • 采用"热门推荐"策略,直到积累足够评分
  • 结合文本描述和海报图像进行多模态推荐

5. 特征选择与重要性分析

不是所有特征都同等重要。我使用随机森林做了特征重要性分析:

from sklearn.ensemble import RandomForestRegressor # 准备特征矩阵X和目标y X = users.drop(['user_id','zip'], axis=1) X = pd.get_dummies(X, columns=['gender','occupation']) y = users['avg_rating'] # 训练随机森林 model = RandomForestRegressor() model.fit(X, y) # 获取特征重要性 importance = pd.DataFrame({ 'feature': X.columns, 'importance': model.feature_importances_ }).sort_values('importance', ascending=False)

结果显示用户活跃度(rating_count)和某些类型偏好(如Drama、Comedy)对预测用户平均评分最重要。这验证了我们的特征工程方向是正确的。

6. 特征存储与监控

最后,处理好的特征需要妥善存储。我推荐使用Feast这样的特征存储系统,它支持:

  • 特征版本控制
  • 线上线下一致性保证
  • 特征新鲜度监控

对于小规模项目,也可以用Parquet文件存储:

users.to_parquet('processed_users.parquet') movies.to_parquet('processed_movies.parquet') ratings.to_parquet('processed_ratings.parquet')

在实际项目中,我养成了定期检查特征质量的习惯,包括:

  • 特征分布变化监控
  • 特征与目标相关性变化
  • 缺失率监控

这些实践帮助我在多个推荐系统项目中避免了特征漂移带来的性能下降。

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

相关文章:

  • 如何在5分钟内为你的网站添加一个会聊天的Live2D动画伙伴?
  • 【Docker】从零构建Conda环境镜像:解决激活难题与生产级最佳实践
  • MATLAB优化建模:当两个连续变量相乘时,除了大M法还能怎么线性化?
  • 2026成都GEO优化公司深度测评:本土标杆橙鱼传媒全域AI流量布局解析 - TOP10品牌推荐榜单
  • 大模型真的“理解”现实世界吗?研究表明它们确实理解
  • 第4集:故障自愈 Agent 实战!重启服务、清理磁盘、自动回滚的面试艺术
  • 给你的STM32项目加个‘U盘’:基于W25Q128和HAL库的文件系统(FatFs)移植实战
  • 玻璃---暖边还是氩气?(下)
  • 2026年江苏一人公司法律顾问选择指南:专业律师的甄别之道与何沈君律师深度解析 - 2026年企业推荐榜
  • 【Unity游戏模板】Sort Match Color Puzzle 一款能赚钱的三消替代游戏项目架构深度分析
  • 04月23日AI每日参考:Google推出AI芯片挑战Nvidia,Workspace升级AI助手
  • 销售拓客全流程赋能:企业级销售智能体落地完整解决方案 —— 2026技术路径与选型实测指南
  • 华为入局智能眼镜赛道,“百镜大战”谁能熬过漫长暗战期?
  • 现代C内存安全编码规范2026落地指南(工业级嵌入式/云原生双场景验证版)
  • 告别手忙脚乱:GSE宏编译器如何让你的魔兽世界操作效率翻倍
  • OpenClaw实操指南25|必装6个基础技能:find-skills/skill-creator/mcp-builder,逐一实战
  • Falcon-H1混合架构与BitNet量化技术解析
  • 零代码部署GME多模态向量:小白也能玩转图文跨模态搜索
  • 混合云架构适配:企业级智能体灵活部署完整方案与最佳实践 | 2026企业自动化选型硬核指南
  • 半导体工程师必看:手把手教你用TCAD仿真优化场限环(FLR)间距,提升器件击穿电压
  • 履带消防机器人电池设计方案(高温/防火/高倍率/高安全系统)【浩博电池】
  • 客户老是忘跟?我用2小时做了个自动提醒系统,销售直接少丢30%单
  • 智读致用|《一人企业》2:放弃扩张执念,保持小规模,才是创业者的顶级清醒
  • TerraMaster D1 SSD Plus硬盘盒评测:Thunderbolt 4/USB4性能解析
  • 零成本解锁VMware Workstation Pro 17:从虚拟化新手到专家的完整指南
  • 从IOMMU到中断注入:图解VFIO直通背后的硬件与KVM/QEMU协作机制
  • 第二章 目录与文件管理(CentOS 7.9 入门+企业生产版)【20260423】002篇
  • MySQL 事务锁等待案例分享
  • 机器人抓取新突破:无线双模态视觉-触觉吸盘技术解析
  • 打卡信奥刷题(3156)用C++实现信奥题 P7741 [AHOI2007] 石块地板