RS in Action-two-利用用户行为数据
感觉第二章应该是整本书的核心内容,讲解的是如何利用用户行为数据,通过“听其言,观其行”。着重讲解了两个算法:
- 基于用户的协同过滤算法
UserIF
- 基于物品的协同过滤算法
ItemIF
以前看过一些博客,很杂乱;这次看了项亮老师的书,至少知道了这两个算法的理论上区别,还是很受益的
用户行为数据
挖掘用户数据
我们可以通过用户留下的文字和行为了解用户兴趣和需求。
用户的行为不是随机的,而是蕴含着很多的模式,需要通过算法自动发掘用户行为数据,从用户的行为中推测出用户的兴趣,从而给用户推荐他们感兴趣的物品。
啤酒和尿布
超市人员发现很多人会同时购买啤酒?和尿布;他们认为,妇女要在家照顾孩子,便让丈夫去买尿布,同时丈夫也不忘给自己买点啤酒。 于是超市人员便将啤酒和尿布摆在一起了。结果,这两个毫无关系东西的销量都提升了。
啤酒和尿布的故事在互联网上被放大:比如分析用户的购物车,找出诸如“购买A商品的用户同时都购买了B商品”。
用户行为数据
数据在网站上存在形式就是日志log。会话日志通常是存储在分布式数据仓库中,如离线的Hadoop Hive和支持在线分析的Google Dremel。两种用户行为:
- 显性反馈行为 explicit feedback :能够反映用户对物品明确的喜好行为
- 隐形反馈行为 implicit feedback:不能明确反映用户喜好的行为,比如最具代表性的页面浏览行为
按照反馈的明确性来分,用户的行为数据分为显性反馈和隐性反馈,按照反馈的方向又分为正反馈和负反馈。
正反馈:用户喜欢某个物品;负反馈:倾向于用户不喜欢该物品
显性反馈能够很明显地区分正反反馈,而隐性反馈中则很难区分
具体的例子:
用户行为的6个指标
- 产生行为的用户
- 行为的对象
- 行为的种类
- 产生行为的上下文
- 行为的内容
- 权重
代表性数据集
不同的数据集代表不同的用户行为
类型 | 记录数据 | 代表性数据 |
---|---|---|
无上下文 隐性 | 用户ID、物品ID | |
无上下文 显性 | 用户ID、物品ID、用户对物品的评分 | |
有上下文 隐性 | 用户ID、物品ID、用户对物品产生行为的时间戳 | Lastfm |
有上下文 显性 | 用户ID、物品ID、用户对物品的评分、行为的时间戳 | Netflix Prize |
用户行为分析
齐夫定律(Zipf定律)
齐夫是哈佛大学的一名语言学家,他在研究英文单词的过程中发现:
如果将单词出现的频率按照由高到低的顺序排列,则每个单词出现的频率和它在人们排行榜中排名的常数次幂是成反比的 英文中大部分词的词频很低,只有很少的词语会被经常使用
长尾分布
资料传送门
互联网上的很多数据分布都满足一种叫Power Law
的分布,也称之为长尾分布:
长尾分布指的是尾巴很长的分布,齐夫定律就是符合长尾分布。
用户行为数据也是满足上面的齐夫定律:
$$begin{array}{l} f_{i}(k)=alpha_{i} k^{beta_{i}} f_{u}(k)=alpha_{u} k^{beta_{u}} end{array}$$
其中,f_u(k)表示对k个物品产生行为的用户数Users;f_i(k)表示被k个用户产生过行为的物品数Items
物品流行度:对该物品产生过行为的用户总数 用户活跃度:用户产生过行为的物品总数
物品的流行度分布曲线:
用户的活跃度分布曲线:
协同过滤算法
用户活跃度和物品流行度的关系:
新用户对网站不熟悉,倾向于浏览热门的物品;老用户则逐渐开始浏览冷门的物品
基于用户行为分析的推荐算法是个性化推荐系统的重要算法,学术界称之为:协同过滤算法。
协同过滤:用户齐心协力,通过不断地和网站互动,使自己推荐列表能够不断地过滤掉自己不敢感兴趣的物品,从而越来越满足自己的需求
协同过滤算法的多种研究:
- 基于邻域的方法NB,
neighborhood-based
(应用最为广泛) - 隐语义模型LFM,
latent factor model
- 基于图的随机游走算法,
random walk on graph
基于邻域的方法中包含两种最为著名且应用广泛的算法:
- 基于用户的协同过滤算法UserIF:给用户推荐和他兴趣相似的用户喜欢的物品
- 基于物品的协同过滤算法ItemIF:给用户推荐和他之前喜欢的物品相似的物品
算法测评
3种方法
评测推荐系统的3种方法
- 离线实验
- 用户调查
- 在线实验
数据集
案例中采用的是MovieLens
数据集,是一个评分数据集,用户可以给电影评5个不同等级的分数(1-5)。
书中重点介绍的是隐反馈数据集中的TopN推荐问题:
TopN推荐问题:预测用户会不会给电影评分,而不是预测用户在准备对某部电影评分的前提下会给电影多少分。
实验设计
离线实验的设计步骤:
- 将用户行为数据集按照均匀随机分布分成M份,挑选一份作为测试集,剩下的M-1份作为训练集
- 在训练集上建立用户的兴趣模型
- 测试集合上对用户模型进行预测,统计出相应的评测指标
为了防止结果过拟合,需要进行M次试验,并且每次使用不同的测试集,M次试验的平均值作为最终的评测指标,利用Python将数据集划分成训练集和测试集:
代码语言:javascript复制def SplitData(data, M, k, seed):
test = []
train = []
random.seed(seed) # 相同的随机种子
for user, item in data:
if random.randint(0,M) == k: # 每次实验选取不同的k
test.append([user,item])
else:
train.append([user,item])
return train, test
评测指标
对用户u推荐N个物品,记为R(u),令用户u在测试集上喜欢的物品集合为T(u),通过召回率
和准确率
来评测算法的精度:
- 召回率的计算:
召回率描述的是有多少比例的用户-物品评分记录包含在最终的推荐列表中
- 准确率的计算:
代码语言:javascript复制准确率描述的是推荐列表中有多少比例是发生过用户-物品评分记录
# 召回率和准确率的计算
# 召回率
def Recall(train, test, N):
hit = 0
all = 0
for user in train.keys():
tu = test[user]
rank = GetRecommendation(user, N)
for item, pui in rank:
if item in tu:
hit = 1
all = len(tu)
return hit / (all * 1.0)
# 准确率
def Precision(train, test, N):
hit = 0
all = 0
for user in train.keys():
tu = test[user]
rank = GetRecommendation(user, N)
for item, pui in rank:
if item in tu:
hit = 1
all = N
return hit / (all * 1.0)
覆盖率
覆盖率反映的是推荐算法发掘长尾物品的能力,覆盖率越高,则说明推荐算法越能够将长尾中的物品推荐给用户,覆盖率的计算
代码语言:javascript复制覆盖率表示的是最终的推荐列表中包含多大比例的物品。 如果所有的物品都至少推荐给一个用户,则覆盖率是100%
def Coverage(train, test, N):
recommend_items = set()
all_items = set()
for user in train.keys():
for item in train[user].keys():
all_items.add(item)
rank = GetRecommendation(user, N)
for item, pui in rank:
recommend_items.add(item)
return len(recommend_items) / (len(all_items) * 1.0)
新颖度
用推荐列表总物品的平均流行度度量推荐结果的新颖度。如果物品都很热门,则说明推荐的新颖度较低,否则推荐效果很好
代码语言:javascript复制def Popularity(train, test, N):
item_popularity = dict()
for user, items in train.items():
for item in items.keys():
if item not in item_popularity:
item_popularity[item] = 0
item_popularity[item] = 1
ret = 0
n=0
for user in train.keys():
rank = GetRecommendation(user, N)
for item, pui in rank:
ret = math.log(1 item_popularity[item])
n = 1
ret /= n * 1.0
return ret
参考资料
- 项亮-《推荐系统实践》
- 参考资料