做者:煉己者算法
歡迎你們訪問 個人簡書 以及 個人博客
本博客全部內容以學習、研究和分享爲主,如需轉載,請聯繫本人,標明做者和出處,而且是非商業用途,謝謝!app
摘要:本文主要講述了用半監督算法作文本分類(二分類),主要借鑑了sklearn的一個例子——用半監督算法作數字識別 。先說結論,這是一個失敗的例子,訓練到第15000條就不行了,就報錯了。若是你的數據量不是很大的話,能夠操做一下。這裏面有不少值得學習的地方,尤爲是關於文本的預處理。後續還會更新,把這條路打通。學習
- 一共100萬條數據,標註7000條,剩下的所有標註爲-1
- 對文本進行預處理(jieba分詞,去掉停用詞等操做)
- 用gensim庫將處理好的文本轉爲TFIDF向量
- 利用scipy庫轉換TFIDF向量的格式,使其能夠被sklearn庫的算法包訓練
- 把預處理的數據輸入到模型中進行訓練
- 獲得前500個不肯定的數據,對其進行人工標註,而後再添加回訓練集
- 重複以上過程,直到你的分類器變得好,符合你的要求
前面的jieba分詞,去停用詞的操做我就不說了,比較容易。在這裏就分享一下怎麼把gensim訓練的TFIDF向量轉爲sklearn庫算法包所要求的格式吧。spa
說到這裏,你們確定會問,幹啥這麼麻煩,直接調用sklearn計算TFIDF不就完了。緣由很簡單,一開始我也是這麼幹的,而後報了內存錯誤,當時我猜想是由於向量的維度太大了,由於sklearn計算出來的TFIDF向量每句話的維度達到了30000多維,因此我打算借用gensim來訓練TFIDF向量,它有個好處,就是能夠指定維度的大小。code
那麼如何計算TFIDF向量呢?
你們也能夠看這篇文章——用不一樣的方法計算TFIDF值blog
from gensim import corpora dictionary = corpora.Dictionary(word_list) new_corpus = [dictionary.doc2bow(text) for text in word_list] from gensim import models tfidf = models.TfidfModel(new_corpus) tfidf.save('my_model.tfidf')
tfidf = models.TfidfModel.load('my_model.tfidf') tfidf_vec = [] for i in range(len(words)): string = words[i] string_bow = dictionary.doc2bow(string.split()) string_tfidf = tfidf[string_bow] tfidf_vec.append(string_tfidf)
[[(0, 0.44219328927835233), (1, 0.5488488134902755), (2, 0.28062764931589196), (3, 0.5488488134902755), (4, 0.3510600763648036)], [(5, 0.2952063480959091), (6, 0.3085138762011414), (7, 0.269806482343891), (8, 0.21686460370108193), (9, 0.4621642239026475), (10, 0.5515758504022944), (11, 0.4242816486479956)], ......]
lsi_model = models.LsiModel(corpus = tfidf_vec,id2word = dictionary,num_topics=2) lsi_vec = [] for i in range(len(words)): string = words[i] string_bow = dictionary.doc2bow(string.split()) string_lsi = lsi_model[string_bow] lsi_vec.append(string_lsi)
[[(0, 9.98164139346566e-06), (1, 0.00017488533996265734)], [(0, 0.004624808817003378), (1, 0.0052712355563472625)], [(0, 0.005992863818284904), (1, 0.0028891269605347066)], [(0, 0.008813713819377964), (1, 0.004300294830187425)], [(0, 0.0010709978891676652), (1, 0.004264312831567625)], [(0, 0.005647948200006063), (1, 0.005816420698368305)], [(0, 1.1749284917071102e-05), (1, 0.0003525210498926822)], [(0, 0.05046596444596279), (1, 0.03750969796637345)], [(0, 0.0007876011346475033), (1, 0.008538972615602887)], ......]
from scipy.sparse import csr_matrix data = [] rows = [] cols = [] line_count = 0 for line in lsi_vec: for elem in line: rows.append(line_count) cols.append(elem[0]) data.append(elem[1]) line_count += 1 lsi_sparse_matrix = csr_matrix((data,(rows,cols))) # 稀疏向量 lsi_matrix = lsi_sparse_matrix.toarray() # 密集向量
Out[53]: array([[9.98164139e-06, 1.74885340e-04], [4.62480882e-03, 5.27123556e-03], [5.99286382e-03, 2.88912696e-03], ..., [1.85861559e-02, 3.24888917e-01], [8.07737902e-04, 5.45659458e-03], [2.61926460e-03, 2.30210522e-02]])
import numpy as np import matplotlib.pyplot as plt from scipy import stats from sklearn.semi_supervised import label_propagation y = list(result.label.values) from scipy.sparse.csgraph import * n_total_samples = len(y) # 1571794 n_labeled_points = 7804 # 標註好的數據共10條,只訓練10個帶標籤的數據模型 unlabeled_indices = np.arange(n_total_samples)[n_labeled_points:] # 未標註的數據 lp_model = label_propagation.LabelSpreading() # 訓練模型 lp_model.fit(lsi_matrix,y) predicted_labels = lp_model.transduction_[unlabeled_indices] # 預測的標籤 # 計算被轉換的標籤的分佈的熵 # lp_model.label_distributions_ : array,shape=[n_samples,n_classes] # Categorical distribution for each item pred_entropies = stats.distributions.entropy( lp_model.label_distributions_.T) # 選擇分類器最不肯定的前2000位數字的索引 uncertainty_index = np.argsort(pred_entropies)[::1] uncertainty_index = uncertainty_index[ np.in1d(uncertainty_index,unlabeled_indices)][:2000] print(uncertainty_index)
我最後沒有繼續往下作了,由於個人數據量很大,只能訓練這麼點數據沒有意義,以上即是個人思路,但願會對你們有所幫助,後續我會更新新的方法來操做這個事情索引