一、PU Learning簡介
PU Learning(Positive and Unlabeled Learning)是一個非常強大的半監督學習算法,旨在解決傳統監督學習中的標籤獲取問題。在多數實際的機器學習場景中,由於獲取標籤的成本高昂和難度較大,導致數據集的標籤缺失,而PU Learning可以在真實情況下進行分類,無需手動標註所有樣本。
PU Learning的思想是通過只有正例和未標註樣本的更改,而不是將未標註的樣本視為負例來訓練分類模型。經過二元分類器的訓練和測試,可以自動標註未標註數據的標籤並提高模型的預測準確率。
二、PU Learning 的應用場景
由於 PU Learning 能夠從未標註的數據中學習,提供無窮的數據來源,因此應用領域很廣泛 。PU Learning 主要應用於以下情況:
醫學診斷
欺詐檢測
圖像分類
醫生只有少量的患者確診,但有大量未確診患者的數據,PU Learning可以從未標註數據中預測可能的患者,並為在診斷中提供幫助。
在信用卡和其他在線交易中使用PU Learning可以提高對欺詐行為的識別。在有效使用PU Learning後,可以更好地識別可疑行為和防止欺詐活動。
PU Learning還可以應用於圖像分類問題,其中標記的數據可能相對較少,但未標記的數據量相對較大。PU Learning可以使用未標記的數據來提高分類器的準確性。
三、PU Learning的代碼實現
import numpy as np from sklearn.base import BaseEstimator, ClassifierMixin from sklearn.ensemble import RandomForestClassifier from sklearn.svm import SVC from sklearn.utils import check_X_y from sklearn.utils.validation import check_is_fitted class PUClassifier(BaseEstimator, ClassifierMixin): def __init__(self, estimator=SVC()): self.estimator = estimator def fit(self, X, y): X, y = check_X_y(X, y) self.classes_, y = np.unique(y, return_inverse=True) self.positive_class_ = self.classes_[1] # 先把有標籤的正樣本挑出來 y_mask = np.random.choice([True, False], size=len(y), p=[0.5, 0.5]) is_l = np.ones(len(y), 'bool') is_p = np.zeros(len(y), 'bool') is_p[y == self.positive_class_] = True w_l = np.zeros(len(y)) w_u_initial = np.zeros(len(y)) w_u_initial[~is_l] = 0.5 # 正例訓練集 X_l, y_l, w_l = X[y_mask, :], y[y_mask], w_l[y_mask] # 無標籤集 X_u, w_u_initial, is_p = X[~y_mask, :], w_u_initial[~y_mask], is_p[~y_mask] # 初始化分類器權重 pos_prior = w_l.dot(is_p) / w_l.sum() neg_prior = (1. - is_p).dot(w_l) / w_l.sum() self.estimator.weighted = True if isinstance(self.estimator, RandomForestClassifier): self.estimator.set_params(class_weight={0: neg_prior, 1: pos_prior}) else: self.estimator.set_params(class_weight='balanced') # 對無標籤樣本分類,獲取新的權重 is_l_new, is_p_new, w_u_new = self._new_weights(X_u, pos_prior, neg_prior) is_l[~y_mask] = is_l_new is_p[~y_mask] = is_p_new w_u_initial[~y_mask] = w_u_new self.estimator.fit(X[is_l, :], y[is_l], sample_weight=w_l[is_l]) self.X_l_, self.y_l_, self.X_u_ = X[is_l, :], y[is_l], X[is_u, :] self.is_fitted_ = True return self def _new_weights(self, X_u, pos_prior, neg_prior): # 對於無標籤樣本進行分類,獲取新的權重 if isinstance(self.estimator, SVC): decision = self.estimator.decision_function(X_u) else: decision = self.estimator.predict_proba(X_u)[:, 1] - 0.5 is_p_u = decision > self._epsilon(pos_prior, neg_prior) if is_p_u.sum() == 0: print(decision) w_u_new = self._sigma_fn(decision) * (pos_prior - neg_prior) / (pos_prior * (1 - neg_prior)) w_u_new[is_p_u] = (pos_prior - self._sigma_fn(-decision[is_p_u])) / pos_prior / neg_prior return np.ones(len(X_u), 'bool'), is_p_u, w_u_new @staticmethod def _sigma_fn(x): return 1. / (1. + np.exp(-x)) def _epsilon(self, pos_prior, neg_prior): # 調整閾值大小 if pos_prior > neg_prior: eps = 1 - pos_prior / neg_prior else: eps = 1 - neg_prior / pos_prior eps = min(0.5, max(0.0001, eps)) return eps def predict(self, X): check_is_fitted(self, 'is_fitted_') if isinstance(self.estimator, SVC): decision = self.estimator.decision_function(X) else: decision = self.estimator.predict_proba(X)[:, 1] - 0.5 threshold = self._epsilon( self.y_l_[self.y_l_ == self.positive_class_].size / float(self.y_l_.size), self.y_l_[self.y_l_ != self.positive_class_].size / float(self.y_l_.size)) return decision > threshold
四、PU Learning的實驗效果
本文實現了PU Learning算法,並且在標準數據集上進行了實驗。在幾個不同的分類器上的表現已經報告了。其中PU Learning對於沒有標記的數據的大規模數據集來說,準確度通常非常高。
以Madhavan數據集為例,這是一個二元分類的任務,它有800個有標籤樣本和7000個未標籤樣本。我們假設不知道未標標籤樣本的實際標籤,才需要運用PU Learning算法進行預測。實驗結果顯示,PU Learning算法能夠高度準確的預測未標記的樣本。
原創文章,作者:MZNGI,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/334927.html