基于jieba、TfidfVectorizer、LogisticRegression的搜狐新聞文本分類

學(xué)習(xí)資源來源:容大教育,致以誠摯的謝意。
重新編輯:瀟灑坤

jieba中文叫做結(jié)巴,是一款中文分詞工具,官方文檔鏈接:https://github.com/fxsjy/jieba
TfidfVectorizer中文叫做詞袋向量化模型,是用來文章內(nèi)容向量化的工具,官方文檔鏈接:http://sklearn.apachecn.org/cn/0.19.0/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html
LogisticRegression中文叫做邏輯回歸模型,是一種基礎(chǔ)、常用的分類方法。

建議讀者安裝anaconda,這個(gè)集成開發(fā)環(huán)境自帶了很多包。
到2018年9月1日仍為最新版本的anaconda下載鏈接: https://pan.baidu.com/s/1pbzVbr1ZJ-iQqJzy1wKs0A 密碼: g6ex
官網(wǎng)下載地址:https://repo.anaconda.com/archive/Anaconda3-5.2.0-Windows-x86_64.exe
下面代碼的開發(fā)環(huán)境為jupyter notebook,使用在jupyter notebook中的截圖表示運(yùn)行結(jié)果。

0.打開jupyter

在桌面新建文件夾命名為基于TfidfVectorizer的文檔分類,如下圖所示:

image.png

打開基于TfidfVectorizer的文檔分類文件夾,在按住Shift鍵的情況下,點(diǎn)擊鼠標(biāo)右鍵,出現(xiàn)如下圖所示。
選擇在此處打開PowerShell窗口,之后會(huì)在此路徑下打開PowerShell。
image.png

在PowerShell中輸入命令并運(yùn)行:jupyter notebook
image.png

PowerShell運(yùn)行命令后,會(huì)自動(dòng)打開網(wǎng)頁,點(diǎn)擊如下圖所示網(wǎng)頁中的按鈕:
image.png

代碼文件重命名為tfidfVectorizerTest,重命名按鈕位置如下圖所示:
image.png

1.數(shù)據(jù)準(zhǔn)備

訓(xùn)練集共有24000條樣本,12個(gè)分類,每個(gè)分類2000條樣本。
測試集共有12000條樣本,12個(gè)分類,每個(gè)分類1000條樣本。
數(shù)據(jù)集下載鏈接: https://pan.baidu.com/s/1PY3u-WtfBdZQ8FsKgWo_KA 密碼: hq5v
下載完成后,將壓縮文件包放到基于TfidfVectorizer的文檔分類文件夾中,并將其解壓到當(dāng)前文件夾,如下圖所示:

image.png

加載訓(xùn)練集到變量train_df中,并打印訓(xùn)練集前5行,代碼如下。
read_csv方法中有3個(gè)參數(shù),第1個(gè)參數(shù)是加載文本文件的路徑,第2個(gè)關(guān)鍵字參數(shù)sep是分隔符,第3個(gè)關(guān)鍵字參數(shù)header是文本文件的第1行是否為字段名。

import pandas as pd

train_df = pd.read_csv('sohu_train.txt', sep='\t', header=None)
train_df.head()

上面一段代碼的運(yùn)行結(jié)果如下圖所示:


image.png

查看訓(xùn)練集每個(gè)分類的名字以及樣本數(shù)量,代碼如下:

for name, group in train_df.groupby(0):
    print(name,len(group))

上面一段代碼的運(yùn)行結(jié)果如下圖所示:


image.png

加載測試集并查看每個(gè)分類的名字以及樣本數(shù)量,代碼如下:

test_df = pd.read_csv('sohu_test.txt', sep='\t', header=None)
for name, group in test_df.groupby(0):
    print(name, len(group))

上面一段代碼的運(yùn)行結(jié)果如下圖所示:


image.png

載入停頓詞賦值給變量stopWord_list,代碼如下:

with open('stopwords.txt', encoding='utf8') as file:
    stopWord_list = [k.strip() for k in file.readlines()]

2.分詞

需要安裝jieba庫,cmd中安裝命令:pip install jieba
對(duì)訓(xùn)練集的24000條樣本循環(huán)遍歷,使用jieba庫的cut方法獲得分詞列表賦值給變量cutWords。
判斷分詞是否為停頓詞,如果不為停頓詞,則添加進(jìn)變量cutWords中。
代碼如下:

