机器之心报道
文本处理
现有数据中,文本是最非结构化的形式,里面有各种各样的噪声;如果没有预处理,文本数据都不能分析。清理和标准化文本的整个过程叫做文本预处理(text preprocessing),其作用是使文本数据没有噪声并且可以分析。
主要包括三个步骤:
下图展示了文本预处理流程的结构。
移除噪声
任何与数据上下文和最终输出无关的文本都可被判作噪声。
例如,语言停止词(stopword,语言中常用的词汇:系动词is,am,定冠词the,介词of,in)、URL 或链接、社交媒体实体(提及、标签)、标点符号和特定行业词汇。这一步移除了文本中所有类型的噪声。
移除噪声通用的做法是准备一个噪声实体的词典,在文本对象上逐个 token(或逐词)迭代,消除在噪声词典中出现的标签。
以下是实现这一步的 Python 代码:
```
# Sample code to remove noisy words from a text
noise_list = ["is", "a", "this", "..."]
def _remove_noise(input_text):
words = input_text.split()
noise_free_words = [word for word in words if word not in noise_list]
noise_free_text = " ".join(noise_free_words)
return noise_free_text
_remove_noise("this is a sample text")
>>> "sample text"
```
另外一种方法是使用正则表达式,尽管其只能解决特定模式的噪声。我们在之前的文章中详细介绍了正则表达式:https://www.analyticsvidhya.com/blog/2015/06/regular-expression-python/
以下是从输入文本中移除正则表达式的 Python 代码:
```
# Sample code to remove a regex pattern
import re
def _remove_regex(input_text, regex_pattern):
urls = re.finditer(regex_pattern, input_text)
for i in urls:
input_text = re.sub(i.group().strip(), '', input_text)
return input_text
regex_pattern = "#[A-Za-z0-9\w]*"
_remove_regex("remove this #hashtag from analytics vidhya", regex_pattern)
>>> "remove this from analytics vidhya"
```
词汇规范化
另外一种文本形式的噪声是由一个词汇所产生的多种表示形式。
例如,“play”,“player”,“played”,“plays”和“playing”,这些词汇都是由“play”变化而来的。虽然它们意义不一,但根据上下文都是相似的。词汇规范化这一步把一个词的不同展现形式转化为了他们规范化的形式(也叫做引理(lemma))。规范化是文本上的特征工程起中枢作用的一步,因为它把高维特征(N个不同的特征)转化为了对任何机器学习模型都很理想的低维空间(1个特征)。
最常见的词汇规范化是:
词干提取:词干提取是词汇后缀(“ing”,“ly”,“es”,“s”等)去除过程的一个基本规则。
词形还原:词形还原与词干提取相反,是有组织地逐步获取词汇根形式的步骤,它使用到了词汇(词汇字典序)和形态分析(词的结构和语法关系)。
下面是实现词形还原和词干提取的代码,使用了一个流行的 Python 库 NLTK:
```
from nltk.stem.wordnet import WordNetLemmatizer
lem = WordNetLemmatizer()
from nltk.stem.porter import PorterStemmer
stem = PorterStemmer()
word = "multiplying"
lem.lemmatize(word, "v")
>> "multiply"
stem.stem(word)
>> "multipli"
```
对象标准化
文本数据经常包含不在任何标准词典里出现的词汇或短语。搜索引擎和模型都识别不了这些。
比如,首字母缩略词、词汇附加标签和通俗俚语。通过正则表达式和人工准备的数据词典,这种类型的噪声可以被修复。以下代码使用了词典查找方法来替代文本中的社交俚语。
```
lookup_dict = {'rt':'Retweet', 'dm':'direct message', "awsm" : "awesome", "luv" :"love", "..."}
def _lookup_words(input_text):
words = input_text.split()
new_words = []
for word in words:
if word.lower() in lookup_dict:
word = lookup_dict[word.lower()]
new_words.append(word) new_text = " ".join(new_words)
return new_text
_lookup_words("RT this is a retweeted tweet by Shivam Bansal")
>> "Retweet this is a retweeted tweet by Shivam Bansal"
```
除了目前为止讨论过的三个步骤,其他类型的文本预处理有编码-解码噪声,语法检查器和拼写改正等。我之前的一篇文章给出了预处理及其方法的细节。
文本到特征(文本数据上的特征工程)
为了分析已经预处理过的数据,需要将数据转化成特征(feature)。取决于用途,文本特征可通过句法分析、实体/N元模型/基于词汇的特征、统计特征和词汇嵌入等方法来构建。下面来详细理解这些技巧。
句法分析
句法分析涉及到对句中词的语法分析和位置与词汇的关系的分析。依存语法(Dependency Grammar)和词性标注(Part of Speech tags)是重要的文本句法属性。
依赖树(Dependency Trees)——由一些词汇共同组成的句子。句中词与词之间的联系是由基本的依存语法决定的。从属关系语法是一类解决(已标签)两个词汇项(字词)间二元不对称关系的句法文本分析。每一种关系都可用三元组(关系、支配成分、从属成分)来表示。例如:考虑下面这个句子:“Bills on ports and immigration were submitted by Senator Brownback, Republican of Kansas.”词汇间的关系可由如下所示的树的形式观察得到
观察树的形状可得:“submitted”是该句的根词(root word),由两颗子树所连接(主语和宾语子树)。每一颗子树本身又是一颗依存关系树(dependency tree ),其中的关系比如有 - (“Bills” <-> “ports” <by> “proposition” 关系),(“ports” <-> “immigration” <by> “conjugation” 关系)
这种类型的树,当从上至下迭代分析时可以得到语法关系三元组。对于很多自然语言处理问题,比如实体性情感分析,执行者(actor)与实体识别和文本分类等,语法关系三元组都可以用作特征。Python wrapper 的StanfordCoreNLP( http://stanfordnlp.github.io/CoreNLP/ 来自斯坦福自然语言处理组,只允许商业许可证)和NTLK从属关系语法可以用来生成依赖树。
词性标注(PoS/Part of speech tagging)——除了语法关系外,句中每个词都与词性(名词、动词、形容词、副词等等)联系起来。词性标注标签决定了句中该词的用法和作用。这里有宾夕法尼亚大学定义的所有可能的词性标签表。以下代码使用了NTLK包对输入文本执行词性标签注释。(NTLK提供了不同的实现方式,默认是感知器标签)
```
from nltk import word_tokenize, pos_tag
text = "I am learning Natural Language Processing on Analytics Vidhya"
tokens = word_tokenize(text)
print pos_tag(tokens)
>>> [('I', 'PRP'), ('am', 'VBP'), ('learning', 'VBG'), ('Natural', 'NNP'),('Language', 'NNP'),
('Processing', 'NNP'), ('on', 'IN'), ('Analytics', 'NNP'),
词性标注被用在许多重要的自然语言处理目的上:
A. 词义消歧:一些词汇根据用法有很多种意思。例如,下面的两个句子:
I.“Please book my flight for Delhi”
II. “I am going to read this book in the flight”
“Book”在不同的上下文中出现,然而这两种情况的词性标签却不一样。在第一句中,“book”被用作动词,而在第二句中,它被用作名词。(Lesk算法也可被用于相同的目的)
B. 提高基于词汇的特征:当词汇作为特征时,一个学习模型可以学习到不同的词汇上下文,然而特征与词性连接起来,上下文就被保留了,因此得到了很强的特征。例如:
句 - “book my flight, I will read this book”
标签 – (“book”, 2), (“my”, 1), (“flight”, 1), (“I”, 1), (“will”, 1), (“read”, 1), (“this”, 1)带有POS的标签 – (“book_VB”, 1), (“my_PRP$”, 1), (“flight_NN”, 1), (“I_PRP”, 1), (“will_MD”, 1), (“read_VB”, 1), (“this_DT”, 1), (“book_NN”, 1)
C. 规范化和词形归并(Lemmatizatio):词性标签是将词转化为其基本形式(引理)的基础
D. 高效移除停止词:词性标签在移除停止词方面也非常有用。
例如,有一些标签总是定义低频/较低重要性的词汇。
例如:(IN – “within”, “upon”, “except”), (CD – “one”,”two”, “hundred”), (MD – “may”, “must” 等)
实体提取(实体作为特征)
实体(entity)被定义为句中最重要的部分——名词短语、动词短语或两者都有。实体检测算法通常是由基于规则的解析、词典查询、词性标签和依存分析组合起来的模型。实体检测的适用性很广泛,在自动聊天机器人、内容分析器和消费者见解中都有应用。
主题建模和命名实体识别是自然语言处理领域中两种关键的实体检测方法。
A. 命名实体识别(NER/Named Entity Recognition)
从文本中检测命名实体比如人名、位置、公司名称等的过程叫做命名实体识别(NER)。例如:
句 - Sergey Brin, the manager of Google Inc. is walking in the streets of New York.命名实体 - ( “人” : “Sergey Brin” ), (“公司名” : “Google Inc.”), (“位置” : “New York”)典型NER模型包含三个模块:
名词短语识别:使用从属关系分析和词性分析将所有名词性短语从文本中提取出来。
短语分类:将提取出的名词短语分类到各自的目录(位置,名称等)中。谷歌地图API提供了通往消除歧义位置的很好路径。然后,dbpedia,维基百科的开源数据库可以用来识别人名或公司名。除了这个,我们能通过结合不同来源的信息精确的查找表和词典。
实体消歧:有些时候实体可能会误分类,因此在结果层上建一层交叉验证层非常有用。知识图谱就可以用来使用。目前流行的知识图谱有:谷歌知识图谱、IBM Watson 和维基百科。
B.主题建模
主题建模是自动识别文本集中主题的过程,它以无监督的方式从语料库中的词汇里提取隐藏的模式。主题(topic)被定义为“文本集中共同出现术语的重复模式”。一个好的主题模型能对“健康”、“医生”、“病人”、“医院”建模为“健康保健”,“农场”、“作物”、“小麦”建模为“耕作”。
隐含狄利克雷分布(LDA)是最流行的主题建模技术,以下是在Python环境下使用LDA技术实现主题建模的代码。若想查看更详细的细节,请参看:https://www.analyticsvidhya.com/blog/2016/08/beginners-guide-to-topic-modeling-in-python/
```
doc1 = "Sugar is bad to consume. My sister likes to have sugar, but not my father."
doc2 = "My father spends a lot of time driving my sister around to dance practice."
doc3 = "Doctors suggest that driving may cause increased stress and blood pressure."
doc_complete = [doc1, doc2, doc3]
doc_clean = [doc.split() for doc in doc_complete]
import gensim from gensim
import corpora
# Creating the term dictionary of our corpus, where every unique term is assigned an index.
dictionary = corpora.Dictionary(doc_clean)
# Converting list of documents (corpus) into Document Term Matrix using dictionary prepared above.
doc_term_matrix = [dictionary.doc2bow(doc) for doc in doc_clean]
# Creating the object for LDA model using gensim library
Lda = gensim.models.ldamodel.LdaModel
# Running and Training LDA model on the document term matrix
ldamodel = Lda(doc_term_matrix, num_topics=3, id2word = dictionary, passes=50)
# Results
print(ldamodel.print_topics())
```
C.N-Grams 特征
N-Grams是指N个词汇的结合体。N-Grams(N>1)作为特征与词汇(Unigrams)作为特征相比,通常会更加富含信息。同时,bigrams(N=2)被认为是最重要的特征。以下代码生成了文本的 bigrams。
```
def generate_ngrams(text, n):
words = text.split()
output = []
for i in range(len(words)-n+1):
output.append(words[i:i+n])
return output
>>> generate_ngrams('this is a sample text', 2)
# [['this', 'is'], ['is', 'a'], ['a', 'sample'], , ['sample', 'text']]
```
统计特征
文本数据使用该节所讲的几种技术可直接量化成数字。
A. 术语频率 - 逆文献频率(TF – IDF)
TF-IDF 是经常被使用在信息检索问题上的权重模型。TF-IDF在不考虑文献中词的具体位置情况下,基于文献中出现的词汇将文本文献转化成向量模型。例如,假设有一个N 个文本文献的数据集,在任何一个文献“D”中,TF和IDF会被定义为 - 术语频率(TF) - 术语“t”的术语频率被定义为“t”在文献“D”中的数量。
逆文献频率(IDF)- 术语的逆文献频率被定义为文本集中可用文献的数量与包含术语“t”的文献的数量的比例的对数。
TF-IDF公式给出了文本集中术语的相对重要性,以下为TF-IDF公式和使用Python的scikit学习包将文本转换为tf-idf向量。
```
from sklearn.feature_extraction.text import TfidfVectorizer
obj = TfidfVectorizer()
corpus = ['This is sample document.', 'another random document.', 'third sample document text']
X = obj.fit_transform(corpus)
print X
>>>
(0, 1) 0.345205016865
(0, 4) ... 0.444514311537
(2, 1) 0.345205016865
(2, 4) 0.444514311537
```
模型创建了一个词典并给每一个词汇赋了一个索引。输出的每一行包含了一个元组(i,j)和在第i篇文献索引j处词汇的tf-idf值。
B. 数量/密度/可读性特征
基于数量或密度的特征同样也能被用于模型和分析中。这些特征可能看起来比较繁琐但是对学习模型有非常大的影响。一些特征有:词数、句数、标点符号数和特定行业词汇的数量。其他类型的测量还包括可读性测量(比如音节数量、smog index 和易读性指数)。参考 Textstat 库创建这样的特征:https://github.com/shivam5992/textstat
词嵌入(文本向量)
词嵌入是将词表示为向量的方法,在尽量保存文本相似性的基础上将高维的词特征向量映射为低维特征向量。词嵌入广泛用于深度学习领域,例如卷积神经网络和循环神经网络。Word2Vec和GloVe是目前非常流行的两种做词嵌入的开源工具包,都是将文本转化为对应的向量。
Word2Vec:https://code.google.com/archive/p/word2vec/
GloVe:http://nlp.stanford.edu/projects/glove/
Word2Vec是由预处理模块和两个浅层神经网络(CBOW/Continuous Bag of Words和Skip-gram)组成,这些模型广泛用于自然语言处理问题。Word2Vec首先从训练语料库中组织词汇,然后将词汇做词嵌入,得到对应的文本向量。下面的代码是利用gensim包实现词嵌入表示。
```
from gensim.models import Word2Vec
sentences = [['data', 'science'], ['vidhya', 'science', 'data', 'analytics'],['machine', 'learning'], ['deep', 'learning']]
# train the model on your corpus
model = Word2Vec(sentences, min_count = 1)
print model.similarity('data', 'science')
>>> 0.11222489293
print model['learning']
>>> array([ 0.00459356 0.00303564 -0.00467622 0.00209638, ...])
```
这些向量作为机器学习的特征向量,然后利用余弦相似性、单词聚类、文本分类等方法来衡量文本的相似性。 |