美文网首页
Latent Factor Model(LFM)隐语义模型

Latent Factor Model(LFM)隐语义模型

作者: e883567fee09 | 来源:发表于2017-10-17 16:33 被阅读0次

    隐语义模型为推荐系统中很常见的使用机器学习的思想构建的模型,本文章参考http://blog.csdn.net/sinat_33741547/article/details/52976391以及项亮的《推荐系统实战》中部分理论知识。
    干货奉上,简单的讲隐语义模型就是构建一个物品与用户关系的超大矩阵,如下图1所示:

    图1

    上图中R为用户与物品的历史关系矩阵,其中R11···R34等等为用户对物品的兴趣度。

    对于隐性反馈数据,用户只要浏览了该产品,我们就可以简单的认为用户对该产品的兴趣度为1,也就是Rxx为1,否则为0。

    对于显性反馈数据,比如用户对物品的评分为1-5分,那么Rxx的取值范围为1-5,对于显性数据,也可以将其归一化后进行计算。

    由上述分析,R矩阵即为机器学习中所说label(结果集)。如图1所示P,Q矩阵的乘积得到了R,那么我们需要设置P、Q中的class个数。设置了class个数为n,那么矩阵P、Q的大小就是已知的,我们可以随机初始化P、Q的值。由图一可知,Rxy = Pxn * Qny(矩阵相乘),对于Rxy,我们是已知的,那么我们训练的目标就是要得到一个合适的P、Q。使得他们的乘积结果等于Rxy,其实这就类似一个简单的线性回归的模型。对于隐形数据来说,初始化的P、Q矩阵相乘得到的结果带入sigmod函数计算出结果在0-1之间,肯定与R有差异,那么我们就通过梯度下降来优化模型参数,加入正则化参数来避免过拟合。

    对于如何筛选训练数据,可以参考文章开头所提及的文章。简单的讲正样本就是用户产生过兴趣或行为的物品,负样本就是用户未产生兴趣或行为的物品。

    通过上述内容我们可以确定初始化模型我们需要设置以下参数:正负样本比例、隐特征个数(class个数)、学习率、正则化参数、迭代次数。其中学习率要根据迭代的次数的增加而适当的降低,代码中已经有所体现,简单的讲就是更新参数时步子迈得不要太大,应当适时的降低。
    如下为LFM模型代码,代码中不考虑效率问题:

    # -*- coding: utf-8 -*-
    """
    Created on Thu Aug 03 16:09:09 2017
    
    @author: hdx
    """
    
    import pandas as pd
    import numpy as np
    import random
    
    
    class LatentFactorModel(object):
        def __init__(self, ratio, f, learning_rate, c, iteration_counts):
            """
            :param ratio: 正负样本比例
            :param f: 隐特征个数
            :param learning_rate: 学习率
            :param c: 正则化参数
            :param iteration_counts : 迭代次数
            """
            self._ratio = ratio
            self._f = f
            self._learning_rate = learning_rate
            self._c = c
            self._iteration_counts = iteration_counts
    
        def _getData(self):
            """
            data中每个tuple的第三项数据不用管,也就是pandas中dataframe的status列不用理会
            :return: 商品浏览记录总数据
            """
            data = [('a',101,1),('a',111,1),('a',141,0), 
                    ('b',111,0),('b',151,1),('b',131,0), 
                    ('c',121,1),('c',161,0),('c',141,0), 
                    ('d',111,1),('d',161,1),('d',141,0),('d',121,0), 
                    ('e',131,1),('e',151,0),('e',171,0),
                    ('f',181,0),('f',191,1),
                    ('g',101,1),('g',201,0)]
            data = pd.DataFrame(np.array(data))
            data.columns = ['openid', 'productid', 'status']
            return data
    
        def _getUserPositiveItem(self, data, openid):
            """
            :param data: 总数据
            :param openid: 用户id
            :return: 正反馈物品
            """
            positiveItemList = data[data['openid'] == openid]['productid'].unique().tolist()
            return positiveItemList
    
        def _getUserNegativeItem(self, data, openid):
            """
            :param data: 总数据
            :param openid: 用户id
            :return: 未产生行为的物品
            """
            otherItemList = list(set(data['productid'].unique().tolist()) - set(self._getUserPositiveItem(data, openid)))
            negativeItemList = random.sample(otherItemList, self._ratio * len(self._getUserPositiveItem(data, openid)))
            return negativeItemList
    
        def _initUserItem(self, data):
            userItem = {}
            for openid in data['openid'].unique():
                positiveItem = self._getUserPositiveItem(data, openid)
                negativeItem = self._getUserNegativeItem(data, openid)
                itemDict = {}
                for item in positiveItem: itemDict[item] = 1
                for item in negativeItem: itemDict[item] = 0
                userItem[openid] = itemDict
            return userItem
    
    
        def _initParams(self, data):
            """
            初始化参数
            :param data: 总数据
            :return: p\q参数
            """
            p = np.random.rand(len(data['openid'].unique().tolist()), self._f)
            q = np.random.rand(self._f, len(data['productid'].unique().tolist()))
            userItem = self._initUserItem(data)
            p = pd.DataFrame(p, columns=range(0, self._f), index=data['openid'].unique().tolist())
            q = pd.DataFrame(q, columns=data['productid'].unique().tolist(), index=range(0, self._f))
            return p, q, userItem
    
        def sigmod(self, x):
            """
            单位阶跃函数,将兴趣度限定在[0,1]范围内
            :param x: 兴趣度
            :return: 兴趣度
            """
            y = 1.0 / (1 + np.exp(-x))
            return y
    
        def predict(self, p, q, openid, productid):
            """
            利用参数p, q预测目标用户对目标物品的兴趣度
            """
            p = np.mat(p.ix[openid].values)
            q = np.mat(q[productid].values).T
            r = (p * q).sum()
            r = self.sigmod(r)
            return r
    
        def train(self):
            data = self._getData()
            p, q, userItem = self._initParams(data)
            for step in xrange(1, self._iteration_counts+1):
                for openid, samples in userItem.items():
                    for productid, r in samples.items():
                        loss = r - self.predict(p, q, openid, productid)
                        for f in xrange(0, self._f):
                            print('step %d openid %s class %d loss %f' % (step, openid, f, np.abs(loss)))
                            p[f][openid] += self._learning_rate * (loss * q[productid][f] - self._c * p[f][openid])
                            q[productid][f] += self._learning_rate * (loss * p[f][openid] - self._c * q[productid][f])
                if step % 5 == 0:
                    self._learning_rate *= 0.9
            return p, q, data
    
        def recommend(self, data, p, q):
            rank = []
            for openid in data['openid'].unique():
                for productid in data['productid'].unique():
                    rank.append((openid, productid, self.predict(p, q, openid, productid)))
            return rank
    

    上述代码构建了一个LFM模型,下面为创建模型,训练模型,使用模型。

    lfm = LatentFactorModel(1,5,0.5,0.01,200)
    p,q,data = lfm.train()
    lfm.recommend(data,p,q)
    

    以上代码还可以优化性能,进行大工程计算时还是得使用矢量化计算提高效率。
    最后贴一个本人的机器学习github地址 https://github.com/huangdaoxu/Machine_Learning

    如需转载,请说明出处。

    相关文章

      网友评论

          本文标题:Latent Factor Model(LFM)隐语义模型

          本文链接:https://www.haomeiwen.com/subject/uxbduxtx.html