推荐系统导论笔记(五)——Assignment 2

数据描述

数据1:给定一张 20×10 的表,其中,每一行是一个Doc,若该文档包含某个Topic,则对应的单元格为1,否则为0。
数据2:给定两个用户对文档的评分,若用户喜欢某文档,则对应单元格为1,否则为-1,且评分有缺失。

问题描述

构建基本用户档案

使用上述数据构建一个最基本的档案,不用考虑关键字凸显等问题。完成下面两个问题:

  • 预测用户1最喜欢的文档,并给出相应的分数
  • 预测用户2不喜欢的文档

考虑主题权重

直观来考虑,如果一个文档只说明一个问题,另一个文档也说了这个问题,但它同时涉及到其他9个问题,那么对关心这个问题的用户来说,肯定会优先考虑第一个文档。这就是主题权重思想。
用每个文档的主题数的平方根倒数对文档进行加权,并重做上面练习。

考虑IDF权重

对于一些常见的话题,有必要对其进行惩罚,而TF-IDF算法则提供了一个方便的手段。

问题分析

显然,这里的Item就是一个一个的文档,而其对应的向量空间模型就是每个Topic出现与否所组成的向量。对于问题1,只需对向量空间用用户的评分进行加权即可,即若用户喜欢该文档,则权重为1;若不喜欢,则为-1;若没有评分,则为0。最后进行累加即可得出用户偏好档案,上一篇文章给出了较为详细的解释。当我们预测时,即可直接拿文档的Topic向量与用户偏好向量求夹角余弦值即可(课程实验文档中要求用点积)。
对于问题2和问题3,是在问题1的向量空间模型的基础之上再乘以每个Topic对于的权重即可。

编码解决

数据定义与读入

    topics = [] #主题矩阵,即对原表进行按列(Topic)存储
    topicNames = [] #主题名称列表
    userRatings = [] #用户评分矩阵
    IDF=[] #IDF计算结果

    #加载主题矩阵数据,line为一行数据
    def loadTopic(self, line): 
        loadHeadText = len(self.topics) == 0
        for index in range(1, 11):
            if loadHeadText: #若此行是第一行表头数据,则:
                self.topics.append([]) #开辟主题列
                self.topicNames.append(line[index]) #保存主题名称
            else: #否则,说明该行是文档数据
                self.topics[index - 1].append(int(line[index]))#将第index-1个主题的指示变量放入主题矩阵
    #加载用户评分数据,line为一行数据
    def loadUserRating(self, line):
        for index in range(14, 16):
            cell = line[index]
            if cell.startswith('User'):
                self.userRatings.append([])
            elif cell == '':
                self.userRatings[index - 14].append(0)
            else:
                self.userRatings[index - 14].append(int(cell))

问题1

# 生成用户档案
def generateUserProfiles(self, userIndex):
        #得到用户有效评分的文档下标
        validRatingsIndex = [i for i in range(0,len( self.userRatings[userIndex])) if self.userRatings[userIndex][i] != 0]
        #初始化用户档案向量为空
        userProfile = []
        #遍历所有Topic
        for topic in self.topics:
            sum = 0
            #遍历所有有效评分的文档下标
            for index in validRatingsIndex:
                #如果该文档没有涉及到该Topic,则跳过
                if topic[index] == 0:
                    continue
                #否则,将用户评分加权后累加至sum中
                sum = sum + self.userRatings[userIndex][index]*topic[index]
            #得出用户对一个Topic的喜欢程度,并加入用户偏好向量中
            userProfile.append(sum)
        return userProfile
#计算用户对文档偏好程度
 def evaluateDocument(self, documentIndex, userProfile):
        result = 0
        #遍历该文档的Topic,并与用户偏好向量中对应Topic值相乘后累加(即计算点积)
        for topicKey, profileKey in zip(self.topics, userProfile):
            result += topicKey[documentIndex] * profileKey
        return result
#计算某用户最喜欢的文档
 def cloestMatches(self, userProfile):
        cloestScore = -1
        cloestIndex = -1
        #遍历所有文档
        for index in range(0, len(self.topics[0])):
            #用上述函数评价文档
            evaluateScore = self.evaluateDocument(index, userProfile)
            #选择最大者返回
            if evaluateScore > cloestScore:
                cloestScore = evaluateScore
                cloestIndex = index
        return [cloestIndex,cloestScore]
#计算某用户不喜欢的文档
 def farthestMatches(self,userProfile):
        farthestScore=[]
        farthestIndex=[]
        for index in range(0,len(self.topics[0])):            evaluateScore=self.evaluateDocument(index,userProfile)
            if evaluateScore<0:
                farthestScore.append(evaluateScore)
                farthestIndex.append(index)
        return [farthestIndex,farthestScore]

问题2

#用主题个数的平方根修正Topic矩阵
    def refineTopicMatrix(self):
        #遍历所有文档
        for docIndex in range(0,len(self.topics[0])):
            topicOfDoc=0
            #计算文档中涉及到的主题个数
            for topic in self.topics:
                if topic[docIndex]==1:
                    topicOfDoc=topicOfDoc+1
             #计算修正因子
            factor=1/math.sqrt(topicOfDoc)
            #修正该文档
            for topicIndex in range(0,len(self.topics)):
                self.topics[topicIndex][docIndex]=self.topics[topicIndex][docIndex]*factor

问题3

    #计算Topic的IDF
    def __calcuIDF__(self):
        for topic in self.topics:
            validTopicIndex=[index for index in range(0,len(topic)) if topic[index]!=0]
            self.IDF.append(1.0/len(validTopicIndex))
    #用IDF修正预测结果
    def evaluateDocumentByIDF(self, documentIndex, userProfile):
        if len(self.IDF)==0:
            self.__calcuIDF__()
        result = 0
        index=0
        for topicKey, profileKey in zip(self.topics, userProfile):
            result += topicKey[documentIndex] * profileKey*self.IDF[index]
            index += 1
        return result

代码Github

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值