新聞文本分類
文章目錄
- 新聞文本分類
- 一、專案背景
- 二、資料處理與分析
- 三、基于機器學習的文本分類--樸素貝葉斯
- 1. 模型介紹
- 2. 代碼結構
- 3. 結果分析
- 四、基于深度學習的文本分類--LSTM
- 1. 模型介紹
- 2. 代碼結構
- 3. 結果分析
- 五、小結
- 六、參考與參考
一、專案背景
????本專案來源于天池?賽,利?機器學習和深度學習等知識,對新聞?本進?分類,?共有14個分類類別:財經、彩票、房產、股票、家居、教育、科技、社會、時尚、時政、體育、星座、游戲、娛樂,
?????最終將測驗集的預測結果上傳??賽官?,可查看排名,評價標準為類別f1_score的均值,提交結果與實際測驗集的類別進?對?,(不要求結果領先,但求真才實學)
二、資料處理與分析
?????本次大賽提供的材料是由csv格式撰寫,只需呼叫python中的pandas庫讀取即可,為了更直觀的觀察資料,我計算了檔案的平均長度,以及每個標簽分別對應的檔案,(sen字典與tag字典的獲取方法會在后文中展示,此步只用來呈現資料分布,運行時可先跳過)
import matplotlib.pyplot as plt
from tqdm import tqdm
import time
from numpy import *
import pandas as pd
print('count: 200000') #詞典sen中,每個標簽對應其所有句子的二維串列
print('average: '+str(sum([[sum(sen[i][j]) for j in range(len(sen[i]))] for i in sen])/200000))
x = []
y = []
for key,value in tag.items(): #詞典tag中,每個標簽對應該標簽下的句子數目
x.append(key)
y.append(value)
plt.bar(x,y)
plt.show()
????最終我們得到了以下結果:

