隐语义模型

隐语义模型(LFM)

核心思想:通过隐含特征联系用户兴趣和物品。

我的理解是LFM 就是对物品基于权重进行分类,并同时依据用户对每一类的兴趣来确定用户感兴趣的物品。看似是把一个大问题分解成了两个小问题。

基于兴趣分类的方法大概需要解决三个问题:

  1. 如何给物品分类
  2. 如何确定用户对哪些类的物品感兴趣,以及感兴趣的程度
  3. 对一个给定的类, 选择哪些属于这个类的物品推荐给用户,以及如何确定这些物品在一个类中的权重。

对于第一个问题,采用隐含语义分析技术。该技术采取基于用户统计行为的自动聚类。
对于第二个问题,LFM 通过如下公式计算用户u对物品i 的兴趣:

Perference(u,i)=rui=pTuqi=k=1Fpu,kqi,k(1)

其中, pu=(pu,1,pu,2,...,pu,k)T , qi=(q1,i,q2,i,...,qk,i)T , pu,k 度量了用户 u 的兴趣和第 k 个隐类的关系,而 qi,k 度量了第 k 个隐类和物品 i 之间的关系。我们看到只要这两个参数求出来了,那么 u i 的兴趣也就求出来了。

这里求出 qi pu,k qi,k 是通过最小化下面的损失函数得到的:

C=(u,i)K(ruirˆui)2=(u,i)K(ruik=1Kpu,kqi,k)2+λpu2+λpi2(2)

其中 K 是一个用户-物品集 K=(u,i) , 其中如果 (u,i) 是正样本的话 rui=1 ,否则 rui=0 . 对于我们讨论的隐性反馈数据集,这个数据集里面只有正样本,没有负样本 (我们统计到用户买了该物品,就认为是是正样本)。所以我们要进行采样给里面添加负样本形成数据集 K 。对每个用户负样本采样的时候应该遵循:(1)要保证正负样本的数目相似 (2) 要选取那些很热门,而用户却没有行为的物品。
下面是将书上的伪代码改写后的负样本采样的代码:

def RandomSelectNegativeSample(user, user_items):
    ret = dict()
    items_pool = []#包含所有的item,有重复的,之所以不用set是因为要遵循(2)
    for example, items in user_items.items():
        for item in items:
            items_pool.append(item)
    items_pool=list(items_pool)
    for i in user_items[user]:
        ret[i] = 1 #正样本为1
    n = 0
    for i in range(0, len(user_items[user]) * 3):
        item = items_pool[random.randint(0, len(items_pool) - 1)]
        if item in ret.keys():
            continue
        ret[item]=0 #负样本为0
        n += 1
        if n > len(user_itmes[user]): #确保正负样本数目相似
            break
    return ret

最小化上面的损失函数,求得 pu,k qi,k 。 这里通常有两种方法,一种是随机梯度下降法 (SGD),另一种是交替最小二乘法(ALS). 推荐系统这本书介绍的是SGD, 步骤如下:

1.对 pu,k qi,k 求取偏导数,确定最速下降方向:

Cpu,k=2(ruik=1Fpu,kqk,i)qk,i+2λpu,k

Cqu,k=2(ruik=1Fpu,kqk,i)pk,i+2λqu,k

2.将参数沿着最速下降方向向前推进,迭代,直到参数收敛。

pu,k=pu,k+α[(ruik=1Fpu,kqk,i)qk,iλpu,k]

qu,k=qu,k+α[(ruik=1Fpu,kqk,i)pk,iλqu,k]

这里 α 是学习速率,下面是这一优化的python实现,返回的P和Q分别包含了所有用户u的 pu 和所有物品i的 qi :

def LatentFactorModel(user_items, F, N, alpha, lam):
    [P,Q]=InitModel(user_items,F)
    for step in range(0,N):
        for user, items in user_items.items():
            samples=RandomSelectNegativeSample(user,user_items)
            for item, rui in samples.items():
                p=0
                for i in range(0,F):
                    p+=P[user][i]*Q[i][item]
                eui=rui-p
                for f in range(0,F):
                    P[user][f]+=alpha*(eui*Q[f][item]-lam*P[user][f])
                    Q[f][item]+=alpha*(eui*P[user][f]-lam * Q[f][item])
    return P, Q
#下面是初始话P,Q,全设为1
def InitModel(user_items,F):
    P={}
    Q={}
    for u, items in  user_items.items():
        if u not in P :
            P[u]={}
        for f in range(0,F):
            P[u][f]=1
        for f in range(0,F):
            if f  not in Q:
                Q[f]={}
            for i in items:
                Q[f][i]=1
    return P, Q

计算了P,Q后,下来就是根据 Perference(u,i) 计算兴趣度,然后推荐了。下面是推荐代码:

def Recommend(user,P,Q):
    rank=dict()
    for f, puf in P[user].items():
        for i, qfi in Q[f].items():
            if i not in rank:
                rank[i]=puf*qfi
            rank[i]+=puf*qfi
    return rank

就这个推荐代码,我有几点还没弄清楚:1. 这样计算出来的会包含用户以购买的物品,这不应该啊。2. 如果去除用户已购买的物品,那么之前采样的负样本怎么办,去除吗?有必要再看看资料,解决这两个问题。3. 总感觉这样生成的负样本,不是就是说认为人家用户不喜欢,这是不是太绝对了,人用户也许是喜欢只是没看见。不知道我是不是对这个算法理解的有问题。

在LFM中,重要的参数有四个:1.隐特征的个数F; 2.学习速率 α ; 3.正则化参数 λ ; 4.负样本/正样本比例ratio. 书上的实验看出ratio对LFM的性能影响最大。当数据集非常稀疏时,LFM的性能会明显下降,甚至不如UserCF和ItemCF. LFM很难实现实时推荐,训练时非常耗时, 因为要在所有用户行为记录上反复迭代才能获得比较好的性能。另外,在新闻推荐时冷启动非常明显。

为了解决LFM的一些缺陷,很多论文中提出对 rui 的修正,这个后续我得看看正方面的论文,再来补上。

下面简单总结下LFM与基于邻域的方法的比较:

1.理论基础:LFM具有比较好的理论基础,是一种学习方法。基于的邻域的方法是一种基于统计的方法,没有学习过程。

2.离线计算的空间复杂度:LFM低于UserCF和ItemCF

3.离线计算的时间复杂度:一般情况下, LFM高于UserCF和ItemCF,主要是LFM需要多次迭代。但是书上又说 总体上,这两种算法在时间复杂度上没有质的区别,没弄明白,这是为什么呢。

4.在线实时推荐:LFM不能进行在线实时推荐。

5.推荐解释:ItemCF支持很好的推荐解释,UserCF和LFM都无法提供。

LFM这块看了一篇《Matrix factorization techniques for recommender systems》, 里面提出了一些对(1) 和(2)的修正。 比如,通过置信度权重来处理我们所认为的负样本,也就是没有反馈的物品。就是说对更确信用户的项赋以较大的权重,对于没有反馈的项,赋以较小的权重。则(2)变成了
pu,k qi,k 是通过最小化下面的损失函数得到的:

C=(u,i)Kcui(ruirˆui)2=(u,i)Kcui(ruik=1Kpu,kqi,k)2+λpu2+λpi2(2)

这里, cui 就是那个权重。 还有些修正,还没看懂。

你可能感兴趣的:(推荐系统)