推荐系统之隐语义模型(LFM)

一 基本概念

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

对于UserCF,我们可以先计算和目标用户兴趣相似的用户,之后再根据计算出来的用户喜欢的物品给目标用户推荐物品。

而ItemCF,我们可以根据目标用户喜欢的物品,寻找和这些物品相似的物品,再推荐给用户。

我们还有一种方法,先对所有的物品进行分类,再根据用户的兴趣分类给用户推荐该分类中的物品,LFM就是用来实现这种方法。

如果要实现最后一种方法,需要解决以下的问题:

(1)给物品分类

(2)确定用户兴趣属于哪些类及感兴趣程度

(3)对于用户感兴趣的类,如何推荐物品给用户

对分类,很容易想到人工对物品进行分类,但是人工分类是一种很主观的事情,比如一部电影用户可能因为这是喜剧片去看了,但也可能因为他是周星驰主演的看了,也有可能因为这是一部属于西游类型的电影,不同的人可以得到不同的分类。

而且对于物品分类的粒度很难控制,究竟需要把物品细分到个程度,比如一本线性代数,可以分类到数学中,也可以分类到高等数学,甚至根据线性代数主要适用的领域再一次细分,但对于非专业领域的人来说,想要对这样的物品进行小粒度细分无疑是一件费力不讨好的事情。

而且一个物品属于某个类,但是这个物品相比其他物品,是否更加符合这个类呢?这也是很难人工确定的事情。

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

对于某个物品是否属与一个类,完全由用户的行为确定,我们假设两个物品同时被许多用户喜欢,那么这两个物品就有很大的几率属于同一个类。

而某个物品在类所占的权重,也完全可以由计算得出。

以下公式便是隐语义模型计算用户u对物品i兴趣的公式:

其中,p为用户兴趣和第k个隐类的关系,q为第k个隐类和物品i的关系,F为隐类的数量,r便是用户对物品的兴趣度。

接下的问题便是如何计算这两个参数p和q了,对于这种线性模型的计算方法,这里使用的是梯度下降法,详细的推导过程可以看一下我的另一篇博客。大概的思路便是使用一个数据集,包括用户喜欢的物品和不喜欢的物品,根据这个数据集来计算p和q。

下面给出公式,对于正样本,我们规定r=1,负样本r=0:

后面的lambda是为了防止过拟合的正则化项,下面给出python代码。

二 实战

我们这里依旧使用movielen的1M数据集

1 首先我们需要计算包含用户喜欢与不喜欢物品的数据集,采用不计算评分的隐反馈方式,只要用户评过分均认为用户对该物品有兴趣,而没有评分则可能没兴趣。

(1)用户正反馈数据

[python] view plain copy

def getUserPositiveItem(frame, userID):  

'''''

    获取用户正反馈物品:用户评分过的物品

    :param frame: ratings数据

    :param userID: 用户ID

    :return: 正反馈物品

    '''  

series = frame[frame['UserID'] == userID]['MovieID']  

    positiveItemList = list(series.values)  

return positiveItemList  

(2)用户负反馈数据,根据用户无评分物品进行推荐,越热门的物品用户却没有进行过评分,认为用户越有可能对这物品没有兴趣

[python] view plain copy

def getUserNegativeItem(frame, userID):  

'''''

    获取用户负反馈物品:热门但是用户没有进行过评分 与正反馈数量相等

    :param frame: ratings数据

    :param userID:用户ID

    :return: 负反馈物品

    '''  

userItemlist = list(set(frame[frame['UserID'] == userID]['MovieID']))                       #用户评分过的物品  

otherItemList = [itemfor item in set(frame['MovieID'].values) if item not in userItemlist] #用户没有评分的物品  

itemCount = [len(frame[frame['MovieID'] == item]['UserID']) for item in otherItemList]      #物品热门程度  

    series = pd.Series(itemCount, index=otherItemList)  

