N-grams模型、停顿词(stopwords)和标准化处理 - NLP学习(2)

在上一节《Tokenization - NLP(1)》的学习中,我们主要学习了如何将一串字符串分割成单独的字符,并且形成一个词汇集(vocabulary),之后我们将形成的词汇集合转换成计算机可以处理的数字信息,以方便我们做进一步文本分析。这篇博客的主题还是我们如何将文本转成成更有用的成分,让我们能从文本当中提取到更多的信息以便作为特征输入到模型中训练,首先会介绍一下N-grams算法,之后会提到停顿词及英文文本常见的标准化处理手段,如大小写的改变、词干提取等(文章中的某些例子会涉及到正则表达式的使用,但是因为不是主要的内容,对使用到的正则表达式不做过多解释,如果有需要的话自己找下书籍和在网上搜索下如何使用正则表达式)。

一、N-grams

自然语言处理过程中,一个值得我们注意的是,如果我们仅仅是将文本字符串分割成单独的文本,此时我们只是简单的去分析文本中每个字符所代表的潜在意义与我们需要分析的结果的关系性,然而我们忽略一个非常重要的信息,文本的顺序是含有非常的重要信息。举一个简单的例子,“钓鱼”两个词,如果我们单独去分析这两个词,而不是看作一个整体的话,那么我们得到的语意意思就是“钓”是一个动作词,“鱼”是一个名词,而当两个字放在一起的时候,我们知道其实我们想表述的“钓鱼”是我们要做的一个活动(event)。又比如英文“hot dog",我们都知道这个词组想表达的是我们吃的食物”热狗香肠包“,所以我们不希望单独去看hot和dog两个意思,如果是这样子我们可以看出意思相差非常的远,由此我们可以看出文本顺序的重要性。

而实际操作中,我们将这种把文本顺序保留下来的行为称之为建立N-grams模型,也就是我们将一个字符串分割成含有多个词的标识符(tokens)。当然,需要记住的一点是不论是上一节说的还是N-grams,他们都属于文本字符串Tokenization的一个过程。

 1 import re
 2 from nltk.util import ngrams
 3
 4 sentence = "I love deep learning as it can help me resolve some complicated problems in 2018."
 5
 6 # tokenize the sentence into tokens
 7 pattern = re.compile(r"([-\s.,;!?])+")
 8 tokens = pattern.split(sentence)
 9 tokens = [x for x in tokens if x and x not in ‘- \t\n.,;!?‘]
10
11 bigrams = list(ngrams(tokens, 2))
12 print([" ".join(x) for x in bigrams])

上述代码的输出结果是:

[‘I love‘, ‘love deep‘, ‘deep learning‘, ‘learning as‘, ‘as it‘, ‘it can‘, ‘can help‘, ‘help me‘, ‘me resolve‘, ‘resolve some‘, ‘some complicated‘, ‘complicated problems‘, ‘problems in‘, ‘in 2018‘]

上述代码的执行是首先将文本字符串分割成单独(unique)标识符,并且引入了正则表达式(更多的正则表达式请参看其他资料,这里有必要指出,当我们做一些大型的文本分析时,其实真正用正则表达式去书写相应的规则执行起来的效率是很低的,因为文本是千变万化,几乎没有相同的,例如每个人在微博上post的东西,所附在文本上的字符是千差万别,然后我们一般电子书上的文本又与网络的不同,所以就形成了无法用一套正则表达式的规则去完成所有的任务,普适性是很差的。)来更精准的分割字符串。除此之外,我们运用了NLTK的库来分割出一个含有两个词(Bi-Gram)的标识符。所以从上面我们可以看出,如“deep learning"和”complicated problems“这样子的组合更切合我们想要表达的意思,但是独个字符看的话我们就未必看得出了。

