深入浅出Embedding:原理解析与应用实践
上QQ阅读APP看书,第一时间看更新

1.7 使用Word Embedding实现中文自动摘要

本节通过一个实例讲解如何使用Word Embedding实现中文自动摘要,这里使用Gensim中的word2vev模型来生成Word Embedding。

1.7.1 背景说明

使用Word Embedding方法提取关键字,主要步骤如下:

1)导入一个中文语料库;

2)基于这个中文语料库,搭建word2vec模型,训练得到各单词的词向量;

3)导入一个文档,包括各主题及其概要描述信息,预处理该文档,并转换为词向量;

4)用聚类的方法,生成各主题的若干个关键词。

1.7.2 预处理中文语料库

利用jieba分词,过滤停用词等,实现代码如下。

import jieba
import numpy as np

filePath='corpus.txt'
fileSegWordDonePath ='corpusSegDone_1.txt'

# 打印中文列表
def PrintListChinese(list):
    for i in range(len(list)):
        print (list[i])

# 读取文件内容到列表
fileTrainRead = []
with open(filePath,'r') as fileTrainRaw:
    for line in fileTrainRaw:  # 按行读取文件
        fileTrainRead.append(line)

# jieba分词后保存在列表中
fileTrainSeg=[]
for i in range(len(fileTrainRead)):
    fileTrainSeg.append([' '.join(list(jieba.cut(fileTrainRead[i][9:-11],cut_all=False)))])
    if i % 10000 == 0:
        print(i)

# 保存分词结果到文件中
with open(fileSegWordDonePath,'w',encoding='utf-8') as fW:
    for i in range(len(fileTrainSeg)):
        fW.write(fileTrainSeg[i][0])
        fW.write('\n')

1.7.3 生成词向量

使用Gensim word2vec库生成词向量,实现代码如下。

"""
gensim word2vec获取词向量
"""

import warnings
import logging
import os.path
import sys
import multiprocessing

import gensim
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
# 忽略警告
warnings.filterwarnings(action='ignore', category=UserWarning, module='gensim')

if __name__ == '__main__':

    program = os.path.basename(sys.argv[0]) # 读取当前文件的文件名
    logger = logging.getLogger(program)
    logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s',
        level=logging.INFO)
    logger.info("running %s" % ' '.join(sys.argv))

    # inp为输入语料, outp1为输出模型, outp2为vector格式的模型
    inp = 'corpusSegDone_1.txt'
    out_model = 'corpusSegDone_1.model'
    out_vector = 'corpusSegDone_1.vector'

    # 训练skip-gram模型
    model = Word2Vec(LineSentence(inp), size=50, window=5, min_count=5,
                     workers=multiprocessing.cpu_count())

    # 保存模型
    model.save(out_model)
    # 保存词向量
    model.wv.save_word2vec_format(out_vector, binary=False)

1.7.4 把文档的词转换为词向量

对数据进行预处理,并用Skip-Gram模型将其转换为词向量,实现代码如下。

# 采用word2vec词聚类方法抽取关键词1—获取文本词向量表示
import warnings
warnings.filterwarnings(action='ignore', category=UserWarning, module='gensim')  # 忽略警告
import sys, codecs
import pandas as pd
import numpy as np
import jieba
import jieba.posseg
import gensim

# 返回特征词向量
def getWordVecs(wordList, model):
    name = []
    vecs = []
    for word in wordList:
        word = word.replace('\n', '')
        try:
            if word in model:  # 模型中存在该词的向量表示
                #name.append(word.encode('utf8'))
                name.append(word)
                vecs.append(model[word])
        except KeyError:
            continue
    a = pd.DataFrame(name, columns=['word'])
    b = pd.DataFrame(np.array(vecs, dtype='float'))
    return pd.concat([a, b], axis=1)

# 数据预处理操作:分词,去停用词,词性筛选
def dataPrepos(text, stopkey):
    l = []
    pos = ['n', 'nz', 'v', 'vd', 'vn', 'l', 'a', 'd']  # 定义选取的词性
    seg = jieba.posseg.cut(text)  # 分词
    for i in seg:
        if i.word not in l and i.word not in stopkey and i.flag in pos:  # 去重 +
            去停用词 + 词性筛选
            # print i.word
            l. append(i.word)
    return l

# 根据数据获取候选关键词词向量
def buildAllWordsVecs(data, stopkey, model):
idList, titleList, abstractList = data['id'], data['title'], data['abstract']
    for index in range(len(idList)):
        id = idList[index]
        title = titleList[index]
        abstract = abstractList[index]
        l_ti = dataPrepos(title, stopkey)  # 处理标题
        l_ab = dataPrepos(abstract, stopkey)  # 处理摘要
        # 获取候选关键词的词向量
        words = np.append(l_ti, l_ab)  # 拼接数组元素
        words = list(set(words))  # 数组元素去重,得到候选关键词列表
        wordvecs = getWordVecs(words, model)  # 获取候选关键词的词向量表示
        # 词向量写入csv文件,每个词400维
        data_vecs = pd.DataFrame(wordvecs)
        data_vecs.to_csv('wordvecs_' + str(id) + '.csv', index=False)
        print("document ", id, " well done.")

