做者|Doug Steen
編譯|VK
來源|Towards Data Sciencepython
當涉及到機器學習分類任務時,用於訓練算法的數據越多越好。在監督學習中,這些數據必須根據目標類進行標記,不然,這些算法將沒法學習獨立變量和目標變量之間的關係。可是,在構建用於分類的大型標記數據集時,會出現兩個問題:算法
那麼,這些未標記的數據能夠用在分類算法中嗎?併發
這就是半監督學習的用武之地。在半監督方法中,咱們能夠在少許的標記數據上訓練分類器,而後使用該分類器對未標記的數據進行預測。機器學習
因爲這些預測可能比隨機猜想更好,未標記的數據預測能夠做爲「僞標籤」在隨後的分類器迭代中採用。雖然半監督學習有不少種風格,但這種特殊的技術稱爲自訓練。函數
在概念層面上,自訓練的工做原理以下:性能
步驟1:將標記的數據實例拆分爲訓練集和測試集。而後,對標記的訓練數據訓練一個分類算法。學習
步驟2:使用通過訓練的分類器來預測全部未標記數據實例的類標籤。在這些預測的類標籤中,正確率最高的被認爲是「僞標籤」。測試
(第2步的幾個變化:a)全部預測的標籤能夠同時做爲「僞標籤」使用,而不考慮機率;或者b)「僞標籤」數據能夠經過預測的置信度進行加權。)編碼
步驟3:將「僞標記」數據與正確標記的訓練數據鏈接起來。在組合的「僞標記」和正確標記訓練數據上從新訓練分類器。.net
步驟4:使用通過訓練的分類器來預測已標記的測試數據實例的類標籤。使用你選擇的度量來評估分類器性能。
(能夠重複步驟1到4,直到步驟2中的預測類標籤再也不知足特定的機率閾值,或者直到沒有更多未標記的數據保留。)
好的,明白了嗎?很好!讓咱們經過一個例子解釋。
爲了演示自訓練,我使用Python和surgical_deepnet 數據集,能夠在Kaggle上找到:https://www.kaggle.com/omnamahshivai/surgical-dataset-binary-classification
此數據集用於二分類,包含14.6k+手術的數據。這些屬性是bmi、年齡等各類測量值,而目標變量complexing則記錄患者是否因手術而出現併發症。顯然,可以準確地預測患者是否會因手術而出現併發症,這對醫療保健和保險供應商都是最有利的。
導入庫
對於本教程,我將導入numpy、pandas和matplotlib。我還將使用sklearn中的LogisticRegression分類器,以及用於模型評估的f1_score和plot_confusion_matrix 函數
import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.linear_model import LogisticRegression from sklearn.metrics import f1_score from sklearn.metrics import plot_confusion_matrix
加載數據
# 加載數據 df = pd.read_csv('surgical_deepnet.csv') df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 14635 entries, 0 to 14634 Data columns (total 25 columns): bmi 14635 non-null float64 Age 14635 non-null float64 asa_status 14635 non-null int64 baseline_cancer 14635 non-null int64 baseline_charlson 14635 non-null int64 baseline_cvd 14635 non-null int64 baseline_dementia 14635 non-null int64 baseline_diabetes 14635 non-null int64 baseline_digestive 14635 non-null int64 baseline_osteoart 14635 non-null int64 baseline_psych 14635 non-null int64 baseline_pulmonary 14635 non-null int64 ahrq_ccs 14635 non-null int64 ccsComplicationRate 14635 non-null float64 ccsMort30Rate 14635 non-null float64 complication_rsi 14635 non-null float64 dow 14635 non-null int64 gender 14635 non-null int64 hour 14635 non-null float64 month 14635 non-null int64 moonphase 14635 non-null int64 mort30 14635 non-null int64 mortality_rsi 14635 non-null float64 race 14635 non-null int64 complication 14635 non-null int64 dtypes: float64(7), int64(18) memory usage: 2.8 MB
數據集中的屬性都是數值型的,沒有缺失值。因爲我這裏的重點不是數據清理,因此我將繼續對數據進行劃分。
數據劃分
爲了測試自訓練的效果,我須要將數據分紅三部分:訓練集、測試集和未標記集。我將按如下比例拆分數據:
對於未標記集,我將簡單地放棄目標變量complexing,並僞裝它從未存在過。
因此,在這個病例中,咱們認爲74%的手術病例沒有關於併發症的信息。我這樣作是爲了模擬這樣一個事實:在實際的分類問題中,可用的大部分數據可能沒有類標籤。然而,若是咱們有一小部分數據的類標籤(在本例中爲1%),那麼可使用半監督學習技術從未標記的數據中得出結論。
下面,我隨機化數據,生成索引來劃分數據,而後建立測試、訓練和未標記的劃分。而後我檢查各個集的大小,確保一切都按計劃進行。
X_train dimensions: (146, 24) y_train dimensions: (146,) X_test dimensions: (3659, 24) y_test dimensions: (3659,) X_unlabeled dimensions: (10830, 24)
類分佈
多數類的樣本數((併發症))是少數類(併發症)的兩倍多。在這樣一個不平衡的類的狀況下,我想準確度可能不是最佳的評估指標。
選擇F1分數做爲分類指標來判斷分類器的有效性。F1分數對類別不平衡的影響比準確度更爲穩健,當類別近似平衡時,這一點更爲合適。F1得分計算以下:
其中precision是預測正例中正確預測的比例,recall是真實正例中正確預測的比例。
初始分類器(監督)
爲了使半監督學習的結果更真實,我首先使用標記的訓練數據訓練一個簡單的Logistic迴歸分類器,並對測試數據集進行預測。
Train f1 Score: 0.5846153846153846 Test f1 Score: 0.5002908667830134
分類器的F1分數爲0.5。混淆矩陣告訴咱們,分類器能夠很好地預測沒有併發症的手術,準確率爲86%。然而,分類器更難正確識別有併發症的手術,準確率只有47%。
預測機率
對於自訓練算法,咱們須要知道Logistic迴歸分類器預測的機率。幸運的是,sklearn提供了.predict_proba()方法,它容許咱們查看屬於任一類的預測的機率。以下所示,在二元分類問題中,每一個預測的總機率總和爲1.0。
array([[0.93931367, 0.06068633], [0.2327203 , 0.7672797 ], [0.93931367, 0.06068633], ..., [0.61940353, 0.38059647], [0.41240068, 0.58759932], [0.24306008, 0.75693992]])
自訓練分類器(半監督)
既然咱們知道了如何使用sklearn得到預測機率,咱們能夠繼續編碼自訓練分類器。如下是簡要概述:
第1步:首先,在標記的訓練數據上訓練Logistic迴歸分類器。
第2步:接下來,使用分類器預測全部未標記數據的標籤,以及這些預測的機率。在這種狀況下,我只對機率大於99%的預測採用「僞標籤」。
第3步:將「僞標記」數據與標記的訓練數據鏈接起來,並在鏈接的數據上從新訓練分類器。
第4步:使用訓練好的分類器對標記的測試數據進行預測,並對分類器進行評估。
重複步驟1到4,直到沒有更多的預測具備大於99%的機率,或者沒有未標記的數據保留。
下面的代碼使用while循環在Python中實現這些步驟。
Iteration 0 Train f1: 0.5846153846153846 Test f1: 0.5002908667830134 Now predicting labels for unlabeled data... 42 high-probability predictions added to training data. 10788 unlabeled instances remaining. Iteration 1 Train f1: 0.7627118644067796 Test f1: 0.5037463976945246 Now predicting labels for unlabeled data... 30 high-probability predictions added to training data. 10758 unlabeled instances remaining. Iteration 2 Train f1: 0.8181818181818182 Test f1: 0.505431675242996 Now predicting labels for unlabeled data... 20 high-probability predictions added to training data. 10738 unlabeled instances remaining. Iteration 3 Train f1: 0.847457627118644 Test f1: 0.5076835515082526 Now predicting labels for unlabeled data... 21 high-probability predictions added to training data. 10717 unlabeled instances remaining. ... Iteration 44 Train f1: 0.9481216457960644 Test f1: 0.5259179265658748 Now predicting labels for unlabeled data... 0 high-probability predictions added to training data. 10079 unlabeled instances remaining.
自訓練算法通過44次迭代,就不能以99%的機率預測更多的未標記實例了。即便一開始有10,830個未標記的實例,在自訓練以後仍然有10,079個實例未標記(而且未被分類器使用)。
通過44次迭代,F1的分數從0.50提升到0.525!雖然這只是一個小的增加,但看起來自訓練已經改善了分類器在測試數據集上的性能。上圖的頂部面板顯示,這種改進大部分發生在算法的早期迭代中。一樣,底部面板顯示,添加到訓練數據中的大多數「僞標籤」都是在前20-30次迭代中出現的。
最後的混淆矩陣顯示有併發症的手術分類有所改善,但沒有併發症的手術分類略有降低。有了F1分數的提升,我認爲這是一個能夠接受的進步-可能更重要的是肯定會致使併發症的手術病例(真正例),而且可能值得增長假正例率來達到這個結果。
警告語
因此你可能會想:用這麼多未標記的數據進行自訓練有風險嗎?答案固然是確定的。請記住,儘管咱們將「僞標記」數據與標記的訓練數據一塊兒包含在內,但某些「僞標記」數據確定會不正確。當足夠多的「僞標籤」不正確時,自訓練算法會強化糟糕的分類決策,而分類器的性能實際上會變得更糟。
可使用分類器在訓練期間沒有看到的測試集,或者使用「僞標籤」預測的機率閾值,能夠減輕這種風險。
歡迎關注磐創AI博客站:
http://panchuang.net/
sklearn機器學習中文官方文檔:
http://sklearn123.com/
歡迎關注磐創博客資源彙總站:
http://docs.panchuang.net/