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
|
至此,完成了文本规范化处理模块所需的全部函数的讨论和实现。