任務(wù)4:論文種類分類
學(xué)習(xí)鏈接:
- 多標(biāo)簽分類(multi-label classification)綜述:https://www.cnblogs.com/cxf-zzj/p/10049613.html
- MultiLabelBinarizer的使用方法鏈接:https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MultiLabelBinarizer.html
- TfidfVectorizer簡介:https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html
- Tokenizer使用方法:https://zhuanlan.zhihu.com/p/138054335
- tokenizer的制作和embedding的使用:https://zhuanlan.zhihu.com/p/65192903
4.1 任務(wù)說明
- 學(xué)習(xí)主題:論文分類(數(shù)據(jù)建模任務(wù))蟀俊,利用已有數(shù)據(jù)建模,對新論文進(jìn)行類別分類魏身;
- 學(xué)習(xí)內(nèi)容:使用論文標(biāo)題和摘要完成類別分類涕蚤;
- 學(xué)習(xí)成果:學(xué)會文本分類的基本方法宛裕、TF-IDF等腰懂;
4.2 數(shù)據(jù)處理步驟
在原始arxiv論文中論文都有對應(yīng)的類別刁俭,而論文類別是作者填寫的窜管。在本次任務(wù)中我們可以借助論文的標(biāo)題和摘要完成:
- 對論文標(biāo)題和摘要進(jìn)行處理散劫;
- 對論文類別進(jìn)行處理;
- 構(gòu)建文本分類模型幕帆;
4.3 文本分類思路
- 思路1:TF-IDF+機(jī)器學(xué)習(xí)分類器
直接使用TF-IDF對文本提取特征获搏,使用分類器進(jìn)行分類,分類器的選擇上可以使用SVM失乾、LR常熙、XGboost等
- 思路2:FastText
FastText是入門款的詞向量,利用Facebook提供的FastText工具碱茁,可以快速構(gòu)建分類器
- 思路3:WordVec+深度學(xué)習(xí)分類器
WordVec是進(jìn)階款的詞向量裸卫,并通過構(gòu)建深度學(xué)習(xí)分類完成分類。深度學(xué)習(xí)分類的網(wǎng)絡(luò)結(jié)構(gòu)可以選擇TextCNN纽竣、TextRnn或者BiLSTM畦韭。
- 思路4:Bert詞向量
Bert是高配款的詞向量,具有強(qiáng)大的建模學(xué)習(xí)能力桑涎。
4.4 具體代碼實(shí)現(xiàn)以及講解
#導(dǎo)入所需的package并讀取原始數(shù)據(jù)
import seaborn as sns
import re
import json
import pandas as pd # 數(shù)據(jù)處理和分析
import matplotlib.pyplot as plt # 畫圖工具
data = []
with open('arxiv-metadata-oai-snapshot.json','r') as f:
for idx, line in enumerate(f):
d = json.loads(line)
d = {'title':d['title'],'categories':d['categories'],'abstract':d['abstract']}
data.append(d)
# 只選取部分?jǐn)?shù)據(jù)
if idx > 200000:
break
data = pd.DataFrame(data)
data.head()
為了完成數(shù)據(jù)處理萌踱,我們可以將標(biāo)題和摘要拼接在一起完成
# 合并title和abstract
data['text'] = data['title'] + data['abstract']
# 將換行符替換為空格
data['text'] = data['text'].apply(lambda x: x.replace('\n',''))
# 將所有大寫字母替換為小寫字母
data['text'] = data['text'].apply(lambda x: x.lower())
# 刪除多余的列
data = data.drop(['abstract','title'], axis=1)
data.head()
由于原始論文有可能有多個類別,所以需要處理:
# 多個類別函筋,包含子分類
data['categories'] = data['categories'].apply(lambda x: x.split(' '))
# 單個類別,不包含子分類
data['categories_big'] = data['categories'].apply(lambda x: [xx.split('.')[0] for xx in x])
data.head()
然后將類別進(jìn)行編碼,這里類別是多個缰泡,所以需要多編碼:
- MultiLabelBinarizer的使用方法鏈接:https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MultiLabelBinarizer.html
- 類似于one-hot編碼,只不過自變量可以是元組或列表
from sklearn.preprocessing import MultiLabelBinarizer
mlb = MultiLabelBinarizer()
data_label = mlb.fit_transform(data['categories_big'].iloc[:])
data_label
4.4.1 思路1:TF-IDF
使用TFIDF提取特征代嗤,限制最多4000個單詞
- TfidfVectorizer簡介:https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html
- 將原始句子轉(zhuǎn)換成詞頻向量
什么是TF-IDF棘钞?
TF-IDF(term frequency-inverse document frequency)詞頻-逆向文件頻率。在處理文本時干毅,如何將文字轉(zhuǎn)化為模型可以處理的向量呢宜猜?TF-IDF就是這個問題的解決方案之一。字詞的重要性與其在文本中出現(xiàn)的頻率成正比(TF)硝逢,與其在語料庫中出現(xiàn)的頻率成反比(IDF)姨拥。
TF:詞頻。TF(w)=(詞w在文檔中出現(xiàn)的次數(shù))/(文檔的總詞數(shù))
IDF:逆向文件頻率渠鸽。有些詞可能在文本中頻繁出現(xiàn)叫乌,但并不重要,也即信息量小徽缚,如is,of,that這些單詞憨奸,這些單詞在語料庫中出現(xiàn)的頻率也非常大,我們就可以利用這點(diǎn)凿试,降低其權(quán)重排宰。IDF(w)=log_e(語料庫的總文檔數(shù))/(語料庫中詞w出現(xiàn)的文檔數(shù))
將上面的TF-IDF相乘就得到了綜合參數(shù):TF-IDF=TF*IDF
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(max_features=4000) # 限制最多詞4000
data_tfidf = vectorizer.fit_transform(data['text'].iloc[:])
data_tfidf
由于這里是多標(biāo)簽分類,可以使用sklearn的多標(biāo)簽分類進(jìn)行封裝:
# 劃分訓(xùn)練集和測試集
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(data_tfidf,
data_label,
test_size=0.2,
random_state=1)
- MultiOutputClassifier將單類預(yù)測模型轉(zhuǎn)換為多類模型那婉,類似于一個模型只預(yù)測一個類
# 構(gòu)建多標(biāo)簽分類模型
from sklearn.multioutput import MultiOutputClassifier
from sklearn.naive_bayes import MultinomialNB
clf =MultiOutputClassifier(MultinomialNB()).fit(x_train,y_train)
# 精度評價
from sklearn.metrics import accuracy_score
accuracy_score(y_test,clf.predict(x_test))
0.5631859203519912
from sklearn.metrics import classification_report
print(classification_report(y_test,clf.predict(x_test)))
XGBoost模型
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import GridSearchCV,KFold
import xgboost as xgb
model = MultiOutputClassifier(xgb.XGBClassifier(n_jobs = -1))
model.fit(x_train, y_train)
accuracy_score(y_test,model.predict(x_test))
0.6109097272568186
4.4.2 思路2:使用深度學(xué)習(xí)
思路2使用深度學(xué)習(xí)模型板甘,單詞進(jìn)行詞嵌入然后訓(xùn)練。
- 首先按照文本劃分?jǐn)?shù)據(jù)集,將數(shù)據(jù)集處理進(jìn)行編碼吧恃,并進(jìn)行截斷
- 定義模型并完成訓(xùn)練
- Tokenizer使用方法:https://zhuanlan.zhihu.com/p/138054335
- tokenizer的制作和embedding的使用:https://zhuanlan.zhihu.com/p/65192903
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(data['text'].iloc[:100000],
data_label[:100000],
test_size = 0.95,random_state = 1)
# parameter
max_features= 500
max_len= 150
embed_size=100
batch_size = 128
epochs = 5
from keras.preprocessing.text import Tokenizer
from keras.preprocessing import sequence
tokens = Tokenizer(num_words = max_features)
tokens.fit_on_texts(list(data['text'].iloc[:100000]))
y_train = data_label[:100000]
x_sub_train = tokens.texts_to_sequences(data['text'].iloc[:100000])
x_sub_train = sequence.pad_sequences(x_sub_train, maxlen=max_len)
# LSTM model
# Keras Layers:
from keras.layers import Dense,Input,LSTM,Bidirectional,Activation,Conv1D,GRU
from keras.layers import Dropout,Embedding,GlobalMaxPooling1D, MaxPooling1D, Add, Flatten
from keras.layers import GlobalAveragePooling1D, GlobalMaxPooling1D, concatenate, SpatialDropout1D# Keras Callback Functions:
from keras.callbacks import Callback
from keras.callbacks import EarlyStopping,ModelCheckpoint
from keras import initializers, regularizers, constraints, optimizers, layers, callbacks
from keras.models import Model
from keras.optimizers import Adam
sequence_input = Input(shape=(max_len, ))
x = Embedding(max_features, embed_size, trainable=True)(sequence_input)
x = SpatialDropout1D(0.2)(x)
x = Bidirectional(GRU(128, return_sequences=True,dropout=0.1,recurrent_dropout=0.1))(x)
x = Conv1D(64, kernel_size = 3, padding = "valid", kernel_initializer = "glorot_uniform")(x)
avg_pool = GlobalAveragePooling1D()(x)
max_pool = GlobalMaxPooling1D()(x)
x = concatenate([avg_pool, max_pool])
preds = Dense(19, activation="sigmoid")(x)
model = Model(sequence_input, preds)
model.compile(loss='binary_crossentropy',optimizer=Adam(lr=1e-3),metrics=['accuracy'])
model.fit(x_sub_train, y_train,
batch_size=batch_size,
validation_split=0.2,
epochs=epochs)
保存模型
import pickle
with open("clf.pkl","wb")as f:
pickle.dump(clf,f)
model.save('keras_model')