2019-03 NER命令实体识别归纳

1. 基本概念

  概念:一般来说,NER的标注列表为['O' ,'B-MISC', 'I-MISC', 'B-ORG' ,'I-ORG', 'B-PER' ,'I-PER', 'B-LOC' ,'I-LOC']。其中,一般一共分为四大类:PER(人名),LOC(位置),ORG(组织)以及MISC,而且B表示开始,I表示中间,O表示单字词。
  评估指标:一般看Acc、Precision、Recall、F1值和ROC、AUC。但是由于在很多场景中,'O'的这个label出现次数是最多的,所以光看Acc肯定是没用的咯!
  CRF学到的constrains:
    1. 句子首个单词接下来的不是“B-“ 就是 “O”, 而非 “I-“
    2. “B-label1 I-label2 I-label3 I-…”中的label1, label2, label3 … 应该是相同的实体标签。
    3. 等等很多标签的搭配问题。

2. 数据清洗

  1. 控制句子长度,100左右吧。
  2. 符号清理。
  3. 舍去全是‘O’的标注句子。
  4. 如果对数字识别不做要求,干脆转换成0进行识别,做成统一符号。

3. 模型

  当前来讲,主流的有两种:一种是BiLSTM+CRF的;另一种是BERT直接预测的。当然,对于BERT模型来说,在其上层也是可以再加CRF进行限制一下的。不过本人还没进行实战的试验,后续把结果整理整理。

4. 评估指标代码

  对于评估的指标,上面已经说到是Acc、Precision、Recall和F1值。但是对于多个分类时,理论上要一个类别一个类别地去计算对应的Acc、Precision、Recall和F1值。其中需要了解的理论是混淆矩阵(confusion matrix)的概念,如下所示:


confusion matrix.png

如有150个样本数据,这些数据分成3类,每类50个。分类结束后得到的混淆矩阵为上图所示。第一行第一列中的43表示有43个实际归属第一类的实例被预测为第一类,同理,第二行第一列的2表示有2个实际归属为第二类的实例被错误预测为第一类。
  所以通过混淆矩阵来得到各个评估指标,拿precision这个指标来举例,其他的同理:

from tensorflow.python.ops.metrics_impl import _streaming_confusion_matrix

def precision(labels,
              predictions, 
              num_classes, 
              pos_indices=None,    ## 这里表示要计算指标的label对应的index
              weights=None, 
              average='micro'):
    cm, op = _streaming_confusion_matrix(labels, predictions, num_classes, weights)
    pr, _, _ = metrics_from_confusion_matrix(cm, pos_indices, average=average)
    op, _, _ = metrics_from_confusion_matrix(op, pos_indices, average=average)
    return (pr, op) 

def metrics_from_confusion_matrix(cm, pos_indices=None, average='micro', beta=1):
    num_classes = cm.shape[0]
    if pos_indices is None:
        pos_indices = [i for i in range(num_classes)]

    if average == 'micro':
        return pr_re_fbeta(cm, pos_indices, beta)

    elif average in {'macro', 'weighted'}:
        precisions, recalls, fbetas, n_golds = [], [], [], []
        for idx in pos_indices:
            pr, re, fbeta = pr_re_fbeta(cm, [idx], beta)
            precisions.append(pr)
            recalls.append(re)
            fbetas.append(fbeta)
            cm_mask = np.zeros([num_classes, num_classes])
            cm_mask[idx, :] = 1
            n_golds.append(tf.to_float(tf.reduce_sum(cm * cm_mask)))

        if average == 'macro':
            pr = tf.reduce_mean(precisions)
            re = tf.reduce_mean(recalls)
            fbeta = tf.reduce_mean(fbetas)
            return pr, re, fbeta

        if average == 'weighted':
            n_gold = tf.reduce_sum(n_golds)
            pr_sum = sum(p * n for p, n in zip(precisions, n_golds))
            pr = safe_div(pr_sum, n_gold)
            re_sum = sum(r * n for r, n in zip(recalls, n_golds))
            re = safe_div(re_sum, n_gold)
            fbeta_sum = sum(f * n for f, n in zip(fbetas, n_golds))
            fbeta = safe_div(fbeta_sum, n_gold)
            return pr, re, fbeta

    else:
        raise NotImplementedError()

