基于内容相似度的推荐与TF-IDF算法

基于内容相似度的推荐与TF-IDF算法
1 基于内容相似度的推荐
1.1概念
基于内容相似度的推荐就是把与你喜欢看的新闻内容相似新闻推荐给你。基于内容的推荐算法的主要优势在于⽆冷启动问题,只要⽤户产⽣了初始的历史数据,就可以开始进⾏推荐的计算。⽽且随着⽤户的浏览记录数据的增加,这种推荐⼀般也会越来越准确。
这⾥有两个重要的关键点需要⾸先有个基本理解:
1. 怎么知道⽤户喜欢看那些新闻?⽤户有历史的浏览记录,我们可以从这些⽤户历史浏览的新闻中”提取”能代表新闻主要内容的关键
词,看哪些关键词出现的最多。⽐如可以有”⼿机“,”电脑游戏“,”发布会“等等关键词。或者,统计这些新闻所属的领域是哪些,⽐如国际政治、社会、民⽣、娱乐,出⽤户看的新闻来源最多的⼏个领域。不过按这种⽅式判断⽤户兴趣容易太宽泛,哪怕是同⼀个领域下的新闻,可能也会差异很⼤。⽐如某⽤户可能喜欢A⼥星,⽽不喜欢B⼥星,⽽如果你只是认为该⽤户喜欢娱乐新闻,结果把B⼥星的新闻不停给⽤户推,那就肯定不好。⽽上述的关键词就可以⽐较好地规避这个问题。
2. 怎么判断两个新闻内容相似?到定义⽤户喜好的⽅法——关键词,那么我们⾃然⽽然就可以想到,**能不能提取出两个新闻的关键
词,然后对⽐看它们两的关键词是不是相同的呢?**恩!思路正确,不过毕竟⼀个新闻可以有好⼏个关键词,要想全部⼀样,还是⽐较困难的。所以我们需要对两个新闻的关键词匹配程度做⼀个合理的量化。那么这时就需要⽤到TFIDF算法了(第⼆部分介绍)。TFIDF 算法可以能够返回给我们⼀组属于某篇⽂本的”关键词-TFIDF值”的词数对,这些关键词最好地代表了这篇⽂本的核⼼内容,⽽这些关键词的相对于本篇⽂章的关键程度由它的TFIDF值量化。那我们现在也有了提取关键词并量化关键程度的⽅法,那么我们现在就可以来对⽐两篇⽂本的相似程度了。公式如下:
举例:
刚抓进系统的两个新闻,分别提取出关键词与TFIDF值如下:
A新闻:“美⼥模特”:100,“⼥装”:80,“奔驰”:40
B新闻:“程序员”:100,“⼥装”:90,“编程”:30
两篇⽂章只有⼀个共同关键词“⼥装”,故相似度为:80*90=7200。
1.2⽤户喜好衡量:喜好关键词表
但是实际操作中,以上思路有⼀个问题了,⽤户以前看了辣么多新闻,每个新闻有好些个关键词,我们难道拿刚抓进系统的新闻跟它们⼀个个⽐对吗?为了解决这个问题,我们需要引⼊新的东西:喜好关键词表。
其实很好理解:我们为每个⽤户在数据库⾥维持⼀个map,这个map⾥放的都是“⽤户喜好的关键词-喜好程度”这样的Key-Value对。⽽这个map最开始当然是空的,⽽从任意时刻开始,我们可以开始跟踪某⽤户的浏览⾏为,每当该⽤户新浏览了⼀条新闻,我们就把该新闻的“关键词-TFIDF值”“插⼊”到该⽤户的喜好关键词表中。当然这个“插⼊”要考虑关键词表⾥已经预先有了某预插⼊的关键词的情况,那么在这个基础上,我们可以将预插⼊的关键词的TFIDF值直接和词表⾥的值加起来。
当然,考虑到存储问题,我们可以为⽤户的喜好关键词表设定⼀个容量上限,⽐如最多1000个词,当然具体数值还是需要在实际运⾏过程根据效果做调整。
1.3兴趣迁移——衰减机制
我们⼤家会不会想到,我们的兴趣点可能是会随时间改变的呢?⽐如这段时间苹果出了⼀款新产品,我关注⼀下,但⼀个⽉后,我可能就完全不在意这件事了,但是可能苹果相关的关键词还⼀直在我的
关键词表⾥,那会不会导致我依然收到相似的我已经不关⼼的新闻的推荐呢?也就是如何处理这种兴趣迁移问题呢?
为了解决这个问题,我们可以引⼊⼀个衰减机制,即让⽤户的关键词表中的每个关键词喜好程度都按⼀定周期保持衰减。考虑到不同词的TFIDF值可能差异已经在不同的数量级,我们考虑⽤指数衰减的形式来相对进⾏公平的衰减。即引⼊⼀个λ 系数,1>λ>0 ,我们每隔⼀段时间,对所有⽤户的所有关键词喜好程度进⾏λ的衰减,那么就完成了模拟⽤户兴趣迁移的过程。
当然,⼀直衰减下去,也会使得⼀些本来就已经完全不感兴趣的关键词可能衰减到了0.0000001了,还在衰减,还死⽪赖脸地待在词表⾥占位置,那么⾃然⽽然,我们可以设置⼀个阈值L,规定对每个⽤户的每次衰减更新完成后,将词表⾥喜好值⼩于L的关键词直接清除。
2 TFIDF 算法
2.1概念
TF-IDF(term frequency–inverse document frequency)是⼀种⽤于资讯检索与资讯探勘的常⽤加权技术。
TF-IDF是⼀种统计⽅法,⽤以评估⼀字词对于⼀个⽂件集或⼀个语料库中的其中⼀份⽂件的重要程度。
字词的重要性随着它在⽂件中出现的次数成正⽐增加,但同时会随着它在语料库中出现的频率成反⽐下降。
TF-IDF加权的各种形式常被搜寻引擎应⽤,作为⽂件与⽤户查询之间相关程度的度量或评级。除了TF-IDF以外,因特⽹上的搜寻引擎还会使⽤基于连结分析的评级⽅法,以确定⽂件在搜寻结果中出现的顺序。
2.2核⼼思想
TFIDF的主要思想是:如果某个词或短语在⼀篇⽂章中出现的频率TF⾼,并且在其他⽂章中很少出现,则认为此词或者短语具有很好的类别区分能⼒,适合⽤来分类。TFIDF实际上是:TF * IDF。
在⼀份给定的⽂件⾥,词频 (term frequency, TF) 指某⼀个给定的词语在该⽂件中出现的次数。这个数字通常会被归⼀化(分⼦⼀般⼩于分母区别于IDF),以防⽌它偏向长的⽂件。(同⼀个词语在长⽂件⾥可能会⽐短⽂件有更⾼的词频,⽽不管该词语重要与否。)
逆向⽂件频率 (inverse document frequency, IDF) 是⼀个词语普遍重要性的度量。某⼀特定词语的IDF,可以由总⽂件数⽬除以包含该词语之⽂件的数⽬,再将得到的商取对数得到。**如果包含词条t的⽂档越少,也就是n越⼩,IDF越⼤,则说明词条t具有很好的类别区分能⼒。**如果某⼀类⽂档C中
包含词条t的⽂档数为m,⽽其它类包含t的⽂档总数为k,显然所有包含t的⽂档数n=m+k,当m⼤的时候,n也⼤,按照IDF公式得到的IDF的值会⼩,就说明该词条t类别区分能⼒不强。
某⼀特定⽂件内的⾼词语频率,以及该词语在整个⽂件集合中的低⽂件频率,可以产⽣出⾼权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。
2.3公式
对于某个特定⽂件中的词语t
⽽⾔,它的 TF 可以表⽰为:
其中 n  是该词在⽂件 d  中出现的次数,⽽分母则是⽂件 d
中所有词汇出现的次数总和。如果⽤更直⽩的表达是来描述就是:
某⼀特定词语的IDF,可以由总⽂件数⽬除以包含该词语之⽂件的数⽬,再将得到的商取对数即可,I
DF表⽰为:
公安机关中级执法资格考试其中,|D| 是语料库中的⽂件总数。 | { j:t ∈d  } | 表⽰包含词语 t  的⽂件数⽬(即 n ≠0 的⽂件数⽬)。如果该词语不在语料库中,就会导致分母为零,因此⼀般情况下使⽤ 1+| { j:t ∈d
} |。同样,如果⽤更直⽩的语⾔表⽰就是 :
woc
某⼀特定⽂件内的⾼词语频率,以及该词语在整个⽂件集合中的低⽂件频率,可以产⽣出⾼权重的TF-IDF。因此,TF-IDF倾向于过滤掉常见的词语,保留重要的词语。
2.4应⽤
i i,j j j i j i i,j i j
⼀:有很多不同的数学公式可以⽤来计算TF-IDF。这边的例⼦以上述的数学公式来计算。词频 (TF)
是⼀词语出现的次数除以该⽂件的总词语数。假如⼀篇⽂件的总词语数是100个,⽽词语“母⽜”出现了3次,那么“母⽜”⼀词在该⽂件中的词频就是3/100=0.03。⼀个计算⽂件频率 (DF) 的⽅法是测定有多少份⽂件出现过“母⽜”⼀词,然后除以⽂件集⾥包含的⽂件总数。所以,如果“母⽜”⼀词在1,000份⽂件出现过,⽽⽂件总数是10,000,000份的话,其逆向⽂件频率就是 log(10,000,000 / 1,000)=4。最后的TF-IDF的分数为0.03 *
4=0.12。
⼆:根据关键字k1,k2,k3进⾏搜索结果的相关性就变成TF1IDF1 + TF2IDF2 + TF3IDF3。⽐如document1的term总量为
1000,k1,k2,k3在document1出现的次数是100,200,50。包含了 k1, k2, k3的docuement总量分别是 1000,
10000,5000。document set的总量为10000。 TF1 = 100/1000 = 0.1 TF2 = 200/1000 = 0.2 TF3 = 50/1000 = 0.05
IDF1 = log(10000/1000) = log(10) = 2.3 IDF2 = log(10000/100000) = log(1) = 0; IDF3 = log(10000/5000) = log(2) =
0.69 这样关键字k1,k2,k3与docuement1的相关性= 0.12.3 + 0.20 + 0.050.69 = 0.2645 其中k1⽐k3的⽐重在document1要
⼤,k2的⽐重是0.
涉江采芙蓉教案
三:在某个⼀共有⼀千词的⽹页中“原⼦能”、“的”和“应⽤”分别出现了 2 次、35 次 和 5 次,那么它们的词频就分别是 0.002、0.035 和 0.005。 我们将这三个数相加,其和 0.042 就是相应⽹页和查询“原⼦能的应⽤” 相关性的⼀个简单的度量。概括地讲,如果⼀个查询包含关键词 w1,w2,…,wN, 它们在⼀篇特定⽹页中的词频分别是: TF1, TF2, …, TFN。 (TF: term frequency)。 那么,这个查询和该⽹页的相关性就是:TF1 + TF2 + … + TFN。
读者可能已经发现了⼜⼀个漏洞。在上⾯的例⼦中,词“的”站了总词频的 80% 以上,⽽它对确定⽹页的主题⼏乎没有⽤。我们称这种词叫“应删除词”(Stopwords),也就是说在度量相关性是不应考虑它们的频率。在汉语中,应删除词还有“是”、“和”、“中”、“地”、“得”等等⼏⼗个。忽略这些应删除词后,上述⽹页的相似度就变成了0.007,其中“原⼦能”贡献了 0.002,“应⽤”贡献了0.005。细⼼的读者可能还会发现另⼀个⼩的漏洞。在汉语中,“应⽤”是个很通⽤的词,⽽“原⼦能”是个很专业的词,后者在相关性排名中⽐前者重要。因此我们需要给汉语中的每⼀个词给⼀个权重,这个权重的设定必须满⾜下⾯两个条件:
1. ⼀个词预测主题能⼒越强,权重就越⼤,反之,权重就越⼩。我们在⽹页中看到“原⼦能”这个词,或多或少地能了解⽹页的主题。
我们看到“应⽤”⼀次,对主题基本上还是⼀⽆所知。因此,“原⼦能“的权重就应该⽐应⽤⼤。
2. 应删除词的权重应该是零。我们很容易发现,如果⼀个关键词只在很少的⽹页中出现,我们通过它就容易锁定搜索⽬标,它的权重也
就应该⼤。反之如果⼀个词在⼤量⽹页中出现,我们看到它仍然不很清楚要什么内容,因此它应该⼩。概括地讲,假定⼀个关键词w 在 Dw 个⽹页中出现过,那么 Dw 越⼤,w的权重越⼩,反之亦然。在信息检索中,使⽤最多的权重是“逆⽂本频率指数”
(Inverse document frequency 缩写为IDF),它的公式为log(D/Dw)其中D是全部⽹页数。⽐如,我们假定中⽂⽹页数是D=10亿,应删除词“的”在所有的⽹页中都出现,即Dw=10亿,那么它的IDF=log(10亿/10亿)= log (1) = 0。假如专⽤词“原⼦能”在两百万个⽹页中出现,即Dw=200万,则它的权重IDF=log(500) =6.2。⼜假定通⽤词“应⽤”,出现在五亿个⽹页中,它的权重IDF = log(2)则只有 0.7。也就只说,在⽹页中到⼀个“原⼦能”的⽐配相当于到九个“应⽤”的匹配。利⽤ IDF,上述相关性计算个公式就由词频的简单求和变成了加权求和,即 TF1IDF1 + TF2IDF2 +… +
TFN*IDFN。在上⾯的例⼦中,该⽹页和“原⼦能的应⽤”的相关性为 0.0161,其中“原⼦能”贡献了 0.0126,⽽“应⽤”只贡献了0.0035。这个⽐例和我们的直觉⽐较⼀致了。
2.5python实现
2.5.1 数据预处理
import math
import string
pus import stopwords
from collections import Counter
from nltk.stem.porter import *
from sklearn. import TfidfVectorizer
text1 = "Python is a 2000 made-for-TV horror movie directed by Richard \
Clabaugh. The film features several cult favorite actors, including William \
Zabka of The Karate Kid fame, Wil Wheaton, Casper Van Dien, Jenny McCarthy, \
Keith Coogan, Robert Englund (best known for his role as Freddy Krueger in the \
A Nightmare on Elm Street series of films), Dana Barron, David Bowe, and Sean \
Whalen. The film concerns a genetically engineered snake, a python, that \
escapes and unleashes itself on a small town. It includes the classic final\
girl scenario evident in films like Friday the 13th. It was filmed in Los Angeles, \
California and Malibu, California. Python was followed by two sequels: Python \
II (2002) and Boa vs. Python (2004), both also made-for-TV films."
康莱特
text2 = "Python, from the Greek word (πύθων/πύθωνας), is a genus of \
nonvenomous pythons[2] found in Africa and Asia. Currently, 7 species are \
recognised.[2] A member of this genus, P. reticulatus, is among the longest \
snakes known."
text3 = "The Colt Python is a .357 Magnum caliber revolver formerly \
manufactured by Colt's Manufacturing Company of Hartford, Connecticut. \
It is sometimes referred to as a \"Combat Magnum\".[1] It was first introduced \
in 1955, the same year as Smith & Wesson's M29 .44 Magnum. The now discontinued \
Colt Python targeted the premium revolver market segment. Some firearm \
collectors and writers such as Jeff Cooper, Ian V. Hogg, Chuck Hawks, Leroy \
Thompson, Renee Smeets and Martin Dougherty have described the Python as the \
finest production revolver ever made."
构建分词函数:
def get_tokens(text):
"""
⾸先我们来做分词,其中⽐较值得注意的地⽅是我们设法剔除了其中的标点符号(显然,标点符号不应该成为最终的关键词)。
"""
lowers = text.lower()                                                              # 转换字符串中所有⼤写字符为⼩写。
print('first step:',lowers,'\n')
remove_punctuation_map = dict((ord(char), None) for char in string.punctuation)  # 即为去掉标点符号的 string,⽽line本⾝没有变化
no_punctuation = anslate(remove_punctuation_map)
print('second step:',no_punctuation,'\n')
tokens = nltk.word_tokenize(no_punctuation)                                        # 将成段落的语料转化为了⼀个以单词为单位的Python List对象完成分词    print('third step:',tokens,'\n')
欧锦赛2013
return tokens
测试分词函数:
tokens = get_tokens(text1)
count = Counter(tokens)                                                                # 统计每个单词出现的次数重庆之窗
print (st_common(10))
词⼲抽取:
def stem_tokens(tokens, stemmer):
"""
进⾏对已经分完词进⾏词⼲抽取
"""
stemmed = []
for item in tokens:
stemmed.append(stemmer.stem(item))
return stemmed
测试词⼲抽取:
nltk.download('punkt')                                                                  # 分词
nltk.download('stopwords')                                                              # 停⽤词
tokens = get_tokens(text1)
filtered = [w for w in tokens if not w in stopwords.words('english')]                  # 去掉停⽤词print('filtered\t\t\t',filtered,'\n')
stemmer = PorterStemmer()
stemmed = stem_tokens(filtered, stemmer)
print('stemmed\t\t\t',stemmed,'\n')
count = Counter(stemmed)
print('count\t\t\t',count)
结果:

本文发布于:2024-09-22 07:11:47,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/244889.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:关键词   新闻   出现   词语   喜好   内容
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议