1. 程式人生 > >中文電子病例命名實體識別專案

中文電子病例命名實體識別專案

MedicalNamedEntityRecognition

Medical Named Entity Recognition implement using bi-directional lstm and crf model with char embedding.CCKS2018中文電子病例命名實體識別專案,主要實現使用了基於字向量的四層雙向LSTM與CRF模型的網路.該專案提供了原始訓練資料樣本(一般專案,出院情況,病史情況,病史特點,診療經過)與轉換版本,訓練指令碼,預訓練模型,可用於序列標註研究.把玩和PK使用.
專案地址:https://github.com/liuhuanyong/MedicalNamedEntityRecognition

專案介紹

電子病歷結構化是讓計算機理解病歷、應用病歷的基礎。基於對病歷的結構化,可以計算出症狀、疾病、藥品、檢查檢驗等多個知識點之間的關係及其概率,構建醫療領域的知識圖譜,進一步優化醫生的工作.
CCKS2018的電子病歷命名實體識別的評測任務,是對於給定的一組電子病歷純文字文件,識別並抽取出其中與醫學臨床相關的實體,並將它們歸類到預先定義好的類別中。組委會針對這個評測任務,提供了600份標註好的電子病歷文字,共需識別含解剖部位、獨立症狀、症狀描述、手術和藥物五類實體。
領域命名實體識別問題自然語言處理中經典的序列標註問題, 本專案是運用深度學習方法進行命名實體識別的一個嘗試.

實驗資料

一, 目標序列標記集合
O非實體部分,TREATMENT治療方式, BODY身體部位, SIGN疾病症狀, CHECK醫學檢查, DISEASE疾病實體,
二, 序列標記方法
採用BIO三元標記

self.class_dict ={
                 'O':0,
                 'TREATMENT-I': 1,
                 'TREATMENT-B': 2,
                 'BODY-B': 3,
                 'BODY-I': 4,
                 'SIGNS-I': 5,
                 'SIGNS-B': 6,
                 'CHECK-B': 7,
                 'CHECK-I': 8,
                 'DISEASE-I': 9,
                 'DISEASE-B': 10
                }

三, 資料轉換
評測方提供了四個目錄(一般專案, 出院專案, 病史特點, 診療經過),四個目錄下有txtoriginal檔案和txt標註檔案,內容樣式如下:

一般專案-1.txtoriginal.txt

女性,88歲,農民,雙灤區應營子村人,主因右髖部摔傷後疼痛腫脹,活動受限5小時於2016-10-29;11:12入院。

一般專案-1.txt:

右髖部	21	23	身體部位
疼痛	27	28	症狀和體徵
腫脹	29	30	症狀和體徵

轉換指令碼函式:

  def transfer(self):
    f = open(self.train_filepath, 'w+')
    count = 0
    for root,dirs,files in os.walk(self.origin_path):
        for file in files:
            filepath = os.path.join(root, file)
            if 'original' not in filepath:
                continue
            label_filepath = filepath.replace('.txtoriginal','')
            print(filepath, '\t\t', label_filepath)
            content = open(filepath).read().strip()
            res_dict = {}
            for line in open(label_filepath):
                res = line.strip().split('	')
                start = int(res[1])
                end = int(res[2])
                label = res[3]
                label_id = self.label_dict.get(label)
                for i in range(start, end+1):
                    if i == start:
                        label_cate = label_id + '-B'
                    else:
                        label_cate = label_id + '-I'
                    res_dict[i] = label_cate

            for indx, char in enumerate(content):
                char_label = res_dict.get(indx, 'O')
                print(char, char_label)
                f.write(char + '\t' + char_label + '\n')
    f.close()
    return

模型輸出樣式:

,	O
男	O
,	O
雙	O
塔	O
山	O
人	O
,	O
主	O
因	O
咳	SIGNS-B
嗽	SIGNS-I
、	O
少	SIGNS-B
痰	SIGNS-I
1	O
個	O
月	O
,	O
加	O
重	O
3	O
天	O
,	O
抽	SIGNS-B
搐	SIGNS-I

模型搭建

本模型使用預訓練字向量,作為embedding層輸入,然後經過兩個雙向LSTM層進行編碼,編碼後加入dense層,最後送入CRF層進行序列標註.

   '''使用預訓練向量進行模型訓練'''
def tokenvec_bilstm2_crf_model(self):
    model = Sequential()
    embedding_layer = Embedding(self.VOCAB_SIZE + 1,
                                self.EMBEDDING_DIM,
                                weights=[self.embedding_matrix],
                                input_length=self.TIME_STAMPS,
                                trainable=False,
                                mask_zero=True)
    model.add(embedding_layer)
    model.add(Bidirectional(LSTM(128, return_sequences=True)))
    model.add(Dropout(0.5))
    model.add(Bidirectional(LSTM(64, return_sequences=True)))
    model.add(Dropout(0.5))
    model.add(TimeDistributed(Dense(self.NUM_CLASSES)))
    crf_layer = CRF(self.NUM_CLASSES, sparse_target=True)
    model.add(crf_layer)
    model.compile('adam', loss=crf_layer.loss_function, metrics=[crf_layer.accuracy])
    model.summary()
    return model

模型效果

1, 模型的訓練:

模型 訓練集 測試集 訓練集準確率 測試集準確率 備註
醫療實體識別 6268 1571 0.9649 0.8451 5個epcho

2, 模型的測試:
python lstm_predict.py, 對訓練好的實體識別模型進行測試,測試效果如下:

    enter an sent:他最近頭痛,流鼻涕,估計是發燒了
    [('他', 'O'), ('最', 'O'), ('近', 'O'), ('頭', 'SIGNS-B'), ('痛', 'SIGNS-I'), (',', 'O'), ('流', 'O'), ('鼻', 'O'), ('涕', 'O'), (',', 'O'), ('估', 'O'), ('計', 'O'), ('是', 'O'), ('發', 'SIGNS-B'), ('燒', 'SIGNS-I'), ('了', 'SIGNS-I')]
    enter an sent:口腔潰瘍可能需要多吃維生素
    [('口', 'BODY-B'), ('腔', 'BODY-I'), ('潰', 'O'), ('瘍', 'O'), ('可', 'O'), ('能', 'O'), ('需', 'O'), ('要', 'O'), ('多', 'O'), ('吃', 'O'), ('維', 'CHECK-B'), ('生', 'CHECK-B'), ('素', 'TREATMENT-I')]
    enter an sent:他骨折了,可能需要拍片
    [('他', 'O'), ('骨', 'SIGNS-B'), ('折', 'SIGNS-I'), ('了', 'O'), (',', 'O'), ('可', 'O'), ('能', 'O'), ('需', 'O'), ('要', 'O'), ('拍', 'O'), ('片', 'CHECK-I')]

總結

1,本專案針對中文電子病例命名實體任務,實現了一個基於Bilstm+CRF的命名實體識別模型
2,本專案使用charembedding作為原始特徵,訓練集準確率為0.9649,測試集準確達到0.8451
3,命名實體識別可以加入更多的特徵進行訓練,後期將逐步實驗其他方式.

any question? 請聯絡我:
郵箱:[email protected]
csdn:https://blog.csdn.net/lhy2014
我的自然語言處理專案: https://liuhuanyong.github.io/