任何分类问题, 都须要从数据中挖掘有用的特征, 文本分类也不例外. 这里会介绍几种从文本中提取特征的方式. 也是处理文本最基础的方法.python
在机器学习算法的训练过程当中,假设给定$N$个样本,每一个样本有$M$个特征,这样组成了$N×M$的样本矩阵,而后完成算法的训练和预测。一样的在计算机视觉中能够将图片的像素看做特征,每张图片看做hight×width×3的特征图,一个三维的矩阵来进入计算机进行计算。算法
可是在天然语言领域,上述方法却不可行:文本是不定长度的。文本表示成计算机可以运算的数字或向量的方法通常称为词嵌入(Word Embedding)方法。词嵌入将不定长的文本转换到定长的空间内,是文本分类的第一步。dom
one-hot一般被用来编码不一样类别, 一个编码的每一位对应一个类别, 且只有其中一位是1, 其他均为0. 按照相同的思想, 咱们也能够用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]
这种思路看似是合理的, 但存在明显的2个问题学习
bag of words(BoW)也叫词袋模型, 是一种从文本中提取特征用于建模的方法.this
词袋模型是一种描述一个文档中的单词出现的文本表示,它主要包括编码
之因此被称为词袋, 由于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-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(term frequency-inverse document frequency), 它是一种统计度量的方法, 用来评估一个单词对于文档库中的一个文档的相关程度. 它在信息检索和文本挖掘常常被使用.
对于一个文档中的一个单词, 它的TF-IDF能够经过乘以两个不一样的指标来获得
好比一个文档中包含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
经过本次的学习, 对于文本的表示方法以及文本数据集的特征构建有了一个基本的了解.
[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?
[4] what does tf-idf mean?