sklearn半監督學習

標籤: 半監督學習html


做者:煉己者
歡迎你們訪問 個人簡書 以及 個人博客
本博客全部內容以學習、研究和分享爲主,如需轉載,請聯繫本人,標明做者和出處,而且是非商業用途,謝謝!
---git

摘要:半監督學習很重要,爲何呢?由於人工標註數據成本過高,如今你們參加比賽的數據都是標註好的了,那麼若是老闆給你一份沒有標註的數據,並且有幾百萬條,讓你作個分類什麼的,你怎麼辦?不可能等標註好數據再去訓練模型吧,因此你得會半監督學習算法。算法

不過我在這裏先打擊你們一下,用sklearn的包作不了大數據量的半監督學習,我用的數據量大概在15000條以上就要報MemoryError錯誤了,這個是我最討厭的錯誤。暫時我尚未解決的辦法,若是同志們是小數據量,那就用這個作着玩玩吧。你們若是有興趣也能夠看一下這篇文章——用半監督算法作文本分類apache

報MemoryError錯誤怎麼辦?sklearn提供這麼全的文檔固然會有這部分的考慮啦。看這裏——sklearn 中的模型對於大數據集的處理。能夠用partial_fit增量式計算,惋惜只針對部分算法,對於半監督學習沒有辦法。數組

好了,該說正題了,最近看了sklearn關於半監督學習的例子,它裏面有三個例子,在這裏我主要想分享一下第三個例子——用半監督學習算法作數字識別dom


一. 數據集的解讀

首先咱們來看一下這份數據集的特色
煉己者函數

煉己者

二. 代碼的解讀

sklearn官方例子——用半監督學習作數字識別學習

咱們來看一下操做流程測試

  • 一共330個點,都是已經標註好的了,咱們把其中的320個點賦值爲-1,這樣就能夠僞裝這320個點都是沒有標註的了
  • 訓練一個只有10個標記點的標籤傳播模型
  • 而後從全部數據中選擇要標記的前五個最不肯定的點,把它們(帶有正確標籤)放到原來的10個點中
  • 接下來能夠訓練15個標記點(原始10個 + 5個新點)
  • 重複這個過程四次,就可使用30個標記好的點來訓練模型
  • 能夠經過改變max_iterations將這個值增長到30以上

以上是sklearn的操做流程,你們可能會有點糊塗
實際任務應該是這樣的。假設咱們有一份數據集,共330個數字,其中前十個是已知的,已經標註好了,後320個是未知的,須要咱們預測出來的。大數據

  • 首先把這330個數據所有都放到半監督學習算法裏,訓練模型,預測那320個標籤
  • 而後用某種方法(看下面代碼的操做)得知這320個數據裏最不肯定的前5個數據,對它進行人工標註,而後把它放到以前的10個數據裏,如今就有15個已知數據了
  • 這樣循環個幾回,已標註的數據就變多了,那麼分類器的效果確定也就變好了

1.導入各類數據包

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
from sklearn import datasets
from sklearn.semi_supervised import label_propagation
from sklearn.metrics import classification_report,confusion_matrix

# 再加下面這個,否則會報錯
from scipy.sparse.csgraph import *

2.讀取數據集

digits = datasets.load_digits()
rng = np.random.RandomState(0)
# indices是隨機產生的0-1796個數字,且打亂
indices = np.arange(len(digits.data))
rng.shuffle(indices)

# 取前330個數字來玩
X = digits.data[indices[:330]]
y = digits.target[indices[:330]]
images = digits.images[indices[:330]]

n_total_samples = len(y) # 330
n_labeled_points = 10 # 標註好的數據共10條
max_iterations = 5 # 迭代5次

unlabeled_indices = np.arange(n_total_samples)[n_labeled_points:] # 未標註的數據320條
f = plt.figure() # 畫圖用的

3. 訓練模型且畫圖

建議你們把本身不懂的地方打印出來看看是啥意思,好比下面

for i in range(max_iterations):
    if len(unlabeled_indices) == 0:
        print("no unlabeled items left to label") # 沒有未標記的標籤了,所有標註好了
        break
    y_train = np.copy(y)
    y_train[unlabeled_indices] = -1 #把未標註的數據所有標記爲-1,也就是後320條數據
    
    lp_model = label_propagation.LabelSpreading(gamma=0.25,max_iter=5) # 訓練模型
    lp_model.fit(X,y_train)
    
    predicted_labels = lp_model.transduction_[unlabeled_indices] # 預測的標籤
    true_labels = y[unlabeled_indices] # 真實的標籤
    
    cm = confusion_matrix(true_labels,predicted_labels,
                         labels = lp_model.classes_)
    
    print("預測標籤")
    print(predicted_labels)
    print("真實標籤")
    print(true_labels)
    print('----------------------------------------------')

