NLP賽事數(shù)據(jù)分析和提分總結(jié)!
賽題名稱:互聯(lián)網(wǎng)輿情企業(yè)風(fēng)險(xiǎn)事件的識(shí)別和預(yù)警
賽題鏈接:http://ailab.aiwin.org.cn/competitions/48
賽題背景
近些年來(lái),資本市場(chǎng)違約事件頻發(fā),財(cái)務(wù)造假、董事長(zhǎng)被抓、股權(quán)質(zhì)押爆倉(cāng)、城投非標(biāo)違約等負(fù)面事件屢屢出現(xiàn)。而在大數(shù)據(jù)和人工智能技術(shù)加持下,各種新興的金融風(fēng)險(xiǎn)控制手段也正在高速發(fā)展,其中通過(guò)采集互聯(lián)網(wǎng)上的企業(yè)輿情信息來(lái)挖掘潛在風(fēng)險(xiǎn)事件是一種較為有效的方式。但這些風(fēng)險(xiǎn)信息散落在互聯(lián)網(wǎng)上的海量資訊中,若能從中及時(shí)識(shí)別出涉及企業(yè)的風(fēng)險(xiǎn)事件,并挖掘出潛在的風(fēng)險(xiǎn)特征,將使得銀行、證券等金融機(jī)構(gòu)在風(fēng)險(xiǎn)監(jiān)控領(lǐng)域中更及時(shí)、全面和直觀地掌握客戶風(fēng)險(xiǎn)情況,大幅提升識(shí)別和揭示風(fēng)險(xiǎn)的能力。而風(fēng)險(xiǎn)事件以文本的形式存在,需要采用人工智能方法進(jìn)行自然語(yǔ)言理解,實(shí)現(xiàn)風(fēng)險(xiǎn)事件的高精度智能識(shí)別。
賽題任務(wù)
從給定的互聯(lián)網(wǎng)信息中提取、識(shí)別出企業(yè)主體名稱,以及標(biāo)記風(fēng)險(xiǎn)標(biāo)簽。選手預(yù)測(cè)標(biāo)簽對(duì)應(yīng)格式為(新聞ID,主體全稱,對(duì)應(yīng)風(fēng)險(xiǎn)標(biāo)簽)。
注:
1)每篇互聯(lián)網(wǎng)信息可能會(huì)涉及零到多個(gè)主體(公司),每篇互聯(lián)網(wǎng)信息中對(duì)每個(gè)主體只預(yù)測(cè)一個(gè)風(fēng)險(xiǎn)標(biāo)簽;
2)賽事會(huì)提供一份主體(公司)的全稱清單(其范圍大于待預(yù)測(cè)名單),新聞中提及的主體可能為其簡(jiǎn)稱或別名或主體相關(guān)的自然人(如其董事長(zhǎng)、總經(jīng)理等),選手提交答案時(shí)需要統(tǒng)一識(shí)別并將他們映射至主體全稱輸出在最終的結(jié)果文件中。主體全稱的映射關(guān)系需選手自行處理。
3)請(qǐng)注意在訓(xùn)練集中存在一類「無(wú)」標(biāo)簽,其指的是對(duì)應(yīng)的新聞內(nèi)容中不包含需識(shí)別的金融風(fēng)險(xiǎn)事件。對(duì)于測(cè)試集中此類情況,選手模型在輸出時(shí)只需準(zhǔn)確打上「無(wú)」的標(biāo)簽,對(duì)應(yīng)主體標(biāo)記為「/」即可。即輸出的為:"新聞 ID,/ ,無(wú)"。
4)測(cè)試集(需選手利用模型進(jìn)行預(yù)測(cè))的數(shù)據(jù)中會(huì)包含一些噪音數(shù)據(jù),比如在主體(公司)的全稱清單之外的輿情等,選手同樣需要對(duì)其預(yù)測(cè),不計(jì)入自動(dòng)評(píng)分。
評(píng)價(jià)方式
統(tǒng)一評(píng)審階段
將選手預(yù)測(cè)結(jié)果和答案進(jìn)行對(duì)比計(jì)算出F1值,F(xiàn)1越大約好
F1計(jì)算公式為:
P = 預(yù)測(cè)對(duì)的標(biāo)簽總數(shù) / 預(yù)測(cè)出的標(biāo)簽數(shù)
R = 預(yù)測(cè)對(duì)的標(biāo)簽總數(shù) / 需要預(yù)測(cè)的總標(biāo)簽數(shù)
F1 = 2 * P * R /(P+R)
數(shù)據(jù)描述
數(shù)據(jù)集文件如下:
├── data
│ ├── RISKLABEL_Training
│ │ ├── 1_元數(shù)據(jù)格式.docx
│ │ ├── 2_公司實(shí)體匯總_20210414_A1.xlsx
│ │ ├── 3_訓(xùn)練集匯總_20210414_A1.xlsx
│ │ ├── readme.txt
│ │ ├── result.csv
│ │ └── ~$_元數(shù)據(jù)格式.docx
│ └── T1_ID
│ ├── readme.txt
│ └── result.csv
| 列名 | 數(shù)據(jù)類型 | 能否為空 | 備注 |
|---|---|---|---|
| NEWS_BASICINFO_SID | NUMBER(22) | NOT NULL | 新聞ID |
| NEWS_TITLE | VARCHAR2(3000) | 新聞標(biāo)題 | |
| ABSTRACT | VARCHAR2(4000) | 摘要 | |
| CONTENT | CLOB | 正文 | |
| AUTHOR | VARCHAR2(1000) | 作者 | |
| SRC_URL | VARCHAR2(1000) | 下載源地址 | |
| SOURCE_TYPE | VARCHAR2(100) | 文章類型 | 01-新聞;02-論壇;03-博客;04-微博;05-平媒;06-微信;07-視頻;08-長(zhǎng)微博;09-APP;10-評(píng)論;99-其他 |
| PUBLISH_SITE | VARCHAR2(100) | 來(lái)源 | |
| FIRST_WEB | VARCHAR2(100) | 首發(fā)網(wǎng)站名稱 | |
| CHANNEL | VARCHAR2(100) | 網(wǎng)站頻道 | |
| NOTICE_DT | DATE | 發(fā)布時(shí)間 | |
| COMPANY_NM | VARCHAR2(300) | 企業(yè)名稱 | |
| LABEL | VARCHAR2(60) | 業(yè)務(wù)標(biāo)簽 | 主板/創(chuàng)業(yè)板/中小板/債券退市 債務(wù)逾期 實(shí)控人變更 破產(chǎn)重整 股票質(zhì)押率過(guò)高 被政府職能部 處罰 被監(jiān)管機(jī)構(gòu)罰款或查處 被采取監(jiān)管措施 重大訴訟仲裁 信息披露違規(guī)等 |
數(shù)據(jù)統(tǒng)計(jì)分析
首先加載看下數(shù)據(jù)內(nèi)容:

