基于内容的推荐系统

来自CloudWiki
Cloud17讨论 | 贡献2020年9月19日 (六) 08:00的版本
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳转至: 导航搜索

什么是基于内容的推荐

基于内容的推荐算法(Content-based Recommendations, CB)也是一种工业界应用比较广的一种推荐算法。由于协同过滤推荐算法中仅仅基于用户对于商品的评分进行推荐,所以有可能出现冷启动的问题,如果可以根据物品的特性和用户的特殊偏好等特征属性进行比较直观的推荐就可以解决这个冷启动的问题。

CB算法虽然需要依赖物品和用户偏好的额外信息,但是不需要太多的用户评分或者群体记录,也就是说,就是只有一个用户也可以完成推荐功能,产生一个物品推荐列表。

CB算法的初始设计的目标是推荐有意思的文本文档,现阶段也会将该算法应用到其它推荐领域中。

基于内容的推荐算法结构

CB算法主要包含三个步骤:

特征抽取

1. Item Representation: 为每一个item抽取一些特征属性出来,也就是结构化物品的描述操作,对应的处理过程叫做: Content Analyzer(内容分析);

特征学习

2. Profile Learning:利用一个用户过去喜欢(不喜欢)的item特征数据,来学习该用户的喜好特征(profile);对应的处理过程叫做:Profile Learning(特征学习);

物品推荐

3. Recommendation Generation:通过比较上一步得到的用户profile于特征item的特征,为此用户推荐一组相关性最大的item即可;对应的处理过程叫做:Filtering Component(过滤组件)。

基于内容推荐系统的算法原理

将物品特征表征为向量

例子:电影构造物品画像

Bd20-6-37.png

问题:如何把这些特征表示成向量?

离散型变量——通过独热编码的形式来转换成向量

数值型变量——直接使用等等

问题:那文本类的特征如何处理呢? 比如电影的描述。

答:设计NLP领域。我们可以直接使用TF-IDF的方式即可以转换成向量的形式。当然我们也可以使用Word2Vec等技术来表示成向量的。

向量表示特征

例子:特征也叫作画像。



相似度计算

那又如何计算相似度呢?

答:转换成了向量的形式,计算两个向量之间的相似度。最经典的评估方法就是使用余弦相似度。

计算相似度公式(常用余弦相似度)

问题:如何使用余弦相似度来计算每两个物品之间的相似度。

Bd20-6-35.png

相似度排序推荐

Bd20-6-36.png

冷启动

解决冷启动问题总结:

1、 推荐目前热度最高的商品;

2、让用户自己标记一下自己喜欢的商品类型(APP新用户)

参考文档:https://zhuanlan.zhihu.com/p/98295397

项目实战

生成数据

# coding: utf-8 -*-
 
"""
    Author: maxin
    
"""

import json

import json

#模拟商品们 有5个维度,用基于内容的算法比较他们的相似度
'''
dt={"item1":{"class1":1,"class2":2,"class3":3,"site":4,"nation":5},
    "item2":{"class1":1,"class2":2,"class3":3,"site":4,"nation":5}};
'''
dt={"1":[1,2,3,4,5],
    "2":[2,3,4,5,6],
    "3":[5,5,5,5,5]}

with open('user_profile.json', 'w') as fp:
    json.dump(dt, fp) #写入文件

with open('item_profile.json', 'w') as fp:
    json.dump(dt, fp) #写入文件

load_dict ={}
with open('user_profile.json', 'r') as fp:
    load_dict = json.load(fp)  #从文件中读取
    print(load_dict)

for k in load_dict:
    print(k,load_dict.get(k))


计算商品相似度

# coding: utf-8 -*-
 
"""
    Author: Alan
    Desc:
         编写一个基于内容推荐算法的电影推荐系统(训练模型)
"""
import json
import pandas as pd
import numpy as np
import math
import random
 
class CBRecommend:
    # 加载dataProcessing.py中预处理的数据
    def __init__(self,K):
        # 给用户推荐的item个数
        self.K = K
        self.item_profile=json.load(open("item_profile.json","r"))
        self.user_profile=json.load(open("user_profile.json","r"))
 
    # 获取用户未进行评分的item列表
    def get_none_score_item(self,user):#user是用户id号
        items=pd.read_csv("movies.csv")["MovieID"].values
        data = pd.read_csv("ratings.csv")
        have_score_items=data[data["UserID"]==user]["MovieID"].values
        none_score_items=set(items)-set(have_score_items)
        #return none_score_items
        return set(items)
 
    # 获取用户对item的喜好程度(余弦相似度)
    def cosUI(self,user,item):
        Uia=sum(
            np.array(self.user_profile[str(user)])#这里的user是用户id号
            *
            np.array(self.item_profile[str(item)])
        )
        Ua=math.sqrt( sum( [ math.pow(one,2) for one in self.user_profile[str(user)]] ) )
        Ia=math.sqrt( sum( [ math.pow(one,2) for one in self.item_profile[str(item)]] ) )
        return  Uia / (Ua * Ia)
    
    # 获取列表的第三个元素
    def takeSecond(elem):
        return elem[2]
    
    # 为用户进行电影推荐
    def recommend(self,user):
        user_result={}
        item_list=self.get_none_score_item(user)
        print(item_list)

        #商品关系矩阵
        user_result = [[0 for item in item_list] for j in item_list]
        print(user_result)

        #计算商品之间的余弦值
        for item in item_list:
            for j in item_list:
                user_result[item-1][j-1]=tuple([item,j,self.cosUI(item,j)])
                print(item,j,self.cosUI(item,j))

        print(user_result)

        #每一行代表其他商品 与某个商品的相似度
        #这里对相似度进行排序
        for item in item_list:
            u =user_result[item-1]
            u.sort(key= lambda k:k[2], reverse=True)
            print("排序后:"+str(u))
            
        '''
        if self.K is None:
            result = sorted(
                user_result.items(), key= lambda k:k[1], reverse=True
            )
        else:
            result = sorted(
                user_result.items(), key= lambda k:k[1], reverse=True
            )[:self.K]
        print(result)
        '''
 
    # 推荐系统效果评估
    def evaluate(self):
        evas=[]
        data = pd.read_csv("ratings.csv")
        # 随机选取20个用户进行效果评估
        for user in random.sample([one for one in range(1,6040)], 20):
            have_score_items=data[data["UserID"] == user]["MovieID"].values
            items=pd.read_csv("data/movies.csv")["MovieID"].values
 
            user_result={}
            for item in items:
                user_result[item]=self.cosUI(user,item)
            results = sorted(
                user_result.items(), key=lambda k: k[1], reverse=True
            )[:len(have_score_items)]
            rec_items=[]
            for one in results:
                rec_items.append(one[0])
            eva = len(set(rec_items) & set(have_score_items)) / len(have_score_items)
            evas.append( eva )
        return sum(evas) / len(evas)
 
 
if __name__=="__main__":
    cb=CBRecommend(K=10)
    cb.recommend(1)#1代表用户的id
    #print(cb.evaluate())

参考文档:https://blog.csdn.net/weixin_37736146/article/details/96705138