一些概念前摇

word2vec涉及到的知识点很多,包括:神经网络、语言模型、n-gram、One-Hot、NNLM、到CBOW、Skip-gram、哈夫曼编码、反向传播、Hierarchical SoftMax、负采样。

一、使用Gensim库构造词向量

首先需要导入gensim包,以下是计算词汇 'dogs' 和 'you' 之间的相似度的代码。

from gensim.models import word2vec
import logging

logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s',level=logging.INFO)
raw_sentences=["the quick brown fox jumps over the lazy dogs","yoyoyo you go home to sleep"]
sentences=[s.split() for s in raw_sentences]
print(sentences)

model=word2vec.Word2Vec(sentences,min_count=1)
p1=model.wv.similarity('dogs','you')
print(p1)

二、中文语料处理

查了很多资料和视频,这一步大多是自行下载维基百科中文语料,然后使用opencc进行繁简体转换,个人觉得这步不是很重要,所以用之前旅游网站爬取的评论作文本分析。

没有下载维基百科中文语料的,可以随便找本电子书,需要UTF-8格式。

导入jieba包,对自己的语料进行分词。

import jieba
import codecs

def cut_words(sentence):
    return " ".join(jieba.cut(sentence))

f = codecs.open("critic.txt", 'r', encoding="utf8")
target = codecs.open("critic.seg.txt", 'w', encoding="utf8")
print('open files')
line_num = 1

for line in f:
    print('----processing ', line_num, ' article----')
    line_seg = cut_words(line.strip())  # 使用strip()去除换行符
    target.write(line_seg + "\n")  # 写入文件时加上换行符
    line_num += 1

f.close()
target.close()

看一下分词的效果: 

分词前:

蛮好的,豪华游轮视野很好。自助餐也蛮不错,菜品比较丰富,不过到饭点得提前排队,排在后面基本没啥好吃的了,后面再续得话,也没几个菜。不过都能吃饱
“客路青山外,行舟綠水前。潮平兩岸闊,風正一帆懸。”雖然詩中所描繪的並非桂林,但用在陽朔灕江上更加貼切。不管是站在船頭還是船尾景色都是無可挑剔的。
携程买的三星游船,不包饭。比我想象中好很多呢!有茶水供应!二楼一楼其实没大所谓。拍照都会去甲板的。到景点的时候会有很多人,要提前占好位置。自拍杆准备好。单程!不走回头路!去码头在郊区,建议坐旅行社的大巴送。磨盘山客运港是漓江精华游(桂林-阳朔航线)的始发港,距桂林市区28千米,因紧邻磨盘山而得名。除了当天天气阴,其他都很好!直接到阳朔继续浪!
真不愧是桂林山水甲天下。景色,景点都十分吸引,整个旅程感觉良好。遊船上的服务员态度友善,介绍的小吃也不错。船上环境和卫生都很滿意。
非常感谢桂林携程的小谭尾号8480和陆导游,他们为我们的旅行提供了出色的服务和难忘的经历。小谭的专业素养和耐心让我们感到宾至如归。他详细介绍了桂林的风景胜地,使我们对这个地方有了更深入的了解。
陆导游也是一位卓越的导游,她对桂林的历史和文化知识丰富而深刻。她引导我们探索了令人惊叹的自然景观,并与我们分享了许多有趣的故事。她的幽默和友好使整个旅行更加愉快。

分词后:

蛮 好 的 , 豪华 游轮 视野 很 好 。 自助餐 也 蛮 不错 , 菜品 比较 丰富 , 不过 到 饭点 得 提前 排队 , 排 在 后面 基本 没 啥 好吃 的 了 , 后面 再续 得话 , 也 没 几个 菜 。 不过 都 能 吃饱
“ 客路 青山 外 , 行舟 綠水前 。 潮平 兩岸闊 , 風正 一帆 懸 。 ” 雖然 詩中 所 描繪 的 並非 桂林 , 但用 在 陽朔 灕 江上 更加 貼切 。 不管 是 站 在 船頭 還是 船尾 景色 都 是 無 可 挑剔 的 。
携程 买 的 三星 游船 , 不 包饭 。 比 我 想象 中好 很多 呢 ! 有 茶水供应 ! 二楼 一楼 其实 没 大 所谓 。 拍照 都 会 去 甲板 的 。 到 景点 的 时候 会 有 很多 人 , 要 提前 占 好 位置 。 自拍杆 准备 好 。 单程 ! 不 走回头路 ! 去 码头 在 郊区 , 建议 坐 旅行社 的 大巴 送 。 磨盘 山 客运港 是 漓江 精华游 ( 桂林 - 阳朔 航线 ) 的 始发 港 , 距 桂林 市区 28 千米 , 因 紧邻 磨盘 山而 得名 。 除了 当天 天气 阴 , 其他 都 很 好 ! 直接 到 阳朔 继续 浪 !
真不愧是 桂林山水 甲天下 。 景色 , 景点 都 十分 吸引 , 整个 旅程 感觉良好 。 遊 船上 的 服务员 态度 友善 , 介绍 的 小吃 也 不错 。 船上 环境 和 卫生 都 很 滿意 。
非常感谢 桂林 携程 的 小 谭 尾号 8480 和 陆 导游 , 他们 为 我们 的 旅行 提供 了 出色 的 服务 和 难忘 的 经历 。 小谭 的 专业 素养 和 耐心 让 我们 感到 宾至如归 。 他 详细 介绍 了 桂林 的 风景 胜地 , 使 我们 对 这个 地方 有 了 更 深入 的 了解 。
陆 导游 也 是 一位 卓越 的 导游 , 她 对 桂林 的 历史 和 文化 知识 丰富 而 深刻 。 她 引导 我们 探索 了 令人惊叹 的 自然景观 , 并 与 我们 分享 了 许多 有趣 的 故事 。 她 的 幽默 和 友好 使 整个 旅行 更加 愉快 。

 三、Gensim构造word2vec模型

