zoukankan      html  css  js  c++  java
  • Python 结巴分词 + Word2Vec利用维基百科训练词向量

    结巴分词是一个跨语言的中文分词器,整体效果还算不错,功能也够用,这里直接用Python了,其他主流语言版本均有提供。

    Word2Vec,起源于谷歌的一个项目,在我刚开始接触的时候就关注到了他的神奇,大致是通过深度神经网络把词映射到N维空间,处理成向量之后我们终于可以在自然语言处理上方便的使用它进行一些后续处理。

    Python的gensim库中有word2vec包,我们使用这个就可以了,接下来我们就对维基百科进行处理,作为训练集去训练。(包地址:http://radimrehurek.com/gensim/models/word2vec.html

    本文参考:http://www.52nlp.cn/中英文维基百科语料上的word2vec实验

    处理

    使用维基百科的数据很方便,一是Wiki给我们提供了现成的语料库(听说是实时更新的),虽然中文体积不大,但比起自己爬来方便了不少。

    如果使用英文那就更棒了,非常适合作为语料库。

    当然只是说在通用的情况下,在专业词汇上,经过测试效果比较一般(考虑到专业词库有专业wiki,以及中文词条本身也不太多)。

    首先,我们把Wiki处理成Text格式待处理的文本,这一步在本文参考中有现成的代码。

    process_wiki_data.py
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # process_wiki_data.py 用于解析XML,将XML的wiki数据转换为text格式
    import logging
    import os.path
    import sys
    from gensim.corpora import WikiCorpus
    if __name__ == '__main__':
        program = os.path.basename(sys.argv[0])
        logger = logging.getLogger(program)
        logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s')
        logging.root.setLevel(level=logging.INFO)
        logger.info("running %s" % ' '.join(sys.argv))
        # check and process input arguments
        if len(sys.argv) < 3:
            print(globals()['__doc__'] % locals())
            sys.exit(1)
        inp, outp = sys.argv[1:3]
        space = " "
        i = 0
        output = open(outp, 'w',encoding='utf-8')
        wiki = WikiCorpus(inp, lemmatize=False, dictionary={})
        for text in wiki.get_texts():
            output.write(space.join(text) + "
    ")
            i = i + 1
            if (i % 10000 == 0):
                logger.info("Saved " + str(i) + " articles")
        output.close()
        logger.info("Finished Saved " + str(i) + " articles")

    loggerprint更规范,过去没有用过相关的,不太会用,其实用起来还是蛮方便的,这里暂时就先不介绍了。

    Wiki的处理函数在gensim库中有,通过处理我们可以发现,最终效果是变成一行一篇文章并且空格分隔一些关键词,去掉了标点符号。

    执行:python process_wiki.py zhwiki-latest-pages-articles.xml.bz2 wiki.zh.text,等待处理结果。

    处理中文繁体转简体

    Wiki中文语料中包含了很多繁体字,需要转成简体字再进行处理,这里使用到了OpenCC工具进行转换。

    (1)安装OpenCC

    到以下链接地址下载对应版本的OpenCC,下载的版本是opencc-1.0.1-win32。
    https://bintray.com/package/files/byvoid/opencc/OpenCC
    另外,资料显示还有python版本的,使用pip install opencc-python进行安装,未实践不做赘述。

    (2)使用OpenCC进行繁简转换

    进入解压后的opencc的目录(opencc-1.0.1-win32),双击opencc.exe文件。在当前目录打开dos窗口(Shift+鼠标右键->在此处打开命令窗口),输入如下命令行:

     opencc -i wiki.zh.txt -o wiki.zh.simp.txt -c t2s.json
    

    则会得到文件wiki.zh.simp.txt,即转成了简体的中文。

    (3)结果查看

    解压后的txt有900多M,用notepad++无法打开,所以采用python自带的IO进行读取。Python代码如下:

       import codecs,sys
       f = codecs.open(‘wiki.zh.simp.txt‘,‘r‘,encoding="utf8")
       line = f.readline()
       print(line)

    分词

    下一步,分词,原文中用的似乎有些复杂,结巴分词的效果其实已经不错了,而且很好用,这里就用结巴分词处理一下。本身而言结巴分词是不去掉标点的,但是由于上一步帮我们去掉了,所以这里我们比较省力(不然的话原本准备遍历去掉,根据词性标注标点为x)。

    我的Python还是不太6,所以写的代码比较难看OTZ,不过效果是实现了,处理起来比较慢,我觉得readlines里的参数可以更多一点。

    这里下面处理完了之后用map处理,拼接list并且使用utf-8编码,此外,保证一行一个文章,空格分隔(这是后续处理函数的规定)。

    这里分词没开多线程,不过后来发现瓶颈似乎在读取的IO上。

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    import jieba
    import jieba.analyse
    import jieba.posseg as pseg
    def cut_words(sentence):
        #print sentence
        return " ".join(jieba.cut(sentence)).encode('utf-8')
    f = open("wiki.zh.text",encoding='utf8')
    target = open("wiki.zh.text.seg", 'wb')
    # print 'open files'
    line = f.readlines(100000)
    while line:
        curr = []
        for oneline in line:
            #print(oneline)
            curr.append(oneline)
        '''
        seg_list = jieba.cut_for_search(s)
        words = pseg.cut(s)
        for word, flag in words:
            if flag != 'x':
                print(word)
        for x, w in jieba.analyse.extract_tags(s, withWeight=True):
            print('%s %s' % (x, w))
        '''
        after_cut = map(cut_words, curr)
        # print lin,
        #for words in after_cut:
            #print words
        target.writelines(after_cut)
        # print 'saved 100000 articles'
        line = f.readlines(100000)
    f.close()
    target.close()

    训练

    最后就能愉快的训练了,训练函数还是参考了原文:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # train_word2vec_model.py用于训练模型
    import logging
    import os.path
    import sys
    import multiprocessing
    from gensim.corpora import WikiCorpus
    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')
        logging.root.setLevel(level=logging.INFO)
        logger.info("running %s" % ' '.join(sys.argv))
        # check and process input arguments
        if len(sys.argv) < 4:
            print (globals()['__doc__'] % locals())
            sys.exit(1)
        inp, outp1, outp2 = sys.argv[1:4]
        model = Word2Vec(LineSentence(inp), size=400, window=5, min_count=5,
                workers=multiprocessing.cpu_count())
        # trim unneeded model memory = use(much) less RAM
        #model.init_sims(replace=True)
        model.save(outp1)
        model.save_word2vec_format(outp2, binary=False)

    这里用了一个个LineSentence函数,官方文档:http://radimrehurek.com/gensim/models/word2vec.html

    文档这么说:

    Simple format: one sentence = one line; words already preprocessed and separated by whitespace.
    简单的格式:一句话 = 一行,预处理过并且用空白符分隔。

    这里我们一篇文章等于一行。

    执行训练:python train_word2vec_model.py wiki.zh.text.jian.seg wiki.zh.text.model wiki.zh.text.vector,训练速度也还可以。

    之后我们就可以根据这个进行Word2Vec相关操作了:

    In [1]: import gensim
    In [2]: model = gensim.models.Word2Vec.load("wiki.zh.text.model")
    In [3]: model.most_similar(u"足球")
    Out[3]: 
    [(u'u8054u8d5b', 0.6553816199302673),
     (u'u7532u7ea7', 0.6530429720878601),
     (u'u7beeu7403', 0.5967546701431274),
     (u'u4ff1u4e50u90e8', 0.5872289538383484),
     (u'u4e59u7ea7', 0.5840631723403931),
     (u'u8db3u7403u961f', 0.5560152530670166),
     (u'u4e9au8db3u8054', 0.5308005809783936),
     (u'allsvenskan', 0.5249762535095215),
     (u'u4ee3u8868u961f', 0.5214947462081909),
     (u'u7532u7ec4', 0.5177896022796631)]
    In [4]: result = model.most_similar(u"足球")
    In [5]: for e in result:
        print e[0], e[1]
       ....:     
    联赛 0.65538161993
    甲级 0.653042972088
    篮球 0.596754670143
    俱乐部 0.587228953838
    乙级 0.58406317234
    足球队 0.556015253067
    亚足联 0.530800580978
    allsvenskan 0.52497625351
    代表队 0.521494746208
    甲组 0.51778960228
    In [6]: result = model.most_similar(u"男人")
    In [7]: for e in result:
        print e[0], e[1]
       ....:     
    女人 0.77537125349
    家伙 0.617369174957
    妈妈 0.567102909088
    漂亮 0.560832381248
    잘했어 0.540875017643
    谎言 0.538448691368
    爸爸 0.53660941124
    傻瓜 0.535608053207
    예쁘다 0.535151124001
    mc刘 0.529670000076
    In [8]: result = model.most_similar(u"女人")
    In [9]: for e in result:
        print e[0], e[1]
       ....:     
    男人 0.77537125349
    我的某 0.589010596275
    妈妈 0.576344847679
    잘했어 0.562340974808
    美丽 0.555426716805
    爸爸 0.543958246708
    新娘 0.543640494347
    谎言 0.540272831917
    妞儿 0.531066179276
    老婆 0.528521537781
    In [10]: result = model.most_similar(u"青蛙")
    In [11]: for e in result:
        print e[0], e[1]
       ....:     
    老鼠 0.559612870216
    乌龟 0.489831030369
    蜥蜴 0.4789905250070.46728849411
    鳄鱼 0.461885392666
    蟾蜍 0.448014199734
    猴子 0.436584025621
    白雪公主 0.434905380011
    蚯蚓 0.433413207531
    螃蟹 0.4314712286
    In [12]: result = model.most_similar(u"姨夫")
    In [13]: for e in result:
        print e[0], e[1]
       ....:     
    堂伯 0.583935439587
    祖父 0.574735701084
    妃所生 0.569327116013
    内弟 0.562012672424
    早卒 0.5580426454540.553856015205
    胤祯 0.553288519382
    陈潜 0.550716996193
    愔之 0.550510883331
    叔父 0.550032019615
    In [14]: result = model.most_similar(u"衣服")
    In [15]: for e in result:
        print e[0], e[1]
       ....:     
    鞋子 0.686688780785
    穿着 0.672499775887
    衣物 0.67173999548
    大衣 0.667605519295
    裤子 0.662670075893
    内裤 0.662210345268
    裙子 0.659705817699
    西装 0.648508131504
    洋装 0.647238850594
    围裙 0.642895817757
    In [16]: result = model.most_similar(u"公安局")
    In [17]: for e in result:
        print e[0], e[1]
       ....:     
    司法局 0.730189085007
    公安厅 0.634275555611
    公安 0.612798035145
    房管局 0.597343325615
    商业局 0.597183346748
    军管会 0.59476184845
    体育局 0.59283208847
    财政局 0.588721752167
    戒毒所 0.575558543205
    新闻办 0.573395550251
    In [18]: result = model.most_similar(u"铁道部")
    In [19]: for e in result:
        print e[0], e[1]
       ....:     
    盛光祖 0.565509021282
    交通部 0.548688530922
    批复 0.546967327595
    刘志军 0.541010737419
    立项 0.517836689949
    报送 0.510296344757
    计委 0.508456230164
    水利部 0.503531932831
    国务院 0.503227233887
    经贸委 0.50156635046
    In [20]: result = model.most_similar(u"清华大学")
    In [21]: for e in result:
        print e[0], e[1]
       ....:     
    北京大学 0.763922810555
    化学系 0.724210739136
    物理系 0.694550514221
    数学系 0.684280991554
    中山大学 0.677202701569
    复旦 0.657914161682
    师范大学 0.656435549259
    哲学系 0.654701948166
    生物系 0.654403865337
    中文系 0.653147578239
    In [22]: result = model.most_similar(u"卫视")
    In [23]: for e in result:
        print e[0], e[1]
       ....:     
    湖南 0.676812887192
    中文台 0.626506924629
    収蔵 0.621356606483
    黄金档 0.582251906395
    cctv 0.536769032478
    安徽 0.536752820015
    非同凡响 0.534517168999
    唱响 0.533438682556
    最强音 0.532605051994
    金鹰 0.531676828861
  • 相关阅读:
    10. 王道考研-树与二叉树
    Shell基础论证实例
    关系型数据库与非关系型数据库区别
    中高级测试工程师面试题
    idea中cucumber环境搭建
    Java开发中对Redis的基本操作总结
    TestNG 单元测试框架(针对于testNG.xml配置)
    jmeter(四十五)常用Beanshell脚本
    Jmeter(二十一)_脚本两种参数化
    Jmeter(十五)_上传与下载
  • 原文地址:https://www.cnblogs.com/chen8023miss/p/11419541.html
Copyright © 2011-2022 走看看