前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >问句类型分类器

问句类型分类器

作者头像
luxuantao
发布2021-02-24 14:18:15
3570
发布2021-02-24 14:18:15
举报
文章被收录于专栏:Fdu弟中弟Fdu弟中弟

到目前为止,复旦的不倒翁问答系统只能回答事实类问题,不具备闲聊功能,为了真正做到“不倒问答”,我使用 fasttext 做了一个问句类型分类器,用来判断是事实类问题还是闲聊问题,效果好的出奇。

数据集

闲聊部分的数据集使用的是青云数据集,这个数据集很脏(里面有很多不文明的话),大概长这样:

代码语言:javascript
复制
南京在哪里 	 在这里了
咋死???红烧还是爆炒 	 哦了哦了哦了,咱聊点别的吧
你个小骚货,哥哥的巴操你爽不爽? 	 不要这样说嘛!很不文明哦
额麻麻怎么会有那玩意儿 	 无法理解您的话,获取帮助请发送 help
拿尿冲一冲 	 今天这天气很适合聊天的说
那重点是什么 	 好话不分轻重!
章子怡新宠 	 夜曲小三

前面是问题,后面是答案,这里我们只需要问题。

事实类问题是从学长们的遗留代码中找到的,也不知道是哪来的(咱也不敢问),大概长这样:

代码语言:javascript
复制
许嵩哪里人!
预期结果导向法的摘要主要写了什么?
功夫的产品类型有哪些?
有谁知道鞭打快牛这个词语怎样用
id设计的专业代码是多少?
西奈半岛属于哪个国家
西门社区的交通位置在哪?

好了,接下来要把数据处理成 fasttext 想要的样子,这里我用0表示闲聊,1表示事实类问题:

代码语言:javascript
复制
__label__0 , 不要 每次 都 是 这句 撒
__label__0 , 不要 你 抱
__label__1 , 女人 左手 无名指 戴 戒指 代表 什么
__label__1 , 请问 师范生 技能 适应 于 哪些 人群
__label__1 , 请问 连连看 5 是 什么 语言 的 游戏
__label__0 , 充满 了 我 的 想像
__label__0 , 算 算数
__label__1 , 昀 朵 是 谁 的 粉丝
__label__1 , 根据 声波 测距 原理 开发 出 的 水下 探测器 是
__label__1 , 张 老庄 村 对 战役 有 啥 影响

代码如下:

代码语言:javascript
复制
import random
import jieba 


data = []

with open('question_corpus.txt', 'r', encoding='utf-8') as f:
	for line in f.readlines():
		line = line.strip(' ?!,.?!,。\n\t\r')
		data.append((' '.join(jieba.lcut(line)), 1))
		# re = '' #是否只保留中文
		# for ch in line:
		# 	if '\u4e00' <= ch <= '\u9fff':
		# 		re += ch
		# if re:
		# 	data.append((re, 1))

with open('qingyun.tsv', 'r', encoding='utf-8') as f:
	for line in f.readlines():
		line = line.split('\t')[0].strip(' ?!,.?!,。\n\t\r')
		data.append((' '.join(jieba.lcut(line)), 0))
		# re = ''
		# for ch in line:
		# 	if '\u4e00' <= ch <= '\u9fff':
		# 		re += ch
		# if re:
		# 	data.append((re, 0))

random.shuffle(data)

with open('text_classification_data.txt', 'w', encoding='utf-8') as f:
	for each in data:
		text, label = each
		f.write(text)
		f.write('\t')
		f.write(str(label))
		f.write('\n')

with open('text_classification_data.txt', 'r', encoding='utf-8') as f:
	with open('text_classification_data_train.txt', 'w', encoding='utf-8') as f1:
		with open('text_classification_data_test.txt', 'w', encoding='utf-8') as f2:
			data = f.readlines()
			length = len(data)
			train_length = int(length * 0.8)
			for i in range(train_length):
				text, label = data[i].split('\t')
				f1.write(f'__label__{label[:-1]} , {text}\n')
			for i in range(train_length, length):
				text, label = data[i].split('\t')
				f2.write(f'__label__{label[:-1]} , {text}\n')

分类器

这里使用的是 fasttext 进行文本分类,代码如下:

代码语言:javascript
复制
import fasttext.FastText as fasttext
import numpy as np
import os
import jieba 


def train_model(ipt=None, opt=None, model='', dim=100, epoch=5, lr=0.1, loss='softmax'):
    np.set_printoptions(suppress=True)
    if os.path.isfile(model):
        classifier = fasttext.load_model(model)
    else:
        classifier = fasttext.train_supervised(ipt, label='__label__', 
          minCount=1, dim=dim, epoch=epoch, lr=lr, wordNgrams=2, loss=loss)
        """
          训练一个监督模型, 返回一个模型对象
          @param input:           训练数据文件路径
          @param lr:              学习率
          @param dim:             向量维度
          @param ws:              cbow模型时使用
          @param epoch:           次数
          @param minCount:        词频阈值, 小于该值在初始化时会过滤掉
          @param minCountLabel:   类别阈值,类别小于该值初始化时会过滤掉
          @param minn:            构造subword时最小char个数
          @param maxn:            构造subword时最大char个数
          @param neg:             负采样
          @param wordNgrams:      n-gram个数
          @param loss:            损失函数类型, softmax, ns: 负采样, hs: 分层softmax
          @param bucket:          词扩充大小, [A, B]: A语料中包含的词向量, B不在语料中的词向量
          @param thread:          线程个数, 每个线程处理输入数据的一段, 0号线程负责loss输出
          @param lrUpdateRate:    学习率更新
          @param t:               负采样阈值
          @param label:           类别前缀
          @param verbose:         ??
          @param pretrainedVectors: 预训练的词向量文件路径, 如果word出现在文件夹中初始化不再随机
          @return model object
        """
        classifier.save_model(opt)
    return classifier

dim = 50
lr = 0.5
epoch = 5
model = f'data_dim{str(dim)}_lr0{str(lr)}_iter{str(epoch)}.model'

classifier = train_model(ipt='text_classification_data_train.txt',
                         opt=model,
                         model=model,
                         dim=dim, epoch=epoch, lr=lr
                         )

# 整体的结果为(测试数据量,precision,recall):
result = classifier.test('text_classification_data_test.txt')
print(result)

if __name__ == '__main__':
    while True:
        s = input('请输入问句:')
        s = s.strip(' ?!,.?!,。\n\t\r')
        print(classifier.predict(' '.join(jieba.lcut(s))))

训练的速度出奇的快,基本上都在半分钟以内,而且准确度和召回率都在98%以上。

唯一的缺点是保存下来的模型很大。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-06-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数据集
  • 分类器
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档