继续学习摸索,看到很多博客都在研究Word2Vec,感觉挺有意思,我也来尝试一下。
实验环境:Python3,Java8
Word2Vec的输入是句子序列,而每个句子又是一个单词列表,由于没有这样结构的现成输入,所以决定自己动手对原始语料进行预处理。
NLPIR是一个汉语分词系统,挺感谢张华平博士,便利了我们的文本处理工作。下载地址:http://ictclas.nlpir.org/newsdownloads?DocId=389
这里还有一个自然语言处理与信息检索共享平台(感觉挺好的,有资料,还有演示,个人觉得那个在线演示挺赞的):http://www.nlpir.org/
NLPIR可以应用于C/C++/C#/Java/Python,我尝试了Java和Python两个版本,只是Python版在测试的时候报错:初始化失败!费解了半天也没找出到底是什么原因,因而先转向使用Java版的。
NLPIR-Java使用起来比较简单,首先下载zip文件,我的是【20160405172043_ICTCLAS2016分词系统下载包.zip】
然后解压,调用sample目录下的JnaTest_NLPIR项目即可。有两个地方需要注意:第16行的dll路径,根据自己的路径修改,可以考虑放在项目里;第44行的ICTCLAS路径,即解压文件里的bin下的ICTCLAS2015文件夹的路径,也可以考虑放在项目里。如果这两个文件是放在项目里的,那么解压文件里还有一个Data文件夹需要放在项目里的ICTCLAS2015下。结构如下:
修改好后便可以测试了。
package code; import java.io.UnsupportedEncodingException; import utils.SystemParas; import com.sun.jna.Library; import com.sun.jna.Native; public class NlpirTest { // 定义接口CLibrary,继承自com.sun.jna.Library public interface CLibrary extends Library { // 定义并初始化接口的静态变量,该路径根据实际dll路径修改,32位或64位也根据实际情况修改 CLibrary Instance = (CLibrary) Native.loadLibrary( "D:\\NLPIR\\bin\\ICTCLAS2013\\x64\\NLPIR", CLibrary.class); public int NLPIR_Init(String sDataPath, int encoding, String sLicenceCode); public String NLPIR_ParagraphProcess(String sSrc, int bPOSTagged); public String NLPIR_GetKeyWords(String sLine, int nMaxKeyLimit, boolean bWeightOut); public String NLPIR_GetFileKeyWords(String sLine, int nMaxKeyLimit, boolean bWeightOut); public int NLPIR_AddUserWord(String sWord);//add by qp 2008.11.10 public int NLPIR_DelUsrWord(String sWord);//add by qp 2008.11.10 public String NLPIR_GetLastErrorMsg(); public void NLPIR_Exit(); } public static String transString(String aidString, String ori_encoding, String new_encoding) { try { return new String(aidString.getBytes(ori_encoding), new_encoding); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } public static void main(String[] args) throws Exception { String argu = "D:\\NLPIR"; // String system_charset = "GBK";//GBK----0 String system_charset = "UTF-8"; //UTF-8----1 int charset_type = 1; int init_flag = CLibrary.Instance.NLPIR_Init(argu, charset_type, "0"); String nativeBytes = null; if (0 == init_flag) { nativeBytes = CLibrary.Instance.NLPIR_GetLastErrorMsg(); System.err.println("初始化失败!fail reason is "+nativeBytes); return; } //sInput是原始待处理字符串 String sInput = "据悉,质检总局已将最新有关情况再次通报美方,要求美方加强对输华玉米的产地来源、运输及仓储等环节的管控措施,有效避免输华玉米被未经我国农业部安全评估并批准的转基因品系污染。"; try { //分词和标注处理,1表示标注,0表示不标注 nativeBytes = CLibrary.Instance.NLPIR_ParagraphProcess(sInput, 1); System.out.println("分词结果为: " + nativeBytes); //添加用户自定义词语 CLibrary.Instance.NLPIR_AddUserWord("要求美方加强对输 n"); CLibrary.Instance.NLPIR_AddUserWord("华玉米的产地来源 n"); nativeBytes = CLibrary.Instance.NLPIR_ParagraphProcess(sInput, 1); System.out.println("增加用户词典后分词结果为: " + nativeBytes); //删除用户自定义词语 CLibrary.Instance.NLPIR_DelUsrWord("要求美方加强对输"); nativeBytes = CLibrary.Instance.NLPIR_ParagraphProcess(sInput, 1); System.out.println("删除用户词典后分词结果为: " + nativeBytes); int nCountKey = 0; //获取关键词,第二个参数是最大关键词数量,默认为50;第三个参数表示是否输出权重 //每个关键词以#分隔,若有权重输出,则权重分别为信息熵权重与词频权重,权重以/分隔 String nativeByte = CLibrary.Instance.NLPIR_GetKeyWords(sInput, 10,false); System.out.print("关键词提取结果是:" + nativeByte); //获取文件关键词,第二个参数是最大关键词数量,默认为50;第三个参数表示是否输出 //权重,该权重表示信息熵权重。 //测试NLPIR的readme文件 nativeByte = CLibrary.Instance.NLPIR_GetFileKeyWords("D:/Readme.txt", 10,false); System.out.print("关键词提取结果是:" + nativeByte); //退出 CLibrary.Instance.NLPIR_Exit(); } catch (Exception ex) { // TODO Auto-generated catch block ex.printStackTrace(); } } }
测试输出:
分词结果为: 据悉/v ,/wd 质检/vn 总局/n 已/d 将/d 最新/a 有关/vn 情况/n 再次/d 通报/v 美方/n ,/wd 要求/v 美方/n 加强/v 对/p 输/v 华/b 玉米/n 的/ude1 产地/n 来源/n 、/wn 运输/vn 及/cc 仓储/vn 等/udeng 环节/n 的/ude1 管/v 控/v 措施/n ,/wd 有效/ad 避免/v 输/v 华/b 玉米/n 被/pbei 未经/d 我国/n 农业部/nt 安全/an 评估/vn 并/cc 批准/v 的/ude1 转基因/n 品系/n 污染/vn 。/wj 增加用户词典后分词结果为: 据悉/v ,/wd 质检/vn 总局/n 已/d 将/d 最新/a 有关/vn 情况/n 再次/d 通报/v 美方/n ,/wd 要求美方加强对输/n 华玉米的产地来源/n 、/wn 运输/vn 及/cc 仓储/vn 等/udeng 环节/n 的/ude1 管/v 控/v 措施/n ,/wd 有效/ad 避免/v 输/v 华/b 玉米/n 被/pbei 未经/d 我国/n 农业部/nt 安全/an 评估/vn 并/cc 批准/v 的/ude1 转基因/n 品系/n 污染/vn 。/wj 删除用户词典后分词结果为: 据悉/v ,/wd 质检/vn 总局/n 已/d 将/d 最新/a 有关/vn 情况/n 再次/d 通报/v 美方/n ,/wd 要求/v 美方/n 加强/v 对/p 输/v 华玉米的产地来源/n 、/wn 运输/vn 及/cc 仓储/vn 等/udeng 环节/n 的/ude1 管/v 控/v 措施/n ,/wd 有效/ad 避免/v 输/v 华/b 玉米/n 被/pbei 未经/d 我国/n 农业部/nt 安全/an 评估/vn 并/cc 批准/v 的/ude1 转基因/n 品系/n 污染/vn 。/wj 字符串关键词提取结果是:华玉米的产地来源#农业部#有关#污染# 文件关键词提取结果是:NLPIR#ICTCLAS#NLPIR2014#Website#ICTCLAS2014#Linux#Readme.txt#test#Java#English.txt#
分词、词性标注和关键词提取的功能均可用,其他功能可以参考NLPIR下的doc目录里的使用说明文件。
用NLPIR对原始语料分词后,将分词结果保存在corpus_result.txt文件中,接下来将该文件应用于Python版的Word2Vec中。
首先需要在Python中安装gensim,可用命令pip install gensim
安装完成后,在程序中import gensim即可使用。
import logging import os import time import gensim from gensim.models import word2vec import jieba import nltk logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s',level=logging.INFO) sentences = [] start1 = time.clock() file = open('D:/corpus_result.txt','r',encoding='utf-8') <pre name="code" class="python">contents = file.read()
print(‘读取文件耗时:‘,time.clock()
print(‘分词耗时:‘,time.clock())for line in file.readlines(): #按行读取 sentences.append(line.split(" "))# print(sentences)# print(len(sentences))
#sentences是句子序列,句子又是单词列表,
#如[[‘蒙牛‘,‘牛奶‘,‘好喝‘],[‘三星‘,‘手机‘],[‘名车‘,‘抢眼‘,‘奥迪‘,‘拍照‘]]
#min_count表示小于该数的单词会被剔除,默认值为5
#size表示神经网络的隐藏层单元数,默认为100
model = word2vec.Word2Vec(sentences,min_count=2,size=200)
#保存生成的训练模型
model.save(‘model/mymodel4‘)#加载模型文件new_model = gensim.models.Word2Vec.load(‘model/mymodel4‘)
#与“蒙牛”相似的词语,倒排
print(new_model.most_similar(‘蒙牛‘))
#计算词1和词2的余弦相似度
print(‘蒙牛 -- 伊利 间的余弦距离:‘,new_model.similarity(‘蒙牛‘,‘伊利‘))
#计算两个数据集间的余弦相似度
print(‘【三星 手机】--【安卓 手机】间的余弦距离:‘,new_model.n_similarity([‘三星‘,‘手机‘], [‘安卓‘,‘手机‘])) print(‘【牛奶 伊利 iPhone 蒙牛】 中不同的一项是:‘,new_model.doesnt_match(‘牛奶 伊利 iPhone 蒙牛‘.split()))
首先是训练模型,corpus_result.txt大小为4.5M,训练耗时30min,单机下时间还是挺长的。
然后是根据模型计算,输出结果:
[('伊利', 0.9417093992233276), ('奶', 0.9356977343559265), ('牛奶', 0.9347156286239624), ('君乐宝', 0.9280596971511841), ('@张俊英ZJY', 0.918419361114502), ('@弓长王月图样图森破', 0.912131667137146), ('氰', 0.9068763256072998), ('胺', 0.9067373275756836), ('海盐', 0.9053752422332764), ('下毒', 0.902400553226471)] 蒙牛 -- 伊利 间的余弦距离: 0.941709369359 【三星 手机】--【安卓 手机】间的余弦距离: 0.962285233171 【牛奶 伊利 iPhone 蒙牛】 中不同的一项是: iPhone
内存使用情况,word2vec的参数存在在numpy array中,主要有这样三个矩阵,如果有100000个单词,隐藏层单元数为200,那么所需内存大小为100000*200*4*3bytes,约229MB。
现在NLPIR-Java和Word2Vec-Python都可以简单使用起来,接下来就是学习其原理,继续努力!
另外还要感谢一些博主的知识分享:
[1] http://www.mamicode.com/info-detail-870051.html
[2] http://ju.outofmemory.cn/entry/80023
[3] http://www.tuicool.com/articles/7ZnUnq