首页 > 代码库 > Python之NLP(转)
Python之NLP(转)
http://blog.csdn.net/caicai1617/article/details/21191781
《使用Python进行自然语言处理》学习笔记五
版权声明:本文为博主原创文章,未经博主允许不得转载。
目录(?)[+]
第三章 加工原料文本
3.1 从网络和硬盘访问文本
1 电子书
古腾堡项目的其它文本可以在线获得,
整个过程大概需要几十秒(实验室网络不行是硬伤)
使用raw()可以得到原始的字符串。但是raw得到的数据绝对不是我们能直接拿去分析的,还要经过一些预处理。我们要将字符串分解为词和标点符号,正如我们在第 1 章中所看到的。这一步被称为分词, 它产生我们所熟悉的结构,一个词汇和标点符号的链表。
2处理的 HTML
好像很多公测语料都是html或者xml发布的,这个应该可以处理类似的数据。但书里说其中仍然含有不需要的内容,包括网站导航及有关报道等,通过一些尝试和出错你可以找到内容索引的开始和结尾,并选择你感兴趣的标识符,按照前面讲的那样初始化一个文本。
这里面的“尝试和出错”有点不合适吧。难道不能按标签去找吗,写一个网页模版然后去抽取某基础标签的内容,之前都是这么干的。
3处理搜索引擎的结果
网络可以被看作未经标注的巨大的语料库。网络搜索引擎提供了一个有效的手段,搜索大量文本作为有关的语言学的例子。搜索引擎的主要优势是规模:因为你正在寻找这样庞大的一个文件集,会更容易找到你感兴趣语言模式。而且,你可以使用非常具体的模式,仅在较小的范围匹配一两个例子,但在网络上可能匹配成千上万的例子。网络搜索引擎的第个优势是非常容易使用。因此, 它是一个非常方便的工具, 可以快速检查一个理论是否合理。
不幸的是,搜索引擎有一些显著的缺点。首先,允许的搜索方式的范围受到严格限制。不同于本地驱动器中的语料库,你可以编写程序来搜索任意复杂的模式,搜索引擎一般只允许你搜索单个词或词串,有时也允许使用通配符。其次,搜索引擎给出的结果不一致,并且在不同的时间或在不同的地理区域会给出非常不同的结果。当内容在多个站点重复时,搜索结果会增加。最后, 搜索引擎返回的结果中的标记可能会不可预料的改变, 基于模式方法定位特定的内容将无法使用(通过使用搜索引擎 APIs 可以改善这个问题)。
4 处理处理 RSS 订阅
我觉得这个部分可以使用爬虫和html处理来解决,更加方便。
5 读取本地文件
只需要注意一点,使用”\\”就没问题的。path2=‘D:\\PythonSource\\fileTest.txt‘
6从 PDF、MS Word 及其他二进制格式中提取文本
ASCII 码文本和 HTML 文本是人可读的格式。文字常常以二进制格式出现,如 PDF 和MSWord,只能使用专门的软件打开。第三方函数库如 pypdf 和 pywin32 提供了对这些格式的访问。从多列文档中提取文本是特别具有挑战性的。一次性转换几个文件,会比较简单些, 用一个合适的应用程序打开文件, 以文本格式保存到本地驱动器, 然后以如下所述的方式访问它。如果该文档已经在网络上,你可以在 Google 的搜索框输入它的 URL。搜索结果通常包括这个文档的 HTML 版本的链接,你可以将它保存为文本。
7捕获用户输入
Python2.X的版本是s =raw_input("Enter some text: "),到了3.X好像是用input代替了raw_input,更加好记了。
8 NLP 的流程
这个图表示的很清楚,我觉得预处理的任务就是将非结构化的数据尽量结构化,以便进一步处理。
- #!/usr/python/bin
- #Filename:NltkTest89,一些关于文本资源处理的测试
- from__future__ import division
- importnltk, re, pprint
- fromurllib import urlopen
- importtime
- importdatetime
- classNltkTest89:
- def __init__(self):
- print ‘Initing...‘
- def EbookTest(self,url):
- starttime = datetime.datetime.now()
- print ‘Start at:‘
- print time.strftime(‘%Y-%m-%d %H:%M:%S‘,time.localtime(time.time()))
- raw = urlopen(url).read()
- print len(raw)
- print raw[:75]
- endtime = datetime.datetime.now()
- print ‘Finish at:‘
- print time.strftime(‘%Y-%m-%d%H:%M:%S‘,time.localtime(time.time()))
- print ‘下载和读取文本使用了%d秒‘ %(endtime- starttime).seconds
- return raw
- def TokenTest(self,raw):
- ‘‘‘‘‘基于Project Gutenberg的一些分词测试‘‘‘
- tokens = nltk.word_tokenize(raw)
- print type(tokens)
- len(tokens)
- print tokens[:10]
- text = nltk.Text(tokens)
- print type(text)
- print text[1020:1060]
- print text.collocations()
- print raw.rfind("End of ProjectGutenberg‘s Crime")
- def HtmlTest(self,url):
- html = urlopen(url).read()
- html[:60]
- raw= nltk.clean_html(html)
- tokens = nltk.word_tokenize(raw)
- print tokens[:20]
- def FileTest(self,filePath):
- f = open(filePath)
- for line in f:
- print line.strip()
- nt89=NltkTest89()
- url1= "http://www.gutenberg.org/files/2554/2554.txt"
- #nt89.EbookTest(url1)
- #nt89.TokenTest(nt89.EbookTest(url1))
- url2="http://news.bbc.co.uk/2/hi/health/2284783.stm"
- #nt89.HtmlTest(url2)
- path1=nltk.data.find(‘corpora/gutenberg/melville-moby_dick.txt‘)
- path2=‘D:\\PythonSource\\fileTest.txt‘
- nt89.FileTest(path2)
3.2字符串:最底层的文本处理
1字符串的基本操作
这一部分讲的是Pyhton对字符串的处理,字符串处理哪种编程都有,再加上Python那么人性化,所以整个上手很容易。
2输出字符串
也很简单,只注意一点,在需要拼接字符串的时候一定要注意,在拼接处需要空格的地方要加空格。如果没有注意可能就会出现”Monty PythonHoly Grail“的情况,如果这是在处理其他指令的话就容易出大问题。之前用Java时就不小心过,取数据的MySQL指令少了一个空格还找了一会才排掉错。
3访问单个字符
又想起那个关于四六级的笑话了,话说学渣背单词,从前往后背,背不过C,从后往前背,背不过S。看来得说从前往后背,背不过e,从后往前背,背不过t,这样才更科学。
4访问子字符串
主要是列表切片和find,很简单。
5更多的字符串操作
p100有详情。师兄温馨提示我,split和strip非常重要,尤其是strip和Java里的trim一样,处理文本数据经常需要去掉字符串前后的空格什么的,没有会很麻烦。
6链表与字符串的差异
当我们在一个 Python 程序中打开并读入一个文件,我们得到一个对应整个文件内容的字符串。如果我们使用一个 for 循环来处理这个字符串元素,所有我们可以挑选出的只是单
个的字符——我们不选择粒度。相比之下, 链表中的元素可以很大也可以很小, 只要我们喜欢。例如:它们可能是段落、句子、短语、单词、字符。所以,链表的优势是我们可以灵活的决定它包含的元素,相应的后续的处理也变得灵活。因此,我们在一段 NLP 代码中可能做的第一件事情就是将一个字符串分词放入一个字符串链表中。相反, 当我们要将结果写入到一个文件或终端,我们通常会将它们格式化为一个字符串。
字符串是不可变的:一旦你创建了一个字符串,就不能改变它。然而,链表是可变的,其内容可以随时修改。作为一个结论,链表支持修改原始值的操作,而不是产生一个新的值。
- #-*-coding: utf-8-*-
- #!/usr/python/bin
- #Filename:NltkTest98,一些关于字符串处理的测试
- from__future__ import division
- importnltk, re, pprint
- fromurllib import urlopen
- fromnltk.corpus import gutenberg
- importtime
- importdatetime
- classNltkTest98:
- def __init__(self):
- print ‘Initing...‘
- def AlphaTest(self,text):
- raw = gutenberg.raw(text)
- fdist = nltk.FreqDist(ch.lower() for chin raw if ch.isalpha())
- print fdist.keys()
- nt98=NltkTest98()
- text=‘melville-moby_dick.txt‘
- nt98.AlphaTest(text)
3.3使用 Unicode 进行文字处理
1 什么是 Unicode?
Unicode 支持超过一百万种字符。每个字符分配一个编号,称为编码点。文件中的文本都是有特定编码的,所以我们需要一些机制来将文本翻译成 Unicode翻译成 Unicode 叫做解码。相对的,要将 Unicode 写入一个文件或终端,我们首先需要将 Unicode 转化为合适的编码——这种将 Unicode 转化为其它编码的过程叫做编码.
2 从文件中提取已编码文本
3 在 Python 中使用本地编码
在一个 Python 文件中使用你的字符串输入及编辑的标准方法,需要在文件的第一行或第二行中包含字符串:‘# -*- coding: utf-8-*-‘ 。注意windows里面编辑的文件到Linux里面要转码,不然会乱码。
3.4 使用正则表达式检测词组搭配
1 使用基本的元字符
P108正则表达式都是差不多的,pythonli里的,java里的,shell里的都差不多。
2 范围与闭包
T9 系统用于在手机上输入文本。两个或两个以上的词汇以相同的击键顺序输入,这叫做输入法联想提示,这个原来是这样的啊。那么在用户词库里的应该优先权更大一点,这样就符合个性化的要求。
3.5 正则表达式的有益应用
1 提取字符块
2 在字符块上做更多事情
3 查找词干
这表明另一个微妙之处:“*”操作符是“贪婪的”,所以表达式的“.*”部分试图尽可能多的匹配输入的字符串。
regexp= r‘^(.*?)(ing|ly|ed|ious|ies|ive|es|s|ment)?$‘
^abc表示以abc开始
如果我们要使用括号来指定连接的范围,但不想选择要输出的字符串,必须添加“?:”
4 搜索已分词文本
这个在做商品评价什么的应该非常有用的,直接抽取附近的形容词然后统计所占比例就可以了。
3.6 规范化文本
去掉所有的词缀以及提取词干的任务等。更进一步的步骤是确保结果形式是字典中确定的词,即叫做词形归并的任务。
1 词干提取器
NLTK 中包括了一些现成的词干提取器,Porter和 Lancaster 词干提取器按照它们自己的规则剥离词缀。NltkTest105.TokenerCompare试了一下,好像是Porter好一些。虽说专业的比较好,但是据说nltk的预处理也就一般,英文的还是一般用Stanford的,可以试着比较一下。
2词形归并
WordNet 词形归并器删除词缀产生的词都是在它的字典中的词。 这个额外的检查过程使词形归并器比刚才提到的词干提取器要慢。
好吧,确实很慢,大概慢一倍以上,不过还是可以接收的,可以考虑和Porter级联使用。
3.7用正则表达式为文本分词
分词是将字符串切割成可识别的构成一块语言数据的语言单元。
1分词的简单方法
2 NLTK 的正则表达式分词器
函数 nltk.regexp_tokenize()与 re.findall() 类似(我们一直在使用它进行分词) 。 然而,nltk.regexp_tokenize()分词效率更高,且不需要特殊处理括号。
3分词的进一步问题
个人觉得,如果不是专业研究分词,可以简单的使用目前已公认的效果最好的分词工具就可以了,不必要为了造飞机去研究冶铁。
3.8分割
1断句
在将文本分词之前,我们需要将它分割成句子。NLTK通过包含 Punkt句子分割器(Kiss & Strunk,2006)简化了这些。
2分词
现在分词的任务变成了一个搜索问题:找到将文本字符串正确分割成词汇的字位串。我们假定学习者接收词,并将它们存储在一个内部词典中。给定一个合适的词典,是能够由词典中的词的序列来重构源文本的。
好吧,默默的在这里决定了,英文用Stanford的分词,中文用NLPIR2014,不在这里纠结了。
3.9格式化:从链表到字符串
1从链表到字符串
‘‘.join(silly)
2字符串与格式
太基础了,不多说
3排列
%s 和%d。我们也可以指定宽度,如%6s,产生一个宽度为 6 的字符串。
4将结果写入文件
存储和内存是需要协调的,当无法提供足够的内存支持时,要有意识的写文件存储中间结果。尤其是训练时间很长的结果,能少算一次就少算一次。
5文本换行
我们可以在 Python 的 textwrap 模块的帮助下采取换行。
- fromtextwrap import fill
- wrapped= fill(output)
- printwrapped
- 代码片段NltkTest105
- #-*- coding: utf-8-*-
- #!/usr/python/bin
- #Filename:NltkTest105,一些关于字符串处理的测试
- from__future__ import division
- importnltk, re, pprint
- fromurllib import urlopen
- fromnltk.corpus import gutenberg, nps_chat
- importtime
- importdatetime
- classNltkTest105:
- def __init__(self):
- print ‘Initing...‘
- def ReTest(self,lan,regex):
- wordlist = [w for w innltk.corpus.words.words(lan) if w.islower()]
- print [w for w in wordlist ifre.search(regex, w)]
- def T9Test(self,lan,regex):
- wordlist = [w for w innltk.corpus.words.words(lan) if w.islower()]
- print [w for w in wordlist ifre.search(regex, w)]
- def stem(self,word):
- regexp =r‘^(.*?)(ing|ly|ed|ious|ies|ive|es|s|ment)?$‘
- stem, suffix = re.findall(regexp,word)[0]
- return stem
- def TokensReTest(self):
- moby =nltk.Text(gutenberg.words(‘melville-moby_dick.txt‘))
- print moby.findall(r"<a>(<.*>) <man>")
- def TokenerCompare(self,tokens):
- porter = nltk.PorterStemmer()
- lancaster = nltk.LancasterStemmer()
- wnl = nltk.WordNetLemmatizer()
- print [porter.stem(t) for t in tokens]
- print [lancaster.stem(t) for t intokens]
- print [wnl.lemmatize(t) for t intokens]
- def FileWrTest(self,path,content):
- outFile=open(path,‘w‘)
- for word in sorted(content):
- outFile.write(word+‘\n‘)
- nt105=NltkTest105()
- lan=‘en‘
- regex1=‘ed$‘
- regex2=‘^[ghi][mno][jlk][def]$‘
- #nt105.ReTest(lan,regex1)
- #nt105.T9Test(lan,regex2)
- raw="""DENNIS: Listen, strange women lying in ponds distributingswords\
- is nobasis for a system of government. Supreme executive power derives from\
- amandate from the masses, not from some farcical aquaticceremony."""
- tokens= nltk.word_tokenize(raw)
- #print[nt105.stem(t) for t in tokens]
- #nt105.TokensReTest()
- #nt105.TokenerCompare(tokens)
- words= set(nltk.corpus.genesis.words(‘english-kjv.txt‘))
- path=‘D:\\PythonSource\\outfiletest.txt‘
- nt105.FileWrTest(path,words)
Python之NLP(转)