现在的位置: 首页 > 综合 > 正文

python自然语言处理学习笔记第三章4

2014年07月26日 ⁄ 综合 ⁄ 共 8132字 ⁄ 字号 评论关闭

保留所有词首或词尾的元音序列。在下一个例子中,正则表达式匹配词首元音序列,词尾元音序列和所有的辅音;其它的被忽略。

>>> import nlkt
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    import nlkt
ImportError: No module named nlkt
>>> import nltk
>>> regexp = r'^[AEIOUaeiou]+|[AEIOUaeiou]+$|[^AEIOUaeiou]'
>>> def compress(word):
pieces = re.findall(regexp, word)
return ''.join(pieces)

>>> import re
>>> english_udhr = nltk.corpus.udhr.words('English-Latin1')
>>> print nltk.tokenwrap(compress(w) for w in english_udhr[:75])
Unvrsl Dclrtn of Hmn Rghts Prmble Whrs rcgntn of the inhrnt dgnty and
of the eql and inlnble rghts of all mmbrs of the hmn fmly is the fndtn
of frdm , jstce and pce in the wrld , Whrs dsrgrd and cntmpt fr hmn
rghts hve rsltd in brbrs acts whch hve outrgd the cnscnce of mnknd ,
and the advnt of a wrld in whch hmn bngs shll enjy frdm of spch and
>>> rotokas_words = nltk.corpus.toolbox.words('rotokas.dic')
>>> cvs = [cv for w in rotokas_words for cv in re.findall(r'[ptksvr][aeiou]', w)]
>>> cfd = nltk.ConditionalFreqDist(cvs)
>>> cfd.tabulate()
     a    e    i    o    u
k  418  148   94  420  173
p   83   31  105   34   51
r  187   63   84   89   79
s    0    0  100    2    1
t   47    8    0  148   37
v   93   27  105   48   49

对于一些语言处理任务,我们想忽略词语结尾,只是处理词干。抽出一个词的词干的方
法有很多种。这里的是一种简单直观的方法,直接去掉任何看起来像一个后缀的字符:

>>> def stem(word):
...   for suffix in ['ing', 'ly', 'ed', 'ious', 'ies', 'ive', 'es', 's', 'ment']:
... if word.endswith(suffix):
... return word[:-len(suffix)]
... return word

>>> re.findall(r'^.*(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processing')
['ing']

>>> re.findall(r'^.*(?:ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processing')
['processing']

然而,实际上,我们会想将词分成词干和后缀。所以,我们应该只是用括号括起正则表
达式的这两个部分:

>>> re.findall(r'^(.*)(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processing')
[('process', 'ing')]

这看起来很有用途,但仍然有一个问题。让我们来看看另外的词“processes”:
>>> re.findall(r'^(.*)(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processes')
[('processe', 's')]
正则表达式错误地找到了后缀“-s”,而不是后缀“-es”。这表明另一个微妙之处:“*”
操作符是“贪婪的”,所以表达式的“.*”部分试图尽可能多的匹配输入的字符串。如果我
们使用“非贪婪”版本的“*”操作符,写成“*?”,我们就得到我们想要的:
>>> re.findall(r'^(.*?)(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processes')
[('process', 'es')]

分词是将字符串切割成可识别的构成一块语言数据的语言单元。虽然这是一项基础任务。

文本分词的一种非常简单的方法是在空格符处分割文本。

我们可以使用raw.split()在空格符处分割原始文本。使用正则表达式能做同样的事情,
匹配字符串中的所有空格符

保留所有词首或词尾的元音序列。在下一个例子中,正则表达式匹配词首元音序列,词尾元音序列和所有的辅音;其它的被忽略。
>>> import nlkt
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    import nlkt
ImportError: No module named nlkt
>>> import nltk
>>> regexp = r'^[AEIOUaeiou]+|[AEIOUaeiou]+$|[^AEIOUaeiou]'
>>> def compress(word):
pieces = re.findall(regexp, word)
return ''.join(pieces)

