在之前我也看了很多人写的推荐系统的博客,理论的、算法的都有,多是个人的理解和感悟,虽然很深刻,但是对于自己而言还是不成系统,于是我参考大牛项亮编著的《推荐系统实践》将该领域知识系统整理一遍,与大家一起学习。
本系列对应的代码请查看https://github.com/wangyuyunmu/Recommended-system-practice
前面三篇总结了基于用户行为数据的推荐方法——协同过滤、隐语义、图模型,本篇总结推荐系统的冷启动问题。
目录
用户行为数据是推荐系统的重要组成部分和先决条件,如何在没有大量用户数据的情况下设计个性化推荐系统并且让用户对推荐系统满意,就是冷启动问题,主要分为三类:
1)用户冷启动问题。 给新用户做个性化推荐。
2)物品冷启动。 将新物品推荐给对它感兴趣的用户。
3)系统冷启动。 解决如何在新开发的网站上设计个性化推荐系统。
1, 利用用户注册信息(用户冷启动问题)
1)人口统计学信息。年龄、性别、职业、民族、学历和居住地等。
2)用户兴趣的描述
3)外部社交网络数据
推荐步骤:
1)获取用户的注册信息。
2)根据用户注册信息对用户分类。
3)根据用户类别推荐他们喜欢的物品。用户信息可能有多个,每个都有对应的推荐表,加权合并然后推荐。
核心: 计算用户每种信息特征对应的用户喜欢的物品。
用户有多个特征f,对于每一种物品i,计算喜好程度p(f,i)表示物品i在特征f中的热度: p ( f , i ) = ∣ N ( i ) ∩ U ( f ) ∣ p(f,i)=|N(i)\cap U(f)| p(f,i)=∣N(i)∩U(f)∣N(i)表示物品i的用户集合,U(f)|表示特征f的用户集合。
当然,这种表示热度的方法很难推荐给用户个性化的物品,因为热门的物品权重都比较高,所以用f的比例作为热度推荐指标:
p
(
f
,
i
)
=
∣
N
(
i
)
∩
U
(
f
)
∣
∣
N
(
i
)
+
α
∣
p(f,i)=\frac{|N(i)\cap U(f)|}{|N(i)+\alpha|}
p(f,i)=∣N(i)+α∣∣N(i)∩U(f)∣参数alpha是解决稀疏问题的,即如果物品i只有一个人喜欢,那么只有这个人的p=1,其他为0 ,没有意义,所以设置alpha。
用户特征(注册信息)越多,推荐的粒度越小,准确性越高,覆盖率越高。即多个特征f组合,要比单个f更加有效。
1.1 完全根据热度 (mostpopular)
建立一个item-user的倒排索引,推荐时根据热度排序即可。
items = {}
for user in train:
for item in train[user]:
if item not in items:
items[item] = 0
items[item] += 1
items = list(sorted(items.items(), key=lambda x: x[1], reverse=True))
1.2 基于年龄/性别/城市(以age为例)
对每个年龄段进行一个age-item的倒排索引,排序,推荐时再test user的age在相应年龄段进行推荐,缺失值按照流行度排序。
# 对年龄进行分段
ages = []
for user in profile:
if profile[user]['age'] >= 0:
ages.append(profile[user]['age'])
maxAge, minAge = max(ages), min(ages)
items = [{} for _ in range(int(maxAge // 10 + 1))]
# 分年龄段进行统计
for user in train:
if profile[user]['age'] >= 0:
age = profile[user]['age'] // 10
for item in train[user]:
if item not in items[age]:
items[age][item] = 0
items[age][item] += 1
for i in range(len(items)):
items[i] = list(sorted(items[i].items(), key=lambda x: x[1], reverse=True))
1.3 基于多特征组合年龄-性别-城市推荐
实现与单一特征差不多,只不过这里是多重字典,然后测试的时候讲test-user的特征对应到字典即可,缺失的按照热度推荐。
# 建立多重字典,将缺失值当成other,同归为一类进行处理
items = {}
for user in train:
gender = profile[user]['gender']
if gender not in items:
items[gender] = {}
age = profile[user]['age'] // 10
if age not in items[gender]:
items[gender][age] = {}
country = profile[user]['country']
if country not in items[gender][age]:
items[gender][age][country] = {}
for item in train[user]:
if item not in items[gender][age][country]:
items[gender][age][country][item] = 0
items[gender][age][country][item] += 1
for gender in items:
for age in items[gender]:
for country in items[gender][age]:
items[gender][age][country] = list(sorted(items[gender][age][country].items(),
key=lambda x: x[1], reverse=True))
基于用户注册信息的冷启动问题,仍然是一种,统计方法,与CF类似,比如item-item的相似度排序推荐,这里是特征f-items的热度排序推荐,建立特征f与items及item热度的倒排索引。
#这里对前5000个user进行算法性能测试
Average Result (M=10, N=10): {'Precision': 2.25, 'Recall': 4.506, 'Coverage': 3.6090000000000004}
添加热度加权后覆盖率会有上升,其他变化不大。
2, 利用物品信息的内容(物品冷启动)
物品冷启动需要解决的问题是如何将新加入的物品推荐给对它喜欢的用户。
1)对于userCF算法需要解决第一推动力的我问题,即第一个用户从哪发现新的物品。只要第一个用户发现了新物品形成反馈,该物品就能迅速扩散开。
2)对于itemCF算法,物品冷启动是一个严重的问题,itemCF维护了item相似度表,新物品没有用户行为,单纯通过用户行为日志计算不出新物品的相关矩阵,itemCF无法推荐。
为此,我们只能利用物品的内容信息计算物品的相关度表。
2.1 向量空间模型
一般而言物品内容可以通过向量空间模型表示,用一系列的关键词表示物品,如果物品的内容是一些诸如导演、演员等实体的话,可以直接将其作为关键词,但是如果内容是文本形式,则需要引入一些理解自然语言的技术抽取关键词。
物品d的内容表示成一个关键词向量: d = { ( e 1 , w 1 ) , ( e 2 , w 2 ) , . . . } d = \{(e_1,w_1),(e_2,w_2),...\} d={(e1,w1),(e2,w2),...}e是关键词,w是权值。
如果是实体(演员、导演等),w可以通过重要度获得。如果是文本,关键词e需要提取,w常用的计算方法是TF-IDF算法。
整体思路:user——item——world,建立world-item倒排,招待item之间的相关性。
Movieslen数据库,这里每个关键词权值取热度加权。
# 建立word-item倒排表
word_item = {}
for item in content:
for word in content[item]:
if word not in word_item:
word_item[word] = {}
word_item[word][item] = 1#物品item与关键词world的倒排索引world-item
相似度计算
获得物品内容表达后,物品内容的相似度可以通过向量之间的余弦相似度计算。相应的方法与userCF、itemCF的操作类似。
# 计算相似度
item_sim = {}
mo = {}
for word in word_item:
for u in word_item[word]:
if u not in item_sim:
item_sim[u] = {}
mo[u] = 0
mo[u] += word_item[word][u] ** 2
for v in word_item[word]:
if u == v: continue
if v not in item_sim[u]:
item_sim[u][v] = 0
item_sim[u][v] += word_item[word][u] * word_item[word][v] #每个物品与其他物品的相关性
for u in item_sim:
for v in item_sim[u]:
item_sim[u][v] /= math.sqrt(mo[u] * mo[v])
Metric: {‘Precision’: 1.94, ‘Recall’: 0.93, ‘Coverage’: 16.78, ‘Popularity’: 4.643929}
得到相似度后,就可以利用itemCF的思想,给他推荐和他历史上喜欢的物品内容相似的物品。
问题:
内容相似度计算简单、能频繁更新,还能处理冷启动,为什么还需要协同过滤的算法?
一般情况下协同过滤要比内容过滤算法精度高,如果用户行为强烈受某一内容属性的影响,基于内容过滤的算法还是可以在精度上超过协同过滤的。如果能将两种算法结合才是最好的选择。
2.2 主题模型
向量空间模型在内容数据丰富时可以获得比较好的效果。如果文本很短,关键词少,向量空间模型很难计算出准确的精确度。比如两篇文章关键词不同,但是话题是相同的,这种请款下首先需要知道文章的话题分布,然后才能确定文章的相似度。如何建立文章、话题和关键词的关系是主题模型(topic model)的研究重点。
代表性的主题模型是LDA,在使用LDA计算物品的内容相似度时,我们可以先计算出物品在话题上的分布,然后利用两个物品的话题分布计算物品的KL散度。
LDA模型在另一篇博文中详细总结。
3, 选择合适的物品启动用户兴趣
让用户对物品进行评分来收集用户兴趣,首先要解决的是如何选择物品让用户进行反馈。启动用户兴趣的物品一般具有以下特点:
1)比较热门。用户所熟知
2)具有代表性和区别性。不能太大众化,否则大家都喜欢,无法体现个性
3)启动物品集合需要多样性。提高覆盖率。
通过决策树方法解决,如下:
D
(
i
)
=
σ
u
∈
N
(
i
)
+
+
σ
u
∈
N
(
i
)
−
+
σ
u
∈
N
‾
(
i
)
D(i) = \sigma_{u\in N_{(i)}^+}+\sigma_{u\in N _{(i)}^-}+ \sigma_{u\in \overline{N}_{(i)}}
D(i)=σu∈N(i)++σu∈N(i)−+σu∈N(i)针对一个群体,在一个物品的喜好程度上分为3类,喜欢的群体、不喜欢的群体、不知道的群体,分别计算这三个群体对物品评分的方差,第三类计算的是对其他物品的评分的方差,如果D比较小说明这个物品在这个群体中的区分比较大,然后再次在三个群体中依次计算下一个物品的区分度。如下图所示:
4,发挥专家的作用
如果推荐系统建立是,没有用户行为数据、也没有充足的物品内容信息计算物品相似度。就需要专家进行标注。