天池NLP赛事-新闻文本分类(三)——基于机器学习的文本分类


系列文章
天池NLP赛事-新闻文本分类(一) —— 赛题理解
天池NLP赛事-新闻文本分类(二) —— 数据读取和数据分析
天池NLP赛事-新闻文本分类(三)——基于机器学习的文本分类


三、基于机器学习的文本分类

3.1 机器学习模型

  1. 机器学习能解决一定的问题,但不能奢求机器学习是万能的;
  2. 机器学习算法有很多种,看具体问题需要什么,再来进行选择;
  3. 每种机器学习算法有一定的偏好,需要具体问题具体分析;

在这里插入图片描述

对于文本分类问题,这里机器学习,可以用:TF-IDF+sklearn机器学习中的模型完成分类

3.2 文本表示方法

在自然语言领域,文本是不定长度的。文本表示成计算机能够运算的数字或向量的方法一般称为词嵌入(Word Embedding)方法。词嵌入将不定长的文本转换到定长的空间内,是文本分类的第一步。

One-hot
这里的One-hot与数据挖掘任务中的操作是一致的,即将每一个单词使用一个离散的向量表示。具体将每个字/词编码一个索引,然后根据索引进行赋值。

One-hot表示方法的例子如下:

句子1:我 爱 北 京 天 安 门
句子2:我 喜 欢 上 海
首先对所有句子的字进行索引,即将每个字确定一个编号:

{
‘我’: 1, ‘爱’: 2, ‘北’: 3, ‘京’: 4, ‘天’: 5,
‘安’: 6, ‘门’: 7, ‘喜’: 8, ‘欢’: 9, ‘上’: 10, ‘海’: 11
}

在这里共包括11个字,因此每个字可以转换为一个11维度稀疏向量:

我:[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
爱:[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]

海:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]

Bag of Words
Bag of Words(词袋表示),也称为Count Vectors,每个文档的字/词可以使用其出现次数来进行表示。

句子1:我 爱 北 京 天 安 门
句子2:我 喜 欢 上 海
直接统计每个字出现的次数,并进行赋值:

句子1:我 爱 北 京 天 安 门
转换为 [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]

句子2:我 喜 欢 上 海
转换为 [1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]

在sklearn中可以直接CountVectorizer来实现这一步骤:

from sklearn.feature_extraction.text import CountVectorizer
corpus = [
    'This is the first document.',
    'This document is the second document.',
    'And this is the third one.',
    'Is this the first document?',
]
vectorizer = CountVectorizer()
vectorizer.fit_transform(corpus).toarray()

N-gram
N-gram与Count Vectors类似,不过加入了相邻单词组合成为新的单词,并进行计数。

如果N取值为2,则句子1和句子2就变为:

句子1:我爱 爱北 北京 京天 天安 安门
句子2:我喜 喜欢 欢上 上海

TF-IDF
TF-IDF 分数由两部分组成:第一部分是词语频率(Term Frequency),第二部分是逆文档频率(Inverse Document Frequency)。其中计算语料库中文档总数除以含有该词语的文档数量,然后再取对数就是逆文档频率。

T F ( t ) = 该 词 语 在 当 前 文 档 出 现 的 次 数 当 前 文 档 中 词 语 的 总 数 TF(t)= \frac {该词语在当前文档出现的次数 }{ 当前文档中词语的总数} TF(t)=

I D F ( t ) = l o g e 文 档 总 数 出 现 该 词 语 的 文 档 总 数 + 1 IDF(t)= log_e\frac {文档总数}{出现该词语的文档总数+1} IDF(t)=loge+1

如果一个词越常见,那么分母就越大,逆文档频率就越小越接近0。分母之所以要加1,是为了避免分母为0(即所有文档都不包含该词)。log表示对得到的值取对数。

T F − I D F = I F ∗ I D F TF-IDF = IF*IDF TFIDF=IFIDF

可以看到,TF-IDF与一个词在文档中的出现次数成正比,与该词在整个语言中的出现次数成反比。所以,自动提取关键词的算法就很清楚了,就是计算出文档的每个词的TF-IDF值,然后按降序排列,取排在最前面的几个词。

参考: http://www.ruanyifeng.com/blog/2013/03/tf-idf.html
在这里插入图片描述

