Python的gensim库可以训练和使用word2vec模型,R语言中也有与之对应的word2vec包。word2vec是词嵌入技术中最常用的一种技术,如果对词嵌入不太了解,可以阅读前文

本文需要的R包

install.packages(c("word2vec", "jiebaR", "tidyverse", "readtext"))


word2vec包常用函数

  • word2vec 使用文本数据训练word2vec模型
  • as.matrix 获取词向量
  • doc2vec 获取文档向量
  • predict 获取
  • write.word2vec 保存word2vec模型至文件
  • read.word2vec 读取word2vec模型文件


准备数据

原始数据是从网站下载的 三体.txt, 未分词处理,现在需要

  1. 读中文取txt数据
  2. 保留标点符号,进行分词处理
  3. 分词结果重新整理为类似英文(空格间隔词语的形式)字符串
  4. 结果存入新的txt
library(jiebaR)
library(tidyverse)
library(word2vec)


#导入数据
tri_body <- readtext::readtext('data/三体.txt')$text 

#分词(保留标点符号)
tokenizer <- worker(symbol=T)
tri_words <- segment(tri_body, tokenizer)

# 整理为英文格式(词语之间加空格)
segmented_text <- stringr::str_c(tri_words, collapse = " ") %>% c()

#写入txt
readr::write_file(segmented_text, file='data/santi.txt')


训练word2vec模型

word2vec(
  x,
  type = c("cbow", "skip-gram"),
  dim = 50,
  window = ifelse(type == "cbow", 5L, 10L),
  iter = 5L,
  lr = 0.05,
  min_count = 5L,
  split = c(" \n,.-!?:;/\"#$%&'()*+<=>@[]\\^_`{|}~\t\v\f\r", ".\n?!"),
  stopwords = character(),
  threads = 1L,
  ...
)
  • x 英文文本数据txt文件(中文数据txt文件是分词后的txt文件,空格间隔词语)
  • type 训练方式,默认CBOW
  • dim 词向量维度,默认50维
  • window 词向量窗口,默认5
  • iter 训练迭代次数,默认5
  • split 分词、分句对应的分隔符。
  • lr 学习率,默认0.05
  • min_count 词语在语料中至少要出现5次(低于5次的词语,训练好的结果中没有该词语)
  • stopwords 停用词表,默认空字符集
  • threads 并行加速,cpu核数,默认1。为了加速训练过程,可以使用 parallel::detectCores() 获得本电脑的核数
#训练10维的词向量模型
model <- word2vec(x = 'data/santi.txt', 
                  dim = 10,  
                  iter = 20, 
                  split = c(" ",  "。?!;"),
                  threads = parallel::detectCores()) #并行,使用cpu多核加速

emb <- as.matrix(model)

#显示6个词
head(emb)
##             [,1]       [,2]        [,3]        [,4]      [,5]        [,6]
## 煮   -1.02566934 -0.9271542 -0.42417252 -0.54280633 1.8847700  0.41640753
## 报   -0.83992052  1.9440031  0.09093992  0.83522910 1.7909089  0.72149992
## 悬空 -0.06369513 -1.3519955 -2.13137460 -0.06198586 0.6096401  1.32933748
## 略    1.74687469 -0.4278547 -0.33822438  1.08505321 2.0168977 -0.07693915
## 伏   -0.68947995 -1.4147453 -1.95522511 -0.39963767 0.5269030  0.30352208
## 石柱 -0.40561640 -1.3643234  0.30329546 -0.94012892 2.1579018  0.79654717
##            [,7]       [,8]       [,9]      [,10]
## 煮   -1.1708908 -0.7624418 -0.6275516  1.2417521
## 报    0.5235919  0.8448864 -0.2960095 -0.0773837
## 悬空  0.1527163 -0.1337370 -0.1646384  1.1892601
## 略   -0.3246748 -0.9813624  0.5045205  0.2771466
## 伏    0.3166684 -1.4238008 -1.0167172 -0.0976937
## 石柱  0.2237919  0.6933151  0.7412233 -0.7918702


查看某词的vector

查看词语 汪淼 的vector

emb["汪淼",]
##  [1] -0.77559733 -0.90021265  0.66555792 -0.10277803  1.89924443 -0.88817298
##  [7] -1.32665634 -0.75938725 -0.09628224  1.18008399

查看词语 地球 的vector

emb["地球",]
##  [1]  0.29645494 -0.61688840  0.91209215 -0.64530188  0.62816381 -0.72807491
##  [7]  0.50655973  2.38137436  1.19238114 -0.09610342


predict()

找到语料中,词语 罗辑 最相似的 20个词

