Python自然语言处理 NLTK 库用法入门教程【经典】
本文实例讲述了Python自然语言处理NLTK库用法。分享给大家供大家参考,具体如下:
在这篇文章中,我们将基于Python讨论自然语言处理(NLP)。本教程将会使用PythonNLTK库。NLTK是一个当下流行的,用于自然语言处理的Python库。
那么NLP到底是什么?学习NLP能带来什么好处?
简单的说,自然语言处理(NLP)就是开发能够理解人类语言的应用程序和服务。
我们生活中经常会接触的自然语言处理的应用,包括语音识别,语音翻译,理解句意,理解特定词语的同义词,以及写出语法正确,句意通畅的句子和段落。
NLP的作用
正如大家所知,每天博客,社交网站和网页会产生数亿字节的海量数据。
有很多公司热衷收集所有这些数据,以便更好地了解他们的用户和用户对产品的热情,并对他们的产品或者服务进行合适的调整。
这些海量数据可以揭示很多现象,打个比方说,巴西人对产品A感到满意,而美国人却对产品B更感兴趣。通过NLP,这类的信息可以即时获得(即实时结果)。例如,搜索引擎正是一种NLP,可以在正确的时间给合适的人提供适当的结果。
但是搜索引擎并不是自然语言处理(NLP)的唯一应用。还有更好更加精彩的应用。
NLP的应用
以下都是自然语言处理(NLP)的一些成功应用:
- 搜索引擎,比如谷歌,雅虎等等。谷歌等搜索引擎会通过NLP了解到你是一个科技发烧友,所以它会返回科技相关的结果。
- 社交网站信息流,比如Facebook的信息流。新闻馈送算法通过自然语言处理了解到你的兴趣,并向你展示相关的广告以及消息,而不是一些无关的信息。
- 语音助手,诸如苹果Siri。
- 垃圾邮件程序,比如Google的垃圾邮件过滤程序,这不仅仅是通常会用到的普通的垃圾邮件过滤,现在,垃圾邮件过滤器会对电子邮件的内容进行分析,看看该邮件是否是垃圾邮件。
NLP库
现在有许多开源的自然语言处理(NLP)库。比如:
- Naturallanguagetoolkit(NLTK)
- ApacheOpenNLP
- StanfordNLPsuite
- GateNLPlibrary
自然语言工具包(NLTK)是最受欢迎的自然语言处理(NLP)库。它是用Python语言编写的,背后有强大的社区支持。
NLTK也很容易入门,实际上,它将是你用到的最简单的自然语言处理(NLP)库。
在这个NLP教程中,我们将使用PythonNLTK库。在开始安装 NLTK之前,我假设你知道一些Python入门知识。
安装NLTK
如果你使用的是Windows,Linux或Mac,你可以使用PIP安装NLTK:#pipinstallnltk。
在本文撰写之时,你可以在Python2.7,3.4和3.5上都可以使用NLTK。或者可以通过获取tar进行源码安装。
要检查NLTK是否正确地安装完成,可以打开你的Python终端并输入以下内容:Importnltk。如果一切顺利,这意味着你已经成功安装了NLTK库。
一旦你安装了NLTK,你可以运行下面的代码来安装NLTK包:
importnltk nltk.download()
这将打开NLTK下载器来选择需要安装的软件包。
你可以选择安装所有的软件包,因为它们的容量不大,所以没有什么问题。现在,我们开始学习吧!
使用原生Python来对文本进行分词
首先,我们将抓取一些网页内容。然后来分析网页文本,看看爬下来的网页的主题是关于什么。我们将使用urllib模块来抓取网页:
importurllib.request response=urllib.request.urlopen('http://php.net/') html=response.read() print(html)
从打印输出中可以看到,结果中包含许多需要清理的HTML标记。我们可以用这个 BeautifulSoup库来对抓取的文本进行处理:
frombs4importBeautifulSoup importurllib.request response=urllib.request.urlopen('http://php.net/') html=response.read() soup=BeautifulSoup(html,"html5lib") text=soup.get_text(strip=True) print(text)
现在,我们能将抓取的网页转换为干净的文本。这很棒,不是么?
最后,让我们通过以下方法将文本分词:
frombs4importBeautifulSoup importurllib.request response=urllib.request.urlopen('http://php.net/') html=response.read() soup=BeautifulSoup(html,"html5lib") text=soup.get_text(strip=True) tokens=[tfortintext.split()] print(tokens)
词频统计
现在的文本相比之前的html文本好多了。我们再使用PythonNLTK来计算每个词的出现频率。NLTK中的FreqDist()函数可以实现词频统计的功能:
frombs4importBeautifulSoup importurllib.request importnltk response=urllib.request.urlopen('http://php.net/') html=response.read() soup=BeautifulSoup(html,"html5lib") text=soup.get_text(strip=True) tokens=[tfortintext.split()] freq=nltk.FreqDist(tokens) forkey,valinfreq.items(): print(str(key)+':'+str(val))
如果你查看输出结果,会发现最常用的词语是PHP。
你可以用绘图函数为这些词频绘制一个图形: freq.plot(20,cumulative=False)。
从图中,你可以肯定这篇文章正在谈论PHP。这很棒!有一些词,如"the,""of,""a,""an,"等等。这些词是停止词。一般来说,停止词语应该被删除,以防止它们影响我们的结果。
使用NLTK删除停止词
NLTK具有大多数语言的停止词表。要获得英文停止词,你可以使用以下代码:
fromnltk.corpusimportstopwords stopwords.words('english')
现在,让我们修改我们的代码,并在绘制图形之前清理标记。首先,我们复制一个列表。然后,我们通过对列表中的标记进行遍历并删除其中的停止词:
clean_tokens=tokens[:] sr=stopwords.words('english') fortokenintokens: iftokeninstopwords.words('english'): clean_tokens.remove(token)
你可以在这里查看PythonList函数, 了解如何处理列表。
最终的代码应该是这样的:
frombs4importBeautifulSoup importurllib.request importnltk fromnltk.corpusimportstopwords response=urllib.request.urlopen('http://php.net/') html=response.read() soup=BeautifulSoup(html,"html5lib") text=soup.get_text(strip=True) tokens=[tfortintext.split()] clean_tokens=tokens[:] sr=stopwords.words('english') fortokenintokens: iftokeninstopwords.words('english'): clean_tokens.remove(token) freq=nltk.FreqDist(clean_tokens) forkey,valinfreq.items(): print(str(key)+':'+str(val))
如果你现在检查图表,会感觉比之前那张图标更加清晰,因为没有了停止词的干扰。
freq.plot(20,cumulative=False)
使用NLTK对文本分词
我们刚刚了解了如何使用split()函数将文本分割为标记。现在,我们将看到如何使用NLTK对文本进行标记化。对文本进行标记化是很重要的,因为文本无法在没有进行标记化的情况下被处理。标记化意味着将较大的部分分隔成更小的单元。
你可以将段落分割为句子,并根据你的需要将句子分割为单词。NLTK具有内置的句子标记器和词语标记器。
假设我们有如下的示例文本:
HelloAdam,howareyou?Ihopeeverythingisgoingwell. Todayisagoodday,seeyoudude.
为了将这个文本标记化为句子,我们可以使用句子标记器:
fromnltk.tokenizeimportsent_tokenize mytext="HelloAdam,howareyou?Ihopeeverythingisgoingwell.Todayisagoodday,seeyoudude." print(sent_tokenize(mytext))
输出如下:
['HelloAdam,howareyou?','Ihopeeverythingisgoingwell.','Todayisagoodday,seeyoudude.']
你可能会说,这是一件容易的事情。我不需要使用NLTK标记器,并且我可以使用正则表达式来分割句子,因为每个句子前后都有标点符号或者空格。
那么,看看下面的文字:
HelloMr.Adam,howareyou?Ihopeeverythingisgoingwell.Todayisagoodday,seeyoudude.
呃!Mr.是一个词,虽然带有一个符号。让我们来试试使用NLTK进行分词:
fromnltk.tokenizeimportsent_tokenize mytext="HelloMr.Adam,howareyou?Ihopeeverythingisgoingwell.Todayisagoodday,seeyoudude." print(sent_tokenize(mytext))
输出如下所示:
['HelloMr.Adam,howareyou?','Ihopeeverythingisgoingwell.','Todayisagoodday,seeyoudude.']
Great!结果棒极了。然后我们尝试使用词语标记器来看看它是如何工作的:
fromnltk.tokenizeimportword_tokenize mytext="HelloMr.Adam,howareyou?Ihopeeverythingisgoingwell.Todayisagoodday,seeyoudude." print(word_tokenize(mytext))
输出如下:
['Hello','Mr.','Adam',',','how','are','you','?','I','hope','everything','is','going','well','.','Today','is','a','good','day',',','see','you','dude','.']
正如所料,Mr.是一个词,也确实被NLTK当做一个词。NLTK使用nltk.tokenize.punktmodule中的 PunktSentenceTokenizer进行文本分词。这个标记器经过了良好的训练,可以对多种语言进行分词 。
标记非英语语言文本
为了标记其他语言,可以像这样指定语言:
fromnltk.tokenizeimportsent_tokenize mytext="BonjourM.Adam,commentallez-vous?J'espèrequetoutvabien.Aujourd'huiestunbonjour." print(sent_tokenize(mytext,"french"))
结果将是这样的:
['BonjourM.Adam,commentallez-vous?',"J'espèrequetoutvabien.","Aujourd'huiestunbonjour."]
NLTk对其他非英语语言的支持也非常好!
从WordNet获取同义词
如果你还记得我们使用nltk.download()安装NLTK的扩展包时。其中一个扩展包名为WordNet。WordNet是为自然语言处理构建的数据库。它包括部分词语的一个同义词组和一个简短的定义。
通过NLTK你可以得到给定词的定义和例句:
fromnltk.corpusimportwordnet syn=wordnet.synsets("pain") print(syn[0].definition()) print(syn[0].examples())
结果是:
asymptomofsomephysicalhurtordisorder
['thepatientdevelopedseverepainanddistension']
WordNet包含了很多词的定义:
fromnltk.corpusimportwordnet syn=wordnet.synsets("NLP") print(syn[0].definition()) syn=wordnet.synsets("Python") print(syn[0].definition())
结果是:
thebranchofinformationsciencethatdealswithnaturallanguageinformation
largeOldWorldboas
您可以使用WordNet来获得同义词:
fromnltk.corpusimportwordnet synonyms=[] forsyninwordnet.synsets('Computer'): forlemmainsyn.lemmas(): synonyms.append(lemma.name()) print(synonyms)
输出是:
['computer','computing_machine','computing_device','data_processor','electronic_computer','information_processing_system','calculator','reckoner','figurer','estimator','computer']
Cool!
从WordNet获取反义词
你可以用同样的方法得到单词的反义词。你唯一要做的是在将lemmas的结果加入数组之前,检查结果是否确实是一个正确的反义词。
fromnltk.corpusimportwordnet antonyms=[] forsyninwordnet.synsets("small"): forlinsyn.lemmas(): ifl.antonyms(): antonyms.append(l.antonyms()[0].name()) print(antonyms)
输出是:
['large','big','big']
这就是NLTK在自然语言处理中的力量。
NLTK词干提取
单词词干提取就是从单词中去除词缀并返回词根。(比方说working的词干是work。)搜索引擎在索引页面的时候使用这种技术,所以很多人通过同一个单词的不同形式进行搜索,返回的都是相同的,有关这个词干的页面。
词干提取的算法有很多,但最常用的算法是Porter提取算法。NLTK有一个PorterStemmer类,使用的就是Porter提取算法。
fromnltk.stemimportPorterStemmer stemmer=PorterStemmer() print(stemmer.stem('working'))
结果是:
work
结果很清楚。
还有其他一些提取算法,如Lancaster提取算法。这个算法的输出同Porter算法的结果在几个单词上不同。你可以尝试他们两个算法来查看有哪些不同结果。
提取非英语单词词干
SnowballStemmer类,除了英语外,还可以适用于其他13种语言。支持的语言如下:
fromnltk.stemimportSnowballStemmer print(SnowballStemmer.languages) 'danish','dutch','english','finnish','french','german','hungarian','italian','norwegian','porter','portuguese','romanian','russian','spanish','swedish'
你可以使用SnowballStemmer类的stem()函数来提取非英语单词,如下所示:
fromnltk.stemimportSnowballStemmer french_stemmer=SnowballStemmer('french') print(french_stemmer.stem("Frenchword"))
来自法国的朋友欢迎在评论区poll出你们测试的结果!
使用WordNet引入词汇
词汇的词汇化与提取词干类似,但不同之处在于词汇化的结果是一个真正的词汇。与词干提取不同,当你试图提取一些词干时,有可能会导致这样的情况:
fromnltk.stemimportPorterStemmer stemmer=PorterStemmer() print(stemmer.stem('increases'))
结果是:
increas
现在,如果我们试图用NLTKWordNet来还原同一个词,结果会是正确的:
fromnltk.stemimportWordNetLemmatizer lemmatizer=WordNetLemmatizer() print(lemmatizer.lemmatize('increases'))
结果是:
increase
结果可能是同义词或具有相同含义的不同词语。有时,如果你试图还原一个词,比如playing,还原的结果还是playing。这是因为默认还原的结果是名词,如果你想得到动词,可以通过以下的方式指定。
fromnltk.stemimportWordNetLemmatizer lemmatizer=WordNetLemmatizer() print(lemmatizer.lemmatize('playing',pos="v"))
结果是:
play
实际上,这是一个非常好的文本压缩水平。最终压缩到原文本的50%到60%左右。结果可能是动词,名词,形容词或副词:
fromnltk.stemimportWordNetLemmatizer lemmatizer=WordNetLemmatizer() print(lemmatizer.lemmatize('playing',pos="v")) print(lemmatizer.lemmatize('playing',pos="n")) print(lemmatizer.lemmatize('playing',pos="a")) print(lemmatizer.lemmatize('playing',pos="r"))
结果是:
play
playing
playing
playing
词干化和词化差异
好吧,让我们分别尝试一些单词的词干提取和词形还原:
fromnltk.stemimportWordNetLemmatizer fromnltk.stemimportPorterStemmer stemmer=PorterStemmer() lemmatizer=WordNetLemmatizer() print(stemmer.stem('stones')) print(stemmer.stem('speaking')) print(stemmer.stem('bedroom')) print(stemmer.stem('jokes')) print(stemmer.stem('lisa')) print(stemmer.stem('purple')) print('----------------------') print(lemmatizer.lemmatize('stones')) print(lemmatizer.lemmatize('speaking')) print(lemmatizer.lemmatize('bedroom')) print(lemmatizer.lemmatize('jokes')) print(lemmatizer.lemmatize('lisa')) print(lemmatizer.lemmatize('purple'))
结果是:
stone
speak
bedroom
joke
lisa
purpl
----------------------
stone
speaking
bedroom
joke
lisa
purple
词干提取的方法可以在不知道语境的情况下对词汇使用,这就是为什么它相较词形还原方法速度更快但准确率更低。
在我看来,词形还原比提取词干的方法更好。词形还原,如果实在无法返回这个词的变形,也会返回另一个真正的单词;这个单词可能是一个同义词,但不管怎样这是一个真正的单词。当有时候,你不关心准确度,需要的只是速度。在这种情况下,词干提取的方法更好。
我们在本NLP教程中讨论的所有步骤都涉及到文本预处理。在以后的文章中,我们将讨论使用PythonNLTK进行文本分析。
更多关于Python相关内容感兴趣的读者可查看本站专题:《Python数学运算技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》
希望本文所述对大家Python程序设计有所帮助。