基于内容的电影推荐:物品画像和用户画像

基于内容的电影推荐:物品画像(基于tf-idf)、用户画像及推荐结果

1. 基于内容的推荐算法

基于内容的推荐算法非常直接,它以物品的内容描述信息为依据所做出的的推荐,本质上是基于对物品和用户自身的特征或属性的直接分析和计算。

2. 基于内容的推荐实现步骤

  • 画像构建。画像就是刻画物品或用户的特征。本质上就是给用户或物品贴标签。
    • 物品画像
    • 用户画像

2.1 物品的标签来自哪儿?

  • PCG (Platform and Content Group) 物品画像冷启动

    • 物品自带的属性(物品一产生就具备的):如电影的标题、导演、演员、类型等等;
    • 服务提供方设定的属性服务提供方为物品附加的属性):如短视频话题、微博话题(平台拟定)
  • UGC (User Generated Content) 冷启动问题

    • 用户在享受服务过程中提供的物品的属性:如用户评论内容,微博话题(用户拟定)

根据PGC内容构建的物品画像的可以解决物品的冷启动问题

2.2 基于内容推荐的算法流程

  • 根据PGC/UGC内容构建物品画像
  • 根据用户行为记录生成用户画像
  • 根据用户画像从物品中寻找最匹配的TOP-N物品进行推荐

2.3 物品冷启动处理

  • 根据PGC内容构建物品画像
  • 利用物品画像计算物品间两两相似情况
  • 为每个物品产生TOP-N最相似的物品进行相关推荐:与该商品相似的商品有哪些?与该文章相似的文章有哪些?

一、基于内容的电影推荐:物品画像构建步骤

  • 利用tags.csv中每部电影的标签作为电影的候选关键词
  • 利用TF-IDF计算每部电影的标签的tf-idf值,选取top-N个关键词作为电影画像标签
  • 将电影的分类词直接作为每部电影的画像标签

3.1 基于TF-IDF的特征提取技术

物品画像的特征标签主要都是指的如电影的导演、演员、图书的作者、出版社等结构话的数据,也就是他们的特征提取,尤其是体征向量的计算是比较简单的,如直接给作品的分类定义0或者1的状态。

但另外一些特征,比如电影的内容简介、电影的影评、图书的摘要等文本数据,这些被称为非结构化数据,首先他们本应该也属于物品的一个特征标签,但是这样的特征标签进行量化时,也就是计算它的特征向量时是很难去定义的。

因此这时就需要借助一些自然语言处理、信息检索等技术,将如用户的文本评论或其他文本内容信息的非结构化数据进行量化处理,从而实现更加完善的物品画像/用户画像。

TF-IDF算法便是其中一种在自然语言处理领域中应用比较广泛的一种算法。可用来提取目标文档中,并得到关键词用于计算对于目标文档的权重,并将这些权重组合到一起得到特征向量。

算法原理

TF-IDF自然语言处理领域中计算文档中词或短语的权值的方法,是词频(Term Frequency,TF)和逆转文档频率(Inverse Document Frequency,IDF)的乘积。TF指的是某一个给定的词语在该文件中出现的次数。这个数字通常会被正规化,以防止它偏向长的文件(同一个词语在长文件里可能会比短文件有更高的词频,而不管该词语重要与否)。IDF是一个词语普遍重要性的度量,某一特定词语的IDF,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取对数得到。

TF-IDF算法基于一个这样的假设:若一个词语在目标文档中出现的频率高而在其他文档中出现的频率低,那么这个词语就可以用来区分出目标文档。这个假设需要掌握的有两点:

  • 本文档出现的频率高
  • 其他文档出现的频率低

因此,TF-IDF算法的计算可以分为词频(Term Frequency,TF)和逆转文档频率(Inverse Document Frequency,IDF)两部分,由TF和IDF的乘积来设置文档词语的权重。