接下來(lái)我們對(duì)數(shù)據(jù)集中出現(xiàn)的實(shí)體與文本進(jìn)行分析,著重思考比賽思路以及賽題提分點(diǎn)。
def statics(data):
stats = []
for col in data.columns:
stats.append((col, data[col].nunique(), data[col].isnull().sum() * 100 / data.shape[0],
data[col].value_counts(normalize=True, dropna=False).values[0] * 100, data[col].dtype))
stats_df = pd.DataFrame(stats, columns=['Feature', 'Unique_values', 'Percentage_of_missing_values',
'Percentage_of_values_in_the_biggest category', 'type'])
stats_df.sort_values('Percentage_of_missing_values', ascending=False, inplace=True)
return stats_df

實(shí)體長(zhǎng)度分布
統(tǒng)計(jì)每個(gè)實(shí)體的長(zhǎng)度
stats = entities_df['entity_len'].value_counts().rename_axis('unique_entity_len').reset_index(name='counts')
fig = px.bar(stats, x='unique_entity_len', y='counts')
fig.show()

可以看出,實(shí)體最小長(zhǎng)度為4,平均長(zhǎng)度為13,最大長(zhǎng)度為35,過(guò)長(zhǎng)實(shí)體是我們需要解決的難點(diǎn)之一,我們可以通過(guò)將過(guò)長(zhǎng)實(shí)體進(jìn)行拆分標(biāo)注,然后預(yù)測(cè)的時(shí)候根據(jù)是否相鄰進(jìn)行組合,也可以通過(guò)指針網(wǎng)絡(luò)解決crf在過(guò)長(zhǎng)實(shí)體識(shí)別時(shí)出現(xiàn)span斷裂的問(wèn)題。
企業(yè)實(shí)體名稱多樣性
大部分企業(yè)實(shí)體都是以“公司”,“有些股份公司”,“集團(tuán)"結(jié)尾的,另外也存在一些含有括號(hào)的實(shí)體:
entities_df[
(entities_df['公司名'].str.contains('('))|
(entities_df['公司名'].str.contains(')'))|
(entities_df['公司名'].str.contains('\('))|
(entities_df['公司名'].str.contains('\)'))
]
# 英文括號(hào)為0
例如:

除此之外還有一些其他名稱比較靈活組合的實(shí)體

文本長(zhǎng)度分析
新聞標(biāo)題的長(zhǎng)度分布

新聞標(biāo)題最小長(zhǎng)度為6,最大長(zhǎng)度為120,平均長(zhǎng)度為28。
新聞內(nèi)容的長(zhǎng)度分布
train_df['content_len']=train_df['CONTENT'].apply(lambda x:len(x))
train_df['content_len'].describe()
可以看到的是新聞內(nèi)容存在過(guò)長(zhǎng)文本,并且嚴(yán)重超過(guò)了現(xiàn)有模型的輸入長(zhǎng)度
count 11685.000000
mean 3324.683098
std 6741.110801
min 4.000000
25% 31.000000
50% 979.000000
75% 2807.000000
max 32767.000000
Name: content_len, dtype: float64

通過(guò)查看文本,我們可以看到,新聞內(nèi)容中存在大量html代碼標(biāo)簽,我們可以通過(guò)正則表達(dá)式re和BeautifulSoup進(jìn)行去除無(wú)關(guān)標(biāo)簽
# 方式1
import re
pattern = re.compile(r'<[^>]+>',re.S)
result = pattern.sub('', train_df['CONTENT'][11683])
print("".join(result.split()))
# 方式2
from bs4 import BeautifulSoup
cleantext = BeautifulSoup(train_df['CONTENT'][11683], "lxml").text
cleantext
處理前后的文本對(duì)比

清洗文本之后,文本長(zhǎng)度縮減一半:
train_df['content_len'].describe()
count 11685.000000
mean 3324.683098
std 6741.110801
min 4.000000
25% 31.000000
50% 979.000000
75% 2807.000000
max 32767.000000
Name: content_len, dtype: float64
train_df['new_content_len'].describe()
count 11685.000000
mean 890.949679
std 1328.754384
min 0.000000
25% 31.000000
50% 424.000000
75% 1298.000000
max 31840.000000
Name: new_content_len, dtype: float64

業(yè)務(wù)標(biāo)簽數(shù)量分布
train_df['LABEL'].value_counts()
無(wú) 3042
實(shí)控人變更 811
信息披露違規(guī) 800
重大訴訟仲裁 800
股票質(zhì)押率過(guò)高 799
主板/創(chuàng)業(yè)板/中小板/債券退市 799
被政府職能部門處罰 799
債務(wù)逾期 798
被監(jiān)管機(jī)構(gòu)罰款或查處 796
被采取監(jiān)管措施 796
破產(chǎn)重整 796
安全事故 326
環(huán)境污染 323
Name: LABEL, dtype: int64
從上面可以看出,不存在金融事件樣本“無(wú)”所占比列最多,有3042個(gè)樣本;其次是“信息披露違規(guī) ”和“重大訴訟仲裁”,都是800個(gè)樣本,出現(xiàn)次數(shù)最少的兩個(gè)類別是“安全事故”和“環(huán)境污染 ”。