?????平均檔案長約907詞,每個標簽對應的檔案數從標簽0至13逐個減少,
三、基于機器學習的文本分類–樸素貝葉斯
1. 模型介紹
?????樸素貝葉斯分類器的基本思想是利用特征項和類別的聯合概率來估計給定檔案的類別概率,假設文本是基于詞的一元模型,即文本中當前詞的出現依賴于文本類別,但不依賴于其他詞及文本的長度,也就是說,詞與詞之間是獨立的,根據貝葉斯公式,檔案Doc屬于
C
i
C_i
Ci?類的概率為
P
(
C
i
∣
D
o
c
)
=
P
(
D
o
c
∣
C
i
)
×
P
(
C
i
)
P
(
D
o
c
)
P\left(C_{i} \mid \mathrm{Doc}\right)=\frac{P\left(\mathrm{Doc} \mid C_{i}\right) \times P\left(C_{i}\right)}{P(\mathrm{Doc})}
P(Ci?∣Doc)=P(Doc)P(Doc∣Ci?)×P(Ci?)?
?????檔案Doc采用
T
F
TF
TF向量表示法,即檔案向量
V
V
V的分量為相應特征在該檔案中出現的頻度,檔案Doc屬于
C
i
C_i
Ci?類檔案的概率為
P
(
C
i
∣
D
o
c
)
=
P
(
C
i
)
∏
t
i
∈
V
P
(
t
j
∣
C
i
)
T
F
(
t
i
,
D
o
c
)
∑
j
[
P
(
C
j
)
∏
t
i
∈
V
P
(
t
i
∣
C
j
)
T
F
(
t
i
,
D
o
c
)
]
P\left(C_{i} \mid Doc\right)=\frac{P\left(C_{i}\right) \prod_{t_{i} \in V} P\left(t_{j} \mid C_{i}\right)^{T F\left(t_{i} ,\mathrm{Doc}\right)}}{\sum_{j}\left[P\left(C_{j}\right) \prod_{t_{i} \in V} P\left(t_{i} \mid C_{j}\right)^{\mathrm{TF}\left(t_{i}, \mathrm{Doc}\right)}\right]}
P(Ci?∣Doc)=∑j?[P(Cj?)∏ti?∈V?P(ti?∣Cj?)TF(ti?,Doc)]P(Ci?)∏ti?∈V?P(tj?∣Ci?)TF(ti?,Doc)?
?????其中,
T
F
(
t
i
,
D
o
c
)
TF (t_i,Doc)
TF(ti?,Doc)是檔案Doc中特征
t
i
t_i
ti?出現的頻度,為了防止出現不在詞典中的詞導致概率為0的情況,我們取
P
(
t
i
∣
C
i
)
P(t_i|C_i)
P(ti?∣Ci?)是對
C
i
C_i
Ci?類檔案中特征
t
i
t_i
ti?出現的條件概率的拉普拉斯概率估計:
P
(
t
i
∣
C
i
)
=
1
+
TF
?
(
t
i
,
C
i
)
∣
V
∣
+
∑
j
T
F
(
t
j
,
C
i
)
P\left(t_{i} \mid C_{i}\right)=\frac{1+\operatorname{TF}\left(t_{i}, C_{i}\right)}{|V|+\sum_{j} T F\left(t_{j}, C_{i}\right)}
P(ti?∣Ci?)=∣V∣+∑j?TF(tj?,Ci?)1+TF(ti?,Ci?)?
?????這里,
T
F
(
t
i
,
C
i
)
TF(t_i,C_i)
TF(ti?,Ci?)是
C
i
C_i
Ci?類檔案中特征
t
i
t_i
ti?出現的頻度,
∣
V
∣
|V|
∣V∣為特征集的大小,即檔案表示中所包含的不同特征的總數目,
2. 代碼結構
?????我直接通過python自帶的open()函式讀取檔案,并建立對應詞典,設定停用詞,這里的停用詞選擇了words字典中出現在100000個檔案以上的所有詞,訓練集取前19萬個檔案,測驗集取最后一萬個檔案,
train_df = open('./data/train_set.csv').readlines()[1:]
train = train_df[0:190000]
test = train_df[190000:200000]
true_test = open('./data/test_a.csv').readlines()[1:]
tag = {str(i):0 for i in range(0,14)}
sen = {str(i):{} for i in range(0,14)}
words={}
stop_words = {'4149': 1, '1519': 1, '2465': 1, '7539': 1, ...... }
?????接著,我們需要建立標簽詞典和句子詞典,用tqdm函式來顯示進度,
for line in tqdm(train_df):
cur_line = line.split('\t')
cur_tag = cur_line[0]
tag[cur_tag] += 1
cur_line = cur_line[1][:-1].split(' ')
for i in cur_line:
if i not in words:
words[i] = 1
else:
words[i] += 1
if i not in sen[cur_tag]:
sen[cur_tag][i] = 1
else:
sen[cur_tag][i] += 1
?????為了便于計算,我定義了如下函式,其中mul()用來計算串列中所有數的乘積,prob_clas() 用來計算 P ( C i ∣ D o c ) P\left(C_{i} \mid \mathrm{Doc}\right) P(Ci?∣Doc),用probability()來計算 P ( t i ∣ C i ) P\left(t_{i} \mid C_{i}\right) P(ti?∣Ci?),在probability() 函式中,我將輸出結果中分子+1,分母加上字典長度,實作拉普拉斯平滑處理,
def mul(l):
res = 1
for i in l:
res *= i
return res
def prob_clas(clas):
return tag[clas]/(sum([tag[i] for i in tag]))
def probability(char,clas): #P(特征|類別)
if char not in sen[clas]:
num_char = 0
else:
num_char = sen[clas][char]
return (1+num_char)/(len(sen[clas])+len(words))
?????在做好所有準備作業,定義好函式后,分別對測驗集中的每一句話計算十四個標簽對應概率,并將概率最大的標簽儲存在預測串列中,用tqdm函式來顯示進度,
PRED = []
for line in tqdm(true_test):
result = {str(i):0 for i in range(0,14)}
cur_line = line[:-1].split(' ')
clas = cur_tag
for i in result:
prob = []
for j in cur_line:
if j in stop_words:
continue
prob.append(log(probability(j,i)))
result[i] = log(prob_clas(i))+sum(prob)
for key,value in result.items():
if(value == max(result.values())):
pred = int(key)
PRED.append(pred)
?????最后把結果儲存在csv檔案中上傳網站,提交后查看成績,(用此方法撰寫的csv檔案需要打開后刪去第一列再上傳)
res=pd.DataFrame()
res['label']=PRED
res.to_csv('test_TL.csv')
3. 結果分析
?????在訓練前19萬個檔案,測驗后一萬個檔案的程序中,我不斷調整停用詞取用串列,分別用TF和TF-IDF向量表示法進行了測驗,結果發現使用TF表示法準確性較高,最后取用停用詞為出現在十萬個檔案以上的詞,最終得出最高效率為0.622,