TF指的是一个词语在文档中的出现频率。假设文档集包含的文档数为 N N N,文档集中包含关键词 k i k_i ki的文档数为 n i n_i ni f i j f_{ij} fij表示关键词 k i k_i ki在文档 d j d_j dj中出现的次数, f d j f_{dj} fdj表示文档 d j d_j dj中出现的词语总数, k i k_i ki在文档 d j d_j dj中的词频 T F i j TF_{ij} TFij定义为: T F i j = f i j f d j TF_{ij}=\frac {f_{ij}}{f_{dj}} TFij=fdjfij。并且注意,这个数字通常会被正规化,以防止它偏向长的文件(指同一个词语在长文件里可能会比短文件有更高的词频,而不管该词语重要与否)。
IDF是一个词语普遍重要性的度量。表示某一词语在整个文档集中出现的频率,由它计算的结果取对数得到关键词 k i k_i ki的逆文档频率 I D F i IDF_i IDFi I D F i = l o g N n i IDF_i=log\frac {N}{n_i} IDFi=logniN
由TF和IDF计算词语的权重为: w i j = T F i j w_{ij}=TF_{ij} wij=TFij· I D F i = f i j f d j IDF_{i}=\frac {f_{ij}}{f_{dj}} IDFi=fdjfij· l o g N n i log\frac {N}{n_i} logniN

结论:TF-IDF与词语在文档中的出现次数成正比,与该词在整个文档集中的出现次数成反比。

用途:在目标文档中,提取关键词(特征标签)的方法就是将该文档所有词语的TF-IDF计算出来并进行对比,取其中TF-IDF值最大的k个数组成目标文档的特征向量用以表示文档。

注意:文档中存在的停用词(Stop Words),如“是”、“的”之类的,对于文档的中心思想表达没有意义的词,在分词时需要先过滤掉再计算其他词语的TF-IDF值。

算法举例

对于计算影评的TF-IDF,以电影“加勒比海盗:黑珍珠号的诅咒”为例,假设它总共有1000篇影评,其中一篇影评的总词语数为200,其中出现最频繁的词语为“海盗”、“船长”、“自由”,分别是20、15、10次,并且这3个词在所有影评中被提及的次数分别为1000、500、100,就这3个词语作为关键词的顺序计算如下。

  1. 将影评中出现的停用词过滤掉,计算其他词语的词频。以出现最多的三个词为例进行计算如下:

    • “海盗”出现的词频为20/200=0.1
    • “船长”出现的词频为15/200=0.075
    • “自由”出现的词频为10/200=0.05;
  2. 计算词语的逆文档频率如下:

    • “海盗”的IDF为:log(1000/1000)=0
    • “船长”的IDF为:log(1000/500)=0.3
      “自由”的IDF为:log(1000/100)=1
  3. 由1和2计算的结果求出词语的TF-IDF结果,“海盗”为0,“船长”为0.0225,“自由”为0.05。

通过对比可得,该篇影评的关键词排序应为:“自由”、“船长”、“海盗”。把这些词语的TF-IDF值作为它们的权重按照对应的顺序依次排列,就得到这篇影评的特征向量,我们就用这个向量来代表这篇影评,向量中每一个维度的分量大小对应这个属性的重要性。

将总的影评集中所有的影评向量与特定的系数相乘求和,得到这部电影的综合影评向量,与电影的基本属性结合构建视频的物品画像,同理构建用户画像,可采用多种方法计算物品画像和用户画像之间的相似度,为用户做出推荐。

3.2 算法实现

数据集链接:添加链接描述
提取码:yyds

加载数据集
import pandas as pd
import numpy as np

"""
利用tags.csv中每部电影的标签作为电影的候选关键词,利用TF-IDF计算每部电影的标签的tf-idf值,选取Top-N个
关键词作为电影画像标签,并将电影的分类词直接作为每部电影的画像标签。
"""

def get_movie_dataset():
    # 加载基于所有电影的标签,all-tag.csv来自ml-latest数据集中
    _tags = pd.read_csv("tags_all.csv", index_col="movieId", usecols=range(1, 3)).dropna()
    tags = _tags.groupby("movieId").agg(list)

    # 加载电影列表数据集
    movies = pd.read_csv("movies.csv", index_col="movieId")
    # 将类别词分开
    movies["genres"] = movies["genres"].apply(lambda x: x.split("|"))
    # 为每部电影匹配对应的标签数据,如果没有将会使nan
    movies_index = set(movies.index) & set(tags.index)
    new_tags = tags.loc[list(movies_index)]
    ret = movies.join(new_tags)
    """
    构建电影数据集,包含电影id、电影名称、类别、标签四个字段
    如果电影没有标签数据,那么就替换为空列表,map(fun,可迭代对象)
    """
    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", "tags"])
    movie_dataset.set_index("movieId", inplace=True)
    return movie_dataset
