Source: Deep Learning on Medium
Compare MultinomialNB、SVM、Decision tree(CART) with f1-scrore、precision、recall
- Using TFIDF( term frequency–inverse document frequency) for vectorized.
- Using 10-fold for cross validation to get the better split.
首先import要用到的package,接著就可以開始我們的分析
import pandas as pd import numpy as np from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.model_selection import KFold from sklearn import metrics
1. Data preprocessing
今天的目標是要從新聞報導中,正確的分類至相對應的文章類別,有三種類別分別是Sports, Politics, Health,接著我會用三種不同的分類器,來看看三者的效能差異。
首先,先來看看資料長怎樣呢
可以看得出來是直接爬下來的data,每段的開頭是他的分類,那我們把它存成excel格式並分成categorize和content兩類。
colnames = ['categorize', 'content'] news = pd.read_csv('news_files.csv',names=colnames,encoding = 'utf8')
現在我們的資料存進去news的dataframe了,為了方便我們分類,將三種類別標示為0, 1, 2 並存到target的column
news['target'] = pd.Series(0, index=news.index) news_data =news.iloc[:6000]
如果直接做slicing存過去,可能會遇到error — SettingWithCopyWarning,所以我們用.at填值
for i in range(len(news_data)+1): if news_data.iloc[i]['categorize']=='sports': news_data.at[i,'target'] = 0 elif news_data.iloc[i]['categorize']=='politics': news_data.at[i,'target'] = 1 else: news_data.at[i,'target'] = 2
2. KFold
怎麼分training和validation的data是個很重要的議題,分得好不好會影響到我們模型效能,我們這邊用KFold來分,但同時我也寫了Random分類後的結果,這邊是random分類的function,需要的也可以測試看看。
def Separate_TrainAndTest(data_raw): n=int(data_raw.shape[0]) tmp_train=(np.random.rand(n)>=0.5) return data_raw.iloc[np.where(tmp_train==True)[0]],data_raw.iloc[np.where(tmp_train==False)[0]]
他的效能如下
接著我們繼續本文的部分,這邊希望用KFold就是為了避免依賴某一特定的訓練和測試資料產生偏差,那我們快速看一下KFold是怎麼做
我們將資料分成 10 等份,從Round 1開始先拿第 1 等分用來做Validation,其餘拿來training,下一輪我們繼續拿第 2 等分做Validation,其餘 9 份一樣拿來訓練,總共做 10 次,如果想要取不同的fold也可以,但是10次是比較普遍的用法,也不會訓練太久。
接著將10次的Accuracy平均,所得到平均值,我們可以自信的說這個數值就是我們的準確度,相對隨機來的沒有偏差。
實作 Time.
這邊用sklearn裡面的KFold,裡面的參數設定是KFold(n_splits=’warn’, shuffle=False, random_state=None),想知道更詳細的話,詳見: https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.KFold.html
from sklearn.naive_bayes import MultinomialNB
kfold = KFold(10, True) predicted = [] expected = []
for train, test in kfold.split(np.arange(len(news_data))+1): # train、test為index news_train = news_data.iloc[train] news_test = news_data.iloc[test]
上面我們用predicted和expected分別存10次的結果給後面做評分用
3. Vectorized
接下來是向量化(vectorized)的部分,這邊用的是TF-IDF,此演算法包含了兩個部分: 詞頻 (term frequency,TF)跟 逆向文件頻率 (inverse document frequency,IDF)。
詞頻指的是某一個給定的詞語在該文件中出現的頻率,第t個詞出現在第d篇文件的頻率記做
舉例來說,如果文件 1 總共有100個字,而第 1 個字在文件 1 出現的次數是12次,因此
而逆向文件頻率則是用來處理常用字的問題。假設詞彙t總共在第d篇文章中出現過,則詞彙t的 IDF 定義成
舉例來說,假設文字 1 總共出現在 25 篇不同的文件,則
所以如果詞彙t在非常多篇文章中都出現過,代表dt很大,此時idf就會比較小。
接著,我們將第t個詞彙對於第d篇文件的TF-IDF權重定義為
如此一來, 當詞彙t很常出現在文件d時,他的tf項就會比較大,而如果詞彙t也很少出現在其他篇文章,則idf項也會比較大,使Wtd整體來說更大,代表詞彙t對於文件d來說是很重要的 。
實作 Time.
這邊用sklearn.feature_extraction.text的TfidfVectorizer()直接計算,要注意的是需要將格式轉換成unicode,以下我以astype轉換
vectorizer = TfidfVectorizer() vectors_training = vectorizer.fit_transform(news_train['content'].values.astype('U')) vectors_test = vectorizer.transform(news_test['content'].values.astype('U'))
4. Classification
終於到了最後分類的階段,這邊會接續從MultinomialNB、SVM、CART分別進行training,並直接使用metric來計算三個分數,再分別列出,詳細的公式先不在這篇文章討論~
model = MultinomialNB(alpha=.01) model.fit(vectors_training,news_train.target) expected.extend(news_test.target) predicted.extend(model.predict(vectors_test))
print("---------Naive Bayes---------") print("Macro-average: {0}".format(metrics.f1_score(expected,predicted,average='macro'))) print("Micro-average: {0}".format(metrics.f1_score(expected,predicted,average='micro'))) print(metrics.classification_report(expected,predicted)) print(metrics.confusion_matrix(expected, predicted))
from sklearn import svm predicted = [] expected = [] for train, test in kfold.split(np.arange(len(news_data))+1): news_train = news_data.iloc[train] news_test = news_data.iloc[test] vectorizer = TfidfVectorizer() vectors_training = vectorizer.fit_transform(news_train['content'].values.astype('U')) vectors_test = vectorizer.transform(news_test['content'].values.astype('U')) model = svm.SVC(kernel = 'linear') model.fit(vectors_training,news_train.target) #test process #SVM expected.extend(news_test.target) predicted.extend(model.predict(vectors_test))
print("---------SVM---------") print("Macro-average: {0}".format(metrics.f1_score(expected,predicted,average='macro'))) print("Micro-average: {0}".format(metrics.f1_score(expected,predicted,average='micro'))) print(metrics.classification_report(expected,predicted,target_names = ['sports','politics','health'] ))
from sklearn import tree predicted = [] expected = [] for train, test in kfold.split(np.arange(len(news_data))+1): news_train = news_data.iloc[train] news_test = news_data.iloc[test] vectorizer = TfidfVectorizer() vectors_training = vectorizer.fit_transform(news_train['content'].values.astype('U')) vectors_test = vectorizer.transform(news_test['content'].values.astype('U')) model = tree.DecisionTreeClassifier() #不調參數 default = CART model.fit(vectors_training,news_train.target) # predict expected.extend(news_test.target) predicted.extend(model.predict(vectors_test)) #Decision Tree print("---------Decision Tree---------") print("Macro-average: {0}".format(metrics.f1_score(expected,predicted,average='macro'))) print("Micro-average: {0}".format(metrics.f1_score(expected,predicted,average='micro'))) print(metrics.classification_report(expected,predicted,target_names = ['sports','politics','health'] )) print("-----------------------------")
Conclusion
很明顯的可以看到用10-fold所得到的結果比Random好很多,其中Accuracy又以SVM>NB>Decision Tree,但是SVM需要的時間也相對多很多,所以就看怎麼取決了,本文為第一個NLP的小實驗,有甚麼建議可以留言哦~
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。