[关闭]
@aliasliyu4 2017-02-22T10:10:39.000000Z 字数 7634 阅读 1595

digitalx文本相似性推荐

目前的业务下,我司的推荐内容主要是文本相关的推荐。本文也是围绕着如何给一个人推荐他感兴趣的文章。

量化

人看到的东西都是具体化的,而机器看到的东西都是量化的,也就是数字化的东西,稍微回想一下高中学的力的分解和合成,本质上就是向量的计算,向量和人的直觉是向吻合的,有方向,有度量的量,比如说别人告诉你龙华东路,正常人就不会走到黄浦江里面去了。向量在坐标上的表示是【1,2,3】,这是一个三维的向量,单一的向量是说明不了什么的,但是如果这个空间中出现了另外一个向量,我们就可以知道两个向量的距离,也就是相似性。小明喜欢编程,打篮球,看书,小白喜欢旅游,打架,泡妞,小明的向量表示是【0.2,0.1,0.7】,小白的向量表示是【0.1,0.8,0.1】,AB=1.4,相似性还是比较远的,所以用向量去度量每一个人,每一篇文档的相似性是个不错的办法!

tf-idf

tf-idf的作用就是量化每一个词在语料中的比重,反应在量化上就是维度的变化,这一步是非常基础和有必要的。

主题模型

主题模型是目前也比较流行的文本分类的方法了,他主要解决的是文章的分类问题,就是这篇文章属于哪个类别。

如何来对文章进行分类呢?如果按照之前的算法,我们可以把每篇文章的关键词都提取出来,然后按照关键词进行分类,把文章分到每个类别中,但是,那样显得不太高端,我们来想想这么一个情况,就是你是如何写这篇文章的?

比如我目前写的这篇文章文本相似性的计算,一般的思路是这样的。 首先,你想好题目以后会想一些提纲,比如我想我会写一下主题模型,然后写词向量,这两个就是我的主题了。 然后,我开始写了,写主题模型的时候,我的一些词语都是和主题模型相关的,比如LDA,分类,主题,概率啊等等,然后写词向量的时候也会有这么一些词,这些就是主题下的词语。

最后,我就是按照上面的两条规则把文章写完了。

如何让以计算机的思维来按这个规则写作呢?

首先,定两个主题,然后把每个词都分到某一个主题下

开始写作的时候就是先找个主题,然后在主题下找个词,然后写出来

循环到上一步,就是这样么一直写,然后一篇文章就写好了

这样每个词都属于两个主题中的一个。
这样当然写不出东西来,但是我们现在需要的分类,如果反过来想想,我已经有一篇文章了,如果我知道这篇文章的每个词都属于哪个分类,那么我其实就知道了这篇文章都属于哪些个主题了,那么有相似主题的文章,很可能是比较相似的。

于是,现在的关键问题就是找到主题和主题下的词了,把这两个东西当成一个模型,新来一篇文章就在这个模型里面过一遍,然后就知道这篇文章的主题了。
主题和主题下的词怎么找呢?最简单的就是靠人拍啊,人为的设定一些主题和这个主题下的词以及词出现的概率,那不就行了,人怎么拍呢?靠经验啊,我今年30多了,看了二十多年的书,少说有1000本吧,我知道哪些词应该在哪些分类下啊。OK,靠经验估计出来的,我靠,是不是有种似曾相识的赶脚啊?这不是机器学习最喜欢干的事情么?给一堆文章给他『看』,然后自己估算出一个主
题模型出来。

好吧,其实主题模型就是这么干的。LDA模型的数学表达比较复杂,涉及到好几个分布函数,还有采样函数等,这篇文章必然讲不清楚,如果感兴趣的,我后面列了几篇文章,可以看看他的数学原理是什么。这个东西我理解了很久很久才算明白,我现在用说人话的方式来说说整个过程,作为一个抛砖引玉吧,当然,和实际的算法还是有比较大出入的,如果真感兴趣可以看后面的推荐文章。
我们先定义下一个场景,有3篇文档,每个文档有2个词,设定有2个主题,这三篇文档和词分别是:

  1. 你好 世界
  2. 你好 中国
  3. 搜索 你好

那么词就是:你好,世界,中国,搜索 四个

主题定义为:T1,T2

下方这些人话是重点了。
因为我们认为写文章的时候是是按照两步来做的(先确定主题,然后确定词,最后把词写出来),那么在数学上可以变成两个概率的乘积了,所以,这个词为什么会出现在这篇文章呢?是因为