>>> import re
>>> english_udhr = nltk.corpus.udhr.words('English-Latin1')
>>> print nltk.tokenwrap(compress(w) for w in english_udhr[:75])
Unvrsl Dclrtn of Hmn Rghts Prmble Whrs rcgntn of the inhrnt dgnty and
of the eql and inlnble rghts of all mmbrs of the hmn fmly is the fndtn
of frdm , jstce and pce in the wrld , Whrs dsrgrd and cntmpt fr hmn
rghts hve rsltd in brbrs acts whch hve outrgd the cnscnce of mnknd ,
and the advnt of a wrld in whch hmn bngs shll enjy frdm of spch and
>>> rotokas_words = nltk.corpus.toolbox.words('rotokas.dic')
>>> cvs = [cv for w in rotokas_words for cv in re.findall(r'[ptksvr][aeiou]', w)]
>>> cfd = nltk.ConditionalFreqDist(cvs)
>>> cfd.tabulate()
     a    e    i    o    u
k  418  148   94  420  173
p   83   31  105   34   51
r  187   63   84   89   79
s    0    0  100    2    1
t   47    8    0  148   37
v   93   27  105   48   49

对于一些语言处理任务,我们想忽略词语结尾,只是处理词干。抽出一个词的词干的方
法有很多种。这里的是一种简单直观的方法,直接去掉任何看起来像一个后缀的字符:
>>> def stem(word):
...   for suffix in ['ing', 'ly', 'ed', 'ious', 'ies', 'ive', 'es', 's', 'ment']:
... if word.endswith(suffix):
... return word[:-len(suffix)]
... return word
>>> re.findall(r'^.*(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processing')
['ing']
>>> re.findall(r'^.*(?:ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processing')
['processing']
然而,实际上,我们会想将词分成词干和后缀。所以,我们应该只是用括号括起正则表
达式的这两个部分:
>>> re.findall(r'^(.*)(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processing')
[('process', 'ing')]
这看起来很有用途,但仍然有一个问题。让我们来看看另外的词“processes”:
>>> re.findall(r'^(.*)(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processes')
[('processe', 's')]
正则表达式错误地找到了后缀“-s”,而不是后缀“-es”。这表明另一个微妙之处:“*”
操作符是“贪婪的”,所以表达式的“.*”部分试图尽可能多的匹配输入的字符串。如果我
们使用“非贪婪”版本的“*”操作符,写成“*?”,我们就得到我们想要的:
>>> re.findall(r'^(.*?)(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processes')
[('process', 'es')]

