核心思想

隐语义模型LFM和LSI,LDA,Topic Model其实都属于隐含语义分析技术,是一类概念,他们在本质上是相通的,都是找出潜在的主题或分类。这些技术一开始都是在文本挖掘领域中提出来的,近些年它们也被不断应用到其他领域中,并得到了不错的应用效果。比如,在推荐系统中它能够基于用户的行为对item进行自动聚类,也就是把item划分到不同类别/主题,这些主题/类别可以理解为用户的兴趣。

对于一个用户来说,他们可能有不同的兴趣。就以作者举的豆瓣书单的例子来说,用户A会关注数学,历史,计算机方面的书,用户B喜欢机器学习,编程语言,离散数学方面的书, 用户C喜欢大师Knuth, Jiawei Han等人的著作。那我们在推荐的时候,肯定是向用户推荐他感兴趣的类别下的图书。那么前提是我们要对所有item(图书)进行分类。那如何分呢?大家注意到没有,分类标准这个东西是因人而异的,每个用户的想法都不一样。拿B用户来说,他喜欢的三个类别其实都可以算作是计算机方面的书籍,也就是说B的分类粒度要比A小;拿离散数学来讲,他既可以算作数学,也可当做计算机方面的类别,也就是说有些item不能简单的将其划归到确定的单一类别;拿C用户来说,他倾向的是书的作者,只看某几个特定作者的书,那么跟A,B相比它的分类角度就完全不同了。

显然我们不能靠由单个人(编辑)或team的主观想法建立起来的分类标准对整个平台用户喜好进行标准化。

实现这种方法,需要解决以下的问题
(1)给物品分类
(2)确定用户兴趣属于哪些类及感兴趣程度
(3)对于用户感兴趣的类,如何推荐物品给用户

对于上述需要解决的问题,我们的隐语义模型就派上用场了。隐语义模型,可以基于用户的行为自动进行聚类,并且这个类的数量,即粒度完全由可控

对于某个物品是否属与一个类,完全由用户的行为确定,我们假设两个物品同时被许多用户喜欢,那么这两个物品就有很大的几率属于同一个类。而某个物品在类所占的权重,也完全可以由计算得出。

原理

:原理部分借鉴博客,博主画的图非常漂亮、形象,很容易理解。

下面我们就来看看LFM是如何解决上面的问题的?对于一个给定的用户行为数据集(数据集包含的是所有的user, 所有的item,以及每个user有过行为的item列表),使用LFM对其建模后,我们可以得到如下图所示的模型:(假设数据集中有3个user, 4个item, LFM建模的分类数为4)

R矩阵是user-item矩阵,矩阵值Rij表示的是user i 对item j的兴趣度,这正是我们要求的值。对于一个user来说,当计算出他对所有item的兴趣度后,就可以进行排序并作出推荐。LFM算法从数据集中抽取出若干主题,作为user和item之间连接的桥梁,将R矩阵表示为P矩阵和Q矩阵相乘。其中P矩阵是user-class矩阵,矩阵值Pij表示的是user i对class j的兴趣度;Q矩阵式class-item矩阵,矩阵值Qij表示的是item j在class i中的权重,权重越高越能作为该类的代表。所以LFM根据如下公式来计算用户U对物品I的兴趣度

LFM有以下优势

  1. 我们不需要关心分类的角度,结果都是基于用户行为统计自动聚类的,全凭数据自己说了算。
  2. 不需要关心分类粒度的问题,通过设置LFM的最终分类数K就可控制粒度,分类数K越大,粒度约细。
  3. 对于一个item,并不是明确的划分到某一类,而是计算其属于每一类的概率,是一种标准的软分类。
  4. 对于一个user,我们可以得到他对于每一类的兴趣度,而不是只关心可见列表中的那几个类。
  5. 对于每一个class,我们可以得到类中每个item的权重,越能代表这个类的item,权重越高。

那么,接下去的问题就是如何计算矩阵P和矩阵Q中参数值。一般做法就是最优化损失函数来求参数。在定义损失函数之前,我们需要准备一下数据集并对兴趣度的取值做一说明。

数据集应该包含所有的user和他们有过行为的(也就是喜欢)的item。所有的这些item构成了一个item全集。对于每个user来说,我们把他有过行为的item称为正样本,规定兴趣度RUI=1,此外我们还需要从item全集中随机抽样,选取与正样本数量相当的样本作为负样本,规定兴趣度为RUI=0。因此,兴趣的取值范围为[0,1]。

:对于隐性反馈数据集,由于只有正样本,没有负样本,因此在应用LFM进行TopN推荐的时候第一个关键问题就是如何生成负样本。采样原则有以下两点

  1. 对于每个用户,要保证正负样本均衡;
  2. 对于每个用户进行采样时,要选取那些热门但用户没有行为的物品。

