推荐系统小结
什么是推荐系统?
说到推荐系统,我们肯定是要问它是为什么而存在的,即存在的意义是什么。
随着当今技术的飞速发展,数据量也与日俱增,人们越来越感觉在海量数据面前束手无策。正是为了解决信息过载(Information overload)的问题,人们提出了推荐系统(与搜索引擎对应,人们习惯叫推荐系统为推荐引擎)。当我们提到推荐引擎的时候,经常联想到的技术也便是搜索引擎。不必惊讶,因为这两者都是为了解决信息过载而提出的两种不同的技术,一个问题,两个出发点,我更喜欢称它们两者为兄弟,亲近而形象。
兄弟二人有共同的目标,即解决信息过载问题,但具体的做法因人而异。
搜索引擎更倾向于人们有明确的目的,可以将人们对于信息的寻求转换为精确的关键字,然后交给搜索引擎最后返回给用户一系列列表,用户可以对这些返回结果进行反馈,并且是对于用户有主动意识的,但它会有马太效应的问题,即会造成越流行的东西随着搜索过程的迭代会越流行,使得那些越不流行的东西石沉大海。
而推荐引擎更倾向于人们没有明确的目的,或者说他们的目的是模糊的,通俗来讲,用户连自己都不知道他想要什么,这时候正是推荐引擎的用户之地,推荐系统通过用户的历史行为或者用户的兴趣偏好或者用户的人口统计学特征来送给推荐算法,然后推荐系统运用推荐算法来产生用户可能感兴趣的项目列表,同时用户对于搜索引擎是被动的。其中长尾理论(人们只关注曝光率高的项目,而忽略曝光率低的项目)可以很好的解释推荐系统的存在,试验表明位于长尾位置的曝光率低的项目产生的利润不低于只销售曝光率高的项目的利润。推荐系统正好可以给所有项目提供曝光的机会,以此来挖掘长尾项目的潜在利润。
如果说搜索引擎体现着马太效应的话,那么长尾理论则阐述了推荐系统所发挥的价值。
-
马太效应(Matthew Effect),是指好的愈好,坏的愈坏,多的愈多,少的愈少的一种现象。即两极分化现象。
-
长尾理论(The Long Tail)只要产品的存储和流通的渠道足够大,需求不旺或销量不佳的产品所共同占据的市场份额可以和那些少数热销产品所占据的市场份额相匹敌甚至更大,即众多小市场汇聚成可产生与主流相匹敌的市场能量
所属领域
推荐系统是多个领域的交叉研究方向,所以会涉及机器学习以及数据挖掘方面的技巧(推荐系统==》数据挖掘/机器学习==》人工智能)。在这整理了小邬老师上课所介绍的关于主流研究方向的结构图。

会议介绍
在这里主要整理一下上图所涉及到的研究方向相关的会议。
RS(Recommender System):RecSys
IR (Information Retrieval): SIGIR
DM(Data Mining): SIGKDD,ICDM, SDM
ML (Machine Learning): ICML, NIPS
CV (Computer Vision): ICCV, CVPR, ECCV
MM (MultiMedia): ACM MM
DB (Database): CIKM, WIDM
AI (Artificial Intelligence): IJCAI, AAAI
推荐系统实验方法
- 离线方法:从实际系统日志中提取数据,划分训练集测试集训练模型。
优点:不需要有对实际系统控制权,不需要用户参与,速度快,可测试大量算法
缺点:无法计算商业上关心指标。离线实验指标和商业指标存在差距。 - 用户调查:即直接询问用户。优点:可用获取很多体现用户主观感受指标,缺点招募用户代价较大很难组织大规模测试用户,因此测试结果统计意义不大。
- 在线实验:推荐系统上线做AB测试,将它和旧的算法进行比较。(用户分组,不同组采用不同算法).
优点:公平获取不同算法实际在线时性能指标包括商业上关注指标。
缺点:周期长,必须进行长期的实验才能得到比较靠谱的结果。
推荐系统的评测
-
用户满意度:用户作为推荐系统的重要参与者,其满意度是评测推荐系统的最重要指标
-
预测准确度:预测准确度度量一个推荐系统或者推荐算法预测用户行为的能力(最重要离线评测指标)
-
评分预测(一般通过均方根误差( RMSE)和平均绝对误差( MAE)计算),rui实际评分
RMSE的定义为:

MAE采用绝对值计算预测误差,它的定义为:

-
TopN推荐(网站在提供推荐服务时,一般是给用户一个个性化的推荐列表TopN推荐的预测准确率一般通过准确率( precision) /召回率( recall)度量)
-
正确率 = 提取出的正确信息条数 / 提取出的信息条数
-
召回率 = 提取出的正确信息条数 / 样本中的信息条数
令R(u)是根据用户在训练集上的行为给用户作出的推荐列表,而T(u)是用户在测试集上的行为列表。那么,推荐结果的召回率定义为:

推荐结果的准确率定义为:

