推荐系统里的那些算法—— TF-IDF(附python代码)
基于UGC(user Generate Content)的推荐
- 用户用标签来描述对物品的看法,所以用户生成标签(UGC)是联系用户和物品的纽带,也是反应用户兴趣的重要数据源。
- 一个用户标签行为的数据集一般由一个三元组(用户,物品,标签)的集合表示,其中一条记录 (u, i, b)表示用户u给物品i打上了标签b.
- 一个最简单的算法
- 统计每个用户最常用的标签
- 对于每个标签,统计被打过这个标签次数最多的物品
- 对于一个用户,首先找到他常用的标签,然后找到具有这些标签的最热门的物品,推荐给他
- 所以用户u对物品i的兴趣公式为
p
(
u
,
i
)
=
∑
n
u
,
b
×
n
b
,
i
p(u,i)=\sum n_{u,b}\times n_{b,i}
n
u
,
b
n_{u,b}
n
b
,
i
n_{b,i}
TF-IDF
- 词频-逆文档频率(Term Frequency-Inverse Document Frequency,TF-IDF)是一种用于资讯检索与文本挖掘的常用加权技术。
- TF-IDF是一种统计方法,用以评估一个字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
T
F
I
D
F
=
T
F
×
I
D
F
TFIDF=TF\times IDF
- TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
比如专业术语的TF-IDF较高,“的”、“这”、“表明”一类的词语TF-IDF较低。
- TF-IDF加权的各种形式常被搜索引擎应用,作为文件与用户查询之间相关程度的度量或评级。
- 词频(Term Frequency,TF)
- 指的是某一个给定的词语在该文件中出现的频率。这个数字是对词数的归一化,以防止偏向更长的文件。(同一个词语在长文件里可能会比短文件有更离的词数,而不管该词语重要与否。)
T
F
i
,
j
=
n
i
,
j
n
∗
,
j
TF_{i,j}=\frac {n_{i,j}}{n_{*,j}}
T
F
i
,
j
TF_{i,j}
n
i
,
j
n_{i,j}
n
∗
,
j
n_{*,j}
- 指的是某一个给定的词语在该文件中出现的频率。这个数字是对词数的归一化,以防止偏向更长的文件。(同一个词语在长文件里可能会比短文件有更离的词数,而不管该词语重要与否。)
- 逆向文件频率(Inverse Document Frequency,IDF)
- 是一个词语普遍重要性的度量,某一特定词语的 IDF,可以由总文档数目除以包含该词语之文档的数目,再将得到的商取对数得到。
I
D
F
i
=
l
o
g
N
+
1
N
i
+
1
IDF_i=log_{} {\frac {N+1}{N_i+1}}
I
D
F
i
IDF_i
N
i
N_i
- 是一个词语普遍重要性的度量,某一特定词语的 IDF,可以由总文档数目除以包含该词语之文档的数目,再将得到的商取对数得到。
TF-IDF基于UGC推荐的改进
- 为了避免热门标签和热门物品获得更多的权重,我们需要对“热门“进行惩罚借鉴TF-IDF的思想,以一个物品的所有标签作为“文档”,标签作为“词语”,从而计算标签的“词频”(在物品所有标签中的频率)和"逆文档频率”(在其它物品标签中普遍出现的频率)
- 由于“物品i的所有标签”
n
∗
,
i
n_{*,i}
p
(
u
,
i
)
=
∑
b
n
u
,
b
l
o
g
1
+
n
b
(
u
)
l
o
g
n
b
,
i
l
o
g
1
+
n
i
(
u
)
p(u,i)=\sum _b\frac {n_{u,b}}{log_{1+n_b^{(u)}}}\frac{log_{n_{b,i}}}{log_{1+n_i^{(u)}}}
其中,n
b
(
u
)
n_b^{(u)}
n
i
(
u
)
n_i^{(u)}
import pandas as pd
import numpy as np
import math
wordA = "xxx"
wordB = "yyy "
#将单词取出,并建立集合
sepA = wordA.split(" ")
sepB = wordB.split(" ")
setA = set(sepA)
setB = set(sepB)
#取并集,建立字典
union = setA.union(setB)
dictA = dict.fromkeys(setA,0)
dictB = dict.fromkeys(setA,0)
#统计两个字典中单词出现的次数
for word in dictA:
dictA[word] += 1
for word in dictB:
dictB[word] += 1
pd.DataFrame([dictA,dictB])
def computeTF(dict,set):
tfdict = {}
setcount = len(set)
for word,count in dict.items():
tfdict[word] = count / setcount
return tfdict
tfA = computeTF(dictA,setA)
tfB = computeTF(dictB,setB)
#计算逆文档频率
def computeIDF(dictlist):
#用字典对象保存IDF结果,每个词作为key
idfDict = dict.fromkeys(dictlist[0],0)
N = len(dictlist)
for Dict in dictlist:
for word,count in Dict.items():
if count > 0:
idfDict[word] += 1
#得到所有词汇对应的Ni值,求idf
for word ,ni in idfDict.items():
idfDict[word] = math.log10((N+1)/(ni+1))
return idfDict
idfs = computeIDF([dictA,dictB])
#计算TF-IDF
def computeTFIDF(tf,idfs):
tfidf = {}
for word,tfval in tf.items():
tfidf[word] = tfval * idfs[word]
return tfidf
tfidfA = computeTFIDF(tfA,idfs)
tfidfB = computeTFIDF(tfB,idfs)
pd.DataFrame([tfidfA,tfidfB])