内容简介:任何分类问题, 都需要从数据中挖掘有用的特征, 文本分类也不例外. 这里会介绍几种从文本中提取特征的方式. 也是处理文本最基础的方法.在机器学习算法的训练过程中,假设给定$N$个样本,每个样本有$M$个特征,这样组成了$N×M$的样本矩阵,然后完成算法的训练和预测。同样的在计算机视觉中可以将图片的像素看作特征,每张图片看作hight×width×3的特征图,一个三维的矩阵来进入计算机进行计算。但是在自然语言领域,上述方法却不可行:文本是不定长度的。文本表示成计算机能够运算的数字或向量的方法一般称为词嵌入(W
任何分类问题, 都需要从数据中挖掘有用的特征, 文本分类也不例外. 这里会介绍几种从文本中提取特征的方式. 也是处理文本最基础的方法.
文本表示方法
在机器学习算法的训练过程中,假设给定$N$个样本,每个样本有$M$个特征,这样组成了$N×M$的样本矩阵,然后完成算法的训练和预测。同样的在计算机视觉中可以将图片的像素看作特征,每张图片看作hight×width×3的特征图,一个三维的矩阵来进入计算机进行计算。
但是在自然语言领域,上述方法却不可行:文本是不定长度的。文本表示成计算机能够运算的数字或向量的方法一般称为词嵌入(Word Embedding)方法。词嵌入将不定长的文本转换到定长的空间内,是文本分类的第一步。
One-hot独热标签
one-hot通常被用来编码不同类别, 一个编码的每一位对应一个类别, 且只有其中一位是1, 其余均为0. 按照相同的思想, 我们也可以用one-hot编码来表示每一个单词. 比如下面两句话
句子1:我 爱 北 京 天 安 门
首先会统计两句话中的所有字的类别, 并将每个类别编号
{
'我': 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]
这种思路看似是合理的, 但存在明显的2个问题
- 对于一个稍复杂的语料数据, 就已经包含庞大数量的词, 并且一个词还会有多种形式, 如果每个词都用一个one-hot编码向量表示, 会导致维度爆炸.
- one-hot向量无法建模单词之间(one-hot向量相互正交)的关系, 然而这种信息是文本中重要的特征.
Bag of Words
bag of words(BoW)也叫词袋模型, 是一种从文本中提取特征用于建模的方法.
词袋模型是一种描述一个文档中的单词出现的文本表示,它主要包括
- 一个已有单词的词典.
- 已有单词表示的度量.
之所以被称为词袋, 因为BoW只关心已知单词在文档中是否出现, 并不关心它在文档中出现的顺序和结构信息.它将每个词在文档中的计数作为特征.
构建一个BoW模型包括以下几个步骤
-
收集数据
比如
It was the best of times,
it was the worst of times,
it was the age of wisdom,
it was the age of foolishness,
-
设计词典
可以将文档库(收集的数据)中自己认为重要的单词加入到词典中, 词典的形式如下
“it”
“was”
“the”
“best”
“of”
“times”
“worst”
“age”
“wisdom”
“foolishness”
-
创建文档向量
这一步的目的是将每个文档(可以理解成包含不定长度单词的句子)转换为一个固定长度的向量, 向量的长度为词典中单词的个数.
那么如何将文档转换为单个向量呢, 最简单的方式就是, 使用一个布尔值来表示词典中每个词是否在文档中是否出现, 出现了即为1, 否则为0
比如上面的一个文档得到的向量为
“it” = 1
“was” = 1
“the” = 1
“best” = 1
“of” = 1
“times” = 1
“worst” = 0
“age” = 0
“wisdom” = 0
“foolishness” = 0
对应向量为:
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
在sklearn中, 我们可以利用自带的 工具 快速的实现BoW的功能
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?', ] # 将每个单词在词典中出现的次数作为特征 counter = CountVectorizer() vectors = counter.fit_transform(corpus)
N-gram
简单来说, N-gram模型根据前N-1个已有的单词来预测一个单词出现的概率, 但N=2(N-1=1)时, 即一个单词出现的概率仅由它的前一个单词决定.
那么如何根据N-1个已出现的单词来预测一个单词的出现呢?
首先, 我们需要一个语料库(corpus), 包含了大量的句子. 假设现在语料库包含了如下的句子
1.He said thank you.
2.He said bye as he walked through the door.
3.He went to San Diego.
4.San Diego has nice weather.
5.It is raining in San Francisco.
假设我们设置N为2, 即只根据它前一个词来进行预测单词出现的概率.通常而言, 概率的计算方式如下
$\frac{count(wp wn)}{count(wp)}$, wp表示上一个单词, wn表示当前单词, count为计数函数.
比如我们要得到 you
出现在 thank
之后的概率 P(you|thank)
,它等同于
occurence times of "thank you" / occurence times of "thank"
= 1 / 1
= 1
我们可以说, 无论什么时候出现了 thank
, you
都会出现在它后面.
TF-IDF
TF-IDF(term frequency-inverse document frequency), 它是一种统计度量的方法, 用来评估一个单词对于文档库中的一个文档的相关程度. 它在信息检索和文本挖掘经常被使用.
对于一个文档中的一个单词, 它的TF-IDF可以通过乘以两个不同的指标来得到
- term-frequency(TF): $TF(t) = \frac{count(t)}{ total \quad terms} =\frac{单词t在当前文档出现的次数}{当前文档中总的单词数}$
- inverse document frequency(IDF): $IDF(t)=In(\frac{count(document)}{count(document\quad which\quad contain\quad term\quad t)})=In(\frac{总的文档数目}{包含单词t的文档数目})$
比如一个文档中包含100个词, 单词 cat
出现了3次, 则TF( cat
)=3/100=0.03, 假设我们有1e7个文档, cat
在其中的1e3个中出现了, 则IDF( cat
)=log(1e7/1e3)=4, 因此TF_IDF权重为: 0.03 * 4 = 0.12.
现在回到竞赛的数据中去, 尝试使用TF-IDF来构建特征进行分类
import pandas as pd from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer from sklearn.metrics import f1_score from sklearn.model_selection import train_test_split from sklearn.linear_model import RidgeClassifier root_dir = '/content/drive/My Drive/competitions/NLPNews' # 内存有限, 这里只读取10000行 train_df = pd.read_csv(root_dir+'/train.csv', sep='\t', nrows=10000) # max_features表示词典的大小, 包含词频最高的max_features个词 tfidf = TfidfVectorizer(ngram_range=(1, 3), max_features=3000) train_test = tfidf.fit_transform(train_df['text']) # 构建分类器 clf = RidgeClassifier() # 切分数据集 x_train, x_test, y_train, y_test = train_test_split(train_test, train_df['label'], test_size=0.1, random_state=0) # 训练模型 clf.fit(x_train, y_train) # 执行预测 y_pred = clf.predict(x_test) # 输出宏平均f1-score print(f1_score(y_test, y_pred, average='macro'))
0.8802400152512864
总结
通过本次的学习, 对于文本的表示方法以及文本数据集的特征构建有了一个基本的了解.
Reference
[1]Datawhale零基础入门NLP赛事 - Task3 基于机器学习的文本分类)
[2] A Gentle Introduction to the Bag-of-Words Model
[3] An Introduction to N-grams: What Are They and Why Do We Need Them?
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 特征工程:特征获取、特征规范和特征存储
- 特征工程之特征缩放 & 特征编码
- 特征工程:特征设计、特征可用性评估
- [译] 为什么要做特征缩放,怎么做特征缩放,什么时候做特征缩放?特征缩放三连了解一下
- 特征金字塔特征用于目标检测
- 数据挖掘篇——特征工程之特征降维
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
两周自制脚本语言
[日]千叶 滋 / 陈筱烟 / 人民邮电出版社 / 2014-6 / 59.00元
《两周自制脚本语言》是一本优秀的编译原理入门读物。全书穿插了大量轻松风趣的对话,读者可以随书中的人物一起从最简单的语言解释器开始,逐步添加新功能,最终完成一个支持函数、数组、对象等高级功能的语言编译器。本书与众不同的实现方式不仅大幅简化了语言处理器的复杂度,还有助于拓展读者的视野。 《两周自制脚本语言》适合对编译原理及语言处理器设计有兴趣的读者以及正在学习相关课程的大中专院校学生。同时,已经......一起来看看 《两周自制脚本语言》 这本书的介绍吧!