????在提交至網站后,對五萬個檔案進行測驗的F1值僅有 0.29左右,效果較差,

四、基于深度學習的文本分類–LSTM
1. 模型介紹
?????除了傳統的機器學習方法,我使用了深度學習中的LSTM(Long Short-Term Memory)長短期記憶網路,來嘗試處理新聞文本分類,希望能有更高的準確率,LSTM它是一種時間回圈神經網路,適合于處理和預測時間序列中間隔和延遲相對較長的重要事件,LSTM 已經在科技領域有了多種應用,基于 LSTM 的系統可以學習翻譯語言、控制機器人、影像分析、檔案摘要、語音識別影像識別、手寫識別、控制聊天機器人、預測疾病、點擊率和股票、合成音樂等等任務,我采用深度學習庫Keras來建立LSTM模型,進行文本分類,
?????對于卷積神經網路CNN和回圈網路RNN而言,隨著時間的不斷增加,隱藏層一次又一次地乘以權重W,假如某個權重w是一個接近于0或者大于1的數,隨著乘法次數的增加,這個權重值會變得很小或者很大,造成反向傳播時梯度計算變得很困難,造成梯度爆炸或者梯度消失的情況,模型難以訓練,也就是說一般的RNN模型對于長時間距離的資訊記憶很差,因此LSTM應運而生,

