命名实体识别——日期识别
一、命名實(shí)體識(shí)別簡介
其目的是識(shí)別語料中的人名、地名、組織結(jié)構(gòu)名等命名實(shí)體,由于這些命名實(shí)體在不斷地更新,很難在詞典中全部列出,所以就對(duì)這些詞的識(shí)別在詞匯形態(tài)處理任務(wù)中單獨(dú)處理,也就是NER技術(shù)。
而命名實(shí)體識(shí)別效果的評(píng)判標(biāo)準(zhǔn)主要是看實(shí)體的邊界是否劃分正確,以及實(shí)體的類型是否標(biāo)注正確,對(duì)于英文來說命名實(shí)體的邊界識(shí)別相對(duì)簡單,因?yàn)橐话愣加忻黠@的形式標(biāo)志,而對(duì)于實(shí)體類型的確定相對(duì)較難。在中文中相較于實(shí)體類別標(biāo)注,實(shí)體邊界的識(shí)別更加困難。
中文命名實(shí)體識(shí)別難點(diǎn)主要有以下幾點(diǎn):
命名實(shí)體的數(shù)量眾多、命名實(shí)體構(gòu)成規(guī)律復(fù)雜、嵌套情況復(fù)雜、長度不確定、等
命名實(shí)體的識(shí)別目前主要采用的是基于規(guī)則和統(tǒng)計(jì)的混合方法。因?yàn)閱渭兊幕谝?guī)則的話需要手工修改規(guī)則,難以覆蓋所有的語言現(xiàn)象,也就存在可移植性差,維護(hù)困難。而基于統(tǒng)計(jì)的命名實(shí)體識(shí)別,其對(duì)語料庫的依賴比較大,而用來建設(shè)和評(píng)估命名實(shí)體識(shí)別系統(tǒng)的大規(guī)模通用語料庫又比較少。因此目前多采用混合的方法來做。
這里舉一個(gè)簡單的日期識(shí)別的實(shí)例:
例如現(xiàn)有一個(gè)基于語音問答系統(tǒng)的酒店預(yù)訂系統(tǒng)根據(jù)用戶輸入的每句語音進(jìn)行分析,識(shí)別出用戶的酒店預(yù)訂需求,然而由于語音轉(zhuǎn)換的文字大都不是嚴(yán)格的數(shù)字形式,這時(shí)就需要通過一定的規(guī)則來進(jìn)行處理。
二、日期識(shí)別:
主要思想是:這里主要通過正則表達(dá)式和jieba分詞來完成任務(wù)。
首先將輸入的要識(shí)別的句子進(jìn)行jieba分詞,提取出其帶有時(shí)間詞性的詞,比如詞性是“m”(數(shù)字),“t”(時(shí)間)的詞,然后再通過正則化處理,得到相應(yīng)的時(shí)間實(shí)體。注意這里是沒有訓(xùn)練語料,直接用的是jieba的分詞和詞性標(biāo)注功能。
示例代碼:
# -*- coding: utf-8 -*-#日期識(shí)別 import re from datetime import datetime,timedelta from dateutil.parser import parse import jieba.posseg as psgUTIL_CN_NUM = {'零': 0, '一': 1, '二': 2, '兩': 2, '三': 3, '四': 4,'五': 5, '六': 6, '七': 7, '八': 8, '九': 9,'0': 0, '1': 1, '2': 2, '3': 3, '4': 4,'5': 5, '6': 6, '7': 7, '8': 8, '9': 9 }UTIL_CN_UNIT = {'十': 10, '百': 100, '千': 1000, '萬': 10000}def cn2dig(src):if src == "":return Nonem = re.match("\d+", src)if m:return int(m.group(0))rsl = 0unit = 1for item in src[::-1]:if item in UTIL_CN_UNIT.keys():unit = UTIL_CN_UNIT[item]elif item in UTIL_CN_NUM.keys():num = UTIL_CN_NUM[item]rsl += num * unitelse:return Noneif rsl < unit:rsl += unitreturn rsldef year2dig(year):res = ''for item in year:if item in UTIL_CN_NUM.keys():res = res + str(UTIL_CN_NUM[item])else:res = res + itemm = re.match("\d+", res)if m:if len(m.group(0)) == 2:return int(datetime.datetime.today().year/100)*100 + int(m.group(0))else:return int(m.group(0))else:return Nonedef parse_datetime(msg):#print('msg:',msg)if msg is None or len(msg) == 0:return Nonem = re.match(r"([0-9零一二兩三四五六七八九十]+年)?([0-9一二兩三四五六七八九十]+月)?([0-9一二兩三四五六七八九十]+[號(hào)日])?([上中下午晚早]+)?([0-9零一二兩三四五六七八九十百]+[點(diǎn):\.時(shí)])?([0-9零一二三四五六七八九十百]+分?)?([0-9零一二三四五六七八九十百]+秒)?",msg) #print('m.group:',m.group(0),m.group(1),m.group(2),m.group(3),m.group(4),m.group(5))if m.group(0) is not None:res = {"year": m.group(1),"month": m.group(2),"day": m.group(3),"noon":m.group(4), # 上中下午晚早"hour": m.group(5) if m.group(5) is not None else '00',"minute": m.group(6) if m.group(6) is not None else '00',"second": m.group(7) if m.group(7) is not None else '00',}params = {}for name in res:if res[name] is not None and len(res[name]) != 0:tmp = Noneif name == 'year':tmp = year2dig(res[name][:-1])else:tmp = cn2dig(res[name][:-1])if tmp is not None:params[name] = int(tmp)target_date = datetime.today().replace(**params)#print('target_date:',target_date)is_pm = m.group(4)if is_pm is not None:if is_pm == u'下午' or is_pm == u'晚上' or is_pm =='中午':hour = target_date.time().hourif hour < 12:target_date = target_date.replace(hour=hour + 12)return target_date.strftime('%Y-%m-%d %H:%M:%S')else:return None# 對(duì)提取出的拼接日期串進(jìn)行進(jìn)一步的處理,進(jìn)行有效性判斷 def check_time_valid(word):#print('check:',word)m = re.match("\d+$", word)if m:if len(word) <= 6:return Noneword1 = re.sub('[號(hào)|日]\d+$', '日', word)#print('word1:',word1)if word1 != word:return check_time_valid(word1)else:return word1#時(shí)間提取 def time_extract(text):time_res = []word = ''keyDate = {'今天': 0, '明天':1, '后天': 2}for k, v in psg.cut(text):#print(k,v)if k in keyDate:if word != '':time_res.append(word) # 日期的轉(zhuǎn)換,timedelta提取任意延遲天數(shù)的信息word = (datetime.today() +timedelta(days=keyDate.get(k, 0))).\strftime('%Y{y}%m{m}%dozvdkddzhkzd').format(y='年',m='月',d='日') elif word != '':if v in ['m', 't']:word = word + kelse:time_res.append(word)word = ''elif v in ['m', 't']: # m:數(shù)字 t:時(shí)間word = k #print('word:',word)if word != '':time_res.append(word)#print('time_res:',time_res)# filter() 函數(shù)用于過濾序列,過濾掉不符合條件的元素,返回由符合條件元素組成的新列表result = list(filter(lambda x: x is not None, [check_time_valid(w) for w in time_res]))#print('result:',result)final_res = [parse_datetime(w) for w in result]#print('final_res:',final_res)return [x for x in final_res if x is not None]text1 = '我要住到明天下午三點(diǎn)' print(text1, time_extract(text1), sep=':')text2 = '預(yù)定28號(hào)的房間' print(text2, time_extract(text2), sep=':')text3 = '我要從26號(hào)下午4點(diǎn)住到11月2號(hào)' print(text3, time_extract(text3), sep=':')text5 = '今天30號(hào)呵呵' print(text5, time_extract(text5), sep=':')text4 = '我要預(yù)訂今天到30的房間' print(text4, time_extract(text4), sep=':')運(yùn)行結(jié)果:
我要住到明天下午三點(diǎn):['2018-07-27 15:00:00'] 預(yù)定28號(hào)的房間:['2018-07-28 00:00:00'] 我要從26號(hào)下午4點(diǎn)住到11月2號(hào):['2018-07-26 16:00:00', '2018-11-02 00:00:00'] 今天30號(hào)呵呵:['2018-07-26 00:03:00'] 我要預(yù)訂今天到30的房間:['2018-07-26 00:00:00']從運(yùn)行結(jié)果來看,前三句話都很多好的識(shí)別出日期了,而后面兩句則識(shí)別不出來,這也正是基于規(guī)則識(shí)別的限制所在,因?yàn)椴豢赡芨采w所有的規(guī)則場(chǎng)景,但好處就是不需要在系統(tǒng)建設(shè)初期為搜集數(shù)據(jù)標(biāo)注訓(xùn)練而煩惱。
三、筆記:
格式轉(zhuǎn)換成帶有漢字的形式可以通過如下方式:
timedelta(days=keyDate.get(k, 0))).strftime('%Y年%m月%d日')UnicodeEncodeError: 'locale' codec can't encode character '\u5e74' in position 2: Illegal byte sequence解決辦法:
time.strftime('%Y{y}%m{m}%dozvdkddzhkzd %H{h}%M{f}%S{s}').format(y='年',m='月',d='日',h='時(shí)',f='分',s='秒')參考:《pytho自然語言處理實(shí)戰(zhàn) 核心技術(shù)與算法》
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的命名实体识别——日期识别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jieba词性标注
- 下一篇: mac下查看tensorboard中的g