微博立場檢測 60分Baseline
- 2020 年 3 月 17 日
- 筆記
AI研習社最近舉辦了一個比賽——微博立場檢測,實際上就是一個NLP文本分類的比賽

Baseline—FastText
我的Baseline方法用的是pkuseg分詞+FastText,最好成績是60,下面是我幾次提交的得分截圖

Load Data & Preprocess
先import之後要用到的庫
import pkuseg import random import pandas as pd import fasttext
df = pd.read_csv('train.csv', delimiter='t')
官方給的數據,雖然是csv文件,但是欄位之間用的是t
隔開的,所以讀取的時候注意一下就行了。數據樣式如下

stance
欄位有三類,分別是FAVOR
、AGAINST
、NONE
,這也是你需要最終預測的值。但是通過仔細分析數據可以發現,stance
欄位除了上面三個值以外還有別的值,所以要先把其它的數據剔除掉
drop_list = [] for i in range(len(df)): if df.stance[i] != 'FAVOR' and df.stance[i] != 'AGAINST' and df.stance[i] != 'NONE': drop_list.append(i) df.drop(drop_list, inplace=True)
FastText讀取的數據應該滿足__lable__xx text
,例如
__label__A 我 喜歡 打 籃球 __label__B 我 喜歡 鯤鯤 __label__A 我 喜歡 踢 足球
也就是說,每一行表示一個樣本,並且標籤在前,文本在後,兩者之間用空格隔開。標籤必須以__label__
開頭。所以我們要先把原始數據的標籤進行一個轉換,即FAVOR
變成__label__A
,AGAINST
變成__label__B
,NONE
變成__label__C
mapping = {'FAVOR':'__label__A', 'AGAINST':'__label__B', 'NONE':'__label__C'} df['stance'] = df['stance'].map(mapping)
這些都做完以後最好shuffle一下數據
df = df.sample(frac=1)
sample(frac=p)
其中$pin[0,1]$,意思是隨機sample出原始數據的百分之多少,如果$p=1$,則表示隨機sample出原始數據的全部,並且由於是隨機sample的,所以原始數據的順序就被打亂了
Split Train & Validation Data
這裡我以7:3的比例將數據集拆分成Train Data和Valid Data
train_len = int(len(df) * 0.7) df_train = df.loc[:train_len] df_val = df.loc[train_len:]
Word Segmentation
從FastText讀取數據的樣式可以看出,我們需要對一句話進行分詞。這裡我用的是pkuseg,因為我看它官方API介紹的時候,裡面提到它有一個web語料庫
在分詞前,我先從網上找了一些常見的中英文停用詞
stopwords = [] for line in open('stopwords.txt', encoding='utf-8'): stopwords.append(line) stopwords.append('n') stopwords = set(stopwords)
停用詞表我就不提供了,網上有很多,自己下載即可
然後是一行一行讀取數據並分詞,分完詞再過濾。這些都做完以後,按照FastText要求的格式,拼接字元串,保存到文件中
def dump_file(df, filename, mode='train'): seg = pkuseg.pkuseg(model_name='web') with open(filename, 'w',encoding='utf-8') as f: for i in df.index.values: segs = seg.cut(df.text[i]) segs = filter(lambda x:x not in stopwords, segs) #去掉停用詞 # segs = filter(lambda x:len(x)>1,segs) segs = filter(lambda x:x.startswith('http')==False, segs) segs = filter(lambda x:x.startswith('.')==False, segs) segs = filter(lambda x:x.startswith('-')==False, segs) segs = filter(lambda x:x.startswith(',')==False, segs) segs = filter(lambda x:x.startswith('。')==False, segs) segs = filter(lambda x:x.startswith('…')==False, segs) segs = filter(lambda x:x.startswith('/')==False, segs) segs = filter(lambda x:x.startswith('—')==False, segs) segs = filter(lambda x:x.startswith('、')==False, segs) segs = filter(lambda x:x.startswith(':')==False, segs) segs = filter(lambda x:x.startswith('~')==False, segs) segs = filter(lambda x:x.startswith('[')==False, segs) segs = filter(lambda x:x.startswith(']')==False, segs) segs = filter(lambda x:(x.isalpha() and len(x) == 7) == False, segs) string = '' for j in segs: string = string + ' ' + j if mode == 'test': string = string.lstrip() else: string = df.stance[i] + ' ' + string string = string.lstrip() f.write(string + 'n')
dump_file(df_train, 'train.txt', 'train') dump_file(df_val, 'val.txt', 'train')
FastText
首先從它官方的github倉庫中clone dev版本(直接使用pip install fasttext是穩定版)
$ git clone https://github.com/facebookresearch/fastText.git $ cd fastText $ pip install .
因為最新的dev版本中有一個參數autotuneValidationFile
可以在訓練過程中自動搜索使得acc最大的參數。fastText使用也很簡單
clf = fasttext.train_supervised(input='train.txt', autotuneValidationFile='val.txt')
指定訓練集以及用於幫助尋找最優參數的測試集的路徑即可。如果要保存模型就用
clf.save_model('fasttext_model')
Predict & Submit
基本上如果你按照我的方法一路做下來,到現在為止在驗證集上的最大分數也就60左右
然後就是對test集進行預測,預測完了提交就行了
test = pd.read_csv('test.csv', delimiter='t') dump_file(test, 'test.txt', 'test') labels = [] for line in open('test.txt', encoding='utf-8'): if line != '': line = line.strip('n') labels.append(clf.predict(line)[0][0]) test['idx'] = range(len(test)) test['stance'] = labels mapping = {'__label__A':'FAVOR','__label__B':'AGAINST','__label__C':'NONE'} test['stance'] = test['stance'].map(mapping) test = test.drop(['target', 'text'], axis=1) test.to_csv('test_pred.csv',index=False,header=False)
Improve
- 我的做法只用了
text
和stance
這兩列,target
我覺得可以用也可以不用 - 仔細觀察數據集會發現,其實樣本分布及其不均勻,
stance
列中FAVOR
和AGAINST
兩個值特別多,NONE
特別少,這就涉及到不均衡樣本的訓練問題,可以通過sample,將它們的比例設置的比較均衡了再訓練 - 過濾詞設置的更詳細一點。如果你仔細查看了分詞後的數據集,你應該能發現裡面其實還有很多垃圾詞,比方說網址、7位驗證碼、表情之類的
- 直接上BERT