有的时候,为了全面评测TopN推荐的准确率和召回率,一般会选取不同的推荐列表长度N,计算出一组准确率/召回率,然后画出准确率/召回率曲线( precision/recall curve)。
-
-
覆盖率(信息熵,基尼系数( Gini Index)):描述一个推荐系统对物品长尾的发掘能力
-
多样性:多样性描述了推荐列表中物品两两之间的不相似性
-
新颖性:指给用户推荐那些他们以前没有听说过的物品
-
惊喜度:惊喜度指如果推荐结果和用户的历史兴趣不相似,但却让用户觉得满意,那么就可以说推荐结果的惊喜度很高,而推荐的新颖性仅仅取决于用户是否听说过这个推荐结果。
-
信任度
-
实时性:因为物品(新闻、微博等)具有很强的时效性,所以需要在物品还具有时效性时就将它们推荐给用户。
-
健壮性:一个推荐系统抗击作弊的能力
数据集
可采用的数据集:
适用于传统的推荐任务,提供了3种不同规模的数据,包含用户对电影的评分信息,用户的人口统计学特征以及电影的描述特征。
2、Douban
适用于社会化推荐任务,规模适中,包含用户对电影的评分信息,同时包含用户间的信任社交信息。
3、Epinions
适用于社会化推荐任务,规模较大,包含用户对电影的评分信息,同时包含用户间的信任社交信息,值得注意的是,该数据集同时还包括不信任关系信息。
4、KB4Rec
适用于推荐系统与知识图谱相结合的研究需求,该数据集将推荐数据中的物品链接到大型知识图谱中的实体,为推荐系统的物品提供蕴含丰富语义的结构化知识信息。
基本算法:
协同过滤算法
协同过滤算法是一种较为著名和常用的推荐算法,它基于对用户历史行为数据的挖掘发现用户的喜好偏向,并预测用户可能喜好的产品进行推荐。也就是常见的“猜你喜欢”,和“购买了该商品的人也喜欢”等功能。它的主要实现由:
●根据和你有共同喜好的人给你推荐
●根据你喜欢的物品给你推荐相似物品
●根据以上条件综合推荐
因此可以得出常用的协同过滤算法分为两种,基于用户的协同过滤算法(user-based collaboratIve filtering),以及基于物品的协同过滤算法(item-based collaborative filtering)。特点可以概括为“人以类聚,物以群分”,并据此进行预测和推荐。
1.基于用户的协同过滤算法(UserCF)
基于用户的协同过滤算法的实现主要需要解决两个问题,一是如何找到和你有相似爱好的人,也就是要计算数据的相似度:
计算相似度需要根据数据特点的不同选择不同的相似度计算方法,有几个常用的计算方法:
(1)杰卡德相似系数(Jaccard similarity coefficient)
其实就是集合的交集除并集

(2)夹角余弦(Cosine)
在二维空间中向量A(x1,y1)与向量B(x2,y2)的夹角余弦公式:

两个n维样本点a(x11,x12,…,x1n)和b(x21,x22,…,x2n)的夹角余弦:

即 
(3)其余方法,例如欧式距离、曼哈顿距离等相似性度量方法可以点此了解
userCF算法会给用户推荐和他兴趣最相似的k个用户喜欢的物品,如下公式计算用户u对物品i的感兴趣程度:

其中S(u,K)表示和用户u最为相似的k个用户,N(i)表示和物品i产生行为的用户列表。Wuv表示用户u和用户v的相似度。rvi表示用户v对物品i的兴趣,因为使用的是单一行为的隐反馈,故所有rvi=1.
找到与目标用户最相邻的K个用户
我们在寻找有有相同爱好的人的时候,可能会找到许多个,例如几百个人都喜欢A商品,但是这几百个人里,可能还有几十个人与你同时还喜欢B商品,他们的相似度就更高,我们通常设定一个数K,取计算相似度最高的K个人称为最相邻的K个用户,作为推荐的来源群体。
这里存在一个小问题,就是当用户数据量十分巨大的时候,在所有人之中找到K个基友花的时间可能会比较长,而且实际中大部分的用户是和你没有什么关系的,所以在这里需要用到倒排表
所谓倒排表,就是比如你喜欢的商品有A、B、C,那就分别以ABC为行名,列出喜欢这些商品的人都有哪些,其他的人就必定与你没有什么相似度了,从这些人里计算相似度,找到K个人
通过这K个人推荐商品
我们假设找到的人的喜好程度如下
| A | B | C | D | |
|---|---|---|---|---|
| 你 | √ | √ | √ | |
| 甲 | √ | √ | √ | |
| 乙 | √ | √ |
倒排表
| A | 你 | 甲 |
|---|---|---|
| B | 你 | 甲 |
| C | 你 | 乙 |
| D | 甲 | 乙 |
前面计算用户间兴趣相似度使用的是余弦相似度,该公式过于粗糙,需要改进该公式。
以图书为例,如果两个用户都曾经买过《新华字典》,这丝毫不能说明他们兴趣相似,因为绝大多数中国人小时候都买过《新华字典》。但如果两个用户都买过《数据挖掘导论》,那可以认为他们的兴趣比较相似,因为只有研究数据挖掘的人才会买这本书。换句话说,两个用户对冷门物品采取过同样的行为更能说明他们兴趣的相似度。因此,John S. Breese在论文中提出了如下公式,根据用户行为计算用户的兴趣相似度:

其中,N(i)表示用户u,v共同感兴趣的物品的个数。该公式通过
惩罚了用户u,v共同兴趣商品中热门商品对他们相似度的影响。
讲上述公式记为UserCF-IIF算法
2.基于物品的协同过滤(ItemCF)
ItemCF算法不是根据物品内容的属性计算物品之间的相似度,而是通过分析用户的行为记录来计算用户的相似度。该算法认为物品A和物品B相似的依据是因为喜欢物品A的用户也喜欢物品B。
基于物品的协同过滤算法实现步骤:
1、计算物品之间的相似度
2、根据物品的相似度和用户的历史行为记录给用户生成推荐列表
下面我们一起来看一下这两部是如何实现的:
一、计算物品之间的相似度
通过查询一下资料,ItemCF的物品相似度计算模型如下:

公式中|N(i)|表示喜欢物品i的用户数,|N(j)|表示喜欢物品j的用户数, |N(i)∩N(j)|表示同时喜欢物品i和物品j的用户数。从上面的公式我们可以看出物品i和物品j相似是因为他们共同别很多的用户喜欢,相似度越高表示同时喜欢他们的用户数越多。
下面举例讲解一下相似度的计算过程:
假设用户A对物品a,b,d有过评价,用户B对物品b,c,e有过评价,如下图:
A : a b d
B : b c e
C : c d
D : b c d
E : a d
根据上面用户的行为构建:用户——物品倒排表:例如:物品a有用户A和E做过评价。
a : A E
b : A B D
c : B C D
d : A C D E
e : B
根据上面的倒排表我们可以构建一个相似度矩阵:

图 1.1 计算物品的相似度
图中最左边的是用户输入的用户行为记录,每一行代表用户感兴趣的物品集合,然后对每个物品集合,我们将里面的物品两两加一,得到一个矩阵。最终将这些矩阵进行相加得到上面的C矩阵。其中Ci记录了同时喜欢物品i和j的用户数。这样我们就得到了物品之间的相似度矩阵W。
二、根据物品的相似度和用户的历史行为记录给用户生成推荐列表
ItemCF通过下面的公式计算用户u对一个物品j的兴趣:

