文本预处理方法总结
文本预处理的三个主要组成部分:
- 标记化(tokenization)
- 归一化(normalization)
- 替换(substitution)
标记化(tokenization)
标记化是将文本中的长字符串分割成小的片段或tokens的过程.大段文字可以被分割成句子,句子又可以分割成单词等等.有时,分割(segmentation)用来表示大段文字编程小片段的过程(例如段落或句子).而tokenization指的是将文本变为只用单词表示的过程.
这里的tokenization其实就是分词操作,在python里我们可以使用split()函数,1
2
3
4
5sentence_example = """I love deep learning, I love natural language processing."""
token_seq1 = str.split(sentence_example)
token_seq2 = sentence_example.split(' ')
print("token_seq1: ", token_seq1)
print("token_seq2: ", token_seq2)
其中token_seq1和token_seq2的效果是一样的.
而用nltk.word_tokenize也可以实现1
text_list = nltk.word_tokenize(sentence_example)
如果要进行句子切分操作,sentence tokenize,也是可以用nltk来实现的.1
2from nltk.tokenize import sent_tokenize
sent_tokenize_list=sent_tokenize(text)
其中Sentence Tokenize是PunktSentenceTokenizer的实例.
nltk.tokenize.punkt中包含了很多预训练好的tokenize模型.1
2
3import nltk.data
tokenizer=nltk.data.load('tokenizers/punkt/english.pickle')
tokenizer.tokenize(text)
归一化(Normalization)
归一化指的是一系列相关的任务,能够将所有文本放在同一水平区域上:将所有文本转化成同样的实例,删除标点,将数字转换成相应的文字等.对文本进行归一化可以执行多种任务.一般的归一化有3种特殊的步骤:
- 词干提取(stemming):删除词缀(包括前缀、后缀、中缀、环缀),从而得到单词的词干,比如running$\rightarrow$ run
- 词形还原(lemmatization):词形还原与词干提取相关性,不同的是,词形还原能够捕捉基于词根的规范单词形式$better\rightarrow good$
- 其他:词性还原和词干提取是文本预处理的主要部分,所以这两项要认真对待.它们不是简单地文本操作,而要依赖语法规则和对规则细致地理解
其他重要地方法包括:
3.1. 将所有字母变成小写
3.2. 删除数字
3.3. 删除标点
3.4. 删除空白格
3.5. 删除默认停用词
3.6. 删除特定的停止词
替换
自然语言数据预处理中经常会涉及到同义词替换,比如计算两个句子的相似度中,把一个词的两个同义词利用同义词替换技术转换为同一个词,那么就提高了相似度计算的可靠性。
文本表示
上面预处理完了以后,我们得到的还是一系列文本字符串,要想要用机器学习方法处理,还需要将字符串向量化,称为文本表示.
文本表示基于类型分为以下几种:
- 长文本表示
- 短文本表示
- 词表示
文本表示分类(基于表示方法)
- 离散表示:One-hot表示,Multi-hot表示
- 分布式表示:基于矩阵、基于降维表示、基于聚类表示
- 基于神经网络的表示:CBOW,Skip-gram,NNLM,C&W
文本离散表示:词袋模型与TF-IDF
词袋模型
词袋子模型是一种非常经典的文本表示。顾名思义,它就是将字符串视为一个 “装满字符(词)的袋子” ,袋子里的 词语是随便摆放的。而两个词袋子的相似程度就以它们重合的词及其相关分布进行判断。
举个例子,对于句子:“我们这些傻傻的路痴走啊走,好不容易找到了饭店的西门”。
我们先进行分词,将所有出现的词储存为一个词表。然后依据 “词语是否出现在词表中” 可以将这句话变为这样的向量:
[1,0,1,1,1,0,0,1,…]
词表:[我们,你们,走,西门,的,吃饭,旅游,找到了,…]
其中向量的每个维度唯一对应着词表中的一个词。可见这个向量的大部分位置是0值,这种情况叫作“稀疏”。为了减少存储空间,我们也可以只储存非零值的位置。
词袋模型的优缺点:
- 优点:
- 简单、方便、快速
- 预料充足前提下,对于简单的自然语言处理任务效果不错,如文本分类
- 缺点:
- 其准确率往往比较低。凡是出现在文本中的词一视同仁,不能体现不同词在一句话中的不同的重要性。
- 无法关注词语之间的顺序关系,这是词袋子模型最大的缺点。如“武松打老虎”跟“老虎打武松”在词袋子模型中是认为一样的。
词袋模型的改进——TF-IDF
第一步,计算词频。
TF=某词在文章中出现的次数,考虑到文章有长短之分,为了便于不同文章的比较,进行”词频”标准化。
TF = 某词在文章中出现的次数/文章的总次数
第二步,计算逆文档频率。
这时,需要一个语料库(corpus),用来模拟语言的使用环境。
逆文档频率(IDF)=log(语料库的文档总数/包含该词的文档数+1)
如果一个词越常见,那么分母就越大,逆文档频率就越小越接近0。分母之所以要加1,是为了避免分母为0(即所有文档都不包含该词)。log表示对得到的值取对数。
第三步,计算TF-IDF。
TF-IDF=TF*IDF
可以看到,TF-IDF与一个词在文档中的出现次数成正比,与该词在整个语言中的出现次数成反比。所以,自动提取关键词的算法就很清楚了,就是计算出文档的每个词的TF-IDF值,然后按降序排列,取排在最前面的几个词。
基于SVD降维的表示方法
这是一种构造词嵌入(即词向量)的方法,步骤如下:
1.遍历所有的文本数据集,统计词出现的次数
2.用一个矩阵X来表示所有的次数情况
3.对X进行奇异值分解得到一个的分解
4.用U的行(rows)作为所有词表中词的词向量
有两种方法来构造矩阵X
方法一:词-文档矩阵
方法二:基于窗口的共现矩阵X
这两种方法都能产生词向量,它们能够充分地编码语义和句法的信息,但同时也带来了其他的问题:
- 矩阵维度会经常变化(新的词语经常会增加,语料库大小也会随时变化)
- 矩阵非常稀疏,因为大多数词并不同时出现
- 矩阵维度通常非常搞,训练需要$O(n^2)$的复杂度
- 需要专门对矩阵X进行特殊处理,以应对词组频率的极度不平衡状况
基于神经网络的表示方法(当前流形方法)
基于神经网络的方法是创建一个模型,他能够一步步迭代地进行学习,最终得出每个单词基于其上下文的条件概率。
我们想建立一个概率模型,它包含已知和未知参数。每增加一个训练样本,它就能从模型的输入、输出和期望输出(标签),多学到一点点未知参数的信息。在每次迭代过程中,这个模型都能够评估其误差,并按照一定的更新规则,惩罚那些导致误差的参数。
两种应用场景
- CBOW——基于上下文预测词语
- skip-gram—基于词语预测上下文