这个词在这篇文章出现的概率=这个主题在这篇文章的概率*这个词在这个主题下出现的概率,也就是

P(W(词)|D(文章))=P(W(词)|T(主题))*P(T(主题)|D(文章)),这个 公式非常重要。

P(W(词)|D(文章)) 这个其实是可以直接统计出来的。

P(W(词)|T(主题)) 这个是模型的一部分,是要求出来的。

P(T(主题)|D(文章)) 这个是最后分类的结果
有新来的文章我们要对这篇文章进行分类的话,先统计出P(W(词)|D(文章)),然后用P(W(词)|D(文章))去除以P(W(词)|T(主题)) ,就得到了这篇文章所属的每个主题的概率了。

实战

环境:

  1. python2.7
  2. mac
  3. digitalx微信语料
  4. go1.7

原始语料(越大越好,因为我们有机器学习)

首先我是从我们的数据库中拉了4000篇文章出来,格式定义为url&@title@contnt

处理掉文章内容中的换行符号

  1. func Transation() {
  2. o := orm.NewOrm()
  3. sql := `select url, head, context from dx_textparse`
  4. var maps []orm.Params
  5. if _, err := o.Raw(sql).Values(&maps); err != nil {
  6. logx.FInfo("%v", err)
  7. }
  8. for _, v := range maps {
  9. url := v["url"].(string)
  10. head := v["head"].(string)
  11. context := v["context"].(string)
  12. contexts := strings.Split(context, "\n")
  13. context = strings.Join(contexts, "")
  14. sql = `insert into dxs_textparse (url, head, context) values('` + url + `', '` + head + `', '` + context + `')`
  15. if _, err := o.Raw(sql).Exec(); err != nil {
  16. logx.FError("%v", err)
  17. }
  18. }
  19. }
  1. type below command in mysql client:
  2. select url, head , context into outfile '/tmp/all.txt' fields terminated by '&@' lines terminated by '\n' from dxs_textparse

这样我们就生成了all.txt预料。

python生成模型

  1. #这里的字典就是我们项目中使用的字典
  2. jieba.load_userdict("newjieba.dict.utf8" )
  3. def saveObject(filename,obj):
  4. f=open(filename,'wb')
  5. pickle.dump(obj,f)
  6. f.close()
  7. return True
  8. etlregex = re.compile("[^\u4e00-\u9f5a0-9]")
  9. def etl(content):
  10. content = etlregex.sub('',content)
  11. return content
  12. #原始语料集合
  13. train_set=[]
  14. docinfos = []
  15. #读取文本,进行切词操作
  16. f=open("./data/all.txt")
  17. lines=f.readlines()
  18. for line in lines:
  19. content = (line.lower()).split("&@")[2] + (line.lower()).split("&@")[1]
  20. #print content
  21. #切词,etl用于去掉无用的符号
  22. word_list = filter(lambda x: len(x)>0,map(etl,jieba.cut(content,cut_all=False)))
  23. train_set.append(word_list)
  24. detail={}
  25. detail["id"]=(line.lower()).split("&@")[0]
  26. detail["title"]=(line.lower()).split("&@")[1]
  27. detail["content"]=(line.lower()).split("&@")[2]
  28. docinfos.append(detail)
  29. f.close()
  30. #语料太大的情况下可以强制GC回收内存空间
  31. gc.collect()
  32. #生成字典
  33. dictionary = corpora.Dictionary(train_set)
  34. #去除极低频的杂质词
  35. dictionary.filter_extremes(no_below=1,no_above=1,keep_n=None)
  36. #将词典保存下来,将语料也保存下来,语料转换成bow形式,方便后续使用
  37. dictionary.save(output + "all.dic")
  38. corpus = [dictionary.doc2bow(text) for text in train_set]
  39. saveObject(output+"all.cps",corpus)
  40. #存储原始的数据
  41. saveObject(output+"all.info",docinfos)
  42. #TF*IDF模型生成
  43. #使用原始数据生成TFIDF模型
  44. tfidfModel = models.TfidfModel(corpus)
  45. #通过TFIDF模型生成TFIDF向量
  46. tfidfVectors = tfidfModel[corpus]
  47. #存储tfidfModel
  48. tfidfModel.save(output + "allTFIDF.mdl")
  49. indexTfidf = similarities.MatrixSimilarity(tfidfVectors)
  50. indexTfidf.save(output + "allTFIDF.idx")
  51. #LDA模型
  52. lda = models.LdaModel(tfidfVectors, id2word=dictionary, num_topics=50)
  53. lda.save(output + "allLDA50Topic.mdl")
  54. corpus_lda = lda[tfidfVectors]
  55. indexLDA = similarities.MatrixSimilarity(corpus_lda)
  56. indexLDA.save(output + "allLDA50Topic.idx")