虽然N-grams模型可以让我们更好的去分割出具有更好语意的标识符,进而让我们做进一步文本分析,但是缺点也是同样明显,那就是运用N-grams模型可能让我们的词汇量成指数级的增长,并且并不是所有的Bigram都含有有用信息,而这个情况在甚至乎在Trigram或者Quad gram等含有更多单独字符在内的N-grams模型会更严重。这样子做产生的问题就是我们最终拿到的特征向量(the dimension of the feature vectors)的维度将会超过我们本身的文件样本数(length of the documents),而最终当我们将这些提取出来的特征放入到机器学习算法中的话,就会导致过拟合(over fitting)的情况。如此训练出来的模型将没有什么太好的performance和预测能力。

二、Stop Words

造成上述问题的一个原因可能是我们分割出来的标识符(n-grams)含有太多的不具备有用信息的组合,如带有停顿词(stop words)的词组组合,停顿词在英文中出现的频率是非常高的,如a, an, and, or, of, at, the等等单词,这些单词携带的信息量(substantive information)是极度有限的。所以我们需要做的就是在NLP分析过程中将文本中的停顿词去掉,这样子做的好处是我们减少词汇量,进而降低我们特征向量的维度。But.......我们还是需要再次注意一个问题,那就是虽然停顿词本身所携带的信息不是很多,但是stop words却可能在n-grams中存在关系性信息(relational information),考虑下面两种情况:

  1. Mark reported to the CEO
  2. Susan reported as the CEO to the board

在上述例子中,如果我们将to the和as the去掉的话,那么我们就会得到reported CEO,这是很迷惑的,因为这两个句子中本身是有一个层级意思的,但是因为我们remove掉了as,the和to这三个stop words导致了关系信息的缺失。正常情况下,我们需要创建一个4-grams的词(如上述紫色字部分标注高亮的部分)。这也就延申出我们需要讨论的关于NLP模型创立过程中碰到的一个问题,那就是基本是特定问题需要特定的解决办法。具体为根据实际运用而定,创建一个过滤器适当的过滤掉我们不需要的stop words。

下面我们通过NLTK的库来看看英文中大概都有那些stop words:

1 import nltk
2
3 nltk.download("stopwords")
4 stopwords = nltk.corpus.stopwords.words("english")
5 print(len(stopwords))
6 print(stopwords[:50])

输出结果为:

[nltk_data] Downloading package stopwords to
[nltk_data]     C:\Users\JielongSSS\AppData\Roaming\nltk_data...
[nltk_data]   Package stopwords is already up-to-date!
179
[‘i‘, ‘me‘, ‘my‘, ‘myself‘, ‘we‘, ‘our‘, ‘ours‘, ‘ourselves‘, ‘you‘, "you‘re", "you‘ve", "you‘ll", "you‘d", ‘your‘, ‘yours‘, ‘yourself‘, ‘yourselves‘, ‘he‘, ‘him‘, ‘his‘, ‘himself‘, ‘she‘, "she‘s", ‘her‘, ‘hers‘, ‘herself‘, ‘it‘, "it‘s", ‘its‘, ‘itself‘, ‘they‘, ‘them‘, ‘their‘, ‘theirs‘, ‘themselves‘, ‘what‘, ‘which‘, ‘who‘, ‘whom‘, ‘this‘, ‘that‘, "that‘ll", ‘these‘, ‘those‘, ‘am‘, ‘is‘, ‘are‘, ‘was‘, ‘were‘, ‘be‘]

三、标准化处理(Normalization)

讨论那么多,我们也应该意识到一个问题:一个NLP模型的表现(performance)很大程度取决于我们所拥有的词汇量(额。。。其实嘛,很难有一个定量的分析,起码目前在学习过程中给我的感觉是如此,词汇量应该掌握在一个具体什么样的程度呢?希望有大神看了我的博客文章也留言给我,是否有一个有效的衡量方法去查看究竟我们所需要的词汇量是多少?)。当然这部分我们要讲的主要是如何通过其他方式来缩减我们tokenize之后创建的feature vector的维度,也就是减少我们的词汇量,以最大程度的保留我们所需要的觉得有用的信息。具体一般有三种处理方式:CASE FOLDING(大小写的改变),Stemming和Lemmatization,下面会展开详细的说明。