采样之后原有的数据集得到扩充,得到一个新的user-item集K={(U,I)},其中如果(U,I)是正样本,则RUI=1,否则RUI=0。

通过优化以下损失函数来找到最合适的P,Q,损失函数如下:

其中, λ||PU||2+λ||QI||2 为正则化项,防止过拟合,lambda通过试验获取。

通过随机梯度下降法优化损失函数C:

梯度下降优化,直至参数收敛:

其中,α是学习速率,α越大,迭代下降的越快。α和λ一样,也需要根据实际的应用场景反复实验得到。《推荐系统实战》中,作者在MovieLens数据集上进行实验,他取分类数F=100,α=0.02,λ=0.01。

综上所述,执行LFM需要

  1. 根据数据集初始化P和Q矩阵(采用随机初始化的方式,将p和q取值在[0,1]之间);
  2. 确定4个参数:分类数F,迭代次数N,学习速率α,正则化参数λ。

伪代码如下:

def LFM(user_items, F, N, alpha, lambda):#初始化P,Q矩阵[P, Q] = InitModel(user_items, F)#开始迭代For step in range(0, N):#从数据集中依次取出user以及该user喜欢的iterms集for user, items in user_item.iterms():#随机抽样,为user抽取与items数量相当的负样本,并将正负样本合并,用于优化计算samples = RandSelectNegativeSamples(items)#依次获取item和user对该item的兴趣度for item, rui in samples.items():#根据当前参数计算误差eui = eui - Predict(user, item)#优化参数for f in range(0, F):P[user][f] += alpha * (eui * Q[f][item] - lambda * P[user][f])Q[f][item] += alpha * (eui * P[user][f] - lambda * Q[f][item])#每次迭代完后,都要降低学习速率。一开始的时候由于离最优值相差甚远,因此快速下降;#当优化到一定程度后,就需要放慢学习速率,慢慢的接近最优值。alpha *= 0.9

Python实现LFM模型

