其他分享
首页 > 其他分享> > 对语料库进行数据清洗、中文分词,建立训练词向量模型

对语料库进行数据清洗、中文分词,建立训练词向量模型

作者:互联网

目录

简述

接前述使用scrapy爬取文件建立聊天语料库一文,在对文件初步清洗之后。由于文本来源的特殊性,需要对其中的特殊关键词进行过滤,以及其他数据清洗操作。这篇文章将在前文基础上,进行数据清洗,中文分词,及word2vec操作。作为中期检测前的最后一篇记录,希望能给大家一点小小的帮助。

数据清洗

由于是对字幕文件的数据清洗,所以除去html标签,去转义,去除特殊符号等操作外,最主要的是去除关键字和去重。以下将着重讲这两个方面。这两个方面应该是放在同一个while中,但我为了方便阅读,分别写了俩while,实际操作时,将俩写入同一个即可。

去除关键字

这一部分比较简单,但是很重要。因为字幕文件的原因,部分关键字频率极高,会影响到后续的词向量模型的训练,所以在此需要去除。直接上代码:
首先,写入需要去除的关键字的列表。

filters = ["字幕", "时间轴:", "校对:", "翻译:", "后期:", "监制:"]
filters.append("时间轴:")
filters.append("校对:")
filters.append("翻译:")
filters.append("后期:")
filters.append("监制:")
filters.append("禁止用作任何商业盈利行为")
filters.append("http")

其次,给出清洗文件(from_path)和输出文件(to_path)的地址,打开文件后,判断每一行是否存在关键字,若存在则跳过,同理,判断改行是否存在剧集信息。当所有条件过滤之后,若该句未被过滤,则写入输出文件中。

f = open(from_path, "r+")
g = open(to_path, "a+")

while True:
    line = f.readline()
    if line:
        line = line.strip()

        # 关键词过滤
        need_continue = False
        for filter in filters:
            try:
                line.index(filter)
           		# 若该行中存在关键字,赋值为True
                need_continue = True
                break
            except:
                pass
        # 若为true,跳过该行
        if need_continue:
            continue

        # 去掉剧集信息
        if re.match('.*第.*季.*', line):
            continue
        if re.match('.*第.*集.*', line):
            continue
        if re.match('.*第.*帧.*', line):
            continue
        g.write(line+"\n")
   else:
        break
f.close()
g.close()
pass

去除重复语句

去除重复语句不是去除整个文件中出现过的重复语句,而是去除无意义的重复语句,在这里,我判定,两百行中出现重复的语句即为无意义的,于是,如下:

lines_seen = set()
while True:
line = f.readline()
   if line:
  		line = line.strip()
  		# 每两百行将不重复的行放入lines_seen中,用于判断行是否重复,超过两百行的重复不作清除处理
       if line not in lines_seen:
           lines_seen.add(line)
           if len(lines_seen) > 200:
               lines_seen.clear()
       else:
           print(line)
           continue
           g.write(line+"\n")
   else:
        break
f.close()
g.close()
pass

做完这些以后,语料库的数据清理也就完成了。下面需要进行分词操作。

中文分词

使用jieba库进行中文分词

import jieba
from jieba import analyse
import os


# input:需要分词的文件地址;output:文件分词后的输出地址
def segment(input, output):
    input_file = open(input, "r+")
    output_file = open(output, "a+", encoding='utf-8')  # 以utf-8输出,方便后续的词向量训练
    while True:
        line = input_file.readline()
        if line:
            line = line.strip()
            seg_list = jieba.cut(line)
            segments = ""
            for str in seg_list:
                segments = segments + " " + str
            output_file.write(segments)
        else:
            break
    input_file.close()
    output_file.close()


if __name__ == '__main__':
    from_path = "my_from_path"
    to_path = "my_to_path"
    if not os.path.isdir(to_path):  # 判断文件夹是否存在,不存在则创建
        os.makedirs(to_path)
    datanames = os.listdir(from_path)  # 打开来源文件夹,将其下所有文件写入datanames中
    for i in datanames:
        input = from_path+"/"+i
        output = to_path+"/all.txt"  # 将结果写入输出文件夹中的all.txt文件中

        segment(input, output)

使用gensim训练词向量模型

word2vec的训练思路

