专栏首页Fdu弟中弟问句类型分类器

问句类型分类器

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

数据集

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

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

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

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

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

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

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

代码如下:

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 进行文本分类,代码如下:

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%以上。

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 分类问题 数据挖掘之分类模型

    判别分析是在已知研究对象分成若干类型并已经取得各种类型的一批已知样本的观测数据,在此基础上根据某些准则建立判别式,然后对未知类型的样品进行判别分析。

    用户2909867
  • pyhanlp 两种依存句法分类器

    HanLP中的基于神经网络的高性能依存句法分析器参考的是14年Chen&Manning的论文(A Fast and Accurate Dependency Pa...

    IT小白龙
  • 机器学习多分类问题转二分类问题

    简单地说就是在监督学习下样本实例的标签有多个,而我们很多问题是二分类分体(正确,错误或者是0,1问题)。

    里克贝斯
  • 问题类型分类的方法比较(AI)

    本文比较研究了逻辑回归、卷积神经网络(CNN)、长短时记忆网络(LSTM)和准循环神经网络(QRNN)等问题分类的方法。所有的模型都使用了预先训练过的GLoVe...

    李欣颖6837176
  • Oracle SQL语句分类

    职场亮哥
  • [Go] GO数据类型分类

    陶士涵
  • python标准类型分类

    Python的类型, 就象绝大多数其它语言一样,能容纳一个或多个值。一个能保存单个字面对象的类型 我们称它为原子或标量存储,那些可容纳多个对象的类型,我们称之为...

    py3study
  • 【Spark Mllib】分类模型——各分类模型使用

    这个数据集源自 Kaggle 比赛,由 StumbleUpon 提供。比赛的问题涉及网页中推荐的页面是短暂(短暂存在,很快就不流行了)还是长久(长时间流行)。

    用户1621453
  • php 弱类型问题

    php 是一门简单而强大的语言,提供了很多 Web 适用的语言特性,其中就包括了变量弱类型,在弱类型机制下,你能够给一个变量赋任意类型的值。

    信安之路

扫码关注云+社区

领取腾讯云代金券