# https://blog.csdn.net/fjssharpsword/article/details/78262539
'''
实现隐语义模型,对隐式数据进行推荐
1.对正样本生成负样本-负样本数量相当于正样本-物品越热门,越有可能成为负样本
2.使用随机梯度下降法,更新参数
'''
import numpy as np
import pandas as pd
from math import exp
import time
import math
from sklearn import cross_validation
import random
import operatorclass LFM:'''初始化隐语义模型参数:*data 训练数据,要求为pandas的dataframe*F  隐特征的个数      *N  迭代次数        *alpha 随机梯度下降的学习速率  *lamda 正则化参数  *ratio 负样本/正样本比例  *topk 推荐的前k个物品'''def __init__(self,data,ratio,F=5,N=2,alpha=0.02,lamda=0.01,topk=10):self.data=data                                     # 样本集self.ratio =ratio                                  # 正负样例比率,对性能最大影响self.F = F                                         # 隐类数量,对性能有影响self.N = N                                         # 迭代次数,收敛的最佳迭代次数未知self.alpha =alpha                                  # 梯度下降步长self.lamda = lamda                                 # 正则化参数self.topk =topk                                    # 推荐top k项'''初始化物品池,物品池中物品出现的次数与其流行度成正比{item1:次数,item2:次数,...}'''    def InitItemPool(self):itemPool=dict()groups = self.data.groupby([1])for item,group in groups:itemPool.setdefault(item,0)itemPool[item] =group.shape[0]itemPool=dict(sorted(itemPool.items(), key = lambda x:x[1], reverse = True))return itemPool'''获取每个用户对应的商品(用户购买过的商品)列表,如{用户1:[商品A,商品B,商品C],用户2:[商品D,商品E,商品F]...}''' def user_item(self):ui = dict()groups = self.data.groupby([0])for item,group in groups:ui[item]=set(group.ix[:,1])return ui'''初始化隐特征对应的参数numpy的array存储参数,使用dict存储每个用户(物品)对应的列'''def initParam(self):users=set(self.data.ix[:,0])items=set(self.data.ix[:,1])arrayp = np.random.rand(len(users), self.F)                   # 构造p矩阵,[0,1]内随机值arrayq = np.random.rand(self.F, len(items))                   # 构造q矩阵,[0,1]内随机值P = pd.DataFrame(arrayp, columns=range(0, self.F), index=users)Q = pd.DataFrame(arrayq, columns=items, index=range(0,self.F))return P,Q'''self.Pdict=dict()self.Qdict=dict()for user in users:self.Pdict[user]=len(self.Pdict)for item in items:self.Qdict[item]=len(self.Qdict)self.P=np.random.rand(self.F,len(users))self.Q=np.random.rand(self.F,len(items))''''''生成负样本'''def RandSelectNegativeSamples(self,items):ret=dict()for item in items:ret[item]=1                                             # 所有正样本评分为1negtiveNum = int(round(len(items)*self.ratio))              # 负样本个数,四舍五入N = 0#while N<negtiveNum:#item = self.itemPool[random.randint(0, len(self.itemPool) - 1)]for item,count in self.itemPool.items():if N > negtiveNum: breakif item in items:                                       # 如果在用户已经喜欢的物品列表中,继续选continueN+=1ret[item]=0                                             # 负样本评分为0return retdef sigmod(self,x):y = 1.0 / (1 + exp(-x))                                     # 单位阶跃函数,将兴趣度限定在[0,1]范围内return ydef lfmPredict(self,p, q, userID, itemID):                      # 利用参数p,q预测目标用户对目标物品的兴趣度p = np.mat(p.ix[userID].values)q = np.mat(q[itemID].values).Tr = (p * q).sum()r = self.sigmod(r)return r'''使用随机梯度下降法,更新参数'''def stochasticGradientDecent(self,p,q):alpha=self.alphafor i in range(self.N):for user,items in self.ui.items():ret=self.RandSelectNegativeSamples(items)for item,rui in ret.items():eui = rui - self.lfmPredict(p,q, user, item)                  for f in range(0, self.F):#df[列][行]定位tmp= alpha * (eui * q[item][f] - self.lamda * p[f][user])q[item][f] += alpha * (eui * p[f][user] - self.lamda * q[item][f])p[f][user] +=tmp              alpha*=0.9return p,qdef Train(self):self.itemPool=self.InitItemPool()                           # 生成物品的热门度排行self.ui = self.user_item()                                  # 生成用户-物品p,q=self.initParam()                                        # 生成p,q矩阵 self.P,self.Q=self.stochasticGradientDecent(p,q)            # 随机梯度下降训练def Recommend(self,user):items=self.ui[user]predictList = [self.lfmPredict(self.P, self.Q, user, item) for item in items]series = pd.Series(predictList, index=items)series = series.sort_values(ascending=False)[:self.topk]return series'''#items=self.ui[user]p=self.P[:,self.Pdict[user]]rank = dict()for item,id in self.Qdict.items():#if item in items:#    continueq=self.Q[:,id];rank[item]=sum(p*q)#return sorted(rank.items(),lambda x,y:operator.gt(x[0],y[0]),reverse=True)[0:self.topk-1];return sorted(rank.items(),key=operator.itemgetter(1),reverse=True)[0:self.topk-1];'''def recallAndPrecision(self,test):#召回率和准确率userID=set(test.ix[:,0])hit = 0recall = 0precision = 0for userid in userID:#trueItem = test[test.ix[:,0] == userid]#trueItem= trueItem.ix[:,1]trueItem=self.ui[userid]preitem=self.Recommend(userid)for item in list(preitem.index):if item in trueItem:hit += 1recall += len(trueItem)precision += len(preitem)return (hit / (recall * 1.0),hit / (precision * 1.0))def coverage(self,test):#覆盖率userID=set(test.ix[:,0])recommend_items = set()all_items = set()for userid in userID:#trueItem = test[test.ix[:,0] == userid]#trueItem= trueItem.ix[:,1]trueItem=self.ui[userid]for item in trueItem:all_items.add(item)preitem=self.Recommend(userid)for item in list(preitem.index):recommend_items.add(item)return len(recommend_items) / (len(all_items) * 1.0)def popularity(self,test):#流行度userID=set(test.ix[:,0])ret = 0n = 0for userid in userID:preitem=self.Recommend(userid)for item in list(preitem.index):ret += math.log(1+self.itemPool[item])n += 1return ret / (n * 1.0)if __name__ == "__main__":   start = time.clock()  #导入数据 data=pd.read_csv('D:\\dev\\workspace\\PyRecSys\\demo\\ratings.csv',nrows=10000,header=None)data=data.drop(0)data=data.ix[:,0:1]train,test=cross_validation.train_test_split(data,test_size=0.2)train = pd.DataFrame(train)test = pd.DataFrame(test)print ("%3s%20s%20s%20s%20s" % ('ratio',"recall",'precision','coverage','popularity'))for ratio in [1,2,3,5]:lfm = LFM(data,ratio)lfm.Train()#rank=lfm.Recommend('1')#print (rank)recall,precision = lfm.recallAndPrecision(test)coverage =lfm.coverage(test)popularity =lfm.popularity(test)print ("%3d%19.3f%%%19.3f%%%19.3f%%%20.3f" % (ratio,recall * 100,precision * 100,coverage * 100,popularity))end = time.clock()    print('finish all in %s' % str(end - start))

LFM变形

1、加入偏置项后的LFM

2、SVD++

