4.文本规范化处理
下文中将定义一个规范化模块以处理文本文档规范化,并在后面建立分类器时使用这个处理模块。尽管有许多可用的技术,但是将坚持简化与直接原则,以便于更容易地一步步参照这里的实现。将在模块中实现和使用下面的规范化技术。
- 扩展缩写词。
- 通过词形还原实现文本处理规范化。
- 去除特殊字符与符号。
- 去停用词。
不在更多的关注拼写纠正及其他高级的技术,但如果你感兴趣,可以集成这些之前讲述过的内容。首先从载入一些依赖的模块开始。来实现缩写词扩展。
下面的代码段显示了必要的引用和依赖项:
from contractions import CONTRACTION_MAP import re import nltk import string from nltk.stem import WordNetLemmatizer stopword_list = nltk.corpus.stopwords.words( 'english' ) wnl = WordNetLemmatizer() |
上面的代码中,载入了英文的停用词、出自 CONTRACTION_MAP 的缩写映射和 WordNetLemmatizer 的一个实例来实现原型还原。实现,定义一个函数实现文本的切分,它将使用在其他的规范化函数中。下面的函数实现词语切分,并去除分割后符号中的多余空格。
def tokenize_text(text): tokens = nltk.word_tokenize(text) tokens = [token.strip() for token in tokens] return tokens |
定义扩展缩写词的函数。输入文本,如果有匹配的缩写,则返回包含扩展缩写词后的文本。下面的代码段有助于实现这些:
def expand_contractions(text, contraction_mapping): contractions_pattern = re. compile ( '({})' . format ( '|' .join(contraction_mapping.keys())), flags = re.IGNORECASE|re.DOTALL) def expand_match(contraction): match = contraction.group( 0 ) first_char = match[ 0 ] expanded_contraction = contraction_mapping.get(match)\ if contraction_mapping.get(match)\ else contraction_mapping.get(match.lower()) expanded_contraction = first_char + expanded_contraction[ 1 :] return expanded_contraction expanded_text = contractions_pattern.sub(expand_match, text) expanded_text = re.sub( "'" , "", expanded_text) return expanded_text |
既然已经有了扩展缩写词的函数,接下来就可以实现一个使用词形还原函数把单词变换为词基或词根形式的函数已对文本进行规范化处理。下面的函数有助于实现这些:
from pattern.en import tag from nltk.corpus import wordnet as wn # Annotate text tokens with POS tags def pos_tag_text(text): def penn_to_wn_tags(pos_tag): if pos_tag.startswith( 'J' ): return wn.ADJ elif pos_tag.startswith( 'V' ): return wn.VERB elif pos_tag.startswith( 'N' ): return wn.NOUN elif pos_tag.startswith( 'R' ): return wn.ADV else : return None tagged_text = tag(text) tagged_lower_text = [(word.lower(), penn_to_wn_tags(pos_tag)) for word, pos_tag in tagged_text] return tagged_lower_text # lemmatize text based on POS tags def lemmatize_text(text): pos_tagged_text = pos_tag_text(text) lemmatized_tokens = [wnl.lemmatize(word, pos_tag) if pos_tag else word for word, pos_tag in pos_tagged_text] lemmatized_text = ' ' .join(lemmatized_tokens) return lemmatized_text |
上面的代码片段描述了两个词形还原函数。主函数是 lemmatize_text,该函数接受文本数据,基于每个词形标签还原词形,接着给用户返回词形还原处理后的文本。为实现这个功能,需要标注每个文本符号的词性标签。使用 pattern 函数库中的 tag 函数对每个符号标注词性标签。因为 WordNetLemmatizer 基于 WordNet 语法格式。将每个单词符号转换为小写,纠正拼写,转换为 WordNet 词性标签,返回这些标注好的单词符号,最后将这些符号送入 lemmatize_text 函数。
下面的函数帮助我们实现了特殊符号和字符的去除:
def remove_special_characters(text): tokens = tokenize_text(text) pattern = re. compile ( '[{}]' . format (re.escape(string.punctuation))) filtered_tokens = filter ( None , [pattern.sub('', token) for token in tokens]) filtered_text = ' ' .join(filtered_tokens) return filtered_text |
通过文本切分去除了一些特殊字符,因此可以去除一些实际上是缩写的标识,但无法在第一步中去除 “s” “re” 等。将在去除停用词时去除它们。然而,也可以不通过文本切分来去除这些特殊字符。通过正则表达式匹配来去除 string.punctuation 中定义的特殊字符。下面的函数有助于去除文本数据中的停用词。
def remove_stopwords(text): tokens = tokenize_text(text) filtered_tokens = [token for token in tokens if token not in stopword_list] filtered_text = ' ' .join(filtered_tokens) return filtered_text |
既然已经定义了全部的函数,就可以通过将所有函数一个接一个地连接在一起的方式简历文本处理流水线。下面的函数实现上述功能,输入文本文档资料,进行规范化处理,返回规范化处理后的文本文档语料。
def normalize_corpus(corpus, tokenize = False ): normalized_corpus = [] for text in corpus: text = expand_contractions(text, CONTRACTION_MAP) text = lemmatize_text(text) text = remove_special_characters(text) text = remove_stopwords(text) normalized_corpus.append(text) if tokenize: text = tokenize_text(text) normalized_corpus.append(text) return normalized_corpus |
至此,完成了文本规范化处理模块所需的全部函数的讨论和实现。