文本分类的目的就是意图识别,如果当前我们的项目下,只有两种意图需要被识别出来,对应的就是二分类问题,如果我们的聊天机器人有多个功能,那么我们需要分类的类别就有多个,就是一个多分类问题。例如,如果我们希望我们的聊天机器人能够播报当前的时间,那么我们就需要准备关于询问时间的语料,同时其目标值就是一个新的类别。在训练之后,通过这个新的模型,判断出用户询问的是当前的时间这个类别,那么就返回当前的时间。
同理,如果我们还希望聊天机器人能够播报未来一天的天气,那么这个机器人就还需要增添一个新的进行分类的意图,重新进行分类。
1.特征工程:对文本进行处理,转化为能够被计算的向量来表示,我们可以考虑使用所有的词语出现的次数,也可以考虑使用tf-idf来处理
2.对模型进行训练
3.对模型进行评估
使用机器学习的方法进行文本分类的时候,为了让结果更好,我们经常从两个角度出发
1.特征工程的过程中处理的更加细致,比如文本中的类似你我他,这种词语可以把它删除,某些词语出现的次数太少,可能并不具有代表意义,(tf-idf)某些词语出现太多,可能导致影响的程度过大等等都是可以考虑的地方
2.使用不同的算法进行训练,获取不同算法的结果,选择最好的或者是使用集成学习的方法(ensemble)
常用操作:
1.对文本进行embedding的操作,转化为向量
2.之后再通过多层的神经网络进行线性和非线性的变化得到结果
3.变化后的结果和目标值进行计算得到损失函数,比如对数似然损失
4.通过最小化损失函数,去更新原来模型中的参数
fasttext是一个单词表示学习和文本分类的库
优点:在标准的多核cpu上,能够训练10亿词级别语料库的词向量在十分钟之内,能够在一分钟之内给三十多万类别的50多万句子进行分类
fasttext模型输入一个词的序列(一段文本或一句话),输出这个词序列属于不同类别的概率
1.把数据准备为需要的格式
2.进行模型的训练、保存和加载、预测
#1.训练
model = fastText.train_supervised("./data/text_classify.txt", wordNgrams=1, epoch=20)
#2.保存
model.save_model("./data/ft_classify.model")
#3.加载
model = fastText.load_model("./data/ft_classify.model")
textlist = [句子1, 句子2]
#4.预测,传入句子列表
ret = model.predict(textlist)
数据准备的最终需要的形式如下:
其中chat、QA字段可以自定义,就是目标值,__label__之前的为特征值,需要使用\t进行分隔,特征值需要进行分词,__label__后面的是目标值
这里使用的是小黄鸡的语料,地址:https://github.com/fateleak/dgk_lost_conv/tree/master/results
对两部分文本进行分词,合并转化为需要的格式
完整过程
import pandas
from tqdm import tqdm
from lib.cut_sentence import cut
import config
import json
# 闲聊语料
xiaohuangji_path = "../../corpus/classify/origin_corpus/小黄鸡未分词.conv"
# 问答语料
byhand_path = "../../corpus/classify/origin_corpus/手动构造的问题.json"
crawled_path = "../../corpus/classify/origin_corpus/爬虫抓取的问题.csv"
def keywords_in_line(line):
# 判断line中是否有不合要求的词
keywords_list = ["传智播客", "传智", "黑马程序员", "黑马", "python"
, "人工智能", "c语言", "c++", "java", "javaee", "前端",
"移动开发", "ui", "ue", "大数据", "软件测试", "php", "h5", "产品经理",
"linux", "运维", "go语言", "区块链", "影视制作", "pmp", "项目管理", "新媒体",
"小程序"]
for word in line:
if word in keywords_list:
return True
else:
return False
def process_xiaohuangji(file):
""" 处理小黄鸡语料"""
flag = 0
num = 0
for line in tqdm(open(xiaohuangji_path).readlines(), desc="xiaohuangji"):
#TODO 句子长度为1 考虑删除
if line.startswith("E"): # 如果开头E 保留
flag = 0
continue
elif line.startswith("M"): # 如果开头M 去掉M
if flag==0: # 第一个M出现
line = line[1:].strip()
flag = 1
else: # 要不要第二个M
continue # continue表示不需要第二个出现的M开头的句子
line_cuted =cut(line) # cut之后返回一个列表 然后用空格join到一起 转化成需要的格式
if not keywords_in_line(line_cuted):
line_cuted =" ".join(line_cuted) + "\t" + "__label__chat"
num += 1
file.write(line_cuted+"\n")
return num
# print(line_cuted)
# 这里的路径很麻烦
def process():
f = open(config.classify_corpus_path, "a") # 要用a的方式读 append
# 1.处理小黄鸡
num_chat = process_xiaohuangji(f)
# 2.处理手动构造的句子
num_qa = process_byhand_data(f)
# 3.处理抓取的句子
num_qa1 = process_crawled_data(f)
f.close()
print(num_chat, num_qa, num_qa1)
def process_crawled_data(file):
"""处理抓取的数据"""
num = 0
for line in tqdm(open(crawled_path).readlines(),desc="crawled data"):
line_cuted = cut(line) # cut之后返回一个列表 然后用空格join到一起 转化成需要的格式
line_cuted = " ".join(line_cuted) + "\t" + "__label__chat"
num += 1
file.write(line_cuted + "\n")
def process_byhand_data(file):
""" 处理手动构造的数据"""
total_lines = json.loads(open(byhand_path).read())
num = 0
for key in total_lines:
for lines in tqdm(total_lines[key], desc="byhand"):
for line in lines:
if "校区" in line:
continue
line_cuted = cut(line) # cut之后返回一个列表 然后用空格join到一起 转化成需要的格式
line_cuted = " ".join(line_cuted) + "\t" + "__label__chat"
num += 1
file.write(line_cuted + "\n") # 这里的处理和之前相同
return num
if __name__ == '__main__':
process()
# 执行之后就生成了我们需要的classify.txt
数据方法很重要! 下一步就是模型构造加训练 相比于模型构造 数据处理部分其实更为重要一些