series = series.sort_values(ascending=False)[:len(userItemlist)]                            #获取正反馈物品数量的负反馈物品  

    negativeItemList = list(series.index)  

return negativeItemList  

2 接下来是初始化参数p和q,这里我们采用随机初始化的方式,将p和q取值在[0,1]之间:

[python] view plain copy

def initPara(userID, itemID, classCount):  

'''''

    初始化参数q,p矩阵, 随机

    :param userCount:用户ID

    :param itemCount:物品ID

    :param classCount: 隐类数量

    :return: 参数p,q

    '''  

    arrayp = np.random.rand(len(userID), classCount)  

    arrayq = np.random.rand(classCount, len(itemID))  

p = pd.DataFrame(arrayp, columns=range(0,classCount), index=userID)  

q = pd.DataFrame(arrayq, columns=itemID, index=range(0,classCount))  

return p,q  

3 定义函数计算用户对物品的兴趣

[python] view plain copy

def lfmPredict(p, q, userID, itemID):  

'''''

    利用参数p,q预测目标用户对目标物品的兴趣度

    :param p: 用户兴趣和隐类的关系

    :param q: 隐类和物品的关系

    :param userID: 目标用户

    :param itemID: 目标物品

    :return: 预测兴趣度

    '''  

    p = np.mat(p.ix[userID].values)  

    q = np.mat(q[itemID].values).T  

    r = (p * q).sum()  

    r = sigmod(r)  

return r  


def sigmod(x):  

'''''

    单位阶跃函数,将兴趣度限定在[0,1]范围内

    :param x: 兴趣度

    :return: 兴趣度

    '''  

y =1.0/(1+exp(-x))  

return y  

4 隐语义模型,利用梯度下降迭代计算参数p和q

[python] view plain copy

def latenFactorModel(frame, classCount, iterCount, alpha, lamda):  

'''''

    隐语义模型计算参数p,q

    :param frame: 源数据

    :param classCount: 隐类数量

    :param iterCount: 迭代次数

    :param alpha: 步长

    :param lamda: 正则化参数

    :return: 参数p,q

    '''  

    p, q, userItem = initModel(frame, classCount)  

for step in range(0, iterCount):  

for user in userItem:  

for userID, samples in user.items():  

for itemID, rui in samples.items():  

                    eui = rui - lfmPredict(p, q, userID, itemID)  

for f in range(0, classCount):  

print('step %d user %d class %d' % (step, userID, f))  

                        p[f][userID] += alpha * (eui * q[itemID][f] - lamda * p[f][userID])  

                        q[itemID][f] += alpha * (eui * p[f][userID] - lamda * q[itemID][f])  

alpha *=0.9  

return p, q  

5 最后根据计算出来的p和q参数对用户进行物品的推荐

[python] view plain copy

def recommend(frame, userID, p, q, TopN=10):  

'''''

    推荐TopN个物品给目标用户

    :param frame: 源数据

    :param userID: 目标用户

    :param p: 用户兴趣和隐类的关系

    :param q: 隐类和物品的关系

    :param TopN: 推荐数量

    :return: 推荐物品

    '''  

userItemlist = list(set(frame[frame['UserID'] == userID]['MovieID']))  

otherItemList = [itemfor item in set(frame['MovieID'].values) if item not in userItemlist]  

predictList = [lfmPredict(p, q, userID, itemID)for itemID in otherItemList]  

    series = pd.Series(predictList, index=otherItemList)  

series = series.sort_values(ascending=False)[:TopN]  

return series  

隐语义模型介绍就到这里了,完整的项目代码可以到我的个人github上面查看:https://github.com/lpty


转载自:http://blog.csdn.net/sinat_33741547/article/details/52976391

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,306评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,657评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,928评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,688评论 0 220
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,105评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,024评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,159评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,937评论 0 212
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,689评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,851评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,325评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,651评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,364评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,192评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,985评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,154评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,955评论 2 279

推荐阅读更多精彩内容