3.1 CASE Folding

在英文的NLP模型中,单词的大小写是非常敏感的,这跟我们中文比较不一样,中文是没有所谓的大小写之说的,在这里因为主要以英文NLP为主,所以就只讲英文的标准了,未来有机会更新博客的时候我会尝试引入中文相关的NLP处理方式。我们都知道,在书写英文句子的时候,我们总是让开头的第一个单词的首字母处于大写状况,或者说我们想要强调某些事件的时候,我们就希望用全大写来表示,但是我们同样知道But和but是同一个单词but并且表示同一个意思,然而文本分析过程中这是两个不同的单词,仅仅是因为他们的首字母不一样,这样子计算机自动分析的时候得到的结果就会导致有偏差,所以我们需要对这But这个单词进行大小写的规范处理,从而减少我们的词汇量。

1 tokens = [‘Horse‘, ‘horse‘, ‘Dog‘, ‘dog‘, ‘Cat‘, ‘cat‘]
2 print(tokens)
3 print("单词数量为: ",len(set(tokens)))
4
5 normalized_tokens = [x.lower() for x in tokens]
6 print(normalized_tokens)
7 print("Normalized之后的单词数量为: ",len(set(normalized_tokens)))

输出结果为:

[‘Horse‘, ‘horse‘, ‘Dog‘, ‘dog‘, ‘Cat‘, ‘cat‘]
单词数量为:  6
[‘horse‘, ‘horse‘, ‘dog‘, ‘dog‘, ‘cat‘, ‘cat‘]
Normalized之后的单词数量为:  3

从上面的结果我们可以看出,我们单词的数量从6个变为了3个,因为Horse和horse表达的就是同一个东西。当然,就如我们开头所说的,英文单词对于大小写是很敏感的,也就意味着大小写的单词对于英文单词所要表达的意思可能是不同的,如Doctor和doctor在大小写方面前者表示为博士,后者我们说的一般是医生的意思,这是我们需要注意的一点,当然你并无法完全针对每个大小写敏感的单词去做case normalization,所以一般情况我们根据需求而定,取舍来做分析,大部分时候的做法是我们只对句子的首个单词的首字母进行case normalization,这只是提供一种分析方法,根据学习过程获得信息,英文的NLP模型最终都是不采用case normalization的,以免丢失太多的信息,对于中文等一些语言,大小写不敏感的,这个就更没意义了。

3.2 Stemming

Stemming是另外一个处理英文文本会用到的技巧,主要是单词的复数形式中或者指代所有格结果等单词中提取出相应的词干(stem)。例如,我们知道cats,horses的词干形式是cat和horse,又比如doing的词干为do。通过这样子的处理,我们将很多不同形式的词回复为其原本的词干形式,这样子做有很大的作用。一个实例就是搜索引擎,当你搜索某样的东西的时候,很多时候你可能不知道你所需要搜索的东西的具体拼写方式,所以我们只是键入你觉得可能的词,但是此时我们需要机器反馈给我具有相关联系的搜索结果,这个结果不仅仅是需要语意上尽可能地相同,大部分时候我们是基于关键字匹配的,如果采取的是100%的匹配的话,得到的结果将会是很有限,这时候通过词干的匹配来检索呈现出相应的结果就显得异常的重要。而对于我们搭建模型,在预处理文本的阶段,则大大的减少了我们的词汇量(意味着我们不需要大空间储存)与此同时它也尽可能地规避减少信息地丢失。不仅如此,提取词干也同时让我们地模型更具普适性,这点符合我们刚才说的搜索引擎的例子。这里有一点需要注意的是,这里的词干并非严格意义上的词干,而只是我们所说的字符或者标识符,这个标识符可能表示的是好几种不同拼写形式的单词。

1 def stemming(sent):
2     return ‘ ‘.join([re.findall(‘^(.*ss|.*?)(s)?$‘, word)[0][0].strip("‘") for word in sent.lower().split()])
3
4 stemming(‘horses‘)

上述代码的输出结果为:

‘horse‘

