赞
踩
1、简介
基于内容的推荐方法是非常直接的,它以物品的内容描述信息为依据来做出的推荐,本质上是基于对物品和用户自身的特征或属性的直接分析和计算。
例如,假设已知电影A是一部喜剧,而恰巧我们得知某个用户喜欢看喜剧电影,那么我们基于这样的已知信息,就可以将电影A推荐给该用户。
基于内容的推荐实现步骤
画像构建。顾名思义,画像就是刻画物品或用户的特征。本质上就是给用户或物品贴标签。
问题:物品的标签来自哪儿?
a)PGC 物品画像--冷启动
根据PGC内容构建的物品画像可以解决物品的冷启动问题
b)UGC 冷启动问题
基于内容推荐的算法流程
物品冷启动处理
物品画像构建步骤:
1、基于TF-IDF的特征提取技术
1)TF-IDF介绍
上面提到,物品画像的特征标签主要都是指的如电影、导演、演员、图书的作者、出版社等结构化的数据,也就是他们的特征提取,尤其是体征向量的计算是比较简单的,如直接给作品的分类定义为0或1的状态。
但另外一些特征,比如电影的内容简介、电影的影评、图书的摘要等文本数据,这些被称为非结构化数据,首先他们本应该也属于物品的一个特征标签,但是这样的特征标签进行量化时,也就是计算他的特征向量时是很难去定义的。
因此这时就需要借助一些自然语言处理、信息检索等技术,如将用户的文本评论或其他文本内容信息的非结构化数据进行量化处理,从而实现更加完善的物品画像或用户画像。
TF-IDF算法便是其中一种在自然语言处理领域中应用比较广泛的一种算法。可用来提取目标文档,并得到关键词用于计算对于目标文档权重,并将这些权重组合到一起得到特征向量。
2)算法原理
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-IDF与词语在文档中的出现次数成正比,与该词在整个文档集中的出现次数成反比。
用途:在目标文档中,提取关键词(特征标签)的方法就是将该文档所有词语的TF-IDF计算出来并进行对比,取其中TF-IDF值最大的k个数组成目标文档的特征向量用以表示文档。
注意:文档中存在的停用词(Stop Words),如“是”、“的”之类,对于文档的中心思想表达没有意义的词,在分词时需要先过滤掉再计算其他词语的TF-IDF值。
2、算法实现
2.1、加载数据集并做处理
- import pandas as pd
- import numpy as np
-
- '''
- - 利用tags.csv中每部电影的标签作为电影的候选关键词
- - 利用TF·IDF计算每部电影的标签的tfidf值,选取TOP-N个关键词作为电影画像标签
- - 并将电影的分类词直接作为每部电影的画像标签
- '''
-
- def get_movie_dataset():
- # 加载基于所有电影的标签
- _tags = pd.read_csv("./all-tags.csv",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) # join按index进行组合,列方向
-
- # 加载电影数据集,包含电影Id、电影名称、类别、标签四个字段
- # 如果电影没有标签数据,那么就替换为空列表 map(fun,可迭代对象)
- movie_dataset = pd.DataFrame(
- list(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
-
2.2、基于TF-IDF提取TOP-N关键词并加入电影类别,构建电影画像
- def create_movie_profile(movie_dataset):
- '''
- 使用tfidf,分析提取topn关键词
- :param movie_dataset:包含电影Id、电影名称、类别、标签四个字段
- :return:
- '''
- dataset = movie_dataset['tags'].values
- from gensim.corpora import Dictionary
- # 根据数据集建立词袋,并统计词频,将所有词放入一个字典中,使用索引进行获取
- dct = Dictionary(dataset)
- # 根据每条数据,返回对应的词索引和词频
- corpus = [dct.doc2bow(line) for line in dataset]
- # 训练TF-IDF模型,即计算TF-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.0
- for g in genres:
- topN_tags_weights[g] = 1.0
- 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
-
- movie_dataset = get_movie_dataset()
- movie_profile = create_movie_profile(movie_dataset)
- movie_profile.head()
结果如图:
2.3、建立倒排索引
为了根据指定关键词迅速匹配到对应的电影,因此需要对物品画像的标签词,建立倒排索引。通常存储数据,都是以物品的ID作为索引,去提取物品的其他信息数据,而倒排索引就是用物品的其他数据作为索引,去提取它们对应的物品的ID列表。
- # 建立tag-物品的倒排索引
- def create_inverted_table(movie_profile):
- inverted_table = {}
- for mid,weights in movie_profile["weights"].iteritems():
- for tag,weight in weights.items():
- # inverted_table dict : 用tag作为key去取值,如果取不到就返回[]
- _ = inverted_table.get(tag,[])
- _.append((mid,weight))
- inverted_table.setdefault(tag,_)
- return inverted_table
-
- inverted_table = create_inverted_table(movie_profile)
- pprint(inverted_table)
运行结果:
1、用户画像构建步骤
- from functools import reduce
- import collections
- from pprint import pprint
-
- '''
- user profile画像建立
- 1.提取用户观看列表;
- 2.根据观看列表和物品画像为用户匹配关键词,并统计词频;
- 3.根据词频排序,最多保留TOP-k个词,这里k设为100,作为用户的标签。
- '''
- 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))
- # 兴趣词
- interest_words = counter.most_common(50)
- maxcount = interest_words[0][1]
- interest_words = [(w,round(c/maxcount,4)) for w,c in interest_words]
- user_profile[uid] = interest_words
-
- return user_profile
-
- user_profile = create_user_profile()
- pprint(user_profile)
运行结果:
2、产生推荐结果
为用户产生TOP-N推荐结果
- user_profile = create_user_profile()
-
- for uid,interest_words in user_profile.items():
- result_table = {} # 电影id:[0.2,0.5,0.7]
- for interest_word,interest_weight in interest_words:
- related_movies = inverted_table[interest_word]
- for mid,related_weight in related_movies:
- _ = result_table.get(mid,[])
- _.append(interest_weight) # 只考虑用户的兴趣程度
- # _.append(related_weight) # 只考虑兴趣词与电影的关联程度
- # _.append(interest_weight*related_weight) # 二者都考虑
- result_table.setdefault(mid,_)
- rs_result = map(lambda x:(x[0],sum(x[1])),result_table.items())
- rs_result = sorted(rs_result,key=lambda x:x[1],reverse=True)[:100]
- print(uid)
- pprint(rs_result)
- break
运行结果:
----------------------------------------------------------------
参考课程:推荐系统及算法,如侵删。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。