推荐系统之隐语义模型(LFM)及Python实现相关推荐

  1. python实现lfm_推荐系统之隐语义模型(LFM)

    一 基本概念 LFM(latent factor model)隐语义模型,这也是在推荐系统中应用相当普遍的一种模型.那这种模型跟ItemCF或UserCF有什么不同呢?这里可以做一个对比: 对于Use ...

  2. 推荐系统(5)—隐语义模型(LFM)

    https://www.toutiao.com/a6663676280782717454/ 2019-03-02 14:27:17 基本概念 LFM(latent factor model)隐语义模型 ...

  3. 【知识发现】隐语义模型LFM算法python实现(三)

    http://blog.csdn.net/fjssharpsword/article/details/78257126 基于上篇再优化. 1.回顾LFM原理,可以更好地理解代码 对于一个给定的用户行为 ...

  4. 【知识发现】隐语义模型LFM算法python实现(一)

    1.隐语义模型: 物品:表示为长度为k的向量q(每个分量都表示  物品具有某个特征的程度) 用户兴趣:表示为长度为k的向量p(每个分量都表示  用户对某个特征的喜好程度) 用户u对物品i的兴趣可以表示 ...

  5. 【知识发现】隐语义模型LFM算法python实现(二)

    http://blog.csdn.net/fjssharpsword/article/details/78015956 基于该篇文章中的代码优化,主要是在生成负样例上提高执行速度,代码参考如下: # ...

  6. 隐语义模型LFM(Latent Factor Model)

    隐语义模型LFM(Latent Factor Model)是主题模型中的一种,跟其他主题模型一样,LFM也需要定义若干"主题",来表示个中隐含的关系,这些"主题" ...

  7. 隐语义模型( LFM )

    基于模型的协同过滤思想         ●基本思想                 -用户具有一定的特征,决定着他的偏好选择;                 -物品具有一定的特征,影响着用户需是否选 ...

  8. 推荐算法之隐语义模型(LFM)矩阵分解梯度下降算法实现

    推荐算法之隐语义模型(LFM)矩阵分解梯度下降算法实现 基于协同过滤的推荐一般分为基于近邻的推荐和基于模型的推荐,其中,基于近邻是指预测时直接使用用户已有的偏好数据,通过近邻数据来预测新物品的偏好.而 ...

  9. 推荐系统算法—隐语义模型(LFM)详解

    文章目录 基本思想 数学原理 协同过滤算法主要包括基于用户的协同过滤(User-Based CF).基于物品的协同过滤(Item-Based CF).隐语义模型(Latent Factor Model ...

  10. python实现lfm_【知识发现】隐语义模型(LFM,Latent Factor Model)推荐算法python实现

    1.隐语义模型: 物品:表示为长度为k的向量q(每个分量都表示  物品具有某个特征的程度) 用户兴趣:表示为长度为k的向量p(每个分量都表示  用户对某个特征的喜好程度) 用户u对物品i的兴趣可以表示 ...

最新文章

  1. 快速建立自己的个人网站!五款建站程序
  2. Docker——Docker Compose
  3. poj2182 Lost Cows-暴力
  4. 《此生未完成》痛句摘抄(4)
  5. 05-图像的平滑处理(不同的滤波操作)
  6. 全面介绍Windows内存管理机制及C++内存分配实例(二):内存状态查询
  7. c++编写算法判断二叉树是否为完全二叉树_字节面试官:连这90道LeetCode算法题都不会也来面试?...
  8. VSLAM技术框架详述
  9. shell mysql 取值_shell 脚本中获取mysql多个字段的值
  10. python-scrapy框架学习笔记
  11. Stack with max and min 查找栈中最大最小数
  12. 趣学算法 陈小玉 书中所有问题的实现代码
  13. 现代软件工程_团队项目_阿尔法阶段_第二次会议记录_2017.11.13
  14. mysql8.0怎么设置中文版_MySQL 8.0 版本修改字符编码
  15. DSP2812 RAM不够用的解决方法【转载】
  16. 无线网和网吧服务器,网吧网络使用无线局域网的几个优势所在
  17. 实用计算机理论基础知识试题及答案,计算机基础知识试题库及答案(5)
  18. 智慧街道(乡镇)二三维网格化管理系统
  19. 测试新人如何编写测试用例?一文带你写一个合格的测试用例
  20. 用Java实现杨辉三角

热门文章

  1. VNC远程控制软件,VNC远程控制软件如何实现批量管理服务器
  2. Docker配置阿里云镜像加速器以及镜像的常用操作命令
  3. 苹果cmsv10怎么添加常见的几种广告代码
  4. 调研 微信小程序客服功能
  5. 什么是网站CDN?原理是什么?
  6. Python命令行command not found
  7. 计算机抖音链接,抖音怎么开始电脑直播
  8. 中间代码生成-四元式
  9. 【Python百日基础系列】Day73 - dash实例:系统发育树
  10. 基于WebSocket的网页聊天室