自动写诗APP项目、基于python+Android实现(技术:LSTM+Fasttext分类+word2vec+Flask+mysql)第二节

一:诗歌分类

首先,从网上搜集到近30万首诗歌,但这些诗歌并没有明确分类。为了将诗歌进行分类,在古诗文网(https://www.gushiwen.org/)上分别爬取边塞征战、写景咏物、山水田园、思乡羁旅、咏史怀古五类诗歌各600首,用于做分类的训练数据集。由这些数据训练得到一个分类模型,由此分类模型对那30万首诗歌进行分类。

数据集(5类诗歌数据600*5+Fasttext.model分类模型(也可自己训练)+停用词表(哈工大停用词表)+30万首诗歌数据+Fasttext处理后的分类数据集):

链接:https://pan.baidu.com/s/1ms2TFhVlbN44JN7Yaw7xZg 
提取码:dbvt 

 

1、爬取6类诗歌的代码实现:

"""
    从古诗文网(https://www.gushiwen.org/)上爬取网页中的6类唐诗
    在古诗文网上,输入一类古诗,可能爬取的数量不够 600 首,对于这中情况,我是又输入了此类诗的主题词,
    能反映出其特点的情感词汇等,最终获取到每类诗600首
    1 边塞征战
    2 写景咏物
    3 山水田园
    4 思乡羁旅
    5 咏史怀古
"""
from config import *
def Get_url():
    # 改变标准输出的默认编码
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gb18030')
    # 需要爬的网址--古诗文网https://www.gushiwen.org/shiwen/
    # 输入一类,翻页爬去,5类诗每类获取 600首,用作分类训练、测试数据
    for i in range(1,20):
        # i 表示页面范围
        # 此网址总共有三种格式,经观察发现 page, A ,后跟随的便是页数,循环更改此值,便可实现翻页爬取
        # url='https://www.gushiwen.org/shiwen/default.aspx?page=9&type=4&id=1'
        # 'https://www.gushiwen.org/shiwen/default_1A589282347eb3A2.aspx'
        # 'https://so.gushiwen.org/search.aspx?type=title&page=3&value=%E7%BE%81%E6%97%85%E6%80%9D%E4%B9%A1'
        url1 = 'https://so.gushiwen.org/search.aspx?type=title&page='
        page = i
        page = '%d' % page
        # 每一个类型的 poem_type在url中的显示形式,5次不同
        poem_type = '&value=%e5%8f%a4%e8%bf%b9'  #(类型的url形式) 事先输入类型,确定页面确切地址
        url = url1+page+poem_type # 最终的 url 值
        head = {}
        # 在浏览器地址栏中输入 about:version (最好谷歌) 得到浏览器版本,用户代理,可实现伪装成浏览器
        head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
        req = request.Request(url, headers=head)
        response = request.urlopen(req)  # 返回 html代码
        html = response.read()
        soup = BeautifulSoup(html, 'lxml') # 使用BeautifulSoup 解析

        # poem = soup.find_all ('textarea')  # 得到<textarea>标签下的内容
        file=r'Data\train_jar\yongshi.txt'
        # 获取textarea标签中的内容
        for i in soup.find_all(re.compile('textarea')):
            str=''.join(i.text)# #列表->字符串
            str,_ = str.rsplit('https')
            # print(str)
            # 截取诗歌中的 题目,作者,内容
            content,str2 = str.rsplit('——')
            try :
                author,title = str2.rsplit('《')
                _, author =author.split('·')
                title,_ = title.split("》")
            except:
                continue
            # print(content) 查看诗歌内容
            with open(file,'a+') as f:
                # 以题目::作者::诗 的格式写入各个文件,一行一首诗
                f.write(title+"::"+author+"::"+content+'\n')
            f.close()

if __name__ == '__main__':
    Get_url()

2、FastText文本分类模型

先对数据做清洗。根据《哈工大停用词表》去停用词,再过滤诗歌中的“,。!()《》”等特殊符号,并去除过长、过短诗歌。

Fasttext原理:

:表示一个句子的特征,初始值采用预训练的词向量

均值层的hidden: 的平均值

输出层:样本的标签

目标函数:

FastText文本分类模型,结合了自然语言处理和机器学习中最成功的理念。包括使用词袋和n-gram袋表征语句,还使用子字(subword)信息,并通过隐藏表征在类别间共享信息。另外采用了一个softmax层级,利用类别不均衡分布的优势来加速运算的过程。

FastText模型包含三部分,模型架构,层次softmax和n-gram特征。模型架构和 Word2Vec 中的 CBOW 模型很类似。不同之处在于,FastText 预测的是标签,而 CBOW 模型是预测中间词。FastText 也利用了类别不均衡这个事实,通过使用 Huffman 算法建立用于表征类别的树形结构。

FastText做分类模型训练时格式:

'__label__'  + classtage(类型) + '\t'+ line(诗内容) + '\n'。

FastText分类主要使用train_supervised()函数,在此分类模型中设置以下参数:

input=path, 训练文件路径

epoch=25, 训练轮次

lr=1.0, 初始学习率

dim=100,向量维度

word_ngrams=2, n-gram 设置

minCount=1 ,最低词频

loss=”softmax” 损失函数类型

由分类模型进行分类后,最终得到各类诗歌:

边塞征战(28932首)、写景咏物(38078首)、山水田园(78294首)、思乡羁旅(70618首)、咏史怀古(81870首)

根据五类诗歌分别绘制了五类诗歌的云图:

在词云中字体显示越大,表示词在此类诗中出现频率越高。

从中可见排名前五的实词分别为:

边塞征战:“万里”、“将军”、“天子”、“四海”、“天下”

写景咏物:“春风”、“梅花”、“江南”、“东风”、“故人”

山水田园:“青山”、“白云”、“人间”、“归来”、“山水”

思乡羁旅:“春风”、“何处”、“故人”、“秋风”、“明月”

咏史怀古:“平生”、“风雨”、“千里”、“人间”、“功名”

可以看出,在每类诗歌中,出现频率较高的词,在一定程度上是能够反映出此类诗歌的主题色彩的,也说明诗歌的分类效果还是不错的。

Fasttext分类具体代码实现如下:

"""
    诗分类模型 ;Fasttext分类
    数据格式 :'__label__'  + classtage(类型) + '\t'+ line(诗内容) + '\n'
"""
from config import *
# 读取停用词
def read_Stopwords():
    # 加载停用词
    stop_word = []
    stop_path = 'Data/Stopwords.txt'
    with open (stop_path, 'r', encoding='utf-8') as stop_file:
        for line in stop_file:
            line = str (line.replace('\n', '').replace ('\r', '').split ())
            stop_word.append (line)
        stop_word = set (stop_word)  # 去重列表中重复的词汇
    return stop_word

# 训练数据统一格式
def fileopems_file_deal(path, classtage):
    stop_word = read_Stopwords()
    path_name = path
    rules = u'[\u4e00-\u9fa5]+' # 只是汉字的正则表达式,可以去除,。!()等特殊符号
    pattern = re.compile(rules)
    sentences = []

    with open(path_name, 'r', encoding = 'utf-8') as f_reader:
        for line in f_reader:
            line = line.replace('\n','').replace('\r',"").split()
            line = str(line)
            line = ' '.join(jieba.cut(line)) # 以空格来分词
            seg_list = pattern.findall(line)
            word_list = []
            for word in seg_list:
                if word not in stop_word:  # 去除停用词
                    word_list.append(word)
            if len(word_list)> 0:
                sentences.append(word_list)
                line = ' '.join(word_list)
                f_write =open('Data/train_jar/shi.txt')
                line2 = '__label__' + classtage + '\t' + line + '\n'  # 统一Fasttext文本分类的格式
                f_write.write(line2)
                f_write.flush()  #强行把缓冲区中的内容放到磁盘中

# 对数据进行训练产生模型   **.model文件
def fasttext_deal():
    path = r'Data/train_jar\shi.txt'
    # 生成模型
    model = fastText.train_supervised(
        input = path,
        wordNgrams = 2, verbose=2, minCount=1
    )
    # 保存模型
    path_save = 'Data/train_jar/class_shi.model'
    model.save_model(path_save)

# 测试数据统一格式
def file_deal(test):
    stop_word = read_Stopwords()
    # 文本预处理
    sentecnces = []
    rules =u'[\u4e00-\u9fa5]+'
    pattern  =re.compile(rules)
    line =test
    line = line.replace('\r','').replace('\n','').split()
    line = str(line)
    line =' '.join(jieba.cut(line))
    seg_list = pattern.findall(line)
    word_list= []
    for word in seg_list:
        if word not in stop_word:
            word_list.append(word)  # 去除停用词
    if len(word_list)>0:  # 去除空行
        sentecnces.append(word_list)
        re_line = ' '.join(word_list) # 以空格来划分各各词
    return re_line

# # 对各类训练数据进行统一格式处理---> 汇总写入shi.txt文件
def sum_filepoems_to_shi():
    path1 = 'Data/train_jar/biansai.txt'
    classtage1 = '边塞征战'
    fileopems_file_deal(path1, classtage1)

    path2 = 'Data/train_jar/jingwu.txt'
    classtage2 = '写景咏物'
    fileopems_file_deal(path2, classtage2)

    path3 = 'Data/train_jar/shanshui.txt'
    classtage3 = '山水田园'
    fileopems_file_deal(path3, classtage3)

    path4 = 'Data/train_jar/sixiang.txt'
    classtage4 = '思乡羁旅'
    fileopems_file_deal(path4, classtage4)

    path5 = 'Data/train_jar/yongshi.txt'
    classtage5 = '咏史怀古'
    fileopems_file_deal(path5,classtage5)

if __name__ =='__main__':
    # 训练模型/加载模型
    save_path = 'Data/train_jar/class_shi.model'
    if os.path.exists('Data/train_jar/class_shi.model'):
        model = fastText.load_model(save_path)
    else: # 没有训练模型,先训练,再加载
        fasttext_deal()
        model = fastText.load_model(save_path)
    test_path = 'Data/train_jar/Whole_30w_poems.txt'  # 30w诗歌数据集
    # f_reader =open(test_path , 'r',encoding='utf-8')
    # 分类后数据写入各类文件
    class_path1 = "Data\Generate_poems_jar/biansai.txt"
    f_write1 = open (class_path1, 'a+', encoding='utf-8')
    class_path2 = "Data\Generate_poems_jar/jingwu.txt"
    f_write2 = open (class_path2, 'a+', encoding='utf-8')
    class_path3 = "Data\Generate_poems_jar/shanshui.txt"
    f_write3 = open (class_path3, 'a+', encoding='utf-8')
    class_path4 = "Data\Generate_poems_jar/sixiang.txt"
    f_write4 = open (class_path4, 'a+', encoding='utf-8')
    class_path5 = "Data\Generate_poems_jar/yongshi.txt"
    f_write5 = open (class_path5, 'a+', encoding='utf-8')

    with open(test_path,'r',encoding='utf-8') as f_reader:
        for line in f_reader:
            tests_str = file_deal(line)
            # print(tests_str)
            label = model.predict(tests_str) # 模型进行预测
            # label[0] 类别 label[1] 概率  label为元组
            value= str(label[0])
            if value ==  "('__label__边塞征战',)" :
                f_write1.write(line)
                f_write1.flush()
            elif value == "('__label__写景咏物',)" :
                f_write2.write(line)
                f_write2.flush()
            elif value == "('__label__山水田园',)" :
                f_write3.write(line)
                f_write3.flush()
            elif value == "('__label__思乡羁旅',)" :
                f_write4.write(line)
                f_write4.flush()
            elif value == "('__label__咏史怀古',)" :
                f_write5.write(line)
                f_write5.flush()

以上2段代码所应用到的工具库以及相应的个别参数设置,都在config.py文件中设置,并实现导入。

具体的完整代码请见Github链接:https://github.com/Whq123/Generate_Poems

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值