經對比發現預測的標籤只有7個類,而非10個類

  • 緣由就是咱們一開始訓練的那10個數據只有7個類,因此預測其餘320條數據的時候只能預測出這7個類
預測標籤
[2 8 6 6 6 6 1 9 5 8 8 2 8 7 7 6 7 9 2 9 7 7 6 8 9 1 8 1 9 1 1 6 7 7 9 9 7
 6 2 1 9 6 7 9 9 9 9 1 6 9 9 2 8 7 2 9 2 6 9 1 8 9 5 1 2 1 2 2 9 7 2 8 6 9
 9 8 7 5 1 2 9 9 8 1 7 7 1 1 6 1 5 9 2 6 8 9 2 1 7 7 9 7 8 9 7 5 8 2 1 9 2
 9 8 1 1 7 9 6 1 5 8 9 9 6 9 9 5 7 9 6 2 8 6 9 6 1 5 1 5 9 9 1 8 9 6 1 8 9
 1 7 6 7 6 5 6 9 8 8 9 8 6 1 9 7 2 6 8 8 6 7 1 9 6 9 9 8 9 8 9 7 7 9 7 8 9
 7 8 9 6 7 5 9 1 7 6 1 9 8 9 9 9 9 2 1 1 2 1 1 1 9 2 1 9 8 7 6 1 8 8 1 6 9
 9 6 9 2 2 9 7 6 1 1 9 7 2 7 8 6 6 7 5 2 8 7 2 7 9 5 7 9 9 2 6 5 9 7 1 8 8
 9 8 6 7 6 9 2 6 1 8 8 1 6 7 5 2 1 5 8 2 1 6 9 1 5 7 9 1 6 2 9 9 1 2 2 9 9
 6 9 7 2 9 7 5 8 6 7 8 2 8 7 9 7 2 6 5 1 5 1 9 8]
真實標籤
[2 8 6 6 6 6 1 0 5 8 8 7 8 4 7 5 4 9 2 9 4 7 6 8 9 4 3 1 0 1 8 6 7 7 1 0 7
 6 2 1 9 6 7 9 0 0 5 1 6 3 0 2 3 4 1 9 2 6 9 1 8 3 5 1 2 8 2 2 9 7 2 3 6 0
 5 3 7 5 1 2 9 9 3 1 7 7 4 8 5 8 5 5 2 5 9 0 7 1 4 7 3 4 8 9 7 9 8 2 6 5 2
 5 8 4 8 7 0 6 1 5 9 9 9 5 9 9 5 7 5 6 2 8 6 9 6 1 5 1 5 9 9 1 5 3 6 1 8 9
 8 7 6 7 6 5 6 0 8 8 9 8 6 1 0 4 1 6 3 8 6 7 4 5 6 3 0 3 3 3 0 7 7 5 7 8 0
 7 8 9 6 4 5 0 1 4 6 4 3 3 0 9 5 9 2 1 4 2 1 6 8 9 2 4 9 3 7 6 2 3 3 1 6 9
 3 6 3 2 2 0 7 6 1 1 9 7 2 7 8 5 5 7 5 2 3 7 2 7 5 5 7 0 9 1 6 5 9 7 4 3 8
 0 3 6 4 6 3 2 6 8 8 8 4 6 7 5 2 4 5 3 2 4 6 9 4 5 4 3 4 6 2 9 0 1 7 2 0 9
 6 0 4 2 0 7 9 8 5 4 8 2 8 4 3 7 2 6 9 1 5 1 0 8]
----------------------------------------------

3.1 完整代碼

for i in range(max_iterations):
    if len(unlabeled_indices) == 0:
        print("no unlabeled items left to label") # 沒有未標記的標籤了,所有標註好了
        break
    y_train = np.copy(y)
    y_train[unlabeled_indices] = -1 #把未標註的數據所有標記爲-1,也就是後320條數據
    
    lp_model = label_propagation.LabelSpreading(gamma=0.25,max_iter=5) # 訓練模型
    lp_model.fit(X,y_train)
    
    predicted_labels = lp_model.transduction_[unlabeled_indices] # 預測的標籤
    true_labels = y[unlabeled_indices] # 真實的標籤
    
    cm = confusion_matrix(true_labels,predicted_labels,
                         labels = lp_model.classes_)
    
    print("iteration %i %s" % (i,70 * "_")) # 打印迭代次數
    print("Label Spreading model: %d labeled & %d unlabeled (%d total)"
         % (n_labeled_points,n_total_samples-n_labeled_points,n_total_samples))
    
    print(classification_report(true_labels,predicted_labels))
    
    print("Confusion matrix")
    print(cm)
    
    # 計算轉換標籤分佈的熵
    # lp_model.label_distributions_做用是Categorical distribution for each item
    pred_entropies = stats.distributions.entropy(
    lp_model.label_distributions_.T)
    
    # 選擇分類器最不肯定的前5位數字的索引
    # 首先計算出全部的熵,也就是不肯定性,而後從320箇中選擇出前5個熵最大的
    # numpy.argsort(A)提取排序後各元素在原來數組中的索引。具體狀況可看下面
    #  np.in1d 用於測試一個數組中的值在另外一個數組中的成員資格,返回一個布爾型數組。具體狀況可看下面
    uncertainty_index = np.argsort(pred_entropies)[::1]
    uncertainty_index = uncertainty_index[
        np.in1d(uncertainty_index,unlabeled_indices)][:5] # 這邊能夠肯定每次選前幾個做爲不肯定的數,最終都會加回到訓練集
    
    # 跟蹤咱們得到標籤的索引
    delete_indices = np.array([])
    
    # 可視化前5次的結果
    if i < 5:
        f.text(.05,(1 - (i + 1) * .183),
              'model %d\n\nfit with\n%d labels' %
              ((i + 1),i*5+10),size=10)
    for index,image_index in enumerate(uncertainty_index):
        # image_index是前5個不肯定標籤
        # index就是0-4
        image = images[image_index]

        # 可視化前5次的結果
        if i < 5:
            sub = f.add_subplot(5,5,index + 1 + (5*i))
            sub.imshow(image,cmap=plt.cm.gray_r)
            sub.set_title("predict:%i\ntrue: %i" % (
                lp_model.transduction_[image_index],y[image_index]),size=10)
            sub.axis('off')
        
        # 從320條裏刪除要那5個不肯定的點
        # np.where裏面的參數是條件,返回的是知足條件的索引
        delete_index, = np.where(unlabeled_indices == image_index)
        delete_indices = np.concatenate((delete_indices,delete_index))
        
    unlabeled_indices = np.delete(unlabeled_indices,delete_indices)
    # n_labeled_points是前面不肯定的點有多少個被標註了
    n_labeled_points += len(uncertainty_index)
    
f.suptitle("Active learning with label propagation.\nRows show 5 most"
          "uncertain labels to learn with the next model")
plt.subplots_adjust(0.12,0.03,0.9,0.8,0.2,0.45)
plt.show()

3.2 numpy.argsort()函數

  • 提取排序後各元素在原來數組中的索引
import numpy as np
B=np.array([[4,2,3,55],[5,6,37,8],[-7,68,9,0]])
print('B:')
print(B)

print('')
print('默認輸出')
print(np.argsort(B))#默認的輸出每行元素的索引值。這些索引值對應的元素是從小到大排序的。

看打印的結果

B:
[[ 4  2  3 55]
 [ 5  6 37  8]
 [-7 68  9  0]]

默認輸出
[[1 2 0 3]
 [0 1 3 2]
 [0 3 2 1]]

3.3 np.in1d() 函數

  • 用於測試一個數組中的值在另外一個數組中的成員資格,返回一個布爾型數組
values = np.array([6, 0, 0, 3, 2, 5, 6])
np.in1d(values, [2, 3, 6])

看打印的結果

array([ True, False, False,  True,  True, False,  True])

三. 總結

此次主要是想用半監督學習算法作NLP文本分類,看到sklearn庫里正好有這個算法包,想拿來試一下,結果跑不了那麼大的數據量,算是失敗了。可是我以爲仍是從中瞭解了不少,後面會寫一篇關於它的博客,裏面關於文本的處理讓我學到了不少,走了不少的彎路。接下來我還會繼續探索怎麼用少標註的數據來作文本分類。

相關文章
相關標籤/搜索