这里的N(u)代表用户喜欢的物品的集合,S(j,k)是和物品j最相似的的k个物品的集合,wij是物品j和i的相似度,r_ui代表用户u对物品i的兴趣。该公式的含义是,和用户历史上最感兴趣的物品月相似的物品,越有可能在用户的推荐列表中获得比较高的排名。
下面是查阅资料找到的一些优化方法:
(1)、用户活跃度对物品相似度的影响
即认为活跃用户对物品相似度的贡献应该小于不活跃的用户,所以增加一个IUF(Inverse User Frequence)参数来修正物品相似度的计算公式:

用这种相似度计算的ItemCF被记为ItemCF-IUF。
ItemCF-IUF在准确率和召回率两个指标上和ItemCF相近,但它明显提高了推荐结果的覆盖率,降低了推荐结果的流行度,从这个意义上说,ItemCF-IUF确实改进了ItemCF的综合性能。
(2)、物品相似度的归一化
Karypis在研究中发现如果将ItemCF的相似度矩阵按最大值归一化,可以提高推荐的准确度。其研究表明,如果已经得到了物品相似度矩阵w,那么可用如下公式得到归一化之后的相似度矩阵w’:

最终结果表明,归一化的好处不仅仅在于增加推荐的准确度,它还可以提高推荐的覆盖率和多样性。用这种相似度计算的ItemCF被记为ItemCF-Norm。
部分代码实现:
#-*- coding: utf-8 -*-
'''
Created on 2015-06-22
@author: Lockvictor
'''
import sys
import random
import math
import os
from operator import itemgetter
random.seed(0)
class UserBasedCF(object):
''' TopN recommendation - User Based Collaborative Filtering '''
def __init__(self):
self.trainset = {}
self.testset = {}
self.n_sim_user = 20
self.n_rec_movie = 10
self.user_sim_mat = {}
self.movie_popular = {}
self.movie_count = 0
print ('Similar user number = %d' % self.n_sim_user, file=sys.stderr)
print ('recommended movie number = %d' %
self.n_rec_movie, file=sys.stderr)
@staticmethod
def loadfile(filename):
''' load a file, return a generator. '''
fp = open(filename, 'r')
for i, line in enumerate(fp):
yield line.strip('\r\n')
if i % 100000 == 0:
print ('loading %s(%s)' % (filename, i), file=sys.stderr)
fp.close()
print ('load %s succ' % filename, file=sys.stderr)
def generate_dataset(self, filename, pivot=0.7):
''' load rating data and split it to training set and test set '''
trainset_len = 0
testset_len = 0
for line in self.loadfile(filename):
user, movie, rating, _ = line.split('::')
# split the data by pivot
if random.random() < pivot:
self.trainset.setdefault(user, {})
self.trainset[user][movie] = int(rating)
trainset_len += 1
else:
self.testset.setdefault(user, {})
self.testset[user][movie] = int(rating)
testset_len += 1
print ('split training set and test set succ', file=sys.stderr)
print ('train set = %s' % trainset_len, file=sys.stderr)
print ('test set = %s' % testset_len, file=sys.stderr)
def calc_user_sim(self):
''' calculate user similarity matrix '''
# build inverse table for item-users
# key=movieID, value=list of userIDs who have seen this movie
print ('building movie-users inverse table...', file=sys.stderr)
movie2users = dict()
for user, movies in self.trainset.items():
for movie in movies:
# inverse table for item-users
if movie not in movie2users:
movie2users[movie] = set()
movie2users[movie].add(user)
# count item popularity at the same time
if movie not in self.movie_popular:
self.movie_popular[movie] = 0
self.movie_popular[movie] += 1
print ('build movie-users inverse table succ', file=sys.stderr)
# save the total movie number, which will be used in evaluation
self.movie_count = len(movie2users)
print ('total movie number = %d' % self.movie_count, file=sys.stderr)
# count co-rated items between users
usersim_mat = self.user_sim_mat
print ('building user co-rated movies matrix...', file=sys.stderr)
for movie, users in movie2users.items():
for u in users:
for v in users:
if u == v:
continue
usersim_mat.setdefault(u, {})
usersim_mat[u].setdefault(v, 0)
usersim_mat[u][v] += 1
print ('build user co-rated movies matrix succ', file=sys.stderr)
# calculate similarity matrix
print ('calculating user similarity matrix...', file=sys.stderr)
simfactor_count = 0
PRINT_STEP = 2000000
for u, related_users in usersim_mat.items():
for v, count in related_users.items():
usersim_mat[u][v] = count / math.sqrt(
len(self.trainset[u]) * len(self.trainset[v]))
simfactor_count += 1
if simfactor_count % PRINT_STEP == 0:
print ('calculating user similarity factor(%d)' %
simfactor_count, file=sys.stderr)
print ('calculate user similarity matrix(similarity factor) succ',
file=sys.stderr)
print ('Total similarity factor number = %d' %
simfactor_count, file=sys.stderr)
def recommend(self, user):
''' Find K similar users and recommend N movies. '''
K = self.n_sim_user
N = self.n_rec_movie
rank = dict()
watched_movies = self.trainset[user]
for similar_user, similarity_factor in sorted(self.user_sim_mat[user].items(),
key=itemgetter(1), reverse=True)[0:K]:
for movie in self.trainset[similar_user]:
if movie in watched_movies:
continue
# predict the user's "interest" for each movie
rank.setdefault(movie, 0)
rank[movie] += similarity_factor
# return the N best movies
return sorted(rank.items(), key=itemgetter(1), reverse=True)[0:N]
def evaluate(self):
''' print evaluation result: precision, recall, coverage and popularity '''
print ('Evaluation start...', file=sys.stderr)
N = self.n_rec_movie
# varables for precision and recall
hit = 0
rec_count = 0
test_count = 0
# varables for coverage
all_rec_movies = set()
# varables for popularity
popular_sum = 0
for i, user in enumerate(self.trainset):
if i % 500 == 0:
print ('recommended for %d users' % i, file=sys.stderr)
test_movies = self.testset.get(user, {})
rec_movies = self.recommend(user)
for movie, _ in rec_movies:
if movie in test_movies:
hit += 1
all_rec_movies.add(movie)
popular_sum += math.log(1 + self.movie_popular[movie])
rec_count += N
test_count += len(test_movies)
precision = hit / (1.0 * rec_count)
recall = hit / (1.0 * test_count)
coverage = len(all_rec_movies) / (1.0 * self.movie_count)
popularity = popular_sum / (1.0 * rec_count)
print ('precision=%.4f\trecall=%.4f\tcoverage=%.4f\tpopularity=%.4f' %
(precision, recall, coverage, popularity), file=sys.stderr)
if __name__ == '__main__':
ratingfile = os.path.join('ml-1m', 'ratings.dat')
usercf = UserBasedCF()
usercf.generate_dataset(ratingfile)
usercf.calc_user_sim()
usercf.evaluate()
3.总结
userCF:被Digg用来给用户推荐个性化网络文章
ItemCF: 亚马逊推荐商品
UserCF 给用户推荐那些和他有共同兴趣爱好的用户喜欢的物品,而 ItemCF 给用户推荐那些和他之前喜欢的物品类似的物品。
从这个算法的原理可以看到, UserCF 的推荐结果着重于反映和用户兴趣相似的小群体的热点,而 ItemCF的推荐结果着重于维系用户的历史兴趣。
UserCF 的推荐更社会化,反映了用户所在的小型兴趣群体中物品的热门程度,而 ItemCF 的推荐更加个性化,反映了用户自己的兴趣传承。
UserCF 可以给用户推荐和他有相似爱好的一群其他用户今天都在看的新闻,这样在抓住热点和时效性的同时,保证了一定程度的个性化。UserCF 适合用于新闻推荐的另一个原因是从技术角度考量的。因为作为一种物品,新闻的更新非常快,每时每刻都有新内容出现,而 ItemCF 需要维护一张物品相关度的表,如果物品更新很快,那么这张表也需要很快更新,这在技术上很难实现。UserCF只需要用户相似表即可。
而对于图书、电影、电子商务,在这些网站中,用户的兴趣是比较固定和持久的。此外,这些系统中的用户大都不太需要流行度来辅助他们判断一个物品的好坏,而是可以通过自己熟悉领域的知识自己判断物品的质量。因此,这些网站中个性化推荐的任务是帮助用户发现和他研究领域相关的物品。同时,从技术上考虑, UserCF 需要维护一个用户相似度的矩阵,而 ItemCF 需要维护一个物品相似度矩阵。
选择方法
首先应该满足产品的需求,比如如果需要提供推荐解释,那么可能得选择 ItemCF 算法。
其次,需要看实现代价,比如若用户太多,很难计算用户相似度矩阵,这个时候可能不得不抛弃 UserCF 算法。
最后,离线指标和点击率等在线指标不一定成正比。而且,这里对比的是最原始的 UserCF 和 ItemCF 算法,这两种算法都可以进行各种各样的改进。一般来说,这两种算法经过优化后,最终得到的离线性能是近似的。
1. ItemCF算法与UserCF算法的基本原理
| 算法名称 | 原理 | 优点 | 相似度计算 | 备注 |
|---|---|---|---|---|
| User CF | 给用户推荐和他有相同兴趣爱好的用户喜欢的物品。(维护一个用户相似度矩阵) | 着重反应和用户 | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FiCP4Qwd-1648010508568)(%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F%E6%80%BB%E7%BB%93.assets/2KTH%25YMC%60EPHKESINF0@D%7BF.png)] | 1.新闻推荐(同群人所关注的特点)2.物品数量远超用户数量 |
| Item CF | 给用户推荐和他之前喜欢的物品类似的物品。(维护一个物品相似度矩阵) | 着重维系用户的历史兴趣,反应了用户自己兴趣的传承,更加个性化。 | [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RZ89LVnm-1648010508569)(%E6%8E%A8%E8%8D%90%E7%B3%BB%E7%BB%9F%E6%80%BB%E7%BB%93.assets/1.png)] | 1. 图书、电影网站、电子商务(用户兴趣比较固定,对热门程度不敏感)2. 用户数量远超物品数量 |
2. User CF 和 Item CF 比较
| User CF | Item CF | |
|---|---|---|
| 性能 | 适用于用户较少的场合,如果用户很多,计算用户相似度矩阵代价很大 | 适用于物品数量明显小于用户数的场合,如果物品很多(网页),计算物品相似度矩阵代价很大 |
| 领域 | 时效性较强,用户个性化兴趣不太明显的领域,如新闻 | 长尾物品丰富,用户个性化需求强烈的领域(电商) |
| 实时性 | 用户有新行为,不一定造成推荐结果的立即变化 | 用户新行为,一定会导致推荐结果的实时变化 |
| 冷启动 | 1. 在新用户对少量物品产生行为后,不能立即地对他进行个性化推荐,因为用户相似度表是每隔一段时间离线计算的。2.物品上一段时间,一旦用户对物品产生行为就可以将新物品推荐给和他产生行为的用户兴趣相似的其他用户 | 1. 新用户只要对一个物品产生行为,就可以给他推荐和该物品相关的其他产品,但没有办法在不离线更新物品相似度表的情况下将新物品推荐给用户 |
| 推荐理由(可解释性) | 很难提供令用户信服的推荐解释(也有这样做的,你有多少好友浏览和购买过) | 利用用户的历史行为给用户做推荐,可以令用户比较信服 |
隐语义模型简述:
LFM(Latent Factor Model)隐语义模型是最近几年推荐系统领域最为热门的研究话题,它的核心思想是通过隐含特征(Latent Factor)联系用户兴趣和物品。那这种模型跟ItemCF或UserCF有什么不同呢?这里可以做一个对比:
-
对于UserCF,我们可以先计算和目标用户兴趣相似的用户,之后再根据计算出来的用户喜欢的物品给目标用户推荐物品。
-
而ItemCF,我们可以根据目标用户喜欢的物品,寻找和这些物品相似的物品,再推荐给用户。
-
还有一种方法,先对所有的物品进行分类,再根据用户的兴趣分类给用户推荐该分类中的物品,LFM就是用来实现这种方法。
就是根据用户的当前偏好信息,得到用户的兴趣偏好,将该类兴趣对应的物品推荐给当前用户。比 如,用户A喜欢的《数据挖掘导论》属于计算机类的书籍,那我们可以将其他的计算机类书籍推荐给用户A;用户B喜欢的是文学类数据,可将《巴黎圣母院》等这 类文字作品推荐给用户B。这就是隐语义模型,依据**“兴趣”**这一隐含特征将用户与物品进行连接,需要说明的是此处的“兴趣”其实是对物品类型的一个分类而 已。
该算法的理论基础是运用矩阵分解,把用户评分矩阵R分解为两个低维矩阵,然后用这两个低维矩阵去估计目标用户对项目的评分。
传统的协同过滤算法是利用用户的历史行为,来预测用户对目标用户的评分。需要在整个用户空间上去寻找最近邻居。随着电子商务的不断发展,用户数量和物品的数量都呈指数型增长,这样传统的算法就不能够满足推荐的实时需求。同时,传统的协同过滤算法只是考虑了用户的历史行为,而没有考虑物品之间的关系。针对这些问题,本文提出了一种融合隐语义模型的聚类协同过滤算法,区别于传统的基于项目聚类的协同过滤[5],本文算法没有直接在用户评分矩阵上进行聚类,而是先将评分矩阵进行分解,将得到的矩阵再进行聚类,这样聚类的维度降低,同时还考虑了物品类别信息,提高了推荐系统实时响应速度。
CF简单直接可解释性强,但隐语义模型能更好地挖掘用户和item关联中的隐藏因子。
2 隐语义模型的数学理解
我们从数学角度来理解隐语义模型。如下图所示,R矩阵是用户对物品的偏好信息(Rij表示的是user i对item j的兴趣度),P矩阵是用户对各物品类别的一个偏好信息(Pij表示的是user i对class j的兴趣度),Q矩阵是各物品所归属的的物品类别的信息(Qij表示的是item j在class i中的权重)。隐语义模型就是要将矩阵R分解为矩阵P和矩阵Q的乘积,即通过矩阵中的物品类别(class)将用户user和物品item联系起来。实际 上我们需要根据用户当前的物品偏好信息R进行计算,从而得到对应的矩阵P和矩阵Q。