import jieba
import time

train_df.columns = ['分類', '文章']
stopword_list = [k.strip() for k in open('stopwords.txt', encoding='utf8').readlines() if k.strip() != '']
cutWords_list = []
i = 0
startTime = time.time()
for article in train_df['文章']:
    cutWords = [k for k in jieba.cut(article) if k not in stopword_list]
    i += 1
    if i % 1000 == 0:
        print('前%d篇文章分詞共花費(fèi)%.2f秒' %(i, time.time()-startTime))
    cutWords_list.append(cutWords)

上面一段代碼的運(yùn)行結(jié)果如下:

前1000篇文章分詞共花費(fèi)67.62秒
前2000篇文章分詞共花費(fèi)133.32秒
前3000篇文章分詞共花費(fèi)272.28秒
前4000篇文章分詞共花費(fèi)405.01秒
前5000篇文章分詞共花費(fèi)529.79秒
前6000篇文章分詞共花費(fèi)660.60秒
前7000篇文章分詞共花費(fèi)696.51秒
前8000篇文章分詞共花費(fèi)732.88秒
前9000篇文章分詞共花費(fèi)788.51秒
前10000篇文章分詞共花費(fèi)841.61秒
前11000篇文章分詞共花費(fèi)903.35秒
前12000篇文章分詞共花費(fèi)970.47秒
前13000篇文章分詞共花費(fèi)1010.61秒
前14000篇文章分詞共花費(fèi)1048.76秒
前15000篇文章分詞共花費(fèi)1100.81秒
前16000篇文章分詞共花費(fèi)1154.80秒
前17000篇文章分詞共花費(fèi)1207.07秒
前18000篇文章分詞共花費(fèi)1256.73秒
前19000篇文章分詞共花費(fèi)1374.76秒
前20000篇文章分詞共花費(fèi)1493.85秒
前21000篇文章分詞共花費(fèi)1523.02秒
前22000篇文章分詞共花費(fèi)1552.69秒
前23000篇文章分詞共花費(fèi)1598.88秒
前24000篇文章分詞共花費(fèi)1644.56秒

從上面的運(yùn)行結(jié)果可以看出,對(duì)24000篇文章進(jìn)行分詞共使用1644秒,即27分24秒。
時(shí)間充裕的讀者可以自己運(yùn)行試試,將分詞結(jié)果保存為本地文件cutWords_list.txt,代碼如下:

with open('cutWords_list.txt', 'w') as file: 
    for cutWords in cutWords_list:
        file.write(' '.join(cutWords) + '\n')

上面一段代碼大概5秒左右運(yùn)行完成,本文作者提供已經(jīng)分詞完成的文本文件。
讀者節(jié)省時(shí)間可以下載,鏈接: https://pan.baidu.com/s/1vCBeHNR6DEGSQQDvA7yQOw 密碼: j49q
下載文件是單個(gè)文本文件壓縮的zip文件,文件大小為50M。
壓縮的zip文件解壓后的文本文件大小為118M。
載入分詞文件的代碼如下:

with open('cutWords_list.txt') as file:
    cutWords_list = [k.split() for k in file.readlines()]

3.TfidfVectorizer模型

調(diào)用sklearn.feature_extraction.text庫的TfidfVectorizer方法實(shí)例化模型對(duì)象。
TfidfVectorizer方法需要4個(gè)參數(shù)。
第1個(gè)參數(shù)是分詞結(jié)果,數(shù)據(jù)類型為列表,其中的元素也為列表;
第2個(gè)關(guān)鍵字參數(shù)stop_words是停頓詞,數(shù)據(jù)類型為列表;
第3個(gè)關(guān)鍵字參數(shù)min_df是詞頻低于此值則忽略,數(shù)據(jù)類型為int或float;
第4個(gè)關(guān)鍵字參數(shù)max_df是詞頻高于此值則忽略,數(shù)據(jù)類型為Int或float。
查看TfidfVectorizer方法的更多參數(shù)用法,官方文檔鏈接:http://sklearn.apachecn.org/cn/0.19.0/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html

from sklearn.feature_extraction.text import TfidfVectorizer

