自然语言处理文本分类实战
第一章 文本分类应用场景介绍
一、文本分类任务描述:input—model—output
二、应用场景:
- 评论数据
2.情感分析
3.意图识别
4.进阶应用:
第二章 文本表征知识
2.1文本表征介绍
2.1.1、文本表示:(转化成电脑能够识别的文字)
2.1.2、文本表示的方法
2.2 One Hot编码(独热编码)
2.2.1、工作流程
- 将句子分词
- 构建词表并编码
- 将编码组成一个数字序列
- One Hot编码(用矩阵来代表一句话的输入)
- 将上述矩阵用来建模、训练、构建文本分类模型
2.2.2、缺点
2.2.3、实战
- 预料准备
- 手动实现
- Sklearn实现
# One Hot编码(独热编码)实战
import numpy as np
# 0:语料准备
corpus = ['这 是 第一个 文档',
'这是 第二个 文档',
'这是 最后 一个 文档',
'现在 没有 文档 了']
# 1:手动实现
# 词袋
words = []
for corpu in corpus:
words.extend(corpu.split())
# 词的列表(去重)
word_list = list(set(words))
# 生成字典
word_dct = {word: index for index, word in enumerate(word_list)}
# 词典大小
vocab_size = len(word_dct)
# print(word_dct)
# {'了': 0, '这是': 1, '这': 2, '最后': 3, '第二个': 4, '第一个': 5, '一个': 6, '是': 7, '没有': 8, '文档': 9, '现在': 10}
def get_one_hot(index):
# 获得一个one hot编码
one_hot = [0 for _ in range(vocab_size)]
one_hot[index] = 1
return np.array(one_hot)
# print(get_one_hot(1)) # [0 1 0 0 0 0 0 0 0 0 0]
# 第一句话
indexs = [word_dct[word] for word in corpus[0].split()]
# 转换成one hot
one_hot_np = np.array([get_one_hot(index) for index in indexs])
# print(one_hot_np)
'''
[[0 0 1 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 1 0 0 0]
[0 0 0 0 0 1 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 1 0]]
'''
# 2 Sklearn实现
from sklearn.preprocessing import LabelBinarizer
# 初始化编码器
lb = LabelBinarizer()
# 将所有分好的的词都放进去
lb.fit(words)
lb.classes_
# 初始化句子
sentence = corpus[0].split()
print(sentence)
# ['这', '是', '第一个', '文档']
LB = lb.transform(sentence)
print(LB)
'''
[[0 0 0 0 0 0 0 0 0 1 0]
[0 0 0 1 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 1 0 0 0]
[0 0 1 0 0 0 0 0 0 0 0]]
'''
# 解码
LB_inverse = lb.inverse_transform(LB)
print(LB_inverse)
# ['这' '是' '第一个' '文档']
2.3 TF-IDF(词频-逆文件频率)
2.3.1 简介
1、词频(TF)
2 、逆文件频率(IDF)
3 、TF-IDF
4、TF-IDF的缺点
2.3.2 TF-IDF实战
# 词频-逆文件频率
# 0:语料准备
corpus = ['这 是 第一个 文档',
'这是 第二个 文档',
'这是 最后 一个 文档',
'现在 没有 文档 了 文档']
# 1、手动实现
# 1.1 词袋统计
words_list = []
for corpu in corpus:
words_list.append(corpu.split())
print(words_list)
# [['这', '是', '第一个', '文档'], ['这是', '第二个', '文档'], ['这是', '最后', '一个', '文档'], ['现在', '没有', '文档', '了', '文档']]
# 1.2统计词频
from collections import Counter
count_list = []
for words in words_list:
count = Counter(words)
count_list.append(count)
print(count_list)
# [Counter({'这': 1, '是': 1, '第一个': 1, '文档': 1}),
# Counter({'这是': 1, '第二个': 1, '文档': 1}),
# Counter({'这是': 1, '最后': 1, '一个': 1, '文档': 1}),
# Counter({'文档': 2, '现在': 1, '没有': 1, '了': 1})]
# 1.3 定义函数
import math
def tf(word, count):
return count[word]/sum(count.values())
def idf(word, count_list):
n_contain = sum([1 for count in count_list if word in count])
return math.log(len(count_list)/(1+n_contain))
def tf_idf(word, count, count_list):
return tf(word, count)*idf(word, count_list)
# 1.4 输出结果
for index, count in enumerate(count_list):
print('第{}个文档的TF IDF的信息;'.format(index+1))
# 分值
scores = {word: tf_idf(word, count, count_list) for word in count}
scores_word = sorted(scores.items(), key=lambda x: x[1], reverse=True)
for word,score in scores_word:
print('word:{}, TF IDF : {} '.format(word, round(score, 5)))
'''
第1个文档的TF IDF的信息;
word:这, TF IDF : 0.17329
word:是, TF IDF : 0.17329
word:第一个, TF IDF : 0.17329
word:文档, TF IDF : -0.05579
第2个文档的TF IDF的信息;
word:第二个, TF IDF : 0.23105
word:这是, TF IDF : 0.09589
word:文档, TF IDF : -0.07438
第3个文档的TF IDF的信息;
word:最后, TF IDF : 0.17329
word:一个, TF IDF : 0.17329
word:这是, TF IDF : 0.07192
word:文档, TF IDF : -0.05579
第4个文档的TF IDF的信息;
word:现在, TF IDF : 0.13863
word:没有, TF IDF : 0.13863
word:了, TF IDF : 0.13863
word:文档, TF IDF : -0.08926
'''
# 2、Gensim
# 2.1 词袋统计
# 2.2 获取词频
from gensim import corpora
dic = corpora.Dictionary(words_list) # 这是一个对象
# print(dic)
# doc2bow()传入的是一个词的列表
new_corpus = [dic.doc2bow(words) for words in words_list]
# 第一个元素是词在词典中的id, 第二个是词在文档中出现的次数
print(new_corpus)
# [[(0, 1), (1, 1), (2, 1), (3, 1)], -----['这', '是', '第一个', '文档']
# [(0, 1), (4, 1), (5, 1)],
# [(0, 1), (5, 1), (6, 1), (7, 1)],
# [(0, 2), (8, 1), (9, 1), (10, 1)]] ----['现在', '没有', '文档', '了', '文档']
# 2.3 每一个词对应的id
print(dic.token2id)
# {'文档': 0, '是': 1, '第一个': 2, '这': 3, '第二个': 4, '这是': 5, '一个': 6, '最后': 7, '了': 8, '没有': 9, '现在': 10}
from gensim import models
tfidf = models.TfidfModel(new_corpus)
# 保存模型
tfidf.save('tfidf.model')
# 加载模型
tfidf = models.TfidfModel.load('tfidf.model')
tf_idf_vec = []
for corpu in corpus:
# 先拿到第一个文档
doc_bow = dic.doc2bow(corpu.lower().split())
vec = tfidf[doc_bow]
tf_idf_vec.append(vec)
print(tf_idf_vec)
# 一个列表对应一个文章
# [[(1, 0.5773502691896258),(2, 0.5773502691896258), (3, 0.5773502691896258)],
# [(4, 0.8944271909999159), (5, 0.4472135954999579)],
# [(5, 0.3333333333333333), (6, 0.6666666666666666), (7, 0.6666666666666666)],
# [(8, 0.5773502691896258),(9, 0.5773502691896258), (10, 0.5773502691896258)]]
# 3、Sklearn
from sklearn.feature_extraction.text import TfidfVectorizer
# 初始化对象
tfidf_vec = TfidfVectorizer()
# 加载所有语料
tf_idf_matrix = tfidf_vec.fit_transform(corpus)
# 得到语料库中所有不重复的词
print(tfidf_vec.get_feature_names())
# ['一个', '文档', '最后', '没有', '现在', '第一个', '第二个', '这是']
# 得到所有单词对应的id
print(tfidf_vec.vocabulary_)
# {'第一个': 5, '文档': 1, '这是': 7, '第二个': 6, '最后': 2, '一个': 0, '现在': 4, '没有': 3}
# 获得tf idf 矩阵输出
print(tf_idf_matrix.toarray())
'''
[[0. 0.46263733 0. 0. 0. 0.88654763 0. 0. ]
[0. 0.37919167 0. 0. 0. 0. 0.72664149 0.5728925 ]
[0.58783765 0.30675807 0.58783765 0. 0. 0. 0. 0.46345796]
[0. 0.59380024 0. 0.56894695 0.56894695 0. 0. 0. ]]
'''
2.4 Word2vec
2.4.1 基础介绍
单词嵌入向量(Word Embedding)
- 理想的词表征:
- 大小合适
- 增量更新
- 语义相似度
- 怎么做?
- One-Hot VS Word Embedding
- 学习方法
2.4.2 Word2vec实战
数据集:
今日头条中文新闻(短文本)分类
地址:https://storage.googleapis.com/cluebenchmark/tasks/tnews_public.zip
import pandas as pd
import json
import jieba
'''
0:gensim词向量实践
1、读取预处理的数据集
2、训练
3、结果
'''
# 1、下载数据
# 1.1 数据预处理
def get_sentence(data_file):
# 读取文件
f = open(data_file, 'r', encoding='utf-8')
reader = f.readlines()
sentence = []
for line in reader:
line = json.loads(line.strip())
sentence.append(line['sentence'])
return sentence
train_sentence = get_sentence('train.json')
test_sentence = get_sentence('test.json')
dev_sentence = get_sentence('dev.json')
# 2、载入数据
train_data = train_sentence + test_sentence + dev_sentence
# print(len(train_data)) # 73360
# 分词
train_data = [list(jieba.cut(sentence)) for sentence in train_data]
# 3、构建词向量模型
from gensim.models.word2vec import LineSentence
from gensim.models import word2vec
import gensim
import logging
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s', level=logging.INFO)
# 构建模型
from gensim.models import FastText
# print(help(FastText))
# model = FastText(test_sentence, vector_size=4, window=3, min_count=1)
# 4、训练模型 skip-gram(sg = 1) & CBOW(sg = 0)
model = word2vec.Word2Vec(train_data, sg=0, workers=8, min_count=5, vector_size=200)
# 5、保存模型
model_save_path = 'word2vec.model'
model.save(model_save_path)
# 6、载入模型
model = word2vec.Word2Vec.load(model_save_path)
# 输出向量维度(1x200) 上面定义的vector_size=200
print(model.wv['智能'].shape)
'''
输出:
(200,)
'''
# 查找一个上下文最近的词
print(model.wv.most_similar(['智能'], topn=10))
'''
输出:
[('金融', 0.970018208026886),
('生态', 0.9675754308700562),
('赋能', 0.9635003209114075),
('服务', 0.9610007405281067),
('电商', 0.9590190052986145),
('创新', 0.9575081467628479),
('布局', 0.956716775894165),
('建设', 0.9556843042373657),
('助力', 0.9543666839599609),
('云', 0.9498512148857117)]
'''
第三章 文本分类任务
3.1 分类任务
3.1.1、图解
3.1.2、分类任务的分类:
- 二分类(两种状态互斥)
- 多分类
- 多标签分类
3.1.3、多分类详解:
一对一策略:
一对其余策略:
3.1.4 多标签问题与二、多分类问题关系
在建模上区别:
3.2 激活函数
3.2.1 Softmax
3.2.2 Sigmoid
3.3 交叉熵
3.4 实战—激活函数练习
# 激活函数练习
# sigmoid
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):
return 1.0/(1+np.exp(-x))
# print(sigmoid(1))
'''
0.7310585786300049
'''
sigmoid_input = np.arange(-10, 10)
sigmoid_output = sigmoid(sigmoid_input)
# print(sigmoid_output)
'''
[4.53978687e-05 1.23394576e-04 3.35350130e-04 9.11051194e-04
2.47262316e-03 6.69285092e-03 1.79862100e-02 4.74258732e-02
1.19202922e-01 2.68941421e-01 5.00000000e-01 7.31058579e-01
8.80797078e-01 9.52574127e-01 9.82013790e-01 9.93307149e-01
9.97527377e-01 9.99088949e-01 9.99664650e-01 9.99876605e-01]
'''
# plt.plot(sigmoid_input, sigmoid_output)
# plt.xlabel('sigmoid_input')
# plt.ylabel('sigmoid_output')
# plt.show()
# softmax
import math
softmax_input = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]
z_exp = [math.exp(i) for i in softmax_input]
print(z_exp)
'''
[2.718281828459045, 7.38905609893065, 20.085536923187668, 54.598150033144236,
2.718281828459045, 7.38905609893065, 20.085536923187668]
'''
sum_z_exp = sum(z_exp)
softmax_output = [round(ex/sum_z_exp, 2) for ex in z_exp]
print(softmax_output)
'''
[0.02, 0.06, 0.17, 0.47, 0.02, 0.06, 0.17]
'''
# 画图
plt.plot(softmax_input, softmax_output)
plt.xlabel('softmax_input')
plt.ylabel('softmax_output')
plt.show()
text_RNN步骤简要介绍
1、embedded层:将句子或文章平铺为词向量
2、进入多层卷积层(卷积核大小不同):算出每个卷积核卷积后的特征值
3、进入池化层:提取出上一步最大的特征值(max pooling)
4、连接:将最大的特征值拼接在一起
5、套一个dropout:防止过拟合
6、进入全连接层:分类(两类或者多类)
第四章 模型评估
1、评价指标
2、混淆矩阵:(指标:准确率、召回率、精确率)
3、预测的效果?
假设样本不平衡:(<0.5 分为0,>0.5分为1)
实例
如果不使用模型,直接计算:
1、Recall(召回率)
2、Precision(精确率)
3、F1
4、FPR
5、ROC
6、AUC(ROC线下面积)
线越靠近左上角效果越好 (SKlearn调用roc_auc_score)
第五章 知识扩展
中文NLP语料库:
https://www.cluebenchmarks.com/
NLP学习框架:BERT
国内可以一件加载模型:
免费的GPU: