机器学习-13 新闻推荐 doc2vec

新闻推荐,用户阅读的是整条新闻,不可能将整条新闻直接送进去模型训练,这样的话什么都训练不出来。
而新闻是由很多词汇组成,需要进行分词,分词后输入模型进行训练,
也只是返回这个词在上下文语境相似的词汇,比如我们输入“公安机关”返回“警察”整片新闻,但是警察不是整篇新闻。
doc2vec 将整篇文章中多个词映射到空间中,转换为向量(使用的也是余弦相似度)。
不再比较单词的相似度,而是比较文档之间的相似度,我们输入的是文档,返回的也是文档。

模型效果评估
doc2vec模型训练好之后,可以对未知的文档进行预测,这个和Word2vec不同。
word2vec如果预测的词是训练语料库中没有的词会出错,不会找出相近的词汇。
而doc2vec可以对未知的文档推断出其映射到空间中是怎样的向量vector。
在这个新闻推荐模型中使用了1000个文档进行训练,就可以推断出这1000个文档的向量,
然后再将其中一个向量送进去模型中推断出那个文档跟送进去的文档最相似,也就是自己跟自己匹配。
如果合适的话,自己跟自己匹配应该是获得的是自己的标记tag。
注,1)这个送进去推断的文档,模型也是当做未知文档进行预测。
2)我们不会只拿一个文档进行推断,而是将这1000个全都送进去,看看最后效果怎样。

import numpy as np
import pandas as pd
import re
import jieba
from gensim.models.doc2vec import Doc2Vec,TaggedDocument
from collections import Counter


# 原始数据的处理
# 数据集‘news_tensite_xml.dat’是一个xml类型的文件,不能使用pandas直接进行加载。
# 通过在文档软件(如submit)中我们可以查看到主要内容包含在标签、标签中。
# 读取原始的数据集,使用正则表达式提取<contenttitle>与</contenttitle>中的标题信息。并将信息输入到另外一个文档中。
re_obj = re.compile(r"<contenttitle>(.+?)</contenttitle>")
re_obj2 = re.compile(r"<content>(.+?)</content>")
# 可以两个with open一起写:
# with open(path1,encoding="") as f,open(path2,encoding="") as f2:
# 如果分开写,注意空格:
with open(r"F:\guanghuan\lesson\正课\07机器学习\day75-20190329\recommend\news_tensite_xml.dat", encoding="ANSI") as f:
    with open(r"news.dat", "wt", encoding="ANSI") as f2:
        for line in f:
            match = re_obj.match(line)  # 返回一个正则表达式对象
            if match:
                f2.write(match.group(1))
                line2 = f.readline() # 能够匹配新闻标题,马上用readline再读下一行
                match2 = re_obj2.match(line2)
                if match2:
                    f2.write(match2.group(1))
                f2.write("\n")
# 上面的编码中ANSI为文本原本的编码,写入f2时也可以使用utf-8,但内存比较大,因此还是用ANSI
# re.match  从前往后进行匹配,re.search只要包含就可以

# 加载数据集
news = pd.read_csv(r"news.dat", header=None, names=["title"], encoding="ANSI")
# 查看内容
# display(news.shape)
# display(news.head())
# news.iloc[0].tolist()

# 数据清洗
# news.isnull().sum()
# display(news.duplicated().sum())
# news.drop_duplicates(inplace=True)
# display(news.shape)

re_obj = re.compile(r"[!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~——!,。?、¥…():【】《》‘’“”\s]+")

def process_text(text):
    text = re_obj.sub("", text)
    return jieba.lcut(text)  # 替换后用jieba分词,因为数据量很大,非常耗时
# 因为执行时间较长,这里,我们只取前1000条新闻。
news = news.iloc[:1000]
news["title"] = news["title"].apply(process_text)
# 注意一下:1,0被jieba拆开了,原因是这里的数字是中文格式的数字,不是阿拉伯数字

# 数据建模
# 训练的语料也必须是二维结构,因此需要转换为列表
documents = news["title"].tolist()  # 每篇新闻分词后的结果
# doc2vec训练的语料与word2vec的格式有些不同。
# word2vec要求语料为二维结构的数组
# doc2vec要求语料为TaggedDocument构成的数组。
# TaggedDocument代表的就是一篇文档,该文档包含若干个词汇。

# TaggedDocument的参数。 doc 一维数组,文档中的词汇。 [index] 表示文档的标签。
documents = [TaggedDocument(doc, [index]) for index, doc in enumerate(documents)]
# documents:用来训练的语料。要求是TaggedDocument构成的数组。
# vector_size:文档进行嵌入的维度。(文档映射到空间当中,向量的维度)。
# window:当前词汇与预测词汇之间的最远距离。类似于word2vec的window-size
# min_count: 考虑最小词频的词汇。(如果词汇低于该词频,则不再考虑该词汇)
# worker:并发的数量。
# epochs:训练的轮数。
model = Doc2Vec(documents, vector_size=100, window=5, min_count=1, workers=4, epochs=50)

print(documents[0])
##  TaggedDocument(words=['公安机关', '销毁', '1', '0', '余万', '非法', '枪支', '跨国', '武器',
#                          '走私', '渐起', '中广网', '唐山', '6', '月',。。。。。])
print(documents[0].words)
# #['公安机关',
# # '销毁',
# #  '1',
# #  '0',
# #  '余万'
# # .........
print(documents[0].tags ## [0])
vector = model.infer_vector(documents[0].words)
print(vector)
sim = model.docvecs.most_similar([vector], topn=5)
print(sim)
# # [(0, 0.9702706933021545),  前面的0是文档的标签,也就是上面的index,后面是文档的相似度

# 依次拿出每个文档进行模型预测,得到向量,接下来拿这个向量跟模型进行匹配,按照相似度的倒序
# 进行排列,因此匹配的结果越靠前是越好的。
ranks = []
for doc in documents:
# doc.words就是一个文档中包含的词汇列表。
# infer_vector方法的作用是将参数指定的文档中的词汇列表表示成向量的形式(推断表示)。
# 即如果参数指定的词汇(文档)映射到当前的模型空间中,应该表示成为怎样的向量。
    inferred_vector = model.infer_vector(doc.words)

# 根据参数指定的向量,返回当前模型中,与参数向量最相似的向量,并进行 倒序 排列。
# topn 取多少个最相似的;len(model.docvecs)表示取的个数是模型当中所有的文档数
#       返回的结果是我们输进去的文档在所有文档中排在第几个
sims = model.docvecs.most_similar([inferred_vector], topn=len(model.docvecs))

# 查看推断文档的向量与自己比较,相似度排行第几。(理想情况下,应该排在最前面)
# [tag for tag, _ in sims]获取文档的标签组成的列表
# 列表。index() 返回查找值在列表中的位置,索引
rank = [tag for tag, _ in sims].index(doc.tags[0])  # 因为是倒序返回,所以取第0个
ranks.append(rank)

在这里插入图片描述

# 模型预测
print(",".join(documents[0].words))  #没有join是二维结构

# 推断一个向量
v = model.infer_vector(documents[0].words)
print(v)

在这里插入图片描述

# 在for循环中score是相似度
similar = model.docvecs.most_similar([v], topn=3)  # 推荐前3个
for index, score in similar:
    display(score, ",".join(documents[index].words))

## 结论:
# 下面三个推荐中,第一个是自己,公安机关、非法  第二个是 走私、案 第三个是 黑社会、通缉犯
# 从语义来看是比较相似的,而且相似度依次下降

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值