机器之心报道


自然语言处理基础知识与操作(自然语言处理中的文本处理和特征工程)(1)

文本处理


现有数据中,文本是最非结构化的形式,里面有各种各样的噪声;如果没有预处理,文本数据都不能分析。清理和标准化文本的整个过程叫做文本预处理(text preprocessing),其作用是使文本数据没有噪声并且可以分析。

主要包括三个步骤:

下图展示了文本预处理流程的结构。

自然语言处理基础知识与操作(自然语言处理中的文本处理和特征工程)(2)

移除噪声

任何与数据上下文和最终输出无关的文本都可被判作噪声。

  • 词干提取:词干提取是词汇后缀(“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.”词汇间的关系可由如下所示的树的形式观察得到

    自然语言处理基础知识与操作(自然语言处理中的文本处理和特征工程)(3)

    观察树的形状可得:“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. 词义消歧:一些词汇根据用法有很多种意思。例如,下面的两个句子:

    “Book”在不同的上下文中出现,然而这两种情况的词性标签却不一样。在第一句中,“book”被用作动词,而在第二句中,它被用作名词。(Lesk算法也可被用于相同的目的)

    B. 提高基于词汇的特征:当词汇作为特征时,一个学习模型可以学习到不同的词汇上下文,然而特征与词性连接起来,上下文就被保留了,因此得到了很强的特征。例如:

    C. 规范化和词形归并(Lemmatizatio):词性标签是将词转化为其基本形式(引理)的基础

    D. 高效移除停止词:词性标签在移除停止词方面也非常有用。

    例如,有一些标签总是定义低频/较低重要性的词汇。

    例如:(IN – “within”, “upon”, “except”), (CD – “one”,”two”, “hundred”), (MD – “may”, “must” 等)

    实体提取(实体作为特征)

    实体(entity)被定义为句中最重要的部分——名词短语、动词短语或两者都有。实体检测算法通常是由基于规则的解析、词典查询、词性标签和依存分析组合起来的模型。实体检测的适用性很广泛,在自动聊天机器人、内容分析器和消费者见解中都有应用。

    自然语言处理基础知识与操作(自然语言处理中的文本处理和特征工程)(4)

    主题建模和命名实体识别是自然语言处理领域中两种关键的实体检测方法。

    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模型包含三个模块:

    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向量。

    自然语言处理基础知识与操作(自然语言处理中的文本处理和特征工程)(5)

    ```

    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是由预处理模块和两个浅层神经网络(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, ...])

    ```

    这些向量作为机器学习的特征向量,然后利用余弦相似性、单词聚类、文本分类等方法来衡量文本的相似性。

    ,