3.3 基于机器学习的文本分类

F1得分

F1分数(F1 Score),是统计学中用来衡量二分类模型精确度的一种指标。它同时兼顾了分类模型的精确率和召回率。F1分数可以看作是模型精确率和召回率的一种调和平均,它的最大值是1,最小值是0。

F1分数(F1 Score),又称平衡F分数(balanced F Score),它被定义为精确率和召回率的调和平均数。

F 1 = 2 ∗ p r e c i s i o n ∗ r e c a l l p r e c i s i o n + r e c a l l F_1=2*\frac{precision*recall}{precision+recall} F1=2precision+recallprecisionrecall

更一般的,我们定义 F β F_\beta Fβ分数为

F β = ( 2 + β 2 ) ∗ p r e c i s i o n ∗ r e c a l l ( β 2 ∗ p r e c i s i o n ) + r e c a l l F_\beta=(2+\beta^2)*\frac{precision*recall}{(\beta^2*precision)+recall} Fβ=(2+β2)(β2precision)+recallprecisionrecall

除了 F 1 F_1 F1分数之外, F 0 . 5 F_0.5 F0.5分数和 F 2 F_2 F2分数在统计学中也得到大量的应用。其中, F 0 . 5 F_0.5 F0.5分数中,召回率的权重高于精确率,而 F 2 F_2 F2分数中,精确率的权重高于召回率。

CountVectorizer解释:

参考:https://blog.csdn.net/weixin_38278334/article/details/82320307

CountVectorizer是通过fit_transform函数将文本中的词语转换为词频矩阵,矩阵元素a[i][j] 表示j词在第i个文本下的词频。即各个词语出现的次数,通过get_feature_names()可看到所有文本的关键字,通过toarray()可看到词频矩阵的结果。

from sklearn.feature_extraction.text import CountVectorizer

texts=["dog cat fish","dog cat cat","fish bird", 'bird'] # “dog cat fish” 为输入列表元素,即代表一个文章的字符串
cv = CountVectorizer()#创建词袋数据结构
cv_fit=cv.fit_transform(texts)
#上述代码等价于下面两行
#cv.fit(texts)
#cv_fit=cv.transform(texts)

print(cv.get_feature_names())    #['bird', 'cat', 'dog', 'fish'] 列表形式呈现文章生成的词典

print(cv.vocabulary_	)              # {‘dog’:2,'cat':1,'fish':3,'bird':0} 字典形式呈现,key:词,value:词频

print(cv_fit)
# (0,3) 1   第0个列表元素,**词典中索引为3的元素**, 词频
#(0,1)1
#(0,2)1
#(1,1)2
#(1,2)1
#(2,0)1
#(2,3)1
#(3,0)1

print(cv_fit.toarray()) #.toarray() 是将结果转化为稀疏矩阵矩阵的表示方式;
#[[0 1 1 1]
# [0 2 1 0]
# [1 0 0 1]
# [1 0 0 0]]

print(cv_fit.toarray().sum(axis=0))  #每个词在所有文档中的词频
#[2 3 2 2]

对于RidgeClassifier,可以参考:
https://blog.csdn.net/LOLUN9/article/details/106012418/

接下来我们将对比不同文本表示算法的精度,通过本地构建验证集计算F1得分。

Count Vectors + RidgeClassifier

import pandas as pd

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score

train_df = pd.read_csv('../input/train_set.csv', sep='\t', nrows=15000)

#超参数 max_features : 默认为None,可设为int,对所有关键词的term frequency进行降序排序,只取前max_features个作为关键词集
vectorizer = CountVectorizer(max_features=3000)
train_test = vectorizer.fit_transform(train_df['text'])

clf = RidgeClassifier()
clf.fit(train_test[:10000], train_df['label'].values[:10000])

val_pred = clf.predict(train_test[10000:])
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
# 0.74

TF-IDF + RidgeClassifier

import pandas as pd

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score

train_df = pd.read_csv('../input/train_set.csv', sep='\t', nrows=15000)

tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])

clf = RidgeClassifier()
clf.fit(train_test[:10000], train_df['label'].values[:10000])

val_pred = clf.predict(train_test[10000:])
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
# 0.87

猜你喜欢

转载自blog.csdn.net/bosszhao20190517/article/details/107583806