tfidf = TfidfVectorizer(cutWords_list, stop_words=stopWord_list, min_df=40, max_df=0.3)

4.特征工程

程序運(yùn)行時(shí)占電腦內(nèi)存的情況如下圖所示:


image.png

從上圖可以看出,此程序占3384MB內(nèi)存,所以電腦需要較高的內(nèi)存配置,
第1行代碼查看向量化的維數(shù),即特征的維數(shù);
第2行代碼調(diào)用TfidfVectorizer對(duì)象的fit_transform方法獲得特征矩陣賦值給X;
第3行代碼查看特征矩陣的形狀。

X = tfidf.fit_transform(train_df[1])
print('詞表大小:', len(tfidf.vocabulary_))
print(X.shape)

上面一段代碼的運(yùn)行結(jié)果如下:

詞表大小: 3946
(24000, 3946)

5.模型訓(xùn)練

5.1 標(biāo)簽編碼

調(diào)用sklearn.preprocessing庫的LabelEncoder方法對(duì)文章分類標(biāo)簽編碼。
最后一行代碼查看預(yù)測目標(biāo)的形狀。

from sklearn.preprocessing import LabelEncoder
import pandas as pd

train_df = pd.read_csv('sohu_train.txt', sep='\t', header=None)
labelEncoder = LabelEncoder()
y = labelEncoder.fit_transform(train_df[0])
y.shape

5.2 邏輯回歸模型

調(diào)用sklearn.linear_model庫的LogisticRegression方法實(shí)例化模型對(duì)象。
調(diào)用sklearn.model_selection庫的train_test_split方法劃分訓(xùn)練集和測試集。

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.2)
logistic_model = LogisticRegression(multi_class='multinomial', solver='lbfgs')
logistic_model.fit(train_X, train_y)
logistic_model.score(test_X, test_y)

上面一段代碼的運(yùn)行結(jié)果如下:

0.8754166666666666

5.3 保存模型

保存模型需要先安裝pickle庫,安裝命令:pip install pickle
調(diào)用pickle庫的dump方法保存模型,需要2個(gè)參數(shù)。
第1個(gè)參數(shù)是保存的對(duì)象,可以為任意數(shù)據(jù)類型,因?yàn)橛?個(gè)模型需要保存,所以下面代碼第1個(gè)參數(shù)是字典。
第2個(gè)參數(shù)是保存的文件對(duì)象,數(shù)據(jù)類型為_io.BufferedWriter

import pickle

with open('tfidf.model', 'wb') as file:
    save = {
        'labelEncoder' : labelEncoder,
        'tfidfVectorizer' : tfidf,
        'logistic_model' : logistic_model
    }
    pickle.dump(save, file)

本文作者提供自己完成的模型持久化文件,下載鏈接: https://pan.baidu.com/s/1JIA_E-S3PotAGY4oLqy93w 密碼: e3yk
壓縮文件大?。?88.8M
解壓后的模型文件大?。?98.9M

5.4 交叉驗(yàn)證

在進(jìn)行此步的時(shí)候,不需要運(yùn)行此步之前的所有步驟,即可以重新運(yùn)行jupyter notebook。
調(diào)用pickle庫的load方法加載保存的模型對(duì)象,代碼如下:

import pickle

with open('tfidf.model', 'rb') as file:
    tfidf_model = pickle.load(file)
    tfidfVectorizer = tfidf_model['tfidfVectorizer']
    labelEncoder = tfidf_model['labelEncoder']
    logistic_model = tfidf_model['logistic_model']

調(diào)用pandas的read_csv方法加載訓(xùn)練集數(shù)據(jù)。
調(diào)用TfidfVectorizer對(duì)象的transform方法獲得特征矩陣。
調(diào)用LabelEncoder對(duì)象的transform方法獲得預(yù)測目標(biāo)值。
代碼如下:

import pandas as pd

train_df = pd.read_csv('sohu_train.txt', sep='\t', header=None)
X = tfidfVectorizer.transform(train_df[1])
y = labelEncoder.transform(train_df[0])

