基于内容的推荐算法
格局用户过去一段时间内喜欢的物品,以及由此推算出来用户偏好,为用户推荐相似物品。其中的“内容”指的便是:用户过去一段时间内喜欢的物品,以及由此推算出来的用户偏好。
算法原理:
基于内容(Content based ,CB)的推荐原理:
向用户推荐所喜欢的Item的相似的Item。
(1)构造Item的特征:
(2) 计算Item内容之间的相似度;
(3)评判用户是否喜欢某个Item。
1.构造Item的特征
在真实应用场景中,往往会用一些属性描述Item的特征,这些属性通常分为以下两种:
.结构化属性:意义明确,其取值固定在某个范围内。
.非结构化属性:特征意义相对不太明确,取值没有什么限制,不可以直接使用。
例子:在电商网站中,Item就是一个商品。例如,Item如果是鞋子,那么尺寸、颜色、品牌等都是结构化属性。
非结构化的数据,需要利用技术手段或人工进行拆分和标注,使之成为结构化数据,才能是使用。
2.计算Item之间的相似度
在确定好Item的特征和用户的偏好模型后,需要计算两个Item之间的相似度。
优化:****使用训练数据得到用户的偏好信息矩阵和物品的特征信息矩阵,然后计算用户对于未进行评分的电影的偏好分,选取前K个推荐给用户。
3.评判用户是否喜欢
在推荐算法中评判用户是否喜欢某个Item就是:利用监督学习或非监督学习的方法,来评判用户喜欢哪些Item,不喜欢那些ITtem,从而为他生成一个偏好模型,对未知的Item进行喜好评判。
结构化数据:
离散型数据:只能采用自然数或整数单位计算的变量。例如,商品属性的唯一编码,虽然是一个整数,但是数值没有意义,只是一个唯一标识。
连续型数据:在一定区间内可以任意取值的变量。例如,商品属性中的长度152.3cm,宽度52.5cm。
注意:使用离散数据和连续型数据需要进行数据归一化处理,实现0-1标准化
基于内容推荐实例
1.实现思路
计算每两个Item内容之间的相似度所产生的算法复杂度是很高的,所以进行优化:首先使用训练数据得到用户的偏好信息矩阵和物品的特征信息矩阵,然后计算用户对于未进行评分的电影的偏好分,选取前K个推荐给用户。
2.构建电影的特征信息矩阵
例如:
A电影的类型为:Animation|Children’s|Comedy
b电影的类型为:Adventure|Children’s|Fantasy
这里假设电影类型为:[Adventure,Animation,Comedy,Children’s,Fantasy]中的一种或几种。对于算法模型来说,这里的类型的名字是没有办法直接使用的,需要将其转化为数字才能够使用。将每条数据的电影类型用一维矩阵表示,则A为[0,1,1,1,0],B为[1,0,0,1,1]。
3.构建用户偏好信息
图表是一个用户-电影评分表(满分5分,空表示未评分)
可以看出张三更喜欢《山楂树之恋》和《芳华》这两部电影。
假设这两部电影都属于青春类型,那么推断出张三喜欢青春类型电影,这样就可以为张三构建偏好信息:
(1)张三的电影平均分:sum=(4+5)/3=4.
(2)根据下面的公式计算出张三对青春电影的偏好程度。
(3)为用户建立偏见矩阵:其中每个元素表示用户对每种电影类型的偏好程度,如张三偏好矩阵为[0.5,…]
4.计算用户与每部电影的距离
用户与每部电影的余弦相似度越高,则说明用户对电影的偏好程度越高。
5.代码实现
1.准备数据(数据格式转换)
为了数据方便这里将data 下面 ml-1m的数据 users.dat movies.dat ratings.dat 转化为CSV文件。
以users.dat为例 开始转换用户数据
def process_user_data(self, file='./data/ml-1m/users.dat'):
if os.path.exists("data/users.csv"):
print("user.csv已经存在")
fp = pd.read_table(file, sep='::', engine='python',names=['UserID', 'Gender', 'Age', 'Occupation', 'Zip-code'])
fp.to_csv('data/users.csv', index=False)
2.获取item的特征信息矩阵
# 获取item的特征信息矩阵
def prepare_item_profile(self,file='data/movies.csv'):
items=pd.read_csv(file)
item_ids=set(items["MovieID"].values) #MovieID{1,2,3,4,.....}
self.item_dict={
}#{1: ['Animation', "Children's", 'Comedy'],2:['Adventure', "Children's", 'Fantasy'],..}#电影ID 和对应的电影类型
genres_all=list()
# 将每个电影的类型放在item_dict中
for item in item_ids:
genres=items[items["MovieID"]==item]["Genres"].values[0].split("|") #['Animation', "Children's", 'Comedy']