3 隐语义模型所需解决的问题
这个基于兴趣分类的方法大概需要解决3个问题。
- 如何给物品进行分类?
- 如何确定用户对哪些类的物品感兴趣,以及感兴趣的程度?
- 对于一个给定的类,选择哪些属于这个类的物品推荐给用户,以及如何确定这些物品在一个类中的权重?
3.1 物品分类
对于第一个问题的简单解决方案是找编辑给物品分类。以图书为例,每本书出版时,编辑都会给书一个分类。为了给图书分类,出版界普遍遵循中国图书分类法。但是,即使有很系统的分类体系,编辑给出的分类仍然具有以下缺点:
- 编辑的意见不能代表各种用户的意见。比如,对于**《具体数学》应该属于什么分类,有人认为应该属于数学,有些人认为应该属于计算机。从内容看,这本书是关于数学的,但从用户看,这本书的读大部分是做计算机出身的。编辑的分类大部分是从书的内容出发,而不是从书的读者群出发。(统计,两个物品多用户同时喜欢可能属于一类)**
- 编辑很难控制分类的粒度。我们知道分类是有不同粒度的,《数据挖掘导论》在粗粒度的分类中可能属于计算机技术,但在细粒度的分类中可能属于数据挖掘。对于不同的用户,我们可能需要不同的粒度。比如对于一位初学者,我们粗粒度地给他做推荐就可以了,而对于一名资深研究人员,我们就需要深入到他的很细分的领域给他做个性化推荐。(分类)
- 编辑很难给一个物品多个分类。有的书不仅属于一个类,而是可能属于很多的类。(权重)
- 编辑很难给出多维度的分类。我们知道,分类是可以有很多维度的,比如按照作者分类、按照译者分类、按照出版社分类。比如不同的用户看《具体数学》原因可能不同,有些人是因为它是数学方面的书所以才看的,而有些人是因为它是大师Knuth的著作所以才去看,因此在不同人的眼中这本书属于不同的分类。(分类都是基于用户行为计算出来的)
- 编辑很难决定一个物品在某一个分类中的权重。比如编辑可以很容易地决定《数据挖掘导论》属于数据挖掘类图书,但这本书在这类书中的定位是什么样的,编辑就很难给出一个准确的数字来表示。(喜欢某类的人都喜欢一个物品,权重就高)
为了解决上面的问题,研究人员提出:为什么我们不从数据出发,自动地找到那些类,然后进行个性化推荐?于是,隐含语义分析技术(latent variable analysis)出现了。隐含语义分析技术因为采取基于用户行为统计的自动聚类,较好地解决了上面提出的5个问题。
最简单的办法是直接矩阵分解:
我们假定隐藏因子F的个数小于user和item数。因为如果每个user都关联一个独立的隐藏因子,那就没法做预测了。
3.2 用户对物品感兴趣程度


