基于内容的推荐,仅仅依赖于物品的信息,对于系统冷启动和物品冷启动,可以有效解决。拿到物品的信息之后,对物品信息进行处理,生成特征向量,然后就可以定义物品相似度,对物品进行推荐。
通常,基于内容的推荐遵循下面三个步骤:
- 物品表达(item representation),即从物品信息中抽出特征向量
- 用户侧写(user profile),即根据用户过去行为中,学习到用户喜欢哪些物品特征,讨厌哪些物品特征
- 生成推荐,即通过物品表达和用户侧写,来给用户推荐最相关的物品
我们用一份西雅图的酒店数据(seatleHotels.txt,已经上传,可以免费下载)作为数据集,里面包含三个特征,分别是 酒店名称、酒店地址和酒店描述。
我们接下来简单介绍下tf-idf。
实际上,tf指的是词频,即一个单词在文档中出现的概率。一般来说,单词出现的越频繁,可能会越能代表这篇文档。举一个计算的例子, doc=‘america is mygod country but it is a shit’,这里,我们分别计算每个单词出现的频率
t
f
=
该
单
词
出
现
次
数
文
档
总
单
词
数
tf=\frac{该单词出现次数}{文档总单词数}
tf=文档总单词数该单词出现次数如下
america | is | mygod | country | but | it | a | shit |
---|---|---|---|---|---|---|---|
1/9 | 2/9 | 1/9 | 1/9 | 1/9 | 1/9 | 1/9 | 1/9 |
而idf则是指逆文档率。如上所示,出现很多的字可能只是介词之类的无意义的词,这类词在绝大多数文档中都会出现,为了降低这类词的权重,我们给出一个逆文档率的概念,也就是说,当这个词在越多文档中出现,那么这个词的权重越低,
i
d
f
=
l
o
g
总
文
档
数
1
+
出
现
该
单
词
的
文
档
数
idf=log\frac{总文档数}{1+出现该单词的文档数}
idf=log1+出现该单词的文档数总文档数
当我们综合考虑,我们希望在众多文档中,挑选出来最能代表这个文档的词,我们给这个词以最大的权重,也就是说,
- 在该文档中,一个词的频率 t f tf tf越大,权重越大
- 在所有文档中,一个词独属于这个文档的概率越大, i d f idf idf越大,则权重越大
因此,我们用 t f ⋅ i d f tf\cdot idf tf⋅idf作为衡量某文档中一个词的重要程度, t f ⋅ i d f tf\cdot idf tf⋅idf越大,越能说明这个词重要,能代表该文档的程度也越高。
我们可以用酒店描述部分,生成酒店的特征信息,具体的,
- 用tf-idf对酒店文字描述部分进行处理,生成特征向量
- 根据酒店的特征向量,计算不同酒店的相似度
- 假设用户喜欢某个酒店,那么给用户推荐相似酒店
# 第三方库
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
# 载入数据
data = pd.read_csv(r'D:\myfile\开课吧\推荐系统\第七节\seatleHotels.txt', sep=',')
data.head()
# 将desc中的大写都改成小写
data['desc'] = data['desc'].apply(str.lower)
data.head()
# 计算tf-idf矩阵
tfidf = TfidfVectorizer(ngram_range=(1, 2), stop_words='english')
tfidf_array = tfidf.fit_transform(data['desc']).toarray()
# 创建tf-idf的dataframe
tfidf_dataframe = pd.DataFrame(tfidf_array, columns=tfidf.get_feature_names(), index=data.name)
tfidf_dataframe.head()
# 计算不同酒店之间的余弦相似度
cos_similarity = tfidf_array.dot(tfidf_array.T)
cos_similarity.shape
# 创建相似度pandas
similarity = pd.DataFrame(cos_similarity, columns=data['name'], index=data['name'])
similarity.head()
# 根据相似度进行推荐
def topN(hotel, N=4):
neighbors = similarity.loc[hotel, :].sort_values(ascending=False)[1: N+1]
return neighbors.index.tolist()
# 测试
topN('Hilton Garden Seattle Downtown')
# 结果
['Staybridge Suites Seattle Downtown - Lake Union',
'Silver Cloud Inn - Seattle Lake Union',
'Residence Inn by Marriott Seattle Downtown/Lake Union',
'The Loyal Inn']