最终生成的文件都保存在output文件夹下面

测试

  1. query= """
  2. 微电影原创,转载请联系授权提起老人和小孩主演的电影,你看过哪些?是前段时间刷爆朋友圈的美丽童话《海蒂和爷爷》?女孩和邻居爷爷去森林寻找的温馨《蝴蝶》?还是让·雷诺和小正太记忆中《普罗旺斯的夏天》?今天微sir推荐的是一部新西兰的电影——《追捕野蛮人》初看海报,微sir是拒绝的,因为对这种老少配温情片的套路太了解了,总觉得少了新意。氮素,看到IMDB8.2分的高分,微sir觉得哪怕套路深也不能错过~看过之后,迫不及待想跟你们分享这部骨骼清奇的电影。诚然,它的套路也是两个没什么感情的人变成了死党,但是和其他老少温情片不同,这部电影有种“反社会”的叛逆,就像电影里瑞奇的混搭装扮,电影也有着幽默讽刺温情并存的绝妙混搭。用自己的话说,小胖子瑞奇是一个被踢来踢去的皮球,不知道在多少个领养家庭呆过。他是儿童福利机构工作人员眼里的坏孩子,是被全国通缉的“不法之徒”。但是口口声声说不放弃每个孩子的儿童福利机构却不能用心关爱孤儿,看不到隐藏在他们叛逆外表下渴望被爱的心。真实的瑞奇,嘴里说想当混混,其实胆小孤独,喜欢抱着暖水袋。瑞奇说,不是我选择了黑帮生活,是黑帮生活选择了我。还记得那个曾经杀人,出狱后想要新生活而不能的《男孩A》吗?《追捕野蛮人》里的另一个主角老赫曾经也杀过人,出狱后人们看他也戴上了有色眼镜。无法过正常都市生活的他选择了在林中生活。在真心关爱瑞奇的贝拉阿姨死后,福利院决定接回瑞奇。瑞奇因不愿回福利院出逃,出逃手法是做个假人烧掉说自己死了。这个假人脸真的不是来搞笑的吗!老赫去森林找他,却被福利院怀疑绑架,进而全国对他们开始追捕。(遇到拖油瓶内心崩溃gif)瑞奇心甘情愿逃亡。哪怕在森林里成为野蛮人,也不愿意回去继续做一个被踢来踢去的皮球。在瑞奇开着“怒马”狂飙的时候,影片到达了高潮。这段致敬了《末路狂花》。真特么太燃太入戏!但老赫不愿继续逃亡,他选择了投降。觉得自己被背叛的瑞奇把枪对准了老赫,他会开枪吗?电影总是在不经意间透露出幽默和喜感:语言误会造成误解也让人发笑:但让人爆笑的情节之下,是让人伤感的人生。想要孩子的老赫不能生育,想要母爱的瑞奇被母亲抛弃。并且因为是孤儿,因为是杀人犯,就被人用偏见看待。在充满危险、野兽遍布的森林,追捕他们的偏偏不是野兽、不是恶劣的天气和匮乏的食物,而是城市的文明人。这是多么的讽刺!电影里让微sir印象深刻的还有两个人,一个是儿童福利机构管理员,在影片里她的形象是刻板严厉的女汉子,她是社会体制的代言人,一边说孩子坏,一边说不会放弃孩子,一边又对孩子威逼利诱。一个是因为厌恶城市程序复杂生活而把自己当做稻草的“神经病Sam”。他对政府深恶痛疾,他说政府就这德性,踩在小人物头上过活。并且Sam还发表了“表格填写器”言论,想必咱们也深有同感,相信你看到这里会跳起来叫到“原来全世界都这样”!电影通过这两个人深深讽刺了社会体制和自以为文明的都市人。‍那些自以为是“文明人”的人却对那些边缘人物妄自揣测、随意评判,这种恶意难道不是一种野蛮吗?看完电影,记忆最深的是瑞奇画的那幅画,老赫、贝拉,自己和自己的狗。就这样简单地在森林里生活多好。回复“追捕野蛮人”,获
  3. """
  4. query_bow = dictionary.doc2bow(filter(lambda x: len(x)>0,map(etl,jieba.cut(query,cut_all=False))))
  5. tfidfvect = tfidfModel[query_bow]
  6. simstfidf = indexTfidf[tfidfvect]
  7. sort_sims = sorted(enumerate(simstfidf), key=lambda item: -item[1])
  8. # 取出相似度前十的文章
  9. print "TFIDF similary Top 10:::"
  10. for sim in sort_sims[:10]:
  11. print "ID : " + docinfos[sim[0]]["id"] + "\t" + docinfos[sim[0]]["title"] + "\tsimilary:::" + str(sim[1])