3.3算法适用
LFM在显性反馈数据(即评分数据)上解决评分预测问题精度较好。若要应用在隐性反馈数据集,首先要解决的一个关键问题是如何给每个用户生成负样本。
一般来说,对负样本采样时应遵循以下原则:
1)对每个用户,要保证正负样本的数目相近
2)对每个用户采样负样本时,要选取那些很热门,而用户却没有行为的物品。(更代表用户对该物品不感兴趣)
LFM在各项指标性能上均优于UserCF和ItemCF。但当数据集非常稀疏时,LFM的性能明显下降。甚至不如UserCF和ItemCF。
LFM在实际应用中有一个困难,很难实现实时的推荐。在新闻推荐中冷启动问题非常明显,那就是它很难实现实时推荐。经典的隐语义模型每次训练时都需要扫描所有的用户行为记录,这样才能计算出用户对于 每个隐分类的喜爱程度矩阵P和每个物品与每个隐分类的匹配程度矩阵Q。而且隐语义模型的训练需要在用户行为记录上反复迭代才能获得比较好的性能,因此 LFM的每次训练都很耗时,一般在实际应用中只能每天训练一次,并且计算出所有用户的推荐结果。从而隐语义模型不能因为用户行为的变化实时地调整推荐结果 来满足用户最近的行为。
3.4LFM VS 基于邻域的方法:
LFM是基于机器学习的算法,基于邻域的方法是基于统计的方法,无学习过程。
基于邻域的方法需维护一张离线的相关表,会占据很大的内存。而LFM则可以很好地节省计算的内存,对于用户数很大的数据量来说较合适。
总体来说,二者的时间复杂度没有质的区别。
基于邻域的算法可较好的实现实时性。LFM不能在线实时推荐。
ItemCF支持很好的推荐解释,而LFM无法提供。
冷启动:
1.什么是冷启动
推荐系统的主要目标是将大量的标的物推荐给可能喜欢的海量用户, 这里涉及到标的物和用户两类对象。任何互联网推荐产品, 标的物和用户都是不断增长变化的,所以一定会频繁面对新标的物和新用户, 推荐系统冷启动问题指的就是对于新注册的用户或者新入库的标的物, 该怎么给新用户推荐标的物让用户满意,怎么将新标的物分发出去,推荐给喜欢它的用户。
另外,如果是新开发的产品,初期用户很少,用户行为也不多(没有大量的用户数据),常用的协同过滤、深度学习等依赖大量用户行为的算法不能很好的训练出精准的推荐模型, 怎么让推荐系统很好的运转起来,让推荐变得越来越准确,这个问题就是系统冷启动。
总之,推荐系统冷启动主要分为标的物冷启动、用户冷启动、系统冷启动三大类。
现在我们大概知道了什么是冷启动,看起来冷启动很好理解,但冷启动不是这么容易搞定的。、
冷启动三大分类:
用户冷启动:用户冷启动主要解决如何给新用户做个性化推荐的问题。 当新用户到来时,没有他的行为数据,所以无法根据他的历史行为预测其兴趣,从而无法借此给他做个性化推荐。
物品冷启动:物品冷启动主要解决如何将新
的物品推荐给可能对它感兴趣的用户这一问题。
系统冷启动:系统冷启动主要解决如何在一个新开发的网站上(没有用户,也没有用户行为,只有一些物品的信息)设计个性化推荐系统,从而在网站刚发布时就让用户体验到个性化推荐服务这一问题。
2.解决冷启动的一般思路
解决冷启动的一般思路,这些思路是帮助我们设计冷启动方案的指导原则。具体思路有如下几个:
- 提供非个性化的推荐
- 利用用户注册时提供的年龄、性别等数据做粗粒度的个性化。
- 利用社交账号登录(需要用户授权),导入用户在社交网络上的好友信息,然后给用户推荐其好友喜欢的物品。
- 要求用户在登录时对一些物品进行反馈,搜集用户对这些物品的兴趣信息,然后给用户推荐那些和这些物品相似的物品。
- 对于新加入的物品,可以利用内容信息,将它们推荐给喜欢过和他们相似物品的用户。(没有购买记录,如何判断物品相似)
- 推荐系统冷启动时,引入专家的知识,通过一定的高效方式迅速建立起物品的相关度表。
3.利用用户注册信息
在网站中,当新用户刚注册时,不知道他喜欢什么物品,于是只能给他推荐一些热门的商品。但如果我们知道她是一位女性,那么可以给她推荐女性都喜欢的热门商品。这也是一种个性化的推荐。当然这个个性化的粒度很粗,因为所有刚注册的女性看到的都是同样的结果,但相对于不区分男女的方式,这种推荐的精度已经大大提高了。因此,利用用户的注册信息可以很好地解决注册用户的冷启动问题。在绝大多数网站中,年龄、性别一般都是注册用户的必备信息。
用户的注册信息分3种。
- 人口统计学信息: 包括用户的年龄、性别、职业、民族、学历和居住地;
- 用户兴趣的描述: 有一些网站会让用户用文字描述他们的兴趣;
- 从其他网站导入的用户站外行为数据: 比如用户通过豆瓣、新浪微博的账号记录,就可以在得到用户同意的情况下获取用户在豆瓣或者新浪微博的一些行为数据和社交网络数据。
人口统计学特征包括年龄、性别、工作、学历、居住地、国籍、民族等,这些特征对预测用户的兴趣有很重要的作用,比如男性和女性的兴趣不同,不同年龄的人性却也不同。
基于人口统计学特征的推荐系统其典型代表是Bruce Krulwich开发的Lifestyle Finder.首先Bruce将美国人群根据人口统计学属性分成62类,然后对比每个新用户根据其填写个个人资料判断他属于什么分类,最后给他推荐这类用户最喜欢的15个链接,其中5个链接是推荐他购买的商品,5个链接是推荐他旅游的地点,剩下的5个链接是推荐他去逛的商店。
为了证明利用用户人口统计学特征后的推荐结果好于随机推荐的结果, Krulwich做了一个AB测试。相对于利用人口统计学特征的算法, Krulwich设计了一个对照组,该组用户看到的推荐结果是完全随机的。实验结果显示,对于利用人口统计学特征的个性化推荐算法,其用户点击率为89%,而随机算法的点击率只有27%。对于利用人口统计学特征的个性化算法,44%的用户觉得推荐结果是他们喜欢的,而对于随机算法只有31%的用户觉得推荐结果是自己喜欢的。因此,我们得到一个结论——使用人口统计学信息相对于随机推荐能够获得更好的推荐效果。当然, Krulwich的实验也有明显的缺点, 即他没有对比和给用户推荐最热门的物品的推荐算法。因为热门排行榜作为一种非个性化推荐算法,一般也比随机推荐具有更高的点击率。
基于注册信息的个性化推荐流程基本如下:
- 获取用户的注册信息;
- 根据用户的注册信息对用户分类;
- 给用户推荐他所属分类中用户喜欢的物品。