正则表达式中想要表达的是如果一个单词的结尾为s的话则词干为去掉s之后的单词,如果多余一个s作为结尾的话,那么这个词保持原型。上述的代码示例能解决的问题是很有限的,因为更复杂的诸如dishes这样子的单词,我们知道去掉的是es,而不仅仅是s,如果要达到足够高的精准度,那我们需要写的正则表达式也会逐步增多。这样子代码执行起来的效率也不够高。下面介绍一下用NLTK库中的PorterStemmer来提取文本的词干。

1 from nltk.stem.porter import PorterStemmer
2
3 stemmer = PorterStemmer()
4 print(‘ ‘.join([stemmer.stem(w).strip("‘") for w in "dishes washer‘s washed dishes".split()]))

输出结果为:

dish washer wash dish

3.3 Lemmatization

词形还原(lemmatization)也是一种在英文语言处理中比较常见的的技巧,大致的作用与词干提取类似,也是希望不同形式的单词可以在经过处理之后恢复为他们原本的模样,但是词形还原更多的是放在了单词本身的语意上。所以,词形还原其实比词干提取和大小写的改变更适合预处理文本,因为他们不是简单的改变单词的大小写或者单复数或者所有格的形式,而是基于语意去做还原。比如,我们如果用词干提取去处理better这个单词的时候,我们可能会把单词的er去掉,这样子单词就会编程bet或者bett,这完全改变了单词的意思,但是如果是基于词形还原,那么我们就得到类似的词,如good,best等等。在正式NLP模型创建过程中,我们一般是希望词形还原的运用是在词干提取前面,因为在英文文本中,lemmatization处理过后的单词更接近单词本身所要表达的意思,并且同样的也可以减少我们特征的维度。下面是通过NLTK上的WordNetLemmatizer函数来让你了解下词形还原是如何工作的:

1 from nltk.stem import WordNetLemmatizer
2
3 lemmatizer = WordNetLemmatizer()
4 print(lemmatizer.lemmatize(‘better‘))
5 print(lemmatizer.lemmatize(‘better‘, pos=‘a‘))

输出结果为:

better
good

上述代码第五行中的pos是part of speech是词性标注的意思,a代表的形容词的形式。

综上,我们可以看出,词干提取和词形还原都可以减少单词的词汇量,但是同时他们也增加了文本的迷惑性,因为不可能将不同形式的单词100%的恢复成所要表达的单词形式,更需要明白的是,即使词干一样,基于该呈现出来的不同形式的单词的意思也会差很多,所以迷惑性也就增加了,这样子对我们自然语言文本分析其实变相的增加了难度,在实际的运用做,我们需要根据实际情况运用上述讲到的算法原理和技巧。

原文地址:https://www.cnblogs.com/jielongAI/p/10189907.html

时间: 2024-10-11 21:59:54

N-grams模型、停顿词(stopwords)和标准化处理 - NLP学习(2)的相关文章

在Solr4.9中使用IKAnalyzer,实现同义词,扩展词库,停顿词的添加

在使用solr4.9的过程中,使用了IKAnalyzer分词器,其中遇到了不少问题,现在做个记录,以备后续只用. 首先使用IKAnalyzer是看到群里有人介绍,但是貌似现在IKAnalyzer已经没人更新了...不知道是不是真的,先不管这些,下面介绍一下如何在solr中使用它. 在solr的配置文件schema.xml中添加 <!--IKAnalyzer-->    <fieldType name="text_ik" class="solr.TextFie

Python Word2Vec使用训练好的模型生成词向量

# 文本文件必须是utf-8无bom格式 from gensim.models.deprecated.word2vec import Word2Vec model = Word2Vec.load( './model/Word60.model') # 3个文件放在一起:Word60.model Word60.model.syn0.npy Word60.model.syn1neg.npy print("read model successful") word_list = ['了', '不

在Solr4.10配置IKAnalyzer 同义词、扩展词库、停顿词详解