分词是将字符串切割成可识别的构成一块语言数据的语言单元。虽然这是一项基础任务。
文本分词的一种非常简单的方法是在空格符处分割文本。
我们可以使用raw.split()在空格符处分割原始文本。使用正则表达式能做同样的事情,
匹配字符串中的所有空格符??是不够的,因为这将导致分词结果包含“\n”换行符;我们需
要匹配任何数量的空格符、制表符或换行符??:
正则表达式?[ \t\n]+?匹配一个或多个空格、制表符(\t)或换行符(\n)。其他空白
字符,如回车和换页符,确实应该包含的太多。
>>> raw ='''jhgkgkh jhgk mvkjc hkh
gkjhg gkhjg vkhv kjh
hgkjh jgf knkj'''
>>> re.split(r' ', raw)
['jhgkgkh', 'jhgk', 'mvkjc', 'hkh\ngkjhg', 'gkhjg', 'vkhv', 'kjh\nhgkjh', 'jgf', 'knkj']
>>> re.split(r'[ \t\n]+', raw)
['jhgkgkh', 'jhgk', 'mvkjc', 'hkh', 'gkjhg', 'gkhjg', 'vkhv', 'kjh', 'hgkjh', 'jgf', 'knkj']
正则表达式?[ \t\n]+?匹配一个或多个空格、制表符(\t)或换行符(\n)。其他空白
字符,如回车和换页符,确实应该包含的太多。于是,我们将使用一个re 库内置的缩写“\
s”,它表示匹配所有空白字符。前面的例子中第二条语句可以改写为re.split(r'\s+', raw)。
记住在正则表达式前加字母“r”,它告诉Python 解释器按照字面表示对待字符串而不去处理正则表达式中包含的反斜杠字符。
在空格符处分割文本给我们如“(not”和“herself,”这样的标识符。另一种方法是使
用Python 提供给我们的字符类“\w”匹配词中的字符,相当于[a-zA-Z0-9_]。也定义了
这个类的补“\W”即所有字母、数字和下划线以外的字符。我们可以在一个简单的正则表
达式中用\W 来分割所有单词字符以外的输入。
>>> re.split(r'\W+', raw)
['jhgkgkh', 'jhgk', 'mvkjc', 'hkh', 'gkjhg', 'gkhjg', 'vkhv', 'kjh', 'hgkjh', 'jgf', 'knkj']

我们用于文本处理的最简单的一种结构化对象是词链表。当我们希望把这些输出到显示
器或文件时,必须把这些词的链表转换成字符串
' '.join(silly)的意思是:取出silly 中的所有项目,将它们连接成一个大的字符串,使
用' '作为项目之间的间隔符,即join()是一个你想要用来作为胶水的字符串的一个方法。(许
多人感到join()的这种表示方法是违反直觉的。)join()方法只适用于一个字符串的链表—
—我们一直把它叫做一个文本——在Python 中享有某些特权的一个复杂的类型。
>>> silly = ['We', 'called', 'him', 'Tortoise', 'because', 'he', 'taught', 'us', '.']
>>> ' '.join(silly)
'We called him Tortoise because he taught us .'
>>> ';'.join(silly)
'We;called;him;Tortoise;because;he;taught;us;.'
>>> ''.join(silly)
'WecalledhimTortoisebecausehetaughtus.'

print 命令产生的是Python 尝试以人最可读的形式输出的一个对象的内容。第二种方法
——叫做变量提示——向我们显示可用于重新创建该对象的字符串。重要的是要记住这些都
仅仅是字符串,为了你——用户——的方便而显示的。它们并不会给我们实际对象的内部表
示的任何线索。
>>> sentence = """hello
world"""
>>> print sentence
hello
world
>>> sentence
'hello\nworld'

格式化输出通常包含变量和预先指定的字符串的一个组合。例如:给定一个频率分布f
dist,我们可以这样做:
>>> fdist = nltk.FreqDist(['dog', 'cat', 'dog', 'cat', 'dog', 'snake', 'dog', 'cat'])
>>> for word in fdist:
print word in fdist:

SyntaxError: invalid syntax
>>> for word in fdist:
print word,'->',fdist[word],';',

dog -> 4 ; cat -> 3 ; snake -> 1 ;

>>> for word in fdist:
print '%s->%d;' %(word,fdist[word]),

dog->4; cat->3; snake->1;

>>> '%s->' % 'cat'
'cat->'
>>> 'I want a %s right now' % 'coffee'
'I
'I want a coffee right now'
>>> 'I want a %s right now' % 'coffee'
'I want a coffee right now'

我们还可以间接的提供占位符的值。下面是使用for 循环的一个例子:
>>> template = 'Lee wants a %s right now'
>>> menu = ['sandwich', 'spam fritter', 'pancake']
>>> for snack in menu:
print template % snack

Lee wants a sandwich right now
Lee wants a spam fritter right now
Lee wants a pancake right now

我们的格式化字符串可以在页面(或屏幕)上输出任意的宽度,如%s 和
%d。我们也可以指定宽度,如%6s,产生一个宽度为6 的字符串。缺省情况它是右对齐
的??,但我们可以包括一个减号使它左对齐??。我们事先不知道要显示的值应该有多宽时,
可以在格式化字符串中用*替换宽度值,然后指定一个变量??。
>>> '%6s' %'dog'
'   dog'
>>> '%-6s' %'dog'
'dog   '
>>> width = 10
>>> '%-*s'  %(width,'dog')
'dog       '

其他控制字符用于十进制整数和浮点数。因为百分号%在格式化字符串中有特殊解释,
我们要在它前面加另一个%才能输出它。
>>> count, total = 3205, 9375
>>> "accuracy for %d words: %2.4f%%"  %(total,100*count/total)
'accuracy for 9375 words: 34.0000%'

将结果写入文件:
下面的代码打开可写文件output.txt,将程序的输出保存到文件。

我们已经看到了如何读取文本文件(3.1 节)。将输出写入文件往往也很有用。下面的
代码打开可写文件output.txt,将程序的输出保存到文件。
>>> output_file = open('output.txt', 'w')
>>> words = set(nltk.corpus.genesis.words('english-kjv.txt'))
>>> for word in sorted(words):
... output_file.write(word + "\n")
轮到你来:在写入文件之前,我们为每个字符串追加\n 会有什么影响?如
果你使用的是Windows 机器,你可能想用word + "\r\n"代替。如果我
们输入output_file.write(word)会发生什么?
当我们将非文本数据写入文件时,我们必须先将它转换为字符串。正如我们前面所看到
的,可以使用格式化字符串来做这一转换。关闭文件之前,让我们把总词数写入我们的文件。
>>> len(words)
2789
>>> str(len(words))
'2789'
>>> output_file.write(str(len(words)) + "\n")
>>> output_file.close()
在Python 中指定一个字符串使用单引号或双引号:'Monty Python',"Monty Pytho
n"。
   字符串中的字符是使用索引来访问的,索引从零计数:'Monty Python'[0]的值是M。
求字符串的长度可以使用len()。
   子字符串使用切片符号来访问: 'Monty Python'[1:5]的值是onty。如果省略起始
索引,子字符串从字符串的开始处开始;如果省略结尾索引,切片会一直到字符串的结
尾处结束。
   字符串可以被分割成链表:'Monty Python'.split()得到['Monty', 'Python']。链表
可以连接成字符串:'/'.join(['Monty', 'Python'])得到'Monty/Python'。
   我们可以使用text = open(f).read()从一个文件f 读取文本。可以使用text = url
open(u).read()从一个URL u 读取文本。我们可以使用for line in open(f)遍历一
个文本文件的每一行。
   在网上找到的文本可能包含不需要的内容(如页眉、页脚和标记),在我们做任何语言
处理之前需要去除它们。
   分词是将文本分割成基本单位或标记,例如词和标点符号等。基于空格符的分词对于许
多应用程序都是不够的,因为它会捆绑标点符号和词。NLTK 提供了一个现成的分词器
nltk.word_tokenize()。
   词形归并是一个过程,将一个词的各种形式(如:appeared,appears)映射到这个词标
准的或引用的形式,也称为词位或词元(如:appear)。
   正则表达式是用来指定模式的一种强大而灵活的方法。只要导入了re 模块,我们就可
以使用re.findall()来找到一个字符串中匹配一个模式的所有子字符串。
   如果一个正则表达式字符串包含一个反斜杠,你应该使用原始字符串与一个r 前缀:r'
regexp',告诉Python 不要预处理这个字符串。
   当某些字符前使用了反斜杠时,例如:\n,处理时会有特殊的含义(换行符);然而,
当反斜杠用于正则表达式通配符和操作符时,如:\.,\|,\$,这些字符失去其特殊的
含义,只按字面表示匹配。
   一个字符串格式化表达式template % arg_tuple 包含一个格式字符串template,
它由如%-6s 和%0.2d 这样的转换标识符符组成。

抱歉!评论已关闭.