在平時的NLP任務中,咱們常常用到命名實體識別(NER),經常使用的識別實體類型爲人名、地名、組織機構名,可是咱們每每也會有識別其它實體的需求,好比時間、品牌名等。在利用算法作實體識別的時候,咱們通常採用序列標註算法,這就對標註的文本格式有必定的要求,所以,一個好的序列標註的平臺必不可少,將會大大減小咱們標註的工做量,有效提高算法的更新迭代速度。
本文將介紹筆者的一個工做:自制的序列標註平臺。咱們以時間識別爲例。好比,在下面的文章中:css
按計劃,2019年8月10日,榮耀智慧屏將在華爲開發者大會上正式亮相,在8月6日,榮耀官微表示該產品的預定量已破十萬臺,8月7日下午,榮耀總裁趙明又在微博上造勢率先打出差別化牌,智慧屏沒有開關機廣告,並表態之後也不會有,消費者體驗至上,營銷一波接一波,可謂來勢洶洶。html
咱們須要從該文章中標註出三個時間:2019年8月10日
,8月6日
,8月7日下午
,並造成標註序列。
下面將詳細介紹筆者的工做。前端
因爲開發時間倉促以及筆者能力有限,所以,序列標註平臺的功能尚未很完善,但願筆者的工做能拋磚引玉。
項目的結構圖以下:python
templates中存放靜態資源,time_index.html爲平臺的操做界面,time_output爲平臺標註完實體後的文件保存路徑,time_server.py是用tornado寫的服務端路徑控制代碼,utils.py中是獲取某個路徑下的txt文件的最大數值的函數。jquery
其中,utils.py的完整代碼以下:git
# -*- coding: utf-8 -*- # time: 2019-03-14 # place: Xinbeiqiao, Beijing import os # 獲取當前所在目錄的txt文本的最大數值 def get_max_num(path): files = os.listdir(path) if files: numbers = list(map(lambda x: int(x.replace('.txt', '')), files)) return max(numbers) else: return 0
time_server.py的完整代碼以下:github
# -*- coding: utf-8 -*- # time: 2019-08-08 # place: Xinbeiqiao, Beijing import os.path import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web from tornado.options import define, options from utils import get_max_num #定義端口爲9005 define("port", default=9005, help="run on the given port", type=int) # GET請求 class QueryHandler(tornado.web.RequestHandler): # get函數 def get(self): self.render('time_index.html', data = ['', []]) # POST請求 class PostHandler(tornado.web.RequestHandler): # post函數 def post(self): # 獲取前端參數, event, time, index event = self.get_argument('event') times = self.get_arguments('time') indices = self.get_arguments('index') print(event) print(times) print(indices) # 前端顯示序列標註信息 tags = ['O'] * len(event) for time, index in zip(times, indices): index = int(index) tags[index] = 'B-TIME' for i in range(1, len(time)): tags[index+i] = 'I-TIME' data = [event, tags] self.render('time_index.html', data=data) # 保存爲txt文件 dir_path = './time_output' with open('./%s/%s.txt' % (dir_path, get_max_num(dir_path)+1), 'w', encoding='utf-8') as f: for char, tag in zip(event, tags): f.write(char+'\t'+tag+'\n') # 主函數 def main(): # 開啓tornado服務 tornado.options.parse_command_line() # 定義app app = tornado.web.Application( handlers=[(r'/query', QueryHandler), (r'/result', PostHandler) ], #網頁路徑控制 template_path=os.path.join(os.path.dirname(__file__), "templates") # 模板路徑 ) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start() main()
time_index.html文件以下:web
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>時間抽取標註平臺</title> <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> <style> mark { background-color:#00ff90; font-weight:bold; } p{text-indent:2em;} </style> <script> var click_cnt = 0; // 雙擊第i個select, 添加文字的index function select_click(i){ var content = document.getElementById('event').value; var time = document.getElementById('time_'+i.toString()).value; for(var j=0; j<=content.length-time.length; j++){ if(content.substr(j, time.length) == time){ var select = document.getElementById('index_'+i.toString()); var option = document.createElement("option"); option.value = j; option.innerHTML = j; select.appendChild(option); } } } // 添加輸入框和select框 $(document).ready(function(){ $("#add_time").click(function(){ click_cnt = click_cnt + 1; var input_id = new String('time_'+click_cnt.toString()); var index_id = new String('index_'+click_cnt.toString()); var content = "<input type='text' id=" + input_id + " class='form-control' style='width:306px;' name='time' /> \     <select class='form-control' name='index' id="+ index_id + " style='width:120px;' \ ondblclick='select_click("+click_cnt.toString()+")'></select>"; $(content).appendTo($("#time_column")); }); }); </script> </head> <body> <center> <br><br><br> <form class="form-horizontal" role="form" method="post" action="/result" style="width:600px"> <div class="form-group"> <label for="event" class="col-sm-2 control-label">輸入語料</label> <div class="col-sm-10"> <textarea type="text" class="form-control" id="event" style="width:490px; height:200px" name="event"></textarea> </div> </div> <div class="form-inline" style="text-align:left;"> <label for="time_0" class="col-sm-2 control-label">時間</label> <div class="col-sm-10" id="time_column"> <input type="text" class="form-control" id="time_0" style="width:306px;" name="time" />     <select class="form-control" id="index_0" name="index" style="width:120px;" ondblclick="select_click(0)"></select> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <br> <button type="button" class="btn btn-default" id="add_time">添加時間</button> <button type="submit" class="btn btn-success">顯示標籤</button> <a href="/query"><button type="button" class="btn btn-danger">返回</button></a> <button type="reset" class="btn btn-warning">重置</button> </div> </div> </form> <br> <div style="width:600px"> <p> 原文:{{data[0]}} </p> <table class="table table-striped"> {% for char, tag in zip(data[0], data[1]) %} <tr> <td>{{char}} </td> <td>{{tag}} </td> </tr> {%end%} </table> </div> </center> </body> </html>
運行上述time_server.py後,在瀏覽器端輸入網址: http://localhost:9005/query , 則會顯示以下界面:算法
在輸入語料框
中,咱們輸入語料:bootstrap
8月8日是「全民健身日」,推出重磅微視頻《咱們要贏的,是本身》。
在時間這個輸入框中,能夠標註語料中的時間,同時雙擊同一行中的下拉列表,就能顯示該標註時間在語料中的起始位置,有時候一樣的標註時間會在語料中出現屢次,那麼咱們在下拉列表中選擇咱們須要的標註的起始位置便可。
點擊添加時間
按鈕,它會增長一行標註,容許咱們在同一份預料中標註多個時間。咱們的一個簡單的標註例子以下:
點擊顯示標註
,則會顯示咱們標註完後造成的序列標註信息,同時將該序列信息保存爲txt文件,該txt文件位於time_output目錄下。在網頁上的序列標註信息以下:
同時,咱們也能夠查看保存的txt文檔信息,以下:
點擊返回
按鈕,它會容許咱們進行下一次的標註。剛纔展現的只是一個簡單例子,稍微複雜的標註以下圖:
它造成的標註序列(部分)以下:
按 O 計 O 劃 O , O 2 B-TIME 0 I-TIME 1 I-TIME 9 I-TIME 年 I-TIME 8 I-TIME 月 I-TIME 1 I-TIME 0 I-TIME 日 I-TIME , O 榮 O 耀 O 智 O 慧 O 屏 O 將 O 在 O 華 O 爲 O 開 O 發 O 者 O 大 O 會 O 上 O 正 O 式 O 亮 O 相 O , O 在 O 8 B-TIME 月 I-TIME 6 I-TIME 日 I-TIME , O 榮 O 耀 O 官 O 微 O 表 O 示 O 該 O 產 O 品 O ......
本平臺僅做爲序列標註算法的前期標註工具使用,並不涉及具體的算法。另外,後續該平臺也會陸續開放出來,若是你們有好的建議,也能夠留言~
本項目已上傳只Github, 網址爲: https://github.com/percent4/entity_tagging_platform
注意:不妨瞭解下筆者的微信公衆號: Python爬蟲與算法(微信號爲:easy_web_scrape), 歡迎你們關注~