def main():
    # 读取数据集
    dataFile = 'sample_data.csv'
    data = pd.read_csv(dataFile)
    # 停用词表
    stopkey = [w.strip() for w in codecs.open('stopWord.txt', 'r').readlines()]
    # 词向量模型
    inp = 'corpusSegDone_1.vector'
    model = gensim.models.KeyedVectors.load_word2vec_format(inp, binary=False)
    buildAllWordsVecs(data, stopkey, model)

if __name__ == '__main__':
    main()

1.7.5 生成各主题的关键词

采用聚类方法对候选关键词的词向量进行聚类分析,实现代码如下。

# 采用Word2Vec词聚类方法抽取关键词1—获取文本词向量表示
import warnings
warnings.filterwarnings(action='ignore', category=UserWarning, module='gensim')  # 忽略警告
import sys, codecs
import pandas as pd
import numpy as np
import jieba
import jieba.posseg
import gensim

# 返回特征词向量
def getWordVecs(wordList, model):
    name = []
    vecs = []
    for word in wordList:
        word = word.replace('\n', '')
        try:
            if word in model:  # 模型中存在该词的向量表示
                #name.append(word.encode('utf8'))
                name.append(word)
                vecs.append(model[word])
        except KeyError:
            continue
    a = pd.DataFrame(name, columns=['word'])
    b = pd.DataFrame(np.array(vecs, dtype='float'))
    return pd.concat([a, b], axis=1)

# 数据预处理操作:分词,去停用词,词性筛选
def dataPrepos(text, stopkey):
    l = []
    pos = ['n', 'nz', 'v', 'vd', 'vn', 'l', 'a', 'd']  # 定义选取的词性
    seg = jieba.posseg.cut(text)  # 分词
    for i in seg:
        if i.word not in l and i.word not in stopkey and i.flag in pos:  # 去重 +
            去停用词 + 词性筛选
            # print i.word
            l.append(i.word)
    return l

# 根据数据获取候选关键词词向量
def buildAllWordsVecs(data, stopkey, model):
    idList, titleList, abstractList = data['id'], data['title'], data['abstract']
    for index in range(len(idList)):
        id = idList[index]
        title = titleList[index]
        abstract = abstractList[index]
        l_ti = dataPrepos(title, stopkey)  # 处理标题
        l_ab = dataPrepos(abstract, stopkey)  # 处理摘要
        # 获取候选关键词的词向量
        words = np.append(l_ti, l_ab)  # 拼接数组元素
        words = list(set(words))  # 数组元素去重,得到候选关键词列表
        wordvecs = getWordVecs(words, model)  # 获取候选关键词的词向量表示
        # 词向量写入csv文件,每个词400维
        data_vecs = pd.DataFrame(wordvecs)
        data_vecs.to_csv('wordvecs_' + str(id) + '.csv', index=False)
        print("document ", id, " well done.")

def main():
    # 读取数据集
    dataFile = 'sample_data.csv'
    data = pd.read_csv(dataFile)
    # 停用词表
    stopkey = [w.strip() for w in codecs.open('stopWord.txt', 'r').readlines()]
    # 词向量模型
    inp = 'corpusSegDone_1.vector'
    model = gensim.models.KeyedVectors.load_word2vec_format(inp, binary=False)
    buildAllWordsVecs(data, stopkey, model)

if __name__ == '__main__':
    main()

1.7.6 查看运行结果

1)查看原材料前4个主题及概要信息,结果如下:

#查看原文件各主题及其概要说明

system head -5 sample_data.csv
['id,title,abstract',
 '1,永磁电机驱动的纯电动大巴车坡道起步防溜策略,本发明公开了一种永磁电机驱动的纯电动大巴车坡道起步防溜策略,即当制动踏板已踩下、永磁电机转速小于设定值并持续一定时间时,整车控制单元产生一个刹车触发信号,当油门踏板开度小于设定值,且档位装置为非空档时,电机控制单元产生一个防溜功能使能信号并自动进入防溜控制使永磁电机进入转速闭环控制于某个目标转速,若整车控制单元检测到制动踏板仍然踩下,则限制永磁电机输出力矩,否则,恢复永磁电机输出力矩;当整车控制单元检测到油门踏板开度大于设置值、档位装置为空档或手刹装置处于驻车位置时,则退出防溜控制,同时切换到力矩控制。本策略无须更改现有车辆结构或添加辅助传感器等硬件设备,即可实现车辆防溜目的。',
 '2,机动车辆车门的肘靠,一种溃缩结构是作为内部支撑件而被提供在机动车辆的车门衬板上的肘靠中,所述溃缩结构具有多个以交叉形方式设计的凹陷,其中被一个装饰层覆盖的一个泡沫元件安排在所述溃缩结构上方。该溃缩结构特别用于吸收侧面碰撞事件中的负荷,以便防止车辆乘车者免受增加的力峰值。',

2)生成的各主题关键词,结果如下:

! head -3 result/keys_word2vec.csv
id,title,key
1,永磁电机驱动的纯电动大巴车坡道起步防溜策略,力矩开度设定值坡道闭环控制使能
2,机动车辆车门的肘靠,溃缩衬板元件交叉凹陷机动车辆

从结果来看,效果非常不错!