?????LSTM長短期記憶網路可以更好地解決這個問題,在LSTM的一個單元中,有四個顯示為黃色框的網路層,每個層都有自己的權重,如以 σ 標記的層是 sigmoid 層,tanh是一個激發函式,這些紅圈表示逐點或逐元素操作,單元狀態在通過 LSTM 單元時幾乎沒有互動,使得大部分資訊得以保留,單元狀態僅通過這些控制門(gate)進行修改,第一個控制門是遺忘門,用來決定我們會從單元狀態中丟棄什么資訊,第二個門是更新門,用以確定什么樣的新資訊被存放到單元狀態中,最后一個門是輸出門,我們需要確定輸出什么樣的值,總結來說 LSTM 單元由單元狀態和一堆用于更新資訊的控制門組成,讓資訊部分傳遞到隱藏層狀態,
2. 代碼結構
?????首先是初始資料的設定和包的呼叫,考慮到平均句長約900,這里取最大讀取長度為平均長度的 2 3 \frac{2}{3} 32?,即max_len為600,之后可通過調整該引數來調整學習效率,
from tqdm import tqdm
import pandas as pd
import time
import matplotlib.pyplot as plt
import seaborn as sns
from numpy import *
from sklearn import metrics
from sklearn.preprocessing import LabelEncoder,OneHotEncoder
from keras.models import Model
from keras.layers import LSTM, Activation, Dense, Dropout, Input, Embedding
from keras.optimizers import rmsprop_v2
from keras.preprocessing import sequence
from keras.callbacks import EarlyStopping
from keras.models import load_model
import os.path
max_words = 7549 #字典最大編號
# 可通過調節max_len調整模型效果和學習速度
max_len = 600 #句子的最大長度
stop_words = {}
?????接下來,我們定義一個將DataFrame的格式轉化為矩陣的函式,該函式輸出一個長度為600的二維檔案串列和其對應的標簽值,
def to_seq(dataframe):
x = []
y = array([[0]*int(i)+[1]+[0]*(13-int(i)) for i in dataframe['label']])
for i in tqdm(dataframe['text']):
cur_sentense = []
for word in i.split(' '):
if word not in stop_words: #最終并未采用停用詞串列
cur_sentense.append(word)
x.append(cur_sentense)
return sequence.pad_sequences(x,maxlen=max_len),y
?????接下來是模型的主體函式,該函式輸入測驗的檔案,測驗集的真值,訓練集和檢驗集,輸出預測得到的混淆矩陣,具體代碼介紹,見下列代碼中的注釋,
def test_file(text,value,train,val):
## 定義LSTM模型
inputs = Input(name='inputs',shape=[max_len])
## Embedding(詞匯表大小,batch大小,每個新聞的詞長)
layer = Embedding(max_words+1,128,input_length=max_len)(inputs)
layer = LSTM(128)(layer)
layer = Dense(128,activation="relu",name="FC1")(layer)
layer = Dropout(0.5)(layer)
layer = Dense(14,activation="softmax",name="FC2")(layer)
model = Model(inputs=inputs,outputs=layer)
model.summary()
model.compile(loss="categorical_crossentropy",optimizer=rmsprop_v2.RMSprop(),metrics=["accuracy"])
## 模型建立好之后開始訓練,如果已經保存訓練檔案(.h5格式),則直接調取即可
if os.path.exists('my_model.h5') == True:
model = load_model('my_model.h5')
else:
train_seq_mat,train_y = to_seq(train)
val_seq_mat,val_y = to_seq(val)
model.fit(train_seq_mat,train_y,batch_size=128,epochs=10, #可通過epochs數來調整準確率和運算速度
validation_data=(val_seq_mat,val_y))
model.save('my_model.h5')
## 開始預測
test_pre = model.predict(text)
##計算混淆函式
confm = metrics.confusion_matrix(argmax(test_pre,axis=1),argmax(value,axis=1))
print(metrics.classification_report(argmax(test_pre,axis=1),argmax(value,axis=1)))
return confm
?????訓練程序如下圖所示,