基于TF-IDF提取top-N关键词,构建电影画像
from gensim.models import TfidfModel
from gensim.corpora import Dictionary
from pprint import pprint

def create_movie_profile(movie_dataset):
    """
    使用tfidf,分析提取topn关键字
    :param movie_dataset: 电影数据集-电影id,电影名,分类,标签
    :return: 电影画像
    """
    dataset = movie_dataset["tags"].values
    # 根据数据集建立词袋,并统计词频,将所有词放入一个词典,使用索引进行获取
    dct = Dictionary(dataset)
    corpus = [dct.doc2bow(line) for line in dataset]
    # 训练TF-IDF模型,即计算TD-IDF值
    model = TfidfModel(corpus)
    _movie_profile = []
    for i, data in enumerate(movie_dataset.itertuples()):
        mid = data[0]
        title = data[1]
        genres = data[2]
        vector = model[corpus[i]]
        movie_tags = sorted(vector, key=lambda x: x[1], reverse=True)[:30]
        topN_tags_weights = dict(map(lambda x: (dct[x[0]], x[1]), movie_tags))
        # 将类别词添加进去,并设置权重值为1
        for g in genres:
            topN_tags_weights[g] = 1
        topN_tags = [i[0] for i in topN_tags_weights.items()]
        _movie_profile.append((mid, title, topN_tags, topN_tags_weights))
    movie_profile = pd.DataFrame(_movie_profile, columns=["movieId", "title", "profile", "weights"])
    movie_profile.set_index("movieId", inplace=True)
    return movie_profile
倒排索引(根据指定关键词迅速匹配到对应的电影)
def create_inverted_table(movie_profile):
    inverted_table = {}
    for mid, weights in movie_profile["weights"].iteritems():
        for tag, weight in weights.items():
            # 到inverted_table字典中用tag作为key取值,如果取不到返回[]
            _ = inverted_table.get(tag, [])
            _.append((mid, weight))
            inverted_table.setdefault(tag, _)
    return inverted_table

if __name__ == "__main__":
    movieDataset = get_movie_dataset()
    movieProfile = create_movie_profile(movieDataset)
    pprint(movieProfile)
    pprint(create_inverted_table(movieProfile))

二、基于内容的电影推荐:用户画像

1.电影推荐用户画像构建步骤

  • 根据用户的评分历史,结合物品画像,将有观影记录的电影的画像标签作为初始标签反打到用户身上
  • 通过对用户观影标签的次数进行统计,计算用户的每个初始标签的权重值,排序后选取top-n作为用户最终的画像标签

2. 用户画像建立

import pandas as pd
import numpy as np
from gensim.models import TfidfModel

from functools import reduce
import collections

from pprint import pprint

"""
user profile画像建立:
1. 提取用户观看列表
2. 根据观看列表和物品画像为用户匹配关键词,并统计词频
3. 根据词频顺序,最多保留topK个词,设k为50,作为用户的标签
"""


def create_user_profile():
    watch_record = pd.read_csv("ratings.csv", usecols=range(2), dtype={"userId": np.int32, "movieId": np.int32})
    watch_record = watch_record.groupby("userId").agg(list)
    movie_dataset = get_movie_dataset()
    movie_profile = create_movie_profile(movie_dataset)
    user_profile = {}
    for uid, mids in watch_record.itertuples():
        record_movie_profile = movie_profile.loc[list(mids)]
        counter = collections.Counter(reduce(lambda x, y: list(x) + list(y), record_movie_profile["profile"].values))
        # 最感兴趣的前50个词
        interset_words = counter.most_common(50)
        maxcount = interset_words[0][1]
        interset_words = [(w, round(c / maxcount, 4)) for w, c in interset_words]
        user_profile[uid] = interset_words
    return user_profile


if __name__ == "__main__":
    userProfile = create_user_profile()
    pprint(userProfile)

三、为用户产生top-N推荐结果