一个基于用户人口统计学特征推荐的简单例子
基于用户注册信息的推荐算法其核心问题是计算每种特征的用户喜欢的物品。也就是说,对于每种特征f,计算具有这种特征的用户对哥哥物品的喜好程度p(f,i).
p(f,i)可以简单地定义为物品i在具有f的特征的用户中的热门程度:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hRfC7BDK-1648010507939)(https://math.jianshu.com/math?formula=p(f%2Ci)]%20%3D%20%7CN(i)%20%5Ccap%20U(f)%7C)
其中,N(i)是喜欢物品i的用户集合,U(f)是具有特征f的用户集合。
根据这种定义可以比较准确地预测具有某种特征的用户是否喜欢某个物品。但是,在这种定义下,往往热门的物品会在各种特征用户中都具有比较高的权重。也就是说具有比较高的|N(i)|的物品会在每一类用户中都有比较高的p(f,i)。对公式进行修正,将p(f,i)定义为喜欢物品i的用户中具有特征f的比例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4KZLn4mv-1648010507939)(https://math.jianshu.com/math?formula=p(f%2Ci)]%20%3D%20%5Cfrac%7B%7CN(i)%20%5Ccap%20U(f)%7C%7D%7B%7CN(i)%7C%20%2B%20%5Calpha%7D)
这里分母中参数alpha用来解决数据稀疏问题。比如,有一个物品只被1个用户喜欢过,而这个用户刚好具有特征f,那么就有p(f,i)=1.但是,这种情况并没有统计意义,因此为分母加上一个比较大的数,可以避免这样的物品产生比较大的权重。
4.选择合适的物品启动用户的兴趣
解决用户冷启动问题的另一个方法是在新用户第一次访问推荐系统时,不立即给用户展示推荐结果,而是给用户提供一些物品,让用户反馈他们对这些物品的兴趣,然后根据用户反馈提供个性化推荐。
对于这些通过让用户对物品进行评分来收集用户兴趣,从而对用户进行冷启动的系统,它们需要解决的首要问题就是如何选择物品让用户进行反馈。
一般来说,能够用来启动用户兴趣的物品需要具有一下特点:
- 比较热门 如果要让用户对一个物品进行反馈,前提是用户知道这个物品是什么东西。以电影为例,如果一开始让用户进行反馈的电影都很冷门,而用户不知道这些电影的情节和内容,也就无法对它们做出准确的反馈。
- 具有代表性和区分性 启动用户兴趣的物品不能是大众化或老少皆宜的,因为这样的物品对用户的兴趣没有区分性。热门物品对区分用户个性化的兴趣没有帮助。
- 启动物品集合需要有多样性 在冷启动时,不知道用户的兴趣,而用户兴趣的可能性非常多,为了匹配多样的兴趣,需要提供具有很高覆盖率的启动物品集合,这些物品能覆盖几乎所有主流的用户兴趣。
上面这些因素是选择启动物品时需要考虑的,但如何设计一个选择启动物品集合的系统?Nadav Golbandi提出可以使用一个决策树解决这个问题。



给用户选择物品以解决冷启动问题的例子
5.利用物品的内容信息
物品冷启动需要解决的问题是如何将新加入的物品推荐给对它感兴趣的用户。物品冷启动在新闻网站等时效性很强的网站中非常重要。
UserCF算法对物品冷启动问题并不非常敏感。因为,USerCF在给用户进行推荐时,会首先找到和用户兴趣相似的一群用户,然后给用户推荐这一群用户喜欢的物品。在很多网站中,推荐列表并不是给用户展示内容的唯一列表,当一个用户对某个物品产生反馈后,和他历史兴趣相似的其他用户的推荐列表中就有可能出现这一物品,从而更多的人就会对这个物品产生反馈,导致更多的人的推荐列表中就会出现这一物品,因此该物品就能不断地扩散开来,从而逐步展示到对它感兴趣用户的推荐列表中。
但是,有些网站中推荐列表可能是用户获取信息的主要途径,比如豆瓣网络电台。那么对于UserCF算法就需要解决第一推动力的问题, 即第一个用户从哪儿发现新的物品。只要有一小部分人能够发现并喜欢新的物品,UserCF算法就能将这些物品扩散到更多的用户中。解决第一推动力最简单的方法是将新的物品随机展示给用户,但这样不太个性化,因此可以考虑利用物品的内容信息,将新物品先投放给曾经喜欢过和它内容相似的其他物品的用户。
对于ItemCF算法来说,物品冷启动是一个严重的问题。因为ItemCF算法的原理是给用户推荐和他之前喜欢的物品相似的物品。ItemCF算法会每隔一段时间利用用户行为计算物品相似度表(一般一天计算一次),在线服务时ItemCF算法会将之前计算好的物品相关度矩阵放在内存中。因此,当新物品加入时,内存中的物品相关表中不会存在这个物品,从而ItemCF算法无法推荐新的物品。解决这一问题的办法是频繁更新物品相似度表,但基于用户行为九三物品相似度是非常耗时的,主要原因是用户行为日志非常庞大。而且,新物品如果不展示给用户,用户就无法对产生行为,通过行为日志计算是计算不出包含新物品的相关矩阵的。为此,只能利用物品的内容信息计算物品相关表,并且频繁地更新相关表(比如半小时计算一次)。
物品的内容可以用向量空间模型表示,该模型会将物品表示成一个关键词向量。对于文本,该模型通过分词、实体检测、关键词排名等步骤将文本表示成一个关键词向量 {(e1,w1),(e2,w2),…} 。其中,ei是关键词,wi是关键词对应的权重。次的权重可以用TF-IDF计算权重:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KKB338jH-1648010507941)(https://math.jianshu.com/math?formula=w_i%20%3D%20%5Cfrac%7BTF(e_i)]%7D%7BlogDF(e_i)%7D)
向量空间模型的优点是简单,缺点是丢失了一些信息,比如关键词之间的关系信息。不过在绝倒数应用中,向量空间模型对于文本的分类、聚类、相似度计算已经可以给出令人满意的结果。
在给定物品内容的关键词向量后,物品的内容相似度可以通过向量之间余弦相似度计算:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5DnPqHiI-1648010507942)(https://math.jianshu.com/math?formula=w_%7Bij%7D%20%3D%20%5Cfrac%7Bd_id_j%7D%7B%5Csqrt%7B%7C%7Cd_i%7C%7C%7C%7Cd_j%7C%7C%7D%7D)]
代码:
function CalculateSimilarity(D)#D文档集合
for di in D:
for dj in D:
w[i][j] = CosineSimilarity(di, dj)
return w
推荐系统动态特性和基于时间的协同过滤算法研究:动态和基于时间含义相似,协同过滤是推荐系统的一种算法
向量空间模型的一个问题是不能理解含义近似的关键词,因此在内容较少时准确度很差。话题模型通过首先计算文本的话题分布,然后再计算相似度来解决这个问题,如LDA模型(Latent Dirichlet Allocation)。
任何模型都有一个假设, LDA作为一种生成模型,对一篇文档产生的过程进行了建模。话题模型的基本思想是,一个人在写一篇文档的时候,会首先想这篇文章要讨论哪些话题,然后
思考这些话题应该用什么词描述,从而最终用词写成一篇文章。因此,文章和词之间是通过话
题联系的.
** LDA 包含文档、话题、词3种元素,每个词属于一个话题,通过迭代收敛得到话题的分布,文档的相似度由话题分布的相似度来度量**. 每一篇文档都会表现为词的集合。这称为词袋模型(bag of words).每个词在一篇文档中属于一个话题。令D为文档集合,D[i]是第i篇文档,w[i][j]是第i篇文档的第j个词,z[i][j]是第i篇文档的第j个词属于的话题。
*LDA的计算过程包括初始化和迭代两部分 **。首先要对z进行初始化,而初始化的方法很多简单,假设一共有K个话题,那么对第i篇文章中的第j个词,可以*随机给它赋予一个话题。在初始化之后,通过迭代使话题的分布收敛到一个合理的分布上去。
在使用LDA计算物品的内容相似度时,我们可以先计算出物品在话题上的分布,然后利用两个物品的话题分布计算物品的相似度。比如,如果两个物品的话题分布相似,则认为两个物品具有较高的相似度,反之则认为两个物品的相似度较低。计算分布的相似度可以利用 KL 散度:

KL散度
其中p和q是两个分布,KL散度越大说明分布的相似度越低。
6.发挥专家作用:
Jinni是典型例子,它通过专家和机器学习相结合的方法解决系统冷启动问题。
标记,基因,分类 运用自然语言理解和机器学习技术 用户反馈
7.设计冷启动需要注意的问题
上面讲了很多冷启动的实现方案, 不同的产品需要结合自身产品特征和拥有的资源来选择采用什么方式做冷启动。在这里我讲一下冷启动落地过程中需要注意的事情, 让大家更好的将冷启动应用于真实的业务场景中。
- 逐步迭代让冷启动效果更好
冷启动有很多方法,我们需要通过AB测试选择一种效果更好的方法,并不断优化,让冷启动的效果达到最佳状态。
- 量化冷启动用户的比例及转化效果
如1中所讲, 需要将用户的行为日志埋点, 日志中需要包含用户userId,采用的算法标识、用户具体行为(点击、播放、购买、点赞)等,这样就可以通过分析日志知道有每天的DAU中多少用户采用了冷启动策略、各种冷启动策略及非冷启动策略的比例、冷启动策略的转化效果及与其他非冷启动策略的转化效果的对比。只有知道了具体数据情况,才能够知道从哪些维度去优化。
- 采用级联推荐策略
一般来说协同过滤的效果比基于内容推荐好,而基于内容推荐会比冷启动推荐好,我们在给用户做推荐时可以采用级联策略。比如如果协同过滤有推荐结果就采用协同过滤的结果,没有的话(可能是新注册不久的用户)就采用基于内容的推荐,如果用户没有看任何内容这时可以采用冷启动推荐(如热门推荐等)。这样做效果肯定会更好,因为总是优先使用最好的算法,但是实现起来可能会复杂一些,为了给用户提供最好的推荐体验,这也是值得的。
如果某个视频有基于item2vector的算法计算出的相关视频就采用该算法的结果,如果没有就采用基于标签的相似推荐,如果该视频是新视频,标签不完善,就采用基于热门的冷启动推荐策略。
采用级联策略的目的主要是优先利用所有已知的最好信息,尽量减少采用非个性化冷启动推荐的比例,最大程度提升用户的使用体验。
馈
7.设计冷启动需要注意的问题
上面讲了很多冷启动的实现方案, 不同的产品需要结合自身产品特征和拥有的资源来选择采用什么方式做冷启动。在这里我讲一下冷启动落地过程中需要注意的事情, 让大家更好的将冷启动应用于真实的业务场景中。
- 逐步迭代让冷启动效果更好
冷启动有很多方法,我们需要通过AB测试选择一种效果更好的方法,并不断优化,让冷启动的效果达到最佳状态。
- 量化冷启动用户的比例及转化效果
如1中所讲, 需要将用户的行为日志埋点, 日志中需要包含用户userId,采用的算法标识、用户具体行为(点击、播放、购买、点赞)等,这样就可以通过分析日志知道有每天的DAU中多少用户采用了冷启动策略、各种冷启动策略及非冷启动策略的比例、冷启动策略的转化效果及与其他非冷启动策略的转化效果的对比。只有知道了具体数据情况,才能够知道从哪些维度去优化。
- 采用级联推荐策略
一般来说协同过滤的效果比基于内容推荐好,而基于内容推荐会比冷启动推荐好,我们在给用户做推荐时可以采用级联策略。比如如果协同过滤有推荐结果就采用协同过滤的结果,没有的话(可能是新注册不久的用户)就采用基于内容的推荐,如果用户没有看任何内容这时可以采用冷启动推荐(如热门推荐等)。这样做效果肯定会更好,因为总是优先使用最好的算法,但是实现起来可能会复杂一些,为了给用户提供最好的推荐体验,这也是值得的。
如果某个视频有基于item2vector的算法计算出的相关视频就采用该算法的结果,如果没有就采用基于标签的相似推荐,如果该视频是新视频,标签不完善,就采用基于热门的冷启动推荐策略。
采用级联策略的目的主要是优先利用所有已知的最好信息,尽量减少采用非个性化冷启动推荐的比例,最大程度提升用户的使用体验。

1776

被折叠的 条评论
为什么被折叠?