##TODO: 这里是对单个类别计算指标的核心代码
def pr_re_fbeta(cm, pos_indices, beta=1):  # for example: pos_indices= [2]
    """Uses a confusion matrix to compute precision, recall and fbeta"""
    num_classes = cm.shape[0]
    neg_indices = [i for i in range(num_classes) if i not in pos_indices]
    cm_mask = np.ones([num_classes, num_classes])
    cm_mask[neg_indices, neg_indices] = 0
    diag_sum = tf.reduce_sum(tf.diag_part(cm * cm_mask))

    cm_mask = np.ones([num_classes, num_classes])
    cm_mask[:, neg_indices] = 0
    tot_pred = tf.reduce_sum(cm * cm_mask)

    cm_mask = np.ones([num_classes, num_classes])
    cm_mask[neg_indices, :] = 0
    tot_gold = tf.reduce_sum(cm * cm_mask)

    pr = safe_div(diag_sum, tot_pred)
    re = safe_div(diag_sum, tot_gold)
    fbeta = safe_div((1. + beta ** 2) * pr * re, beta ** 2 * pr + re)

    return pr, re, fbeta

def safe_div(numerator, denominator):
    """Safe division, return 0 if denominator is 0"""
    numerator, denominator = tf.to_float(numerator), tf.to_float(denominator)
    zeros = tf.zeros_like(numerator, dtype=numerator.dtype)
    denominator_is_zero = tf.equal(denominator, zeros)
    return tf.where(denominator_is_zero, zeros, numerator / denominator)

5. 对ROC的理解

  先结合下图二分类的混淆矩阵,阐述一下含义:


混淆矩阵.png

 这里的T表示真实和预测完全匹配了;而F表示真实和预测的不匹配了。而且,第一列用P表示预测为正,第二列用N表示预测为负。
 对于ROC曲线,是通过TPR和FPR这两个指标来衡量综合得到的:
      TPR=TP/(TP+FN):表示预测为正实际为正的占总正样本的比例。
      FPR=FP/(FP+TN):表示预测为正实际为负的占总负样本的比例。
 则在ROC曲线中,横坐标是FPR,纵坐标是TPR


ROC.png

理解以上图,需要结合二分类中的阈值来阐述:当分类阈值变大时候,预测为正类的样本会减少,那么带来TP、FP这两个都是预测为正的指标也变小,所以最后TPR=0,FPR=0;当分类阈值变小时候,预测为正类的样本会增加,那么带来TP、FP这两个都是预测为正的指标也变大,所以最后TPR=1,FPR=1。
 所以最终会有图上两个极端的点(0,0)和(1,1),那么对于(0,1)这个点来说,表示的是TP=1、FP=0的情况,这是分类模型想要达到的最为理想的情况。所以如果ROC曲线上的某一点距离理想点(0,1)最近,那么就是设定分类模型中阈值最合适的点。

  ROC的作用很大,不仅以上说的可以调节出最优的分类阈值,还可以解决类别不平衡现象。一个类别的样本数量增加很多倍时,ROC曲线基本是保持不变的。

5. 对AUC的理解

  AUC (Area Under Curve) 被定义为ROC曲线下的面积,显然这个面积的数值不会大于1。而它的作用是:使用AUC值作为评价标准是因为很多时候ROC曲线并不能清晰的说明哪个分类器的效果更好,而作为一个数值,对应AUC更大的分类器效果更好。

参考文献:
通俗理解BiLSTM-CRF命名实体识别模型中的CRF
机器学习之分类性能度量指标 : ROC曲线、AUC值、正确率、召回率

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容