自然語言處理中一個(gè)很常見的操作就是文本分類,比如一組新聞文本,通過分類模型,將新聞文本分為政治、體育、軍事、娛樂、財(cái)經(jīng)等等幾大類。那么分類第一步就是文本向量化,前一篇博客講了一些,本文可以說是前文的實(shí)踐版本。本文主要介紹一些常見的文本分類模型,說是介紹,其實(shí)主要以代碼和結(jié)果為主,并不會(huì)詳細(xì)的介紹每個(gè)算法的思想、原理、推導(dǎo)過程等,那樣的話,估計(jì)可以寫一個(gè)7、8篇的系列了,另外我也發(fā)現(xiàn)很多博客都是理論為主,代碼非常少,給人的感覺就是這件事我弄明白了,但具體如何干不知道,講的似乎很難、很神秘,沒有相應(yīng)代碼,讓人望而生畏。所以本文還是偏工程一些,閱讀本文的同學(xué)希望已經(jīng)有了這些文本分類算法的理論基礎(chǔ)。先說說我用的數(shù)據(jù),約20萬短文本,包含8個(gè)大類,分別為:餐飲、交通、購物、娛樂、居家等,每個(gè)大類約25000條數(shù)據(jù),文本平均20個(gè)字左右,最短的文本僅有2個(gè)字。如下面所示:
__label__1 天貓 超市 慕滋 五谷 無 添加 糖 粗糧 雜糧 消化 餅干 g 代 早餐 糕點(diǎn)__label__1 天貓 超市 滿 減 云南 紅 提 kg 提子 葡萄 新鮮 水果__label__1 天貓 超市 原裝 進(jìn)口 噓 噓 樂 成長 褲 紙尿褲 拉拉 褲 L19 片 Kg__label__1 天貓 超市 衛(wèi)龍 小 面筋 g 零食 辣條 辣片 麻辣 素食 豆干 制品 大刀 肉__label__1 天貓 超市 康師傅 礦物質(zhì) 水 ml 瓶 整箱 飲用水__label__1 天貓 超市 紅牛 維生素 功能 飲料 整箱 裝 原味 型 ml 罐 箱__label__1 天貓 超市 香楠 蛋羹 味 麻薯 夾心 麻 糬 糕點(diǎn) 休閑 零食 小吃 g__label__1 天貓 超市 蒙牛 特侖蘇 醇 纖 牛奶 ml 盒 平衡 搭檔 平衡 好搭檔__label__1 天貓 超市 味全 每日 C 純 果汁 胡蘿卜 果蔬汁 ml16 截單__label__1 天貓 超市 金 菜地 豆干 五香 茶 干 g 豆腐干 特色 休閑 零食 豆制品__label__1 天貓 超市 新 希望 牛奶 香蕉 牛奶 ml 盒 箱 甜蜜 好 滋味__label__1 天貓 超市 良品 鋪?zhàn)?爆漿 麻薯 抹 茶味 g 糕點(diǎn) 點(diǎn)心 零食 特產(chǎn) 小吃__label__1 天貓 超市 森永 嗨 酸酸 噠 酸果 軟糖 青 檸味 g 維 c 水果 糖果 零食__label__1 天貓 超市 桂格 即食 純 燕麥片 粗糧 原味 沖 飲 谷物 早餐 g 袋裝__label__1 天貓 超市 滿 減 挪威 冰凍 青花魚 柳 g 包 冷凍 海鮮 魚肉 鯖 魚__label__1 天貓 超市 甘 竹牌 豆豉 鯪魚 罐頭 g 盒 下 飯菜 特產(chǎn) 小吃 休閑 食品__label__1 天貓 超市 姚 太太 青口 梅 g 蜜餞 果脯 話梅 肉 梅子 青梅 酸甜 涼果__label__1 天貓 超市 蒙牛 特侖蘇 醇 纖 牛奶 ml 盒 平衡 搭檔 平衡 好搭檔
- import random
- import fasttext
- import numpy as np
- import tensorflow as tf
- from sklearn.svm import SVC
- from sklearn.naive_bayes import MultinomialNB
- from sklearn.neighbors import KNeighborsClassifier
- from sklearn.ensemble import GradientBoostingClassifier
- from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer
- # 樸素貝葉斯算法
- def nb_model(train, train_label, test, test_label):
- clf_model = MultinomialNB(alpha=0.01)
- clf_model.fit(train, train_label)
- predict_results = clf_model.predict(test)
- count = 0
- predict_list = predict_results.tolist()
- for i, pred in enumerate(predict_list):
- if (pred == test_label[i]):
- count += 1
- print("nb_model_precision_score: " + str(float(count) / len(predict_list)))
- # K近鄰算法
- def knn_model(train, train_label, test, test_label):
- knn_model = KNeighborsClassifier(n_neighbors=8)
- knn_model.fit(train, train_label)
- predict_results = knn_model.predict(test)
- count = 0
- predict_list = predict_results.tolist()
- for i, pred in enumerate(predict_list):
- if (pred == test_label[i]):
- count += 1
- print("knn_model_precision_score: " + str(float(count) / len(predict_list)))
- # 支持向量機(jī)算法
- def svm_model(train, train_label, test, test_label):
- svm_clf = SVC(kernel="linear", verbose=False)
- svm_clf.fit(train, train_label)
- predict_results = svm_clf.predict(test)
- count = 0
- predict_list = predict_results.tolist()
- for i, pred in enumerate(predict_list):
- if (pred == test_label[i]):
- count += 1
- print("svm_model_precision_score: " + str(float(count) / len(predict_list)))
- # 使用傳統(tǒng)方法的文本分類
- def text_classification():
- count = 0
- test_text_list = []
- train_text_list = []
- test_label_list = []
- train_label_list = []
- total_text_list = []
- total_label_list = []
- print("start loading data...")
- finput = open("data/filter_total_half.txt", encoding='utf-8')
- for line in finput:
- count += 1
- text_array = line.split("\t", 1)
- if (len(text_array) != 2):
- continue
- # 保存全部樣本
- total_text_list.append(text_array[1])
- total_label_list.append(text_array[0])
- # 劃分訓(xùn)練集和測試集
- probability = random.random()
- if (probability > 0.2):
- train_text_list.append(text_array[1])
- train_label_list.append(text_array[0])
- else:
- test_text_list.append(text_array[1])
- test_label_list.append(text_array[0])
- finput.close()
- print("load data is finished...")
- print("start building vector model...")
- # 構(gòu)建詞典
- vec_total = CountVectorizer()
- vec_total.fit_transform(total_text_list)
- # 基于構(gòu)建的詞典分別統(tǒng)計(jì)訓(xùn)練集/測試集詞頻, 即每個(gè)詞出現(xiàn)1次、2次、3次等
- vec_train = CountVectorizer(vocabulary=vec_total.vocabulary_)
- tf_train = vec_train.fit_transform(train_text_list)
- vec_test = CountVectorizer(vocabulary=vec_total.vocabulary_)
- tf_test = vec_test.fit_transform(test_text_list)
- # 進(jìn)一步計(jì)算詞頻-逆文檔頻率
- tfidftransformer = TfidfTransformer()
- tfidf_train = tfidftransformer.fit(tf_train).transform(tf_train)
- tfidf_test = tfidftransformer.fit(tf_test).transform(tf_test)
- print("building vector model is finished...")
- # 樸素貝葉斯算法
- nb_model(tfidf_train, train_label_list, tfidf_test, test_label_list)
- # K近鄰算法
- knn_model(tfidf_train, train_label_list, tfidf_test, test_label_list)
- # 支持向量機(jī)算法
- svm_model(tfidf_train, train_label_list, tfidf_test, test_label_list)
- print("building predict model is finished...")
- # 使用fastText的文本分類
- def fastText_model():
- foutput_test = open("data/data_test.txt", 'w', encoding='utf-8')
- foutput_train = open("data/data_train.txt", 'w', encoding='utf-8')
- with open("data/filter_total_half.txt", encoding='utf-8') as finput:
- for line in finput:
- probability = random.random()
- if (probability > 0.2):
- foutput_train.write(line.strip() + "\n")
- else:
- foutput_test.write(line.strip() + "\n")
- foutput_train.flush()
- foutput_train.close()
- foutput_test.flush()
- foutput_test.close()
- classifier = fasttext.supervised("data/data_train.txt", "data/cooking_fasttext_bkk.model",
- label_prefix="__label__", lr=0.25, dim=100,
- silent=False, epoch=25, word_ngrams=3, loss="hs", bucket=2000000)
- result = classifier.test("data/data_test.txt")
- print(result.precision)
- if __name__ == '__main__':
- print("\n傳統(tǒng)方法文本分類...")
- text_classification()
- print("\n----------------------------------------------\n")
- print("FastText文本分類...")
- fastText_model()
程序運(yùn)行結(jié)果如下:
我還寫了一個(gè)基于卷積神經(jīng)網(wǎng)絡(luò)的版本,修改自github,由于公司也有在用,這里就不把代碼貼出來了??傮w看,cnn的準(zhǔn)確度最高,fastText次之。不過基于cnn的方法,需要事先訓(xùn)練詞向量,訓(xùn)練過程也比較慢。而傳統(tǒng)方法,如svm,準(zhǔn)確度達(dá)0.95,已經(jīng)很高了,從這一點(diǎn)也說明,不管是基于深度學(xué)習(xí)的卷積神經(jīng)網(wǎng)絡(luò)分類方法,還是傳統(tǒng)的分類方法,其實(shí)模型反而是其次,最重要的是數(shù)據(jù)集的質(zhì)量,模型選擇和模型調(diào)參,對最終精度提升都是小幅度的,而數(shù)據(jù)集的質(zhì)量高低則是精度提升的瓶頸,有時(shí)真得不怕麻煩,整理出一份高質(zhì)量的數(shù)據(jù)集,才能訓(xùn)練出精度更準(zhǔn)、召回更高的模型??吹竭@里,是不是很多同學(xué)覺得文本分類其實(shí)沒什么神秘的,有現(xiàn)成的訓(xùn)練框架使用,如:sklearn,還有那么多文獻(xiàn)資料可供查閱,唯獨(dú)沒有適合自己業(yè)務(wù)的訓(xùn)練集,整理訓(xùn)練集,這可能是整個(gè)模型訓(xùn)練過程中最花時(shí)間的事情了。當(dāng)然,這里面也涉及很多模型調(diào)參細(xì)節(jié),需要深入算法原理才能真正玩轉(zhuǎn)。
聯(lián)系客服