http://book.zhulang.com/312144/347001.html http://book.zhulang.com/312144/347002.html http://book.zhulang.com/312144/347003.html http://book.zhulang.com/312144/347004.html http://book.zhulang.com/312144/347005.html http://book.zhulang.com/312144/3470

重磅︱R+NLP:text2vec包简介(GloVe词向量、LDA主题模型、各类距离计算等)

词向量的表示主流的有两种方式,一种当然是耳熟能详的google的word2vec,还有一类就是GloVe.那么前面一类有三个开源的包,后面这一类我倒是看到得不多,恰好是在我关注了许久的一个包里面有,它就是text2vec啦.该包提供了一个强大API接口,能够很好地处理文本信息. 本包是由C++写的,流处理器可以让内存得到更好的利用,一些地方是用RcppParallel包进行并行化加乘,同时兼容各个系统的服务器.如果没有并行的地方,大家也可以自己用foreach包来自己加速. ----------

基线系统需要受到更多关注:基于词向量的简单模型

最近阅读了<Baseline Needs More Love: On Simple Word-Embedding-Based Models and Associated Pooling Mechanisms>这篇论文[1],该工作来自杜克大学,发表在ACL 2018上.论文详细比较了直接在词向量上进行池化的简单模型和主流神经网络模型(例如CNN和RNN)在NLP多个任务上的效果.实验结果表明,在很多任务上简单的词向量模型和神经网络模型(CNN和LSTM)的效果相当,有些任务甚至简单模型更好.下

词向量与ELMo模型 词向量漫谈

目录: 基础部分回顾(词向量.语言模型) NLP的核心:学习不同语境下的语义表示 基于LSTM的词向量学习 深度学习中的层次表示以及Deep BI-LSTM ELMo模型 总结 1. 基础部分回顾(词向量.语言模型) 1.1 独热编码-词的表示 1.2 词向量-词的表示 我们为什么需要词向量?(One-hot向量的缺点?) 基于One-hot能否表示单词之间语义相似度? 1.2.1 基于One-hot能否表示单词之间语义相似度? 答:不可以.因为,我们不管是通过欧式距离还是通过余弦相似度,计算用

spacy词向量

spaCy能够比较两个对象,并预测它们的相似程度. 预测相似性对于构建推荐系统或标记重复项很有用. 例如,您可以建议与当前正在查看的用户内容相似的用户内容,或者将支持凭单标记为与现有内容非常相似的副本. 每个Doc.Span和Token都有一个.similarity()方法,它允许您将其与另一个对象进行比较,并确定相似度.当然,相似性总是主观的——“狗”和“猫”是否相似取决于你如何看待它.spaCy的相似模型通常假定一个相当通用的相似性定义. tokens = nlp(u'dog cat ban

简单爬取《小丑》电影豆瓣短评生成词云

导语  在前段时间看了杰昆菲尼克斯的小丑电影,心里很好奇大部分观众看完这部电影之后对此有什么评价,然后看了看豆瓣短评之后,觉得通过python把短评中出现最多的单词提取出来,做成一张词云,看看这部电影给观众们留下的关键词是什么. 抓取数据  首先刚开始的时候 ,是通过requests去模拟抓取数据,发现短评翻页翻到20页之后就需要登录豆瓣用户才有权限查看,所以打算通过使用selenium模拟浏览器动作自动化将页面中的数据爬取下来,然后存储到特定的txt文件,由于没打算做其他的分析,就不打算存放到

自然语言处理中CNN模型几种常见的Max Pooling操作

/* 版权声明:可以任意转载,转载时请标明文章原始出处和作者信息 .*/ author: 张俊林 CNN是目前自然语言处理中和RNN并驾齐驱的两种最常见的深度学习模型.图1展示了在NLP任务中使用CNN模型的典型网络结构.一般而言,输入的字或者词用Word Embedding的方式表达,这样本来一维的文本信息输入就转换成了二维的输入结构,假设输入X包含m个字符,而每个字符的Word Embedding的长度为d,那么输入就是m*d的二维向量. 图1 自然语言处理中CNN模型典型网络结构 这里可以