輸入
輸入1:
本文章采用“python實現中文文檔jieba分詞和分詞結果寫入excel文件”文章中輸出的兩個關於正面中文評價、負面中文評價的excel表格作為輸入。
輸入2:
一些文檔分詞后得到的字符串列表。
輸出
輸出1:根據輸入1,訓練得到的邏輯回歸模型。
輸出2:根據輸入2和輸出1得到的模型,得到對應的預測結果(正類or負類)
工具
本文使用工具為:Anaconda、PyCharm、python語言、sklearn
原理
TF-IDF 是在詞袋方法上的一種擴展,它表示詞頻-逆文檔頻率。TF-IDF的思想主要為以下兩點:在一篇文本中反復出現的詞會更重要,在所有文本中都出現的詞不重要。這兩點分別對應IT和IDF:
- TF(Term Freguency,詞頻)是某一個詞在文本中出現的次數,對於某個文本d中的某個詞w而言,詞w在文本d中的詞頻記為TF(w,d)。
- IDF(Inverse Document Freguency,逆文檔頻率指數)是已有的文本總數除以某一個詞在已有的文本集合中出現的次數。假設總文本數為N,詞w出現的文本數為n,那么詞w在文檔集合中的逆文檔頻率IDF(w) = N/n,也可記為對數形式IDF(w) = log(N/n)。對於一個給定的文本集合,每個詞的逆文本頻率是可以提前統計好的。
TF-IDF就是IF和IDF兩者相乘:TF-IDF(w,d) = TF(w,d) * IDF(w)
以上就是關於TF-IDF的原理介紹。本文采用sklearn包中的TF-IDF工具組件對輸入的數據表格進行操作,得到詞頻-逆文檔頻率矩陣。然后采用sklearn包自帶的邏輯回歸模型進行訓練,通過網格搜索的方式得到最優的正則化參數,通過k折交叉驗證方法減少模型的方差,提高模型對數據的普遍適應性。
Python代碼實現
1 # 從txt生成的excel文件,一定要另存為csv文件,然后再用read_csv讀取,不然會遇到一些格式的問題 2 import pandas as pd 3 import numpy as np 4 f = open('neg_fenci_excel_to_csv.csv') 5 neg_pd = pd.read_csv(f) 6 f.close() 7 8 f = open('pos_fenci_excel_to_csv.csv') 9 pos_pd = pd.read_csv(f) 10 f.close() 11 12 # 連接neg_pd和pos_pd 13 neg_pos_pd = pd.concat([neg_pd, pos_pd], axis=0) 14 neg_pos_pd.to_csv('neg_pos.csv') 15 16 # 划分訓練集、測試集,比例為70%、30% 17 from sklearn.model_selection import train_test_split 18 x_train, x_test, y_train, y_test = train_test_split(neg_pos_pd['review'], neg_pos_pd['label'], test_size = 0.3) 19 20 from sklearn.feature_extraction.text import CountVectorizer 21 from sklearn.feature_extraction.text import TfidfVectorizer 22 from sklearn.feature_extraction.text import TfidfTransformer 23 # fit_transform相當於先fit,再transform 24 # fit入參為訓練數據集(文檔集合),得到詞典 25 # transform 入參為文檔集合,通過fit得到的詞典,得到詞頻矩陣 26 27 #構建詞頻矩陣 28 countVec = CountVectorizer() 29 countVec_bow = countVec.fit_transform(x_train) 30 # countVec 中有一些關於詞典的屬性 31 print('countVec_bow get_feature_names len:{}'.format(len(countVec.get_feature_names()))) 32 print('countVec_bow vocabulary_:\n{}'.format(countVec.vocabulary_)) 33 print('countVec_bow get_feature_names :{}'.format(countVec.get_feature_names())) 34 # 構建詞頻矩陣,轉成矩陣形式 35 # 矩陣元素a[i][j] 表示j詞在第i個文本下的詞頻 36 print('countVec_bow array:\n{}'.format(countVec_bow.toarray())) 37 38 # 兩種得到詞頻-逆文檔頻率矩陣的方法 39 # 經過詞頻矩陣得到詞頻-逆文檔頻率矩陣 40 tfidf_test = TfidfTransformer() 41 tfidf_test_bow = tfidf_test.fit_transform(countVec_bow) 42 print('tfidf_test_bow array:\n{}'.format(tfidf_test_bow)) 43 # 通過原始文檔,直接得到詞頻-逆文檔頻率矩陣 44 tfidf = TfidfVectorizer() 45 tfidf_bow = tfidf.fit_transform(x_train) 46 print('tfidf_bow array:\n{}'.format(tfidf_bow)) 47 48 import sklearn.model_selection as modsel 49 from sklearn.linear_model import LogisticRegression 50 # 搜索網格的范圍(網格搜索:一種基本的超參數調優過程) 51 param_grid = {'C' : [1e-5, 1e-3, 1e-1, 1e0, 1e1, 1e2]} 52 # 采用10折交叉驗證 53 tfidf_search = modsel.GridSearchCV(LogisticRegression(), cv=10, param_grid=param_grid) 54 tfidf_search.fit(tfidf_bow, y_train) 55 print('result:\n{}'.format(tfidf_search.cv_results_)) 56 # 通過cv_results_中的結果,選擇正則化參數為1e0 57 result_model = LogisticRegression(C=1e0).fit(tfidf_bow, y_train) 58 tfidf_x_test = tfidf.transform(x_test) 59 score = result_model.score(tfidf_x_test, y_test) 60 print('score:{}'.format(score)) 61 62 def model_test(model, strList): 63 strList_to_tfidf = tfidf.transform(strList) 64 print('strList_to_tfidf:{}'.format(strList_to_tfidf.toarray().shape)) 65 probaList = model.predict_proba(strList_to_tfidf) 66 print('probaList:\n{}'.format(probaList)) 67 # 6條測試用例,已知前3條為負例,后3條為正例 68 testList = ['商品 划花 忍受 京東 配送 實在 氣憤', 69 '驅動 系統 安裝 光盤 帶來 不便 最讓人 感到 氣憤 硬盤 分區 廠家 做法 未免太 懶惰 太 不負責任', 70 '操作系統 裸機 分成 盤 重裝 acer 光盤 重裝 專用 軟件 網站 找到 美中不足', 71 '優點 外觀 夠 型 配置 不錯 價格合理 非常適合 商務 光驅 聲音 真的 很大 底部 發熱量 很大 特價 4999 價格 購買 超值 值得', 72 '商品 值得一提 性價比 hp 品牌 P8600 CPU 足夠 升級 太 便宜 做工 價位 不錯 IBM T23 X41 距離 價位 整體 不錯 京東 服務 不錯 網上 快遞 進程 客戶 有譜', 73 '幾天 終於 拿到 配置 品牌 令人滿意 商務 選擇'] 74 75 model_test(result_model, testList)
代碼運行結果
模型准確率為:score:0.8875
6條測試用例的測試結果為:
probaList:
[[0.83668722 0.16331278]
[0.80493181 0.19506819]
[0.84483608 0.15516392]
[0.08431679 0.91568321]
[0.03640066 0.96359934]
[0.15293085 0.84706915]]
可以看到前3條為負例的概率大於0.5,后3條為正例的概率大於0.5。所以這6條測試用例預測的都是准確的。