推荐算法:基于物品的协同过滤算法

  • 参考《推荐系统实践》项亮
  • 概念: 基于物品的协同过滤算法,优化算法
  • 对比:用户协同过滤的优缺点
  • python编码实现

1,算法定义

基于用户的协同过滤算法 基于商品的协同过滤算法
适用场景 时效性较强,用户个性化兴趣不太明显的领域 长尾物品丰富,用户个性化需求强烈的领域
用户较少的场合:新闻推荐 物品数远小于用户数的场合:图书、电子商务和电影网站
注重点 兴趣相似的小群体的热点 维系用户的历史兴趣,推荐结果解释性强
用户交互特点 用户有新行为,不一定造成推荐结果的立即变化 推荐结果的实时变化
缺点 计算复杂度 --用户数的增长:近似于平方关系 ,推荐结果解释性不强

推荐算法:基于物品的协同过滤算法

1.1算法优化

推荐算法:基于物品的协同过滤算法
假定<用户-商品数据>如下,可以计算出商品之间的相似度

1::a	1::b	1::c	2::a	
2::b	3::c	4::a	4::d

推荐算法:基于物品的协同过滤算法

2,python实现

第一步: 计算商品之间的相似度(余弦相似度计算公式)

推荐算法:基于物品的协同过滤算法

第二步: 过滤&生成推荐列表,偏好值累加求和

推荐算法:基于物品的协同过滤算法

具体代码如下

# -*-coding:utf-8-*-
import math
#第一步: 计算每个商品之间的相似度
def getMostLikeItemsGroupK(itemUsersDict):
    recommDict = {}
    for i, usersI in itemUsersDict.items():
        for j, usersJ in itemUsersDict.items():
            if i < j:
                if i not in recommDict.keys():
                    recommDict[i] = {}
                if j not in recommDict.keys():
                    recommDict[j] = {}

                # 计算相似度,共同交互商品数
                ratio= 0.0
                setA = set(usersI)
                setB = set(usersJ)
                common = setA.intersection(setB)
                if common.__len__() == 0:
                    ratio= 0.0
                else:
                    bot = math.sqrt(setA.__len__() * setB.__len__())
                    ratio= float(common.__len__()) / bot
                recommDict[i][j] = ratio
                recommDict[j][i] = ratio
    # 对M中每个用的相似度字典按照相似度倒排序
    dict2 = {}
    for k,v in recommDict.items():
        dict2[k] = sorted(v.items(), key=lambda e: e[1], reverse=True)
    #1,物品相似度的未归一化
    #return dict2

    #2,物品相似度的归一化:Karypis 在研究中发现如果将
    def normalItemLike(parmDict):
        dict3 = {}
        for k,v in parmDict.items():
            dict3[k] = []
            mx = v[0][1]
            for t in v:
                dict3[k].append((t[0] , float(t[1]) / mx))
        return dict3
    return normalItemLike(dict2)


##############第二步: 过滤& 生成推荐列表,偏好值累加求和
def recommItemCF(u,K):
    # 准备数据:返回的推荐字典[],用户->商品之间的字典, 商品->用户之间的字典
    recommDict = {}
    userItemsDict = {}
    itemUsersDict = {}
    file = open("/home/wang/IdeaProjects/big124/mypython/a")
    while True :
        line = file.readline()
        if line != '':
            arr = line.replace("\n","").split("::")
            uid = int(arr[0])
            iid = str(arr[1])
            # userItemDict
            if uid in userItemsDict.keys():
                userItemsDict[uid].append(iid)
            else :
                userItemsDict[uid] = [iid]
            # itemUsersDict
            if iid in itemUsersDict.keys():
                itemUsersDict[iid].append(uid)
            else:
                itemUsersDict[iid] = [uid]
        else:
            break ;
    # 1,寻找每个用户history商品:  其他相似的商品组
    dict1 = getMostLikeItemsGroupK(itemUsersDict)

    for i in userItemsDict[u]: # 找到每个用户的历史商品
        itemsK = dict1[i][:K]  #取出k个相似商品
        for j in itemsK:
            if j[0] not in userItemsDict[u]:

                #2, 生成商品推荐列表
                if j[0] not in recommDict.keys():
                    recommDict[j[0]] = 0.0
                recommDict[j[0]] = recommDict[j[0]] + j[1]
    #3,排序商品推荐列表
    return sorted(recommDict.items() , key=lambda e:e[1] ,reverse=True)

###############第三步, 测试结果############################
if __name__ =="__main__":
    recommList=recommItemCF(2,3)
    for i in recommList:
        print i

对比结果:基于商品的协同过滤,物品相似度的归一化后准确率变高

#基于用户的协同过滤:推荐结果
# ('c', 1.533734661597076)
# ('d', 0.8304820237218405)

#基于商品的协同过滤: 物品相似度未归一化,推荐结果
# ('c', 0.9082482904638631)
# ('d', 0.5773502691896258)
#基于商品的协同过滤: 物品相似度的归一化,推荐结果
# ('c', 1.1123724356957945)
# ('d', 0.7071067811865476)