【语言处理与Python】11.3数据采集
从网上获取数据
我们讨论过访问单个文件,如RSS订阅、搜索引擎的结果。
1、有的时候,还需要大量的WEB文本。最简单的方法是获得出版的网页文本的文集。在http://www.sigwac.org.uk/维护的有一个资源列表。
2、使用网络爬虫。
从字处理器文件获取数据
例11-1. 将MicrosoftWord创建的HTML转换成CSV def lexical_data(html_file): SEP='_ENTRY' html = open(html_file).read() html = re.sub(r'<p', SEP+ '<p', html) text = nltk.clean_html(html) text = ' '.join(text.split()) for entry in text.split(SEP): if entry.count(' ') > 2: yield entry.split(' ', 3) >>>import csv >>>writer= csv.writer(open("dict1.csv","wb")) >>>writer.writerows(lexical_data("dict.htm"))
从电子表格和数据库中获得数据
电子表格通常用于获取词表或范式。
我们现在假设在一个CSV文件中有这些内容:
"sleep","sli:p","v.i","a condition of bodyand mind..." "walk","wo:k","v.intr","progress bylifting and setting downeach foot ..." "wake","weik","intrans","cease to sleep"
那么,我们可以查询:
>>>import csv >>>lexicon = csv.reader(open('dict.csv')) >>>pairs = [(lexeme, defn) for (lexeme, _, _,defn) in lexicon] >>>lexemes, defns= zip(*pairs) >>>defn_words= set(w for defn in defnsfor win defn.split()) >>>sorted(defn_words.difference(lexemes)) ['...', 'a', 'and', 'body', 'by', 'cease', 'condition', 'down', 'each', 'foot', 'lifting', 'mind', 'of', 'progress', 'setting', 'to']
这些信息将可以指导正在进行的工作来丰富词汇和更新关系数据库的内容。
转换数据格式
已标注语言数据很少以最方便的格式保存,往往需要进行各种格式转换。
一种是输入和输出格式都是同构的。比如将词汇数据从Toolbox转换成XML。
一种是输出是输入的摘要。例如下面的例子:
>>>idx =nltk.Index((defn_word,lexeme) ... for (lexeme, defn) in pairs ... for defn_wordin nltk.word_tokenize(defn) ... if len(defn_word) > 3) ④ >>>idx_file = open("dict.idx", "w") >>>for wordin sorted(idx): ... idx_words =', '.join(idx[word]) ... idx_line = "%s: %s\n"%(word, idx_words) ⑤ ... idx_file.write(idx_line) >>>idx_file.close() #此时,dict.idx包含下面的内容 body: sleep cease:wake condition: sleep down:walk each: walk foot: walk lifting: walk mind:sleep progress:walk setting: walk sleep: wake
决定要包含的标注层
这里提供了一些常用的标注层:
分词:文本的书写形式不能明确地识别它的标识符。分词和规范化的版本作为常规的正
式版本的补充可能是一个非常方便的资源。
断句:正如我们在第3章中看到的,断句比它看上去的似乎更加困难。因此,一些语料
库使用明确的标注来断句。
分段:段和其他结构元素(标题,章节等)可能会明确注明。
词性:文档中的每个单词的词类。
句法结构:一个树状结构,显示一个句子的组成结构。
浅层语义:命名实体和共指标注,语义角色标签。
对话与段落:对话行为标记,修辞结构。
但是,现在的语料库之间在如何表示标注上并没有多少一致性。
然而,有两个大类的标注应该加以区别。
内联标注:为文档标注词性时,字符串“fly”可能被替换为字符串“fly/NN”来表示词fly在文中是名词。
对峙标注:对峙标注不修改原始文档,而是创建一个新的文档,通过使用指针引用原始文档来增加标注信息。例如:这个新的文档可能包含字符串“<tokenid=8 pos='NN'/>”,表示8号标识符是一个名词。
标注和工具
NLP的挑战是编写程序处理这种格式的泛化。例如:如果编程任务涉及树数据,文件格式允许任意有向图,那么必须验证输入数据检查树的属性如:根、连通性、无环。如果输入文件包含其他层的标注,该程序将需要知道数据加载时如何忽略它们,将树数据保存到文件时不能否定或抹杀这些层。
创建和发布一个新的语料库时,尽可能使用现有广泛使用的格式是权宜之计。如果这样不可能,语料库可以带有一些软件——如nltk.corpus模块——支持现有的接口方法。
处理濒危语言时特别注意事项
世界上大多数语言面临灭绝。对此,许多语言学家都在努力工作,记录语言,构建这个世界语言遗产的重要方面的丰富记录。在NLP的领域能为这方面的努力提供什么帮助吗?开发标注器、分析器、命名实体识别等不是最优先的,通常没有足够的数据来开发这样的工具。相反,最经常提出的是需要更好的工具来收集和维护数据,特别是文本和词汇。
允许通过相似的发音查找词项也是很有益的。
下面是如何做到这一点的一个简单演示:
1、我们要确定易混淆的字母序列,映射复杂版本到更简单的版本。
2、辅音群中字母的相对顺序是拼写错误的一个来源,所以我们将辅音字母顺序规范化。
>>>mappings= [('ph', 'f'), ('ght', 't'), ('^kn', 'n'), ('qu', 'kw'), ... ('[aeiou]+', 'a'), (r'(.)\1', r'\1')] >>>def signature(word): ... for patt,repl in mappings: ... word= re.sub(patt, repl, word) ... pieces= re.findall('[^aeiou]+', word) ... return ''.join(char for piece in pieces for char in sorted(piece))[:8] >>>signature('illefent') 'lfnt' >>>signature('ebsekwieous') 'bskws' >>>signature('nuculerr') 'nclr'
下一步,我们对词典中的所有词汇创建从特征到词汇的映射。
>>>signatures = nltk.Index((signature(w),w)for win nltk.corpus.words.words()) >>>signatures[signature('nuculerr')] ['anicular', 'inocular', 'nucellar', 'nuclear', 'unicolor', 'uniocular', 'unocular']
最后,我们应该按照与原词的相似程度对结果进行排序:
>>>def rank(word, wordlist): ... ranked =sorted((nltk.edit_dist(word, w),w)for win wordlist) ... return [word for (_, word)in ranked] >>>def fuzzy_spell(word): ... sig = signature(word) ... if sig in signatures: ... return rank(word, signatures[sig]) ... else: ... return [] >>>fuzzy_spell('illefent') ['olefiant', 'elephant', 'oliphant', 'elephanta'] >>>fuzzy_spell('ebsekwieous') ['obsequious'] >>>fuzzy_spell('nucular') ['nuclear', 'nucellar', 'anicular', 'inocular', 'unocular', 'unicolor', 'uniocular']