def give_results(user_profile, inverted_tables):
    # 每位用户推荐的10部电影id以及相应的关键词权重和
    all_result = {}
    for uid, interest_words in user_profile.items():
        result_table = {}
        for interest_word, interest_weight in interest_words:
            related_movies = inverted_tables[interest_word]
            for mid, related_weight in related_movies:
                _ = result_table.get(mid, [])
                _.append(interest_weight)
                result_table.setdefault(mid, _)
        rs_result = map(lambda x: (x[0], round(sum(x[1]), 2)), result_table.items())
        rs_result = sorted(rs_result, key=lambda x: x[1], reverse=True)[:10]
        all_result.setdefault(uid, rs_result)
    return all_result

if __name__ == "__main__":
    movieDataset = get_movie_dataset()
    movieProfile = create_movie_profile(movieDataset)
    invertedTable = create_inverted_table(movieProfile)
    userProfile = create_user_profile()
    rsResult = give_results(userProfile, invertedTable)
    print(rsResult)

四、整体流程回顾

  1. 建立物品画像
  • ①用户打tag②电影的分类值
  • 根据电影的id把tag和分类值合并起来求tf-idf
  • 根据tf-idf的结果为每一部电影筛选出top-n(tf-idf比较大)个关键词
  • 最后得到【电影id,电影名称,电影关键词,关键词权重】[“movieId”, “title”, “profile”, “weights”]
  1. 建立倒排索引
  • 通过关键词找到电影
  • 遍历用户画像的【电影关键词】([“profile”])数据,读取每一个关键词和关键词权重,将关键词作为键,列表作为值,列表中存储着每个电影及该关键词在该部电影中的权重值大小。
  1. 用户画像
  • 查看用户看过哪些电影,在物品画像中找到用户看过的电影的关键词
  • 统计关键词的词频
  • 统计出现最多的前n个关键词作为用户画像的关键词
  1. 根据用户的关键词,找到关键词对应的电影,多个关键词可能对应一个电影【电影id:【关键词1权重,关键词2权重】】
  • 把每一部电影对应的关键词权重求和之后,排序比较高的排在前面推荐给用户。

整体代码

import pandas as pd
import numpy as np
from gensim.models import TfidfModel
from gensim.corpora import Dictionary
from functools import reduce
import collections

"""
利用tags.csv中每部电影的标签作为电影的候选关键词,利用TF-IDF计算每部电影的标签的tf-idf值,选取Top-N个
关键词作为电影画像标签,并将电影的分类词直接作为每部电影的画像标签。
"""


def get_movie_dataset():
    # 加载基于所有电影的标签,all-tag.csv来自ml-latest数据集中
    _tags = pd.read_csv("tags_all.csv", index_col="movieId", usecols=range(1, 3)).dropna()
    tags = _tags.groupby("movieId").agg(list)

    # 加载电影列表数据集
    movies = pd.read_csv("movies.csv", index_col="movieId")
    # 将类别词分开
    movies["genres"] = movies["genres"].apply(lambda x: x.split("|"))
    # 为每部电影匹配对应的标签数据,如果没有将会使nan
    movies_index = set(movies.index) & set(tags.index)
    new_tags = tags.loc[list(movies_index)]
    ret = movies.join(new_tags)
    """
    构建电影数据集,包含电影id、电影名称、类别、标签四个字段
    如果电影没有标签数据,那么就替换为空列表,map(fun,可迭代对象)
    """
    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", "tags"])
    movie_dataset.set_index("movieId", inplace=True)
    return movie_dataset


def create_movie_profile(movie_dataset):
    """
    使用tfidf,分析提取topn关键字
    :param movie_dataset: 电影数据集-电影id,电影名,分类,标签
    :return: 电影画像
    """
    dataset = movie_dataset["tags"].values
    # 根据数据集建立词袋,并统计词频,将所有词放入一个词典,使用索引进行获取
    dct = Dictionary(dataset)
    corpus = [dct.doc2bow(line) for line in dataset]
    # 训练TF-IDF模型,即计算TD-IDF值
    model = TfidfModel(corpus)
    _movie_profile = []
    for i, data in enumerate(movie_dataset.itertuples()):
        mid = data[0]
        title = data[1]
        genres = data[2]
        vector = model[corpus[i]]
        movie_tags = sorted(vector, key=lambda x: x[1], reverse=True)[:30]
        topN_tags_weights = dict(map(lambda x: (dct[x[0]], x[1]), movie_tags))
        # 将类别词添加进去,并设置权重值为1
        for g in genres:
            topN_tags_weights[g] = 1
        topN_tags = [i[0] for i in topN_tags_weights.items()]
        _movie_profile.append((mid, title, topN_tags, topN_tags_weights))
    movie_profile = pd.DataFrame(_movie_profile, columns=["movieId", "title", "profile", "weights"])
    movie_profile.set_index("movieId", inplace=True)
    return movie_profile


