实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
2018-03-29 11:08
309 查看
关于隐语义模型,其中之一就是本专栏第(2)节讲过的 -- SVD矩阵分解及其正则化 。LFM 模型通过如下公式计算用户 u 对物品 i 的兴趣:
其中P 和 Q 的解释同第(2)节,不再累述。但可以解释一下隐类 K:
假如用户喜欢看电影,但是兴趣比较广泛。如果采用协同过滤的算法,那么很难满足用户广泛的兴趣及其比重。假如用户80%的时间喜欢看科幻电影,20% 的时间喜欢看动画片。那么协同过滤无法考虑到这种兴趣的比重并合理推荐。我们就将 K 设定为2,定义两个隐类,将用户与隐类的联系设成矩阵 P;同理,将隐类与物品的联系设成矩阵 Q,形成了隐语义模型 LFM。
(1)对每个用户,从他没有行为的物品中采样一些物品作为负样本。
(2)要保证正负样本的数量相当。
(3)对每个用户采样负样本时,选择那些很热门,用户却没有行为的物品比冷门用户没有行为的物品更佳。
负样本采样代码如下:def RandomSelectNegativeSample(items):
ret = dict()
for i in items.keys():
ret[i] = 1 #已有的物品为 1 代表正样本
n = 0
for i in xrange(len(items) * 3):
#items_pool 维护了一个候选物品表,在这个列表中
#物品 i 出现的次数和物品 i 的流行度成正比
item = items_pool[random.randint(0,len(items_pool) - 1)]
if item in ret:continue
ret[item] = 0 #负样本
n += 1
if n > len(items):break #保证正负平衡
return ret
将其中的2
设成 alpha ,称之为学习率,则如下:
下面的代码实现了这一梯度下降过程:def LatenFactorModel(user_items, K, N, alpha, lambda):
[P,Q] = InitModel(user_items,K) #生成 K 个隐类的 P,Q 矩阵
for step in range(0,N):
for user,items in user_items.items():
samples = RandomSelectNegativeSample(items)
for item,rui in samples.items():
eui = rui - Predict(user,item) #Predict 根据 P,Q 矩阵计算 ^rui
for k in range(0,K):
P[user][k] += alpha * (eui * Q[k][item] - lambda * P[user][k])
Q[k][item] += alpha * (eui * P[user][k] - lambda * Q[k][item])
alpha *= 0.9 #学习率衰减
rank = dict()
for u,puk in P[user].items():
for i,qki in Q[u].items():
if i not in rank:
rank[i] = puk * qki #矩阵乘法
return rank
其中P 和 Q 的解释同第(2)节,不再累述。但可以解释一下隐类 K:
假如用户喜欢看电影,但是兴趣比较广泛。如果采用协同过滤的算法,那么很难满足用户广泛的兴趣及其比重。假如用户80%的时间喜欢看科幻电影,20% 的时间喜欢看动画片。那么协同过滤无法考虑到这种兴趣的比重并合理推荐。我们就将 K 设定为2,定义两个隐类,将用户与隐类的联系设成矩阵 P;同理,将隐类与物品的联系设成矩阵 Q,形成了隐语义模型 LFM。
如何通过隐反馈数据获得 SVD 的 UI 矩阵?
在 SVD 中,UI 矩阵的行代表用户U,列代表物品I,其中的数字代表用户 U 对 I 的评分。但是在隐反馈数据中,只有正样本,没有负样本,要得到 UI 矩阵,必须要有负样本。因此要进行负样本采样,采样原则如下:(1)对每个用户,从他没有行为的物品中采样一些物品作为负样本。
(2)要保证正负样本的数量相当。
(3)对每个用户采样负样本时,选择那些很热门,用户却没有行为的物品比冷门用户没有行为的物品更佳。
负样本采样代码如下:def RandomSelectNegativeSample(items):
ret = dict()
for i in items.keys():
ret[i] = 1 #已有的物品为 1 代表正样本
n = 0
for i in xrange(len(items) * 3):
#items_pool 维护了一个候选物品表,在这个列表中
#物品 i 出现的次数和物品 i 的流行度成正比
item = items_pool[random.randint(0,len(items_pool) - 1)]
if item in ret:continue
ret[item] = 0 #负样本
n += 1
if n > len(items):break #保证正负平衡
return ret
梯度下降求解 SVD
直接引入第(2)节的结果,加入了正则化的 SVD 矩阵的梯度下降公式为:将其中的2
设成 alpha ,称之为学习率,则如下:
下面的代码实现了这一梯度下降过程:def LatenFactorModel(user_items, K, N, alpha, lambda):
[P,Q] = InitModel(user_items,K) #生成 K 个隐类的 P,Q 矩阵
for step in range(0,N):
for user,items in user_items.items():
samples = RandomSelectNegativeSample(items)
for item,rui in samples.items():
eui = rui - Predict(user,item) #Predict 根据 P,Q 矩阵计算 ^rui
for k in range(0,K):
P[user][k] += alpha * (eui * Q[k][item] - lambda * P[user][k])
Q[k][item] += alpha * (eui * P[user][k] - lambda * Q[k][item])
alpha *= 0.9 #学习率衰减
得到 P, Q 矩阵后生成推荐
通过梯度下降算法获得 P, Q 矩阵后,我们就可以根据矩阵生成推荐,代码如下:def Recommend(user, P, Q):rank = dict()
for u,puk in P[user].items():
for i,qki in Q[u].items():
if i not in rank:
rank[i] = puk * qki #矩阵乘法
return rank
相关文章推荐
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(10)-- 隐语义模型 LFM (Funk-SVD)
- 实战智能推荐系统(2)-- Funk-SVD 矩阵分解及其正则化
- 实战智能推荐系统(2)-- Funk-SVD 矩阵分解及其正则化