推荐系统项目基础(七)基于内容的推荐系统
简介
基于内容的推荐比较直接,以物品的内容描述信息作为依据来进行推荐,本质上是基于物品和用户自身的特征进行分析和计算
基于内容的推荐实现步骤
1、画像构建
画像的字段一般有100+以上。
用户画像
一般来自于用户的历史信息或者个人信息,例如用户的性别,年龄,消费水平,已经购买物品的记录等。还可以包括活跃程度,风控维度。
物品画像
与物品相关的信息,例如分类信息,标题,电影主演等。一般从两个方面获取:
- PGC 用户画像-冷启动
- 物品自带的属性(物品一产生就具备的):如电影的标题,导演,演员等。
- 服务方提供的属性,如短视频话题,微博话题等
- 爬虫等
- UGC 用户产生的内容
- 用户再进行服务时提供的属性,用户的评论内容,用户拟定的话题(微博话题)
2、匹配用户画像与物品画像
根据用户匹配最相近的物品进行推荐
基于TF-IDF进行数据的推荐
推荐流程:
-
1、建立物品画像
- 筛选出所有物品与其对应的tag列表
- 根据TF-IDF求解出每个电影的topN(TFIDF 比较大的关键词)
- 建立【电影ID,关键词,关键词权重】的DataFrame
-
2、建立倒排索引
- 通过关键词可以找到对应的电影
- 遍历数据,读取每个关键词,用关键词对应的电影id作为value并保存。
-
3、建立用户画像
- 根据用户的评分列表获取到用户都有评分哪些电影,根据这些电影提取关键词
- 根据这些关键词作为用户的标签进行统计,将最常见的标签作为用户的画像关键词。
-
进行推荐
- 根据用户的关键词进行查找,
代码:
from functools import reduce
import pandas as pd
import numpy as np
from gensim.models import TfidfModel
from gensim.corpora import Dictionary
from collections import Counter
if __name__ == '__main__':
dtype = [("userId", np.int32), ("movieId", np.int32), ("tag", np.str), ("timestamp", np.int64)]
tags_df = pd.read_csv("../ml-25m/tags.csv", usecols=range(1, 3)).dropna()
movies_df = pd.read_csv("../ml-25m/movies.csv", index_col="movieId")
tags = tags_df.groupby("movieId").agg(list)
movies_df.loc[:, "genres"] = movies_df.loc[:, "genres"].apply(lambda x: x.split("|"))
# tags_df = tags_df.sort_values(by="movieId")
all_movie_id_set = set(list(movies_df.index)) & set(tags.index)
list(all_movie_id_set)
new_tags = tags.loc[list(all_movie_id_set)]
ret = movies_df.join(new_tags)
ret1 = ret.loc[ret.index == 1]
movie_dataset = pd.DataFrame(
map(lambda x: (x[0], x[1], x[2], x[2] + x[3]) if x[3] is not np.nan else (x[0], x[1], x[2], []),
ret.itertuples()), columns=["movieId", "title", "genres", "tag"])
# 词袋创建
dct = Dictionary(movie_dataset.loc[:, "tag"])
tag_dataset = movie_dataset.loc[:, "tag"]
# 将文章中的词转化为列表,元素为【单词id,词频】
corpus = [dct.doc2bow(line) for line in tag_dataset]
# 计算所有的tfidf值,根据每一列的词对应的ID以及ID对应的TFIDF值 ,计算出的数据为【ID,TFIDF值】
model = TfidfModel(corpus)
movie_profile = {}
vector = []
# for i, mid in enumerate(movie_dataset.index):
# vector = model[corpus[i]]
# movie_tags = sorted(vector, key=lambda x: x[1], reverse=True)[:30]
# movie_profile[mid] = dict(map(lambda x: (dct[x[0]], x[1]), movie_tags))
_movie_profile = []
topN_tags_weight = {}
for i, data in enumerate(movie_dataset.itertuples()):
mid = data[1]
title = data[2]
genres = data[3]
# 获取每一个电影的tf,idf值
vector = model[corpus[data[0]]]
# 取出值最大的30个
movie_tags = sorted(vector, key=lambda x: x[1], reverse=True)[:30]
#
topN_tags_weight = dict(map(lambda x: (dct[x[0]], x[1]), movie_tags))
# 将类别词加入,设置权重为1
for g in genres:
print(g)
topN_tags_weight[g] = 1.0
topN_tags = [i[0] for i in topN_tags_weight.items()]
_movie_profile.append((mid, title, topN_tags, topN_tags_weight))
#
movie_profile = pd.DataFrame(_movie_profile, columns=["movieId", "titleId", "profile", "weights"])
movie_profile.set_index("movieId", inplace=True)
# 建立倒排列表,可以通过标签获取到对应的电影
invert_table = dict()
for mid, weight in movie_profile["weights"].iteritems():
for item in weight.items():
tag = item[0]
movie_id_list = invert_table.get(tag, list())
# 将整个元组作为元素append
movie_id_list.append(mid)
invert_table.setdefault(tag, movie_id_list)
# 获取用户的画像
dtype = [("userId", np.int32), ("movieId", np.int32), ("tag", np.str), ("timestamp", np.int64)]
ratings_df = pd.read_csv("./../ml-25m/ratings.csv", usecols=range(0, 2), dtype=dtype).groupby("userId").agg(list)
user_profile = {}
for user_id, movie_id in ratings_df.iloc[1:3].itertuples():
record_movie_list = movie_profile.loc[movie_id]
counter = Counter(reduce(lambda x, y: list(x) + list(y), record_movie_list["profile"].values))
interested_word = counter.most_common(50)
maxcount = interested_word[0][1]
interested_word = [(w,round(c/maxcount,4)) for w,c in interested_word]
user_profile.setdefault(user_id, interested_word)
基于Word2Vec的推荐系统
# 训练词向量,找到跟一个词最相近的几个词
sentences = list(movie_profile["profile"].values)
model = gensim.models.Word2Vec(sentences, window=3, min_count=1, iter=20)
model.wv.most_similar(positive=['Action'], topn=10)
# 寻找文档向量
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
documents = [TaggedDocument(words, [movieid]) for words, movieid in movie_profile["profile"].iteritems()]
# 训练模型的并保存Doc2Vec表示通过一个向量来表示一篇文章,一篇文章对应了一个电影
# 训练的相似度,代表了电影的相似度
model = Doc2Vec(documents,vector_size=100,window=3,min_count=1,workers=4,epochs=20)
# 传入6号电影的标签
words = movie_profile["profile"].loc[6]
# 计算向量
inferred_vector = model.infer_vector(words)
# 通过doc2vecs找到传入向量最详尽的n个向量,每个向量代表一个电影
sims = model.docvecs.most_similar([inferred_vector], topn=10)