为了更好的理解word2vec的运行,之前自己捣鼓了一个word2vec的文件,但是经过测试,发现只能对较小数据量的文件进行词向量训练,超过2000词的文件就很吃力了,于是我选择使用gensim库,具体的操作在下一步中,所以在这里只简单讲讲思路,:
首先,确定窗口大小,词嵌入的维度,遍历样本次数。
其次,将语料库转为onehot编码,以方便训练。在这里简单讲讲onehot编码。
one-hot在特征提取上属于词袋模型(bag of words),假设语料库中有三句话:
我爱中国
爸爸妈妈爱我
爸爸妈妈爱中国
首先,将语料库中的每句话分成单词,并编号:

1:我 2:爱 3:爸爸 4:妈妈 5:中国

语句爸爸妈妈中国
111001
211110
301111

所以最终得到的每句话的特征向量就是:

我爱中国 -> 1,1,0,0,1
爸爸妈妈爱我 -> 1,1,1,1,0
爸爸妈妈爱中国 -> 0,1,1,1,1
接着,为每一个词建立索引。
其后,使用skip-gram的网络结构,创建两个随机初始化权重矩阵,后向前传递,得出结果后将其映射到[0,1]之间来得到用来预测的概率。
想法很美好,做的也还过得去,就是现实太过残酷,写的文件在对付小一点的文件还凑合,在面对大的训练集当场罢工。所以还是老老实实使用了库比较好,前人栽树,后人乘凉岂不妙哉。

使用gensim训练词向量模型

Gensim 4.0 更新之后,虽然大部分与旧版本相容,但是也有部分差异,详细请看https://github.com/RaRe-Technologies/gensim/wiki/Migrating-from-Gensim-3.x-to-4,以下为训练词向量的代码。

from gensim.models import word2vec
import os
import gensim
import logging


def model_train(train_file_name, save_model_file):  # model_file_name为训练语料的路径,save_model为保存模型名

    # 模型训练,生成词向量
    logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
    sentences = word2vec.Text8Corpus(train_file_name)  # 加载语料
    try:
        model = gensim.models.Word2Vec(sentences, window=5, vector_size=200)  # 训练CBOW算法模型; 默认window=5
        model.save(save_model_file)
        model.wv.save_word2vec_format(save_model_file + ".bin", binary=True)   # 以二进制类型保存模型以便重用
    except:
        pass


def main():
    from_path = "my_to_path/all.txt"  # 接上文中的myt_to_path/all.txt
    save_model_name = 'mymodel.model'
    if not os.path.exists(save_model_name):  # 判断文件是否存在
        model_train(from_path, save_model_name)
    else:
        print('此训练模型已经存在,不用再次训练')

    # 加载已训练好的模型
    model_1 = word2vec.Word2Vec.load(save_model_name)

    # 将获得的词汇及其对应的向量按字典的格式存放到word_vector_dict中
    word_vector_dict = {}
    # print(model_1.wv.index_to_word)  # 获得所有的词汇
    for word in model_1.wv.index_to_key:
        # model_1.wv.get_vector(word)  # 获得词汇及其对应的向量
        word_vector_dict[word] = model_1.wv.get_vector(word)
    output_vector_file = 'word_vector.txt'
    with open(output_vector_file, 'w', encoding='utf-8') as f:
        f.write(str(word_vector_dict))

    # 计算两个词的相似度/相关程度
    word1 = "学习"
    word2 = "快乐"
    y1 = model_1.wv.similarity(word1, word2)
    print("两个词的相关程度为:", y1)
    print("-------------------------------\n")

    # 计算某个词的相关词列表

    y2 = model_1.wv.most_similar(word2, topn=10)  # 10个最相关的
    print("和", word2, "最相关的词有:\n")
    for item in y2:
        print(item[0], item[1])
    print("-------------------------------\n")


if __name__ == "__main__":
    main()

运行结果如下:
ps:学习是快乐的!这个语料库有问题,学习怎么能和快乐相关程度这么低呢?(认真脸)
在这里插入图片描述
这个结果嘛,差强人意,主要是我的训练集有点小,只有10MB,没有搞很多,方便测试。但是这不是也有相对正确的嘛。以后我填充了我的训练集后,再回来补充,我相信,学习是快乐的!

结语

以上便是这两周的学习内容啦,因为各科的实验都开了,作为强迫症晚期角色,实验是不可能活到ddl的,因此这事就耽搁了。而今天打开年级群时,发现原定第9周的中期答辩,改到了下一周周四,这才想起博客没写,今个补上。祝我自己好运。

标签:word,训练,语料库,分词,file,path,model,line,向量
来源: https://blog.csdn.net/weixin_44524843/article/details/115799484