显然我们使用了一篇影评作为查询字段。

输出:

  1. TFIDF similary Top 10:::
  2. 第一次为电影当水军,但我一点不害臊 similary:::0.961907
  3. 旅游买买买星人必须get的终极收纳大法:连收纳盒都被收纳整齐了!similary:::0.828925
  4. 这部imdb评分高达8.2的片子,骨骼清奇,让人都想去当野蛮人 similary:::0.7983
  5. 【风格偶像】美颜与实力共存,和靳东一起,演绎黑白纪遇 similary:::0.749527
  6. 手工曲奇+挂耳咖啡=下午茶的最佳搭配 similary:::0.722935
  7. 我错了,不该害你们期待这种大片 similary:::0.43519
  8. 挖到部冷门高分美剧,密密麻麻全是坑 similary:::0.30584
  9. 图:相亲现场亲手量胸围,你想试试吗? similary:::0.196027
  10. gif图:美女,挺享受的啊 similary:::0.196027
  11. gif图:女司机忘拉手刹后,请注意后面保安的手势!similary:::0.196027
  12. LDA similary Top 10:::
  13. 【风格偶像】美颜与实力共存,和靳东一起,演绎黑白纪遇 similary:::0.978944
  14. 北大才女的一首诗,惊呆亿万中国父母 similary:::0.978944
  15. 比起双腿,你更应该打开这个 similary:::0.978944
  16. 充满浪漫气息的巴厘岛 similary:::0.978944
  17. 德国机械用行动告诉全世界:无敌是多么寂寞 similary:::0.978944
  18. 10万元的车一拆开,大家都惊呆了! similary:::0.978944
  19. 优雅女人一生的必修课! similary:::0.978944
  20. 死于30岁的女人 similary:::0.978401
  21. 杭城秋色渐入佳境,去了这里发现镜子中的自己变了...similary:::0.977829
  22. 1011日沪深两市重要公告集锦 similary:::0.977036

专项测试

导入1600+篇金融数据

测试结果:

  1. TFIDF similary Top 10:::
  2. 2017年,你的钱该往哪儿投? similary:::0.513839
  3. 春运大数据 缩影国与家 similary:::0.513839
  4. 2017,你好! similary:::0.513839
  5. 2017年,房价怎么走? similary:::0.513839
  6. 2017年当你想放弃时,看看这个漫画! similary:::0.513839
  7. 2017最难投资年,你需要一杯化解焦虑的下午茶 similary:::0.49305
  8. 国馆丨中国式聪明(很深刻,也很现实) similary:::0.486169
  9. 注意!“房地产税”快来了!房贷收紧!2017房价终于要跌了? similary:::0.485974
  10. 刚入的薄款秋装还没秀就更冷了,蓝瘦香菇! similary:::0.480081
  11. 福利来了!这项改革惠及上亿人 2017年底基本实现 similary:::0.47844
  12. LDA similary Top 10:::
  13. 读书|关于婚姻的40句狠话 similary:::0.975631
  14. 明日股市预测:市场反弹行情或延续 similary:::0.970108
  15. 金融圈的那些事:扒一扒中信、平安、信达与一个大佬的剩余价值 similary:::0.969657
  16. 三星全球停售note7 中国区正清点库存 similary:::0.965391
  17. 今天总理再谈楼市,这七大关键词信息量很大 similary:::0.960572
  18. 三星爆炸门持续发酵丨note7全球停产,唯中国依旧在卖 similary:::0.957877
  19. 奥巴马刚走,他这个涉及5000万人的政策,就要被抛弃 similary:::0.956485
  20. 三星玩大了!爆炸事件频起的note 7已暂停生产并召回 similary:::0.945706
  21. 专供出口的阳澄湖大闸蟹,国内同步开售 similary:::0.945251
  22. 石原里美和北川景子们的傲人身材,都是这样维持的! similary:::0.943272

结论:还是可以看到结果是和金融强相关的,但是也有其他主题的文章进来了,调试了一下发现时主题模型的时候数据有些不对,可能原因是字典纯度不够。优化一下是可以用在文章推荐上的。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注