从给定的输入文本文件中训练 Word2Vec 模型,并将训练好的模型保存到指定文件中,同时将词向量保存到另一个指定的文件中。

import os.path
import sys
import logging
import multiprocessing
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence

# 如果该脚本是主程序,则执行以下代码
if __name__ == '__main__':
    # 获取当前脚本的文件名
    program = os.path.basename(sys.argv[0])
    # 配置日志记录器,设置日志格式
    logger = logging.getLogger(program)
    logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s')
    # 记录当前正在运行的程序
    logger.info("running %s" % ' '.join(sys.argv))

    # 检查命令行参数数量是否正确
    if len(sys.argv) < 4:
        print("Usage: {} input_text output_model output_vector".format(program))
        sys.exit(1)

    # 从命令行参数中获取输入文本、输出模型和输出词向量文件路径
    inp, outp1, outp2 = sys.argv[1:4]
    
    # 使用输入文本文件创建 Word2Vec 模型
    # 参数说明:
    #   - inp: 输入文本文件路径
    #   - vector_size: 词向量维度
    #   - window: 上下文窗口大小
    #   - min_count: 忽略出现次数低于此值的词汇
    #   - workers: 使用的 CPU 核心数
    model = Word2Vec(LineSentence(inp), vector_size=400, window=5, min_count=5, workers=multiprocessing.cpu_count())
    
    # 将训练好的模型保存到指定文件中
    model.save(outp1)
    
    # 将词向量保存到指定文件中(以文本形式保存)
    model.wv.save_word2vec_format(outp2, binary=False)

打开终端,进入该工程文件夹下,输入以下指令进行建模,如果本身的语料库比较大,可能需要30分钟—几个小时:

建模成功后,工程里会多出两个文件:

四、测试模型相似度结果

模型建好后,可以进行测试。因为我爬取的文本是关于桂林旅游的,所以选取和旅游有关的五个词进行测试。

from gensim.models import  Word2Vec
critic_Word2Vec_model=Word2Vec.load('critic.txt.model')

testwords=['桂林','漓江','价格','漂流','服务']
for i in range(5):
    res=critic_Word2Vec_model.wv.most_similar(testwords[i])
    print(testwords[i])
    print(res)

测试结果:

桂林
[('阳朔', 0.8995137810707092), ('旅游', 0.8843175768852234), ('之一', 0.8491352796554565), ('名片', 0.8369091153144836), ('象鼻山', 0.8300248980522156), ('必游', 0.8245748281478882), ('必', 0.8241394758224487), ('必看', 0.8174369931221008), ('城市', 0.8092430830001831), ('必去', 0.8054908514022827)]
漓江
[('最美', 0.8685281276702881), ('如果说', 0.8612004518508911), ('美景', 0.8414103984832764), ('精华', 0.8383922576904297), ('境内', 0.8309932351112366), ('大家闺秀', 0.8218607902526855), ('之称', 0.8172631859779358), ('游走', 0.8167197704315186), ('而', 0.8148564696311951), ('华灯初上', 0.814479649066925)]
价格
[('票价', 0.9683249592781067), ('贵', 0.9585074186325073), ('便宜', 0.9107561111450195), ('不算', 0.8902684450149536), ('而且', 0.8871752023696899), ('实惠', 0.8830732107162476), ('价格便宜', 0.8742744326591492), ('不好', 0.8733986616134644), ('划算', 0.8707610964775085), ('无聊', 0.8665204644203186)]
漂流
[('人工', 0.8752527832984924), ('电动', 0.8685582876205444), ('坐', 0.852655291557312), ('乘坐', 0.8299727439880371), ('坐船', 0.829564094543457), ('游览', 0.8159646987915039), ('一段', 0.8133681416511536), ('漂', 0.8112012147903442), ('游', 0.8045587539672852), ('游船', 0.8042957782745361)]
服务
[('态度', 0.967018187046051), ('热情', 0.9388080835342407), ('服务态度', 0.936856210231781), ('解说', 0.9367859959602356), ('讲解员', 0.9265632629394531), ('耐心', 0.9222474694252014), ('小姐姐', 0.9177296161651611), ('人员', 0.915381908416748), ('讲', 0.90914386510849), ('细致', 0.9066590070724487)]

可以看出相似度高的还是比较准确的,但是出现了“之一”“而且”“必”这些停用词,可以在测试前先去停用词。

参考:

2-维基百科中文数据处理_哔哩哔哩_bilibili

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