经过对各种机器学习算法的初步了解,我最终选定了word2vec来实现药品推荐的功能
word2vec是word embedding(词向量)的一种浅层神经网络训练方法。word embedding的这一系列的训练方法,都有一个有趣的现象,那就是训练的主要目标居然是获得side effect的词向量,而不是神经网络的预测模型。这是一种Transfer Learning的思想。这种思想非常值得学习。
还很有意思的是word2vec的训练过程是有监督的神经网络学习,但是得到的结果居然是无监督的clustering的效果,就是获取词向量。它是通过从无监督的语料,像维基百科中获取有监督的语料来实现的。比如获取用上下文预测下一个词的语料。
word2vec本质上来说就是一个矩阵分解的模型,简单地说,矩阵刻画了每个词和其上下文的词的集合的相关情况。对这个矩阵进行分解,只取每个词对应在隐含空间的向量。
所以word2vec适合的情况就是对于一个序列的数据,在序列局部数据间存在着很强的关联。典型的就是文本的序列了,邻近的词之间关联很强,甚至可以通过一个词的上下文大概预测出中间那个词是什么。学习到的词向量代表了词的语义,可以用来做分类、聚类、也可以做词的相似度计算。此外,Word2vec本身的层次分类器或者采样方式实际上对热门item做了很大的惩罚,所以不会像一般的矩阵分解一样,最后算出来语义接近的都是热门词,这也是word2vec很好的一个特性。
下面来介绍一下具体实现过程:
在Python下安装个gensim的包就可以用word2vec了,不过gensim只实现了word2vec里面的skip-gram模型。若要用到其他模型,就需要去研究其他语言的word2vec了
有了gensim包之后,看了网上很多教程都是直接传入一个txt文件,但是这个txt文件长啥样,是什么样的数据格式呢,很多博客都没有说明,也没有提供可以下载的txt文件作为例子。进一步理解之后发现这个txt是一个包含巨多文本的分好词的文件。如下图所示,是我自己训练的一个语料,我选取了自己之前用爬虫抓取的维基中文语料库当做语料并进行分词。注意,词与词之间一定要用空格:
至于为什么要使用维基中文语料库,主要原因是我用之前获取到的药品信息进行分词后训练获得的模型,词语间的相关度普遍偏高,这是由于语料库过小导致的,一般来说,想要获得有参考价值的模型,语料库的大小要超过一个G。
维基中文语料库的获取和处理可以参考http://blog.csdn.net/jdbc/article/details/59483767
这里分词依然使用的是jieba分词,代码如下:
__author__='XJX'
__date__='2017.08.04'
# -*- coding: UTF-8 -*-
import jieba
import os.path
import os
import codecs
#jieba.load_userdict("/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/jieba/userdict.txt")
#import jieba.posseg as pseg
print('start')
input_txt = open('/users/xujiaxing/downloads/wiki.txt','r',encoding='utf8')
output_txt = open('/users/xujiaxing/downloads/tmp.txt','w',encoding='utf8')
#mdzz = 'mdzz'
#output_txt.write(mdzz)
for line in input_txt:
print('start')
seg = jieba.cut(line.strip(),cut_all=False)
s = ' '.join(seg)
m = list(s)
for word in m:
output_txt.write(word)
print(word)
output_txt.close()
input_txt.close()
接下来就可以
使用gensim的word2vec训练模型了
代码如下:
import sys
sys.path.remove('/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python')
#sys.path.remove('/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC')
sys.path.append('/Users/xujiaxing/anaconda/lib/python3.6/site-packages')
from gensim.models import word2vec
import logging
file = r'/users/xujiaxing/downloads/temp.txt'
#print(os.sys.path)
# 主程序
logging.basicConfig(format='%(asctime)s:%(levelname)s: %(message)s', level=logging.INFO)
sentences =word2vec.Text8Corpus(file) # 加载语料
model =word2vec.Word2Vec(sentences, size=200) #训练skip-gram模型,默认window=5
print(model)
# 计算两个词的相似度/相关程度
try:
y1 = model.similarity(u"肺炎", u"支气管炎")
except KeyError:
y1 = 0
print (u"【肺炎】和【支气管炎】的相似度为:"+str(y1))
print("-----\n")
# 计算某个词的相关词列表
y2 = model.most_similar(u"肺炎", topn=20) # 20个最相关的
print (u"和【肺炎】最相关的词有:\n")
for item in y2:
print(item[0], item[1])
print("-----\n")
# 保存模型,以便重用
model.save(u"ml.model")
# 对应的加载方式
# model_2 =word2vec.Word2Vec.load("text8.model")
# 以一种c语言可以解析的形式存储词向量
#model.save_word2vec_format(u"书评.model.bin", binary=True)
# 对应的加载方式
# model_3 =word2vec.Word2Vec.load_word2vec_format("text8.model.bin",binary=True)
使用效果如下图: