NLP 教程

NLP 工具库

NLP 神经网络

NLP 笔记

original icon
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.knowledgedict.com/tutorial/nlp-new-word-detection.html

NLP 新词发现 相关算法技术最详解


新词发现是 NLP 的基础任务之一,主要是通过统计,无监督学习等算法技术手段挖掘“未登陆词”。常见的方法有基于左右信息熵的方式、基于神经网络、基于分词的手段等等。

新词发现技术

  1. 基于点间互信息(Pointwise Mutual Information)和左右信息熵(Information Entropy)的方式。
  2. 基于神经网络。

基于互信息和左右熵

这种方法中,首先引入了两个概念:

  1. 点间互信息(Pointwise Mutual Information),它表示凝固程度,即多个词一起出现的可能性。
  2. 左右信息熵(Information Entropy),它表示自由程度,即其独立存在的程度。

点间互信息

首先我们来看一下点间互信息的公式:

\(PMI(x, y) = \log_2{p(x, y) \over p(x)*p(y)}\)

  • 其中 p(x, y) 表示两个词一起出现的概率。
  • 而 p(x) 和 p(y) 表示各词出现的概率。

举个例子,比如一份语料中,“机器学习”出现了18次,“机器”出现了26次,“学习”出现了39次。由于语料库总词数是个定值,那么“机器学习”这个词在“机器”,“学习”上的的点间互信息如下:

\(\log_2{18 * N \over 26 * 39}\)

  • 其中 N 指总词数。

以上例子告诉我们一个结论就是点间互信息越大,说明这两个词经常出现在一起,意味着两个词的凝固程度越大,其组成一个新词的可能性也就越大

左右信息熵

左右熵说白了其实就是信息熵,公式如下:

\(E_{left}(PreW) = - \sum_{\forall Pre \subseteq A}{P(PreW) * \log_2{P(PreW)}}\)

  • 上述公式 PreW 我们需要拆开看,Pre 是 W 词前缀的集合。

我们都知道信息熵是反应不确定程度的一个量,信息熵越大说明不确定程度越高,把其转变为新词发现中可以理解为如下:

左右熵值越大,说明该词的周边词越丰富,意味着词的自由程度越大,其成为一个独立的词的可能性也就越大

实战

算法的逻辑主要分为如下三个步骤:

  1. 将语料文本转换成一个字符串,然后一个生成 n_gram 的词典,并统计个词的词频。
  2. 利用点间互信息从之前的 n_gram 词典中筛选出(通过设置阈值)备选的新词。
  3. 最后通过左右熵从备选新词中筛选出(也通过设置阈值)最终输出的新词。

以下是 python 的实战相关代码:

import math
import re
from collections import Counter


def n_gram_words(text_list, n_gram):
    """
    获取 n_gram 的词频字典

    Args:
        text_list: 中文文章列表
        n_gram: 整数(int)类型的 n_gram 值

    Returns:
        返回词频字典

    """
    words = []
    for i in range(1, n_gram + 1):
        for text in text_list:
            words += [text[j:j + i] for j in range(len(text) - i + 1)]
    words_freq = dict(Counter(words))
    return words_freq


def pmi_filter(word_freq_dic, min_p):
    """
    获取符合 pmi 阈值的词

    Args:
        word_freq_dic: 词频字典
        min_p: PMI 阈值(最小值)

    Returns:
        返回符合条件的词列表

    """
    new_words = []
    for word in word_freq_dic:
        if len(word) == 1:
            #   单个字,跳过忽略
            pass
        else:
            #   p(x)*p(y),根据 PMI 公式,该部分越小,PMI 值越大,所以取最小值即可表示该 word 的最大 PMI 值
            p_x_y = min([word_freq_dic.get(word[:i]) * word_freq_dic.get(word[i:]) for i in range(1, len(word))])
            pmi = math.log2((word_freq_dic.get(word) * len(word_freq_dic)) / p_x_y)
            #   也可以不计算 log2,加快统计速度,这时阈值需要新的量纲设置
            #   pmi = (word_freq_dic.get(word) * len(word_freq_dic)) / p_x_y
            if pmi > min_p:
                new_words.append(word)
    return new_words


def calculate_entropy(char_list):
    """
    计算 char_list 的信息熵

    Args:
        char_list: 出现词的列表

    Returns:
        出现词的信息熵

    """
    char_freq_dic = dict(Counter(char_list))
    entropy = (-1) * sum(
        [char_freq_dic.get(i) / len(char_list) * math.log2(char_freq_dic.get(i) / len(char_list)) for i in
         char_freq_dic])
    return entropy


def entropy_left_right_filter(conditional_words, text_list, ngram, min_entropy):
    """
    在符合 PMI 过滤条件的词中,获取符合最小信息熵条件的最终候选新词

    Args:
        conditional_words: 符合 PMI 过滤条件的词的列表
        text_list: 原始文本列表
        ngram: 指定的 ngram
        min_entropy: 最小信息熵,符合该条件才可以作为候选新词

    Returns:
        最终的候选词,字典(dict)类型
    """
    final_words = {}
    for word in conditional_words:
        left_char_list = []
        right_char_list = []
        for text in text_list:
            left_right_char_tuple_list = re.findall('(?:(.{0,%d}))%s(?=(.{0,%d}))' % (ngram, word, ngram), text)
            if left_right_char_tuple_list:
                for left_right_char_tuple in left_right_char_tuple_list:
                    if left_right_char_tuple[0]:
                        left_char_list += [left_right_char_tuple[0][i:] for i in range(len(left_right_char_tuple[0]))]
                    if left_right_char_tuple[1]:
                        right_char_list += [left_right_char_tuple[1][i:] for i in range(len(left_right_char_tuple[1]))]
        if left_char_list:
            left_entropy = calculate_entropy(left_char_list)
        if right_char_list:
            right_entropy = calculate_entropy(right_char_list)
        if left_char_list and right_char_list:
            if min(right_entropy, left_entropy) > min_entropy:
                final_words[word] = min(right_entropy, left_entropy)
        elif left_char_list:
            if left_entropy > min_entropy:
                final_words[word] = left_entropy
        elif right_char_list:
            if right_entropy > min_entropy:
                final_words[word] = right_entropy
    sorted(final_words.items(), key=lambda x: x[1], reverse=False)
    return final_words

 

NLP,英文全称 Natural Language Processing,中文叫自然语言处理,它是人工智能和语言学领域的分支学科。该领域探讨 ...
这里收集了 NLP 工作相关的常见问题、解决方法等。 ...
排序算法分为两大类,一是内部排序,即数据记录在内存中进行排序,另一个是外部排序,主要是因排序的数据很大,一次不能容纳全部的排序记录,在排序过 ...
查找是在大量的信息中寻找一个特定的信息元素,在计算机应用中,查找是常用的基本运算。折半查找的前提条件是需要有序表顺序存储,对于静态查找表,一 ...
什么是算法?简而言之,任何定义明确的计算步骤都可称为算法,接受一个或一组值为输入,输出一个或一组值。 ...