?????為了更直觀的表現結果,定義如下函式繪制影像,
def plot_fig(matrix):
Labname = [str(i) for i in range(14)]
plt.figure(figsize=(8,8))
sns.heatmap(matrix.T, square=True, annot=True,
fmt='d', cbar=False,linewidths=.8,
cmap="YlGnBu")
plt.xlabel('True label',size = 14)
plt.ylabel('Predicted label',size = 14)
plt.xticks(arange(14)+0.5,Labname,size = 12)
plt.yticks(arange(14)+0.3,Labname,size = 12)
plt.show()
return
?????最后,只需要通過pandas讀取csv檔案,按照比例分為訓練集、檢驗集和測驗集(這里選用比例為15:2:3),即可完成全部的預測程序,
def test_main():
train_df = pd.read_csv("./data/train_set.csv",sep='\t',nrows=200000)
train = train_df.iloc[0:150000,:]
test = train_df.iloc[150000:180000,:]
val = train_df.iloc[180000:,:]
test_seq_mat,test_y = to_seq(test)
Confm = test_file(test_seq_mat,test_y,train,val)
plot_fig(Confm)
?????在獲得預測結果最高的一組引數的選取后,我們訓練整個train_set檔案,訓練程序如下,訓練之前需洗掉已有的訓練檔案(.h5),此函式中的test行可隨意選取,只是為了滿足test_file()函式的變數足夠,此函式只是用于訓練出學習效果最好的資料并儲存,
def train():
train_df = pd.read_csv("./data/train_set.csv",sep='\t',nrows=200000)
train = train_df.iloc[0:170000,:]
test = train_df.iloc[0:10000,:]
val = train_df.iloc[170000:,:]
test_seq_mat,test_y = to_seq(test)
Confm = test_file(test_seq_mat,test_y,train,val)
plot_fig(Confm)
?????在獲得最優的訓練資料后,我們就可以開始預測了,我們將競賽中提供的測驗集帶入模型中,加載儲存好的訓練集進行預測,得到預測矩陣,再將預測矩陣中每一行的最大值轉化為對應的標簽,儲存在輸出串列中即可,最后將該串列寫入’test_DL.csv’檔案中上傳即可,(如此生成的csv檔案同上一個模型一樣,需手動打開洗掉掉第一列)
def pred_file():
test_df = pd.read_csv('./data/test_a.csv')
test_seq_mat = sequence.pad_sequences([i.split(' ') for i in tqdm(test_df['text'])],maxlen=max_len)
inputs = Input(name='inputs',shape=[max_len])
## Embedding(詞匯表大小,batch大小,每個新聞的詞長)
layer = Embedding(max_words+1,128,input_length=max_len)(inputs)
layer = LSTM(128)(layer)
layer = Dense(128,activation="relu",name="FC1")(layer)
layer = Dropout(0.5)(layer)
layer = Dense(14,activation="softmax",name="FC2")(layer)
model = Model(inputs=inputs,outputs=layer)
model.summary()
model.compile(loss="categorical_crossentropy",optimizer=rmsprop_v2.RMSprop(),metrics=["accuracy"])
model = load_model('my_model.h5')
test_pre = model.predict(test_seq_mat)
pred_result = [i.tolist().index(max(i.tolist())) for i in test_pre]
res=pd.DataFrame()
res['label']=pred_result
res.to_csv('test_DL.csv')
????整理后,我們只需要注釋掉對應的指令行即可進行訓練或預測,
#如果想要訓練,取消下行注釋,訓練之前需先洗掉原訓練檔案(.h5)
#train()
#如果想要查看模型效果,取消下行注釋(訓練集:檢驗集:測驗集=15:2:3)
# test_main()
#如果想預測并生成csv檔案,取消下行注釋
# pred_file()
3. 結果分析
?????最侄訓得的混淆矩陣如下圖所示,14個標簽預測的正確率均達到了80%以上,有11個標簽在90%以上,有6個標簽在95%以上,

?????繪制出來的預測結果如下圖所示,可見預測效果相當理想,每個標簽的正確率都尤為可觀,預測錯誤的文本數相比于總量非常少,

?????最終上傳網站得到結果,F1值達90%以上,效果較好,

五、小結
?????本實驗采用了傳統機器學習和基于LSTM的深度學習兩種方法對新聞文本進行了分類,在兩種方法的對比下,深度學習的效果明顯優于傳統的機器學習,并在競賽中取得了較好的成績(排名551),但LSTM仍存在問題,一方面是RNN的梯度問題在LSTM及其變種里面得到了一定程度的解決,但還是不夠;另一方面,LSTM計算費時,每一個LSTM的cell里面都意味著有4個全連接層(MLP),如果LSTM的時間跨度很大,并且網路又很深,這個計算量會很大,很耗時,
?????探尋更好的文本分類方法一直以來都是NLP在探索的方向,希望今后可以學習更多的分類方法,更多的機器學習和深度學習模型,提高分類效率,
?????目前仍是小白,代碼多有繁瑣、不對之處,望指正!
六、參考與參考
????本文在原理介紹、模型優劣分析程序中參考了其他文章,模型構建程序中參考了部分文章引數的選取,在此一一列出,
使用keras建立LSTM模型進行文本分類 - 知乎 (zhihu.com)
(14條訊息) 【個人整理】長短是記憶網路LSTM的原理以及缺點_MIss-Y的博客-CSDN博客_lstm的缺點
(14條訊息) Keras之文本分類實作_cdj0311的專欄-CSDN博客_keras 文本分類
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/382789.html
標籤:AI
上一篇:Windows搭建FTP服務器,JAVA實作讀寫功能
下一篇:python繪圖中的四個繪圖技巧