調(diào)用sklearn.linear_model庫的LogisticRegression方法實(shí)例化邏輯回歸模型對(duì)象。
調(diào)用sklearn.model_selection庫的ShuffleSplit方法實(shí)例化交叉驗(yàn)證對(duì)象。
調(diào)用sklearn.model_selection庫的cross_val_score方法獲得交叉驗(yàn)證每一次的得分。
最后打印每一次的得分以及平均分,代碼如下:

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import ShuffleSplit
from sklearn.model_selection import cross_val_score

logistic_model = LogisticRegression(multi_class='multinomial', solver='lbfgs')
cv_split = ShuffleSplit(n_splits=5, test_size=0.3)
score_ndarray = cross_val_score(logistic_model, X, y, cv=cv_split)
print(score_ndarray)
print(score_ndarray.mean())

上面一段代碼的運(yùn)行結(jié)果如下:

[0.86819444 0.87430556 0.86861111 0.87 0.87430556]
0.8710833333333333

6.模型評(píng)估

繪制混淆矩陣,代碼如下:

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegressionCV
from sklearn.metrics import confusion_matrix
import pandas as pd

train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.2)
logistic_model = LogisticRegressionCV(multi_class='multinomial', solver='lbfgs')
logistic_model.fit(train_X, train_y)
predict_y = logistic_model.predict(test_X)
pd.DataFrame(confusion_matrix(test_y, predict_y), 
             columns=labelEncoder.classes_, 
             index=labelEncoder.classes_)

上面一段代碼的運(yùn)行結(jié)果如下圖所示:


image.png

繪制precision、recall、f1-score、support報(bào)告表,代碼如下:

import numpy as np
from sklearn.metrics import precision_recall_fscore_support

def eval_model(y_true, y_pred, labels):
    # 計(jì)算每個(gè)分類的Precision, Recall, f1, support
    p, r, f1, s = precision_recall_fscore_support(y_true, y_pred)
    # 計(jì)算總體的平均Precision, Recall, f1, support
    tot_p = np.average(p, weights=s)
    tot_r = np.average(r, weights=s)
    tot_f1 = np.average(f1, weights=s)
    tot_s = np.sum(s)
    res1 = pd.DataFrame({
        u'Label': labels,
        u'Precision': p,
        u'Recall': r,
        u'F1': f1,
        u'Support': s
    })
    res2 = pd.DataFrame({
        u'Label': ['總體'],
        u'Precision': [tot_p],
        u'Recall': [tot_r],
        u'F1': [tot_f1],
        u'Support': [tot_s]
    })
    res2.index = [999]
    res = pd.concat([res1, res2])
    return res[['Label', 'Precision', 'Recall', 'F1', 'Support']]

predict_y = logistic_model.predict(test_X)
eval_model(test_y, predict_y, labelEncoder.classes_)

上面一段代碼的運(yùn)行結(jié)果如下圖所示:


image.png

7.模型測試

模型測試,即對(duì)一個(gè)全新的測試集進(jìn)行預(yù)測。
調(diào)用pandas庫的read_csv方法讀取測試集文件。
調(diào)用TfidfVectorizer對(duì)象的transform方法獲得特征矩陣。
調(diào)用LabelEncoder對(duì)象的transform方法獲得預(yù)測目標(biāo)值。
下面一段代碼能夠成功運(yùn)行的前提,是本文第5.4節(jié)和第6節(jié)已經(jīng)運(yùn)行。

import pandas as pd

test_df = pd.read_csv('sohu_test.txt', sep='\t', header=None)
test_X = tfidfVectorizer.transform(test_df[1])
test_y = labelEncoder.transform(test_df[0])
predict_y = logistic_model.predict(test_X)
eval_model(test_y, predict_y, labelEncoder.classes_)

上面一段代碼的運(yùn)行結(jié)果如下圖所示:


模型測試結(jié)果.png

8.結(jié)論

本文是作者第2個(gè)NLP小型項(xiàng)目,訓(xùn)練集數(shù)據(jù)共有24000條,測試集數(shù)據(jù)共有12000條。
經(jīng)過交叉驗(yàn)證,模型平均得分為0.8711。
模型評(píng)估時(shí),使用LogisticRegressionCV模型,得分提高了3%,為0.9076。
最后在測試集上的f1-score指標(biāo)為0.8990,總體來說這個(gè)分類模型較優(yōu)秀,能夠投入實(shí)際應(yīng)用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容