推荐系统项目基础(七)基于内容的推荐系统

推荐系统项目基础(七)基于内容的推荐系统

简介

基于内容的推荐比较直接,以物品的内容描述信息作为依据来进行推荐,本质上是基于物品和用户自身的特征进行分析和计算

基于内容的推荐实现步骤

1、画像构建

画像的字段一般有100+以上。

用户画像

一般来自于用户的历史信息或者个人信息,例如用户的性别,年龄,消费水平,已经购买物品的记录等。还可以包括活跃程度,风控维度。

物品画像

与物品相关的信息,例如分类信息,标题,电影主演等。一般从两个方面获取:

  1. PGC 用户画像-冷启动
    • 物品自带的属性(物品一产生就具备的):如电影的标题,导演,演员等。
    • 服务方提供的属性,如短视频话题,微博话题等
    • 爬虫等
  2. 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)

上一篇:mysqld_multi实现多主一从同步


下一篇:Elasticsearch之文档操作