predict(model, '罗辑', type='nearest', top_n = 20)
## $罗辑
##    term1    term2 similarity rank
## 1   罗辑     胡文  0.9744400    1
## 2   罗辑   申玉菲  0.9678891    2
## 3   罗辑   瓦季姆  0.9550550    3
## 4   罗辑 狄奥伦娜  0.9518393    4
## 5   罗辑     蓝西  0.9472395    5
## 6   罗辑     护士  0.9471439    6
## 7   罗辑   法扎兰  0.9458703    7
## 8   罗辑   白艾思  0.9451101    8
## 9   罗辑     坎特  0.9396626    9
## 10  罗辑     白蓉  0.9387447   10
## 11  罗辑   参谋长  0.9377206   11
## 12  罗辑   弗雷斯  0.9369408   12
## 13  罗辑   第一眼  0.9357565   13
## 14  罗辑     父亲  0.9350463   14
## 15  罗辑   多少次  0.9314436   15
## 16  罗辑     门去  0.9291503   16
## 17  罗辑     维德  0.9267251   17
## 18  罗辑     褐蚁  0.9203902   18
## 19  罗辑       刚  0.9200501   19
## 20  罗辑     吴岳  0.9191605   20

查看均值向量(多个词向量中心的)的10个近义词

vectors <- emb[c("汪淼", "罗辑", "叶文洁"), ]
centroid_vector <- colMeans(vectors)

predict(model, centroid_vector, type = "nearest", top_n = 10)
##        term similarity rank
## 1      罗辑  0.9185568    1
## 2  狄奥伦娜  0.9104245    2
## 3      文洁  0.9088279    3
## 4      汪淼  0.9054156    4
## 5    白艾思  0.9046930    5
## 6      张翔  0.9026827    6
## 7      尴尬  0.8952187    7
## 8      庄颜  0.8952166    8
## 9      皇帝  0.8949283    9
## 10     父亲  0.8915347   10


doc2vec()

  • doc2vec(object, newdata, split = ” “)
    • object word2vec模型对象
    • newdata 文档列表(用空格间隔的字符串列表)
    • split 默认分隔符是空格

将文档转为向量

docs <- c("哦 , 对不起 , 汪 教授 。 这是 我们 史强 队长 。", 
          " 丁仪 博士 , 您 能否 把 杨冬 的 遗书 给 汪 教授 看 一下 ? ")

doc2vec(object=model, newdata = docs, split=' ')
##            [,1]       [,2]       [,3]     [,4]      [,5]       [,6]       [,7]
## [1,] -1.1769752 -0.1065619  0.1983950 1.734068 0.5478012 -0.8320528 -0.2387014
## [2,] -0.4827189  0.0664595 -0.2119484 1.895074 0.6729840 -0.3008853 -0.6857539
##            [,8]      [,9]      [,10]
## [1,] -0.5519856 -2.007002  0.4182127
## [2,] -0.5976922 -2.130454 -0.4653725


保存word2vec模型

保存模型,一般有两个目的

  • 为了分享word2vec模型
  • 避免反复训练模型,节约数据分析时间
word2vec::write.word2vec(x = model, 
                         #新建output文件夹,将模型存入output文件夹内
                         file = "output/santi_word2vec.bin")
## [1] TRUE


导入预训练模型

导入 output/santi_word2vec.bin 的预训练word2vec模型

pre_trained_model <- word2vec::read.word2vec(file = "output/santi_word2vec.bin")
pre_trained_emb <- as.matrix(pre_trained_model)
head(pre_trained_emb)
##              [,1]       [,2]       [,3]       [,4]       [,5]        [,6]
## 回荡   -1.9563367 -0.3099073 -1.2969902 -0.5719763  1.1507142 -0.05515177
## 听证会  0.2756990  1.3702289 -1.3303705 -0.1827691  0.6622804 -1.92008448
## 纲领    0.4495552  1.9311246 -0.5812275 -0.1470096 -0.2678985 -0.01694358
## 很亮    0.3621844 -1.0048453  0.7036168 -2.0917876  0.6459805  1.18436253
## 秒      1.9033701  1.6510324 -0.2616904  0.3671210  1.0618066  0.06588747
## 杰森   -1.2904713 -1.2501229  0.3380587  0.8590797  1.6798494 -0.58775252
##              [,7]       [,8]       [,9]      [,10]
## 回荡    1.1082711 -0.2064489 -0.9264346 -0.7816723
## 听证会 -1.0952694  0.6120903 -0.1326561  0.7252344
## 纲领   -0.6097277  2.1051276 -0.2405726 -0.8808851
## 很亮    0.1964065 -1.3926132 -0.4042619 -0.1645472
## 秒     -0.8347995  0.2591044  0.3594093  1.1929117
## 杰森    0.4941484 -1.1393189 -0.4687541  0.9951217