另外我們從業(yè)務(wù)標(biāo)簽字面我們可以看到的是大部分業(yè)務(wù)標(biāo)簽界限還是比較清晰的,但是“被監(jiān)管機(jī)構(gòu)罰款或查處 ”和“被采取監(jiān)管措施”這兩個(gè)類別的界限還是比較模糊的,這個(gè)也是我們提分的一個(gè)地方:

基于預(yù)訓(xùn)練模型的多任務(wù)學(xué)習(xí)
基于bert_multitask_learning進(jìn)行標(biāo)簽分類和實(shí)體識(shí)別的聯(lián)合任務(wù)訓(xùn)練,首先構(gòu)建輸入,
import bert_multitask_learning
from bert_multitask_learning.preproc_decorator import preprocessing_fn
from bert_multitask_learning.params import BaseParams
@preprocessing_fn
def toy_cls(params: BaseParams, mode: str):
"Simple example to demonstrate singe modal tuple of list return"
if mode == bert_multitask_learning.TRAIN:
toy_input = ['this is a test' for _ in range(10)]
toy_target = ['a' if i <=5 else 'b' for i in range(10)]
else:
toy_input = ['this is a test' for _ in range(10)]
toy_target = ['a' if i <=5 else 'b' for i in range(10)]
return toy_input, toy_target
@preprocessing_fn
def toy_seq_tag(params: BaseParams, mode: str):
"Simple example to demonstrate singe modal tuple of list return"
if mode == bert_multitask_learning.TRAIN:
toy_input = ['this is a test'.split(' ') for _ in range(10)]
toy_target = [['a', 'b', 'c', 'd'] for _ in range(10)]
else:
toy_input = ['this is a test'.split(' ') for _ in range(10)]
toy_target = [['a', 'b', 'c', 'd'] for _ in range(10)]
return toy_input, toy_target
processing_fn_dict = {'toy_cls': toy_cls, 'toy_seq_tag': toy_seq_tag}
創(chuàng)建多任務(wù)實(shí)例并進(jìn)行實(shí)例
from bert_multitask_learning import train_bert_multitask, eval_bert_multitask, predict_bert_multitask
problem_type_dict = {'toy_cls': 'cls', 'toy_seq_tag': 'seq_tag'}
problem = 'toy_cls&toy_seq_tag'
# train
model = train_bert_multitask(
problem=problem,
num_epochs=1,
problem_type_dict=problem_type_dict,
processing_fn_dict=processing_fn_dict,
continue_training=True
)
模型驗(yàn)證與預(yù)測(cè)
eval_dict = eval_bert_multitask(problem=problem,
problem_type_dict=problem_type_dict, processing_fn_dict=processing_fn_dict,
model_dir=model.params.ckpt_dir)
print(eval_dict)
# predict
fake_inputs = ['this is a test'.split(' ') for _ in range(10)]
pred, model = predict_bert_multitask(
problem=problem,
inputs=fake_inputs, model_dir=model.params.ckpt_dir,
problem_type_dict=problem_type_dict,
processing_fn_dict=processing_fn_dict, return_model=True)
for problem_name, prob_array in pred.items():
print(f'{problem_name} - {prob_array.shape}')
完整教程可以查看官網(wǎng):https://jayyip.github.io/bert-multitask-learning/tutorial.html
提分點(diǎn)
企業(yè)實(shí)體提?。?span style="display: none;">
實(shí)體出現(xiàn)位置 實(shí)體存在不是公司 集團(tuán)結(jié)尾 實(shí)體中存在括號(hào) 實(shí)體可能為空 與 業(yè)務(wù)標(biāo)簽有關(guān)系 LABEL 過(guò)長(zhǎng)實(shí)體 嵌套連續(xù)實(shí)體解決
比賽中可能用到的NER Trick
Q1、如何快速有效地提升NER性能?
如果1層lstm+crf,這么直接的打開方式導(dǎo)致NER性能達(dá)不到業(yè)務(wù)目標(biāo),這一點(diǎn)也不意外(這是萬(wàn)里長(zhǎng)征的第一步~)。這時(shí)候除了badcase分析,不要忘記一個(gè)快速提升的重要手段:規(guī)則+領(lǐng)域詞典。
在垂直領(lǐng)域,一個(gè)不斷積累、不斷完善的實(shí)體詞典對(duì)NER性能的提升是穩(wěn)健的,基于規(guī)則+詞典也可以快速應(yīng)急處理一些badcase;對(duì)于通?領(lǐng)域,可以多種分詞工具和多種句法短語(yǔ)?具進(jìn)行融合來(lái)提取候選實(shí)體,并結(jié)合詞典進(jìn)行NER。
Q2、如何構(gòu)建引入詞匯信息(詞向量)的NER?
將詞向量引入到模型中,一種簡(jiǎn)單粗暴的做法就是將詞向量對(duì)齊到相應(yīng)的字符,然后將字詞向量進(jìn)行混合,但這需要對(duì)原始文本進(jìn)行分詞(存在誤差),性能提升通常是有限的。我們知道中文NER通常是基于字符進(jìn)行標(biāo)注的,這是由于基于詞匯標(biāo)注存在分詞誤差問(wèn)題。但詞匯邊界對(duì)于實(shí)體邊界是很有用的,我們?cè)撛趺窗烟N(yùn)藏詞匯信息的詞向量“恰當(dāng)”地引入到模型中呢?
Q3、如何解決NER實(shí)體span過(guò)長(zhǎng)的問(wèn)題?
如果NER任務(wù)中某一類實(shí)體span比較長(zhǎng)(?如醫(yī)療NER中的?術(shù)名稱是很長(zhǎng)的),直接采取CRF解碼可能會(huì)導(dǎo)致很多連續(xù)的實(shí)體span斷裂。除了加入規(guī)則進(jìn)行修正外,這時(shí)候也可嘗試引入指針網(wǎng)絡(luò)+CRF構(gòu)建多任務(wù)學(xué)習(xí)解決。
指針網(wǎng)絡(luò)會(huì)更容易捕捉較長(zhǎng)的span,不過(guò)指針網(wǎng)絡(luò)的收斂是較慢的,可以對(duì)CRF和指針網(wǎng)絡(luò)設(shè)置不同學(xué)習(xí)率,或者設(shè)置不同的loss權(quán)重。
Q4、如何客觀看待BERT在NER中的作用?
在競(jìng)賽任務(wù)中,BERT很有用!我們可以選取不同的預(yù)訓(xùn)練語(yǔ)?模型在底層進(jìn)行特征拼接。具體地,可以將char、bigram和BERT、XLNet等一起拼接喂入1層lstm+crf中。語(yǔ)?模型的差異越?,效果越好。如果需要對(duì)語(yǔ)言模型finetune,需要設(shè)置不同的學(xué)習(xí)率。
業(yè)務(wù)標(biāo)簽識(shí)別:
被采取監(jiān)管措施 vs 被監(jiān)管機(jī)構(gòu)罰款或查處 統(tǒng)計(jì)特征:其他新聞字段統(tǒng)計(jì),html標(biāo)簽分析
資料推薦
天池中藥說(shuō)明書實(shí)體識(shí)別挑戰(zhàn)冠軍方案開源 https://github.com/z814081807/DeepNER 2020阿里云tianchi零基礎(chǔ)入門NLP比賽: rank4選手總結(jié) https://github.com/MM-IR/rank4_NLP_textclassification 刷爆3路榜單,信息抽取冠軍方案分享:嵌套NER+關(guān)系抽取+實(shí)體標(biāo)準(zhǔn)化 https://zhuanlan.zhihu.com/p/326302618 流水的NLP鐵打的NER:命名實(shí)體識(shí)別實(shí)踐與探索 https://zhuanlan.zhihu.com/p/166496466 工業(yè)界如何解決NER問(wèn)題?12個(gè)trick,與你分享~ https://zhuanlan.zhihu.com/p/152463745 中文NER的正確打開方式: 詞匯增強(qiáng)方法總結(jié) (從Lattice LSTM到FLAT) https://zhuanlan.zhihu.com/p/142615620