def create_inverted_table(movie_profile):
    inverted_table = {}
    for mid, weights in movie_profile["weights"].iteritems():
        for tag, weight in weights.items():
            # 到inverted_table字典中用tag作为key取值,如果取不到返回[]
            _ = inverted_table.get(tag, [])
            _.append((mid, weight))
            inverted_table.setdefault(tag, _)
    return inverted_table


"""
user profile画像建立:
1. 提取用户观看列表
2. 根据观看列表和物品画像为用户匹配关键词,并统计词频
3. 根据词频顺序,最多保留topK个词,设k为50,作为用户的标签
"""


def create_user_profile():
    watch_record = pd.read_csv("ratings.csv", usecols=range(2), dtype={"userId": np.int32, "movieId": np.int32})
    watch_record = watch_record.groupby("userId").agg(list)
    movie_dataset = get_movie_dataset()
    movie_profile = create_movie_profile(movie_dataset)
    user_profile = {}
    for uid, mids in watch_record.itertuples():
        record_movie_profile = movie_profile.loc[list(mids)]
        counter = collections.Counter(reduce(lambda x, y: list(x) + list(y), record_movie_profile["profile"].values))
        # 最感兴趣的前50个词
        interset_words = counter.most_common(50)
        maxcount = interset_words[0][1]
        interset_words = [(w, round(c / maxcount, 4)) for w, c in interset_words]
        user_profile[uid] = interset_words
    return user_profile


def give_results(user_profile, inverted_tables):
    # 每位用户推荐的10部电影id以及相应的关键词权重和
    all_result = {}
    for uid, interest_words in user_profile.items():
        result_table = {}
        for interest_word, interest_weight in interest_words:
            related_movies = inverted_tables[interest_word]
            for mid, related_weight in related_movies:
                _ = result_table.get(mid, [])
                _.append(interest_weight)
                result_table.setdefault(mid, _)
        rs_result = map(lambda x: (x[0], round(sum(x[1]), 2)), result_table.items())
        rs_result = sorted(rs_result, key=lambda x: x[1], reverse=True)[:10]
        all_result.setdefault(uid, rs_result)
    return all_result


if __name__ == "__main__":
    movieDataset = get_movie_dataset()
    movieProfile = create_movie_profile(movieDataset)
    invertedTable = create_inverted_table(movieProfile)
    userProfile = create_user_profile()
    allResult = give_results(userProfile, invertedTable)
    print(allResult)
  • 5
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
基于用户画像电影推荐系统是指利用用户的个人信息、兴趣爱好等特征来为用户推荐适合其口味的电影。Django是一个高效的Web应用开发框架,可以用于构建这样的推荐系统。 首先,我们需要建立用户画像模型。通过用户的注册信息、浏览记录、评分等数据,我们可以对用户的偏好进行分析,包括电影类型、导演、演员、评分等特征。然后,我们可以使用Django框架来构建用户画像模型,并将用户的数据存储在数据库中。 接下来,我们需要建立电影信息模型。这个模型可以包括电影的基本信息、类型、评分、导演、演员等特征。我们可以利用Django框架来构建这个电影信息模型,并将电影数据存储在数据库中。 然后,我们可以使用机器学习算法来匹配用户画像电影信息,从而为用户推荐合适的电影。我们可以使用Django框架来构建推荐系统的算法模型,并通过用户的个人画像特征来实现个性化的电影推荐。 最后,我们可以利用Django框架来构建用户界面,使用户可以通过Web应用来进行电影推荐。用户可以通过输入自己的个人信息,系统可以根据用户的画像特征为其推荐适合的电影。同时,用户可以对推荐电影进行浏览、评分等操作,系统可以根据用户的反馈不断优化推荐结果。 综上所述,基于用户画像电影推荐系统可以通过Django框架来构建用户画像模型、电影信息模型、推荐算法模型和用户界面,从而实现个性化的电影推荐服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值