西瓜書習題試答-第13章-半監督學習

試答系列:「西瓜書」-周志華《機器學習》習題試答
系列目錄
[第01章:緒論]
[第02章:模型評估與選擇]
[第03章:線性模型]
[第04章:決策樹]
[第05章:神經網絡]
[第06章:支持向量機]
第07章:貝葉斯分類器
第08章:集成學習
第09章:聚類
第10章:降維與度量學習
第11章:特徵選擇與稀疏學習
第12章:計算學習理論(暫缺)
第13章:半監督學習
第14章:機率圖模型
(後續章節更新中...)html


目錄


13.1 試推導出式(13.5)~(13.8).

:首先,咱們進行一些約定和分析:
約定和分析python

  1. 原教材中用\(y\)表明類別標記,用\(\Theta\)表示(樣本)所隸屬的高斯成分,同時假定第\(i\)個類別對應於第\(i\)個高斯成分。這裏咱們將二者視爲同一個東西,統一用\(y\)來表示,再也不區分。
  2. 將(13.1)式改寫爲

\[\begin{aligned} p(x)&=\sum_i p(y=i)p(x|y=i)\\ &=\sum_i \alpha_i \Bbb{N}(x|\mu_i,\Sigma_i) \end{aligned}\]

  1. 目標函數\(LL\)中,對於有標記樣本項爲似然項,對於無標記樣本項則爲邊際似然項,原(13.4)實際上能夠表達爲:

\[\begin{aligned} LL&=\sum_{(x_j,y_j)\in D_l}\ln p(x_j,y_j)+\sum_{x_j\in D_u}\ln p(x_j)\\ &=\sum_{(x_j,y_j)\in D_l}\ln[\alpha_{y_j}\Bbb{N}(x_j|\mu_{y_j},\Sigma_{y_j})] +\sum_{x_j\in D_u}\ln\sum_i\alpha_i\Bbb{N}(x_j|\mu_i,\Sigma_i)\\ \end{aligned}\]

其中對於無標記樣本的求和項中存在\(\ln[\sum(\cdot)]\)的形式,若直接求取\(\max_{\{\alpha,\mu,\Sigma\}}LL\)會比較困難,一般採用\(EM\)算法來求取。
EM算法求解:git

  • E步:計算未標記樣本所屬類別標記的後驗機率:

\[\begin{aligned} \gamma_{ji}&=p(y=i|x_j)\\ &=\frac{p(y=i)p(x_j|y=i)}{p(x_j)}\\ &=\frac{\alpha_i\Bbb{N}(x_j|\mu_i,\Sigma_i)}{\sum_k\alpha_k\Bbb{N}(x_j|\mu_k,\Sigma_k)} \end{aligned}\]

該結果與 (13.5) 式等同(儘管看起來不同)。面試

  • M步:計算目標函數LL的指望,並最大化:
    1.計算\(LL\)的指望。

\[\begin{aligned} E(LL)&=\sum_{(x_j,y_j)\in D_l}\ln p(x_j,y_j)+\sum_{x_j\in D_u}\sum_i\gamma_{ji}\ln p(x_j,y_j=i)\\ &=\sum_{(x_j,y_j)\in D_l}\ln[\alpha_{y_j}\Bbb{N}(x_j|\mu_{y_j},\Sigma_{y_j})] +\sum_{x_j\in D_u}\sum_i\gamma_{ji}\ln[\alpha_i\Bbb{N}(x_j|\mu_i,\Sigma_i)]\\ \end{aligned} \]

2.最大化\(E(LL)\)
首先介紹一下高斯函數關於均值和協方差的梯度結果:算法

\[\begin{aligned} &\Bbb{N}(x_j|\mu_i,\Sigma_i)=\frac{1}{(2\pi)^{n/2}|\Sigma_i|^{1/2}}exp[-\frac{1}{2}(x_j-\mu_i)^T\Sigma_i^{-1}(x_j-\mu_i)]\\ &\nabla_{\mu_i}\ln\Bbb{N}(x_j|\mu_i,\Sigma_i)=\Sigma_i^{-1}(x_j-\mu_i)\\ &\nabla_{\Sigma_i^{-1}}\ln\Bbb{N}(x_j|\mu_i,\Sigma_i)=\frac{1}{2}[\Sigma_i-(x_j-\mu_i)(x_j-\mu_i)^T] \end{aligned}\]

最後一式應用了關係:\(\nabla_A|A|=|A|(A^{-1})^T\)
下面正式最大化似然函數的指望:\(\max_{\{\alpha,\mu,\Sigma\}}E(LL)\)編程

\[\begin{aligned} &\bf\nabla_{\mu_i}E(LL)\\ &=\sum_{(x_j,y_j)\in D_l}I(y_j=i)\Sigma_{i}^{-1}(x_j-\mu_i)+\sum_{x_j\in D_u}\gamma_{ji}\Sigma_{i}^{-1}(x_j-\mu_i)]\\ &=0\\ &\Rightarrow \mu_i=\frac{1}{l_i+\sum_{D_u}\gamma_{ji}}[\sum_{(x_j,y_j)\in D_l}I(y_j=i)x_j+\sum_{x_j\in D_u}\gamma_{ji}\,x_j] \end{aligned}\]

此即 (13.6) 式,其中\(I(\cdot)\)爲指示函數。網絡

\[\begin{aligned} &\bf\nabla_{\Sigma_i^{-1}}E(LL)\\ &=\sum_{(x_j,y_j)\in D_l}I(y_j=i)\frac{1}{2}[\Sigma_i-(x_j-\mu_i)(x_j-\mu_i)^T]\\ &\quad+\sum_{x_j\in D_u}\gamma_{ji}\frac{1}{2}[\Sigma_i-(x_j-\mu_i)(x_j-\mu_i)^T\\ &=0\\ &\Rightarrow \Sigma_i=\frac{1}{l_i+\sum_{D_u}\gamma_{ji}}[\sum_{(x_j,y_j)\in D_l}I(y_j=i)(x_j-\mu_i)(x_j-\mu_i)^T\\ &\qquad\qquad+\sum_{x_j\in D_u}\gamma_{ji}\,(x_j-\mu_i)(x_j-\mu_i)^T] \end{aligned}\]

此即 (13.7) 式。
對於\(\{\alpha_i\}\),還要考慮約束\(\sum_i \alpha_i=1\),利用拉格朗日方法來求解該約束問題:app

\[\max_{\{\alpha_i\}}L=\max_{\{\alpha_i\}}[E(LL)+\lambda(\sum_i\alpha_i-1)]$$$$\begin{aligned} &\bf\frac{\partial{L}}{\partial{\alpha_i}}\\ &=\sum_{(x_j,y_j)\in D_l}I(y_j=i)\frac{1}{\alpha_i}+\sum_{x_j\in D_u}\gamma_{ji}\frac{1}{\alpha_i}+\lambda\\ &=0\\ &\Rightarrow \alpha_i=-\frac{l_i+\sum_{D_u}\gamma_{ji}}{\lambda} \end{aligned}\]

由約束\(\sum_i \alpha_i=1\)可得\(\lambda=-m\),因此:dom

\[\alpha_i=\frac{l_i+\sum_{D_u}\gamma_{ji}}{m} \]

此即 (13.8) 式。機器學習

13.2 試基於樸素貝葉斯模型推導出生成式半監督學習算法.

:徹底與基於混合高斯模型的生成式算法相似,下面試推導一番。
這裏一樣假設樣本類別數等於樸素貝葉斯模型的類別數,並且第i個樣本類別對應於第i個模型類別,一樣再也不區分\(y\)\(\Theta\)
另外,假設樣本中每一個特徵取值爲離散值。

  • 樸素貝葉斯模型

\[\begin{aligned} p(\boldsymbol{x})&=\sum_{i=1}^N p(y=i)p(\boldsymbol{x}|y=i)\\ &=\sum_{i=1}^N p(y=i)\prod_{f=1}^n p(x_f|y=i)\\ &=\sum_{i=1}^N \alpha_i \prod_{f=1}^n \beta_{i,f,x_j} \end{aligned}\]

其中\(i\)爲類別索引號,共有N個類別,\(f\)爲特徵索引號,共有n個不一樣特徵;\(\alpha_i=p(y=i)\)\(\beta_{i,f,k}=p(x_f=k|y=i)\),知足約束\(\sum_i\alpha_i=1,\sum_k\beta_{ifk}=1\)

  • 似然函數

\[\begin{aligned} LL&=\sum_{(\boldsymbol{x}_j,y_j)\in D_l}\ln p(\boldsymbol{x}_j,y_j)+\sum_{\boldsymbol{x}_j\in D_u}\ln p(\boldsymbol{x}_j)\\ &=\sum_{(\boldsymbol{x}_j,y_j)\in D_l}\ln\left[\alpha_{y_j}\prod_{f}\beta_{y_j,f,x_{jf}}\right] +\sum_{\boldsymbol{x}_j\in D_u}\ln\left[ \sum_i\alpha_i\prod_{f}\beta_{i,f,x_{jf}}\right]\\ \end{aligned}\]

其中\(x_{jf}\)表示樣本\(\boldsymbol{x}_j\)的第\(f\)個特徵取值。

  • EM算法求解參數
    ---E步---
    對於無標記樣本:

\[\begin{aligned} \gamma_{ji}&=p(y=i|x_j)\\ &=\frac{\alpha_i\prod_f\beta_{i,f,x_{jf}}}{\sum_i\alpha_i\prod_f\beta_{i,f,x_{jf}}} \end{aligned}\]

似然函數的指望:

\[E(LL)=\sum_{(\boldsymbol{x}_j,y_j)\in D_l}\ln\left[\alpha_{y_j}\prod_{f}\beta_{y_j,f,x_{jf}}\right] +\sum_{\boldsymbol{x}_j\in D_u}\sum_i\gamma_{ji}\ln\left[ \alpha_i\prod_{f}\beta_{i,f,x_{jf}}\right]\]

---M步---
極大化指望似然函數,獲得:

\[\begin{aligned} \alpha_i&=\frac{l_i+\sum_{D_u}\gamma_{ji}}{m}\\ \beta_{i,f,k}&=\frac{l_{i,f,k}+\sum_{D_u}\gamma_{ji}1(x_{jf=k})}{l_i+\sum_{D_u}\gamma_{ji}} \end{aligned}\]

其中\(l_i\)表示標記樣本中屬於第i類的數目,\(l_{i,f,k}\)表示標記樣本中屬於第\(i\)類,並且第\(f\)個特徵取值爲\(k\)的樣本數目。

13.3 假設數據由混合專家(mixture of experts)模型生成,即數據是基於k個成分混合而得的機率密度生成:

\[p(x|\theta)=\sum_{i=1}^k\alpha_i \,p(x_ |\theta_i)\tag{13.22} \]

其中\(\theta=\{\theta_1,\theta_2,\cdots,\theta_k\}\)是模型參數\(p(x|\theta_i)\)是第\(i\)個混合成分的機率密度,混合係數\(\alpha_i\geq0,\sum_i^k\alpha_i=1\).假定每一個混合成分對應一個類別,但每一個類別可包含多個混合成分.試推導相應的生成式半監督學習算法。

1. 一些認識
對於生成式方法的半監督學習,試借用貝葉斯網中的表示方法來表達各變量間的依賴關係,用以幫助理解:
在這裏插入圖片描述
根據上圖可寫出聯合機率密度:

\[p(\Theta=i,y,x)=\alpha_i\,p(y|\Theta=i)\,p(x|\theta_i) \]

其中\(p(y|\Theta=i)\)是一個機率表,對於教材正文中的高斯混合模型,假定第\(i\)個類別對應於第\(i\)個高斯混合成分,那麼,機率表將爲一個單位矩陣,形如:

\(p(y\|\Theta)\) y=1 y=2
\(\Theta=1\) 1 0
\(\Theta=2\) 0 1

對於本題中的「每一個混合成分對應一個類別,但每一個類別可包含多個混合成分」,此時的機率表將爲形如:

\(p(y\|\Theta)\) y=1 y=2
\(\Theta=1\) 1 0
\(\Theta=2\) 1 0
\(\Theta=3\) 0 1
\(\Theta=4\) 0 1

按論文【Miller and Uyar, 1997】中的說法,以上狀況下的機率表被稱之爲「硬劃分(hard-partition)」,亦便是說,\(p(y|\Theta)\,,y=1,2,\cdots\)中只有一個取值爲1,其他取值爲零。
咱們能夠將這個條件機率表達爲:

\[p(y|\Theta=i)=1(i\in C_y) \]

其中\(C_y\)表示類別\(y\)所包含的混合成分的序號的集合。

2. 對於「每一個混合成分對應於一個類別」的狀況下,求解參數\(\{\alpha_i, \theta_i\}\)
將這種對應關係視爲固定不變,求解參數。若是同時也想學習這種對應關係,能夠嘗試不一樣組合方式,取其最佳組合。
與前面混合高斯模型和樸素貝葉斯模型中的方法徹底相似,寫出似然函數,而後應用EM算法:

\[\begin{aligned} LL&=\sum_{(\boldsymbol{x}_j,y_j)\in D_l}\ln p(\boldsymbol{x}_j,y_j)+\sum_{\boldsymbol{x}_j\in D_u}\ln p(\boldsymbol{x}_j)\\ &=\sum_{(\boldsymbol{x}_j,y_j)\in D_l}\ln\left[\sum_i\alpha_i\cdot1(i\in C_{y_j})p(x_j|\theta_i)\right]\\ &\qquad+\sum_{\boldsymbol{x}_j\in D_u}\ln\left[\sum_i\alpha_i\cdot p(x_j|\theta_i)\right]\\ \end{aligned}\]

注意,因爲似然函數的\(D_l\)\(D_u\)項都有\(\ln[\sum(\cdot)]\)的形式,所以,E步須要針對兩項都要求取隱變量\(\Theta\)的後驗機率:
---E步--

\[\begin{aligned} &For X_u:\quad\gamma_{ji}=p(\Theta=i|x_j)=\frac{\alpha_i p(x_j|\theta_i)}{\sum_i \alpha_i p(x_j|\theta_i)}\\ &For X_l:\quad\gamma_{ji}=p(\Theta=i|x_j,y_j)=\frac{\alpha_i p(x_j|\theta_i)}{\sum_{i\in C_{y_j}} \alpha_i p(x_j|\theta_i)}\cdot 1(i\in C_{y_j}) \end{aligned} \]

---M步--

\[\begin{aligned} &\nabla_{\theta_i}E(LL)=0\\ &\qquad\Rightarrow \theta_i=?\\ &\nabla_{\alpha_i}[E(LL)+\lambda(\sum_i \alpha_i-1)]=0\\ &\qquad\Rightarrow\alpha_i=\frac{1}{m}[\sum_{x_j\in D_u}\gamma_{ji}+\sum_{(x_j,y_j)\in D_l}\gamma_{ji}1(i\in C_{y_i})] \end{aligned}\]

3. 對於「軟劃分」的狀況下,求解參數\(\{\alpha_i, \theta_i\}\)
論文【Miller and Uyar, 1997】中談到更通常的狀況是\(p(y|\Theta=i)\)這個機率表中各個元素不爲零的狀況,論文中稱之爲The generalized mixture model (GM模型),將機率表中的參數值表示爲\(p(y|\Theta=i)=\beta_{y|i}\),此時,它也將是可學習的參數。
此時,似然函數爲:

\[LL=\sum_{(\boldsymbol{x}_j,y_j)\in D_l}\ln\left[\sum_i\alpha_i\cdot\beta_{y_j|i}\cdotp(x_j|\theta_i)\right]+\sum_{\boldsymbol{x}_j\in D_u}\ln\left[\sum_i\alpha_i\cdot p(x_j|\theta_i)\right]\]

在應用EM算法求解參數時,論文中介紹了二者處理方法:
EM-I:對於有標記和無標記樣本,隱變量都只是\(\Theta\).
EM-II:對於有標記,隱變量爲\(\Theta\),對於無標記樣本,隱變量爲\(\Theta,y\).
兩種方法計算獲得的\(\alpha_i,\theta_i\)徹底同樣,可是\(\beta_{y|i}\)不同:

\[\begin{aligned} EM-I:&\quad\beta_{y|i}=\frac{\sum_{(x_j,y_j)\in D_l}\gamma_{ji}\cdot 1(y_j=y)}{\sum_{(x_j,y_j)\in D_l}\gamma_{ji}}\\ EM-II:&\quad\beta_{y|i}=\frac{\sum_{(x_j,y_j)\in D_l}\gamma_{ji}\cdot 1(y_j=y)+\sum_{x_j\in D_u}\gamma_{jiy}}{\sum_{(x_j,y_j)\in D_l}\gamma_{ji}+\sum_{x_j\in D_u}\gamma_{ji}} \end{aligned} \]

其中,\(\gamma_{ji}\)的含義與前相同,而\(\gamma_{jiy}=p(\Theta=i,y|x_j)\)

13.4 從網上下載或本身編程實現TSVM算法,選擇兩個UCI數據集,將其30%的樣例用做測試樣本,10%的樣本用做有標記樣本,60%的樣本用做無標記樣本,分別訓練出無標記樣本的TSVM以及僅利用有標記樣本的SVM,並比較其性能。

:詳細編程代碼附後。

  1. TSVM算法實現
    TSVM算法基於教材圖13.4所示,其中SVM功能基於sklearn.svm.SVC實現。
    在尋找知足條件,須要交換僞標記的樣本\(x_i,x_j\)時,分別對僞正例樣本和僞負例樣本按\(\xi\)值進行排序,取其最大者分別做爲待交換樣本\(x_i,x_j\),而後考察它們是否知足交換條件。只須要考慮這兩個\(\xi\)值最大的樣本便可,由於,若是它們都不知足條件的話,那麼其他樣本對也都沒法知足條件。
  2. 運行結果
    首先爲了觀察TSVM算法的運行效果,人爲生成了一些簡單數據集,並用動畫形式展現了TSVM算法運行過程:
    在這裏插入圖片描述
    上圖中的生成數據集爲明顯可分線性劃分的兩簇數據,對於這樣的數據集,即便少許的有標記樣本便可進行「正確」的劃分,第一次指派僞標記結果即爲「正確」結果,在整個TSVM算法運行過程當中,僞標記再也不發生變化,不會進行僞標記交換操做。
    在這裏插入圖片描述
    上圖生成的數據集的兩簇數據存在交疊,沒法明顯線性劃分,對於這樣的數據集,引入帶僞標記的樣本後獲得的分類器與以前僅有標記樣本訓練的分類器會有較大差別,將會致使樣本僞標記不斷交換。

    而後在兩個UCI數據集上進行試驗,運行結果以下:
    鶯尾花數據集
    sklearn.datasets.load_iris()
    僅用有標記樣本進行訓練模型的預測精度爲: 0.71111111111
    利用無標記樣本的半監督模型的預測精度爲: 0.7333333333
    預測精度提升了3.12%
    手寫數字數據集
    sklearn.datasets.load_digits()
    僅用有標記樣本進行訓練模型的預測精度爲: 0.768518518519
    利用無標記樣本的半監督模型的預測精度爲: 0.77037037037
    預測精度提升了0.24%

13.5 對未標記樣本進行標記指派與調整的過程當中有可能出現類別不平衡問題,試給出考慮該問題後的改進TSVM算法。

:其實教材正文中有提到:在擬合SVM的時候,對於僞正和僞負的樣本採用不一樣的\(C_u\)權重值,\(C^+_u:C^-_u=u_- : u_+\),這裏\(u_+,u_-\)分別表示僞正和僞負的未標記樣本數。

13.6 TSVM對未標記樣本進行標記指派與調整的過程涉及很大的計算開銷,試設計一個高效的改進算法。

:沒太理解題意,指派和調整過程沒感受太大的計算開銷啊。對於調整過程,能夠按題13.4中所述:「在尋找知足條件,須要交換僞標記的樣本\(x_i,x_j\)時,分別對僞正例樣本和僞負例樣本按\(\xi\)值進行排序,取其最大者分別做爲待交換樣本\(x_i,x_j\),而後考察它們是否知足交換條件。只須要考慮這兩個\(\xi\)值最大的樣本便可,由於,若是它們都不知足條件的話,那麼其他樣本對也都沒法知足條件。

13.7 試設計一個能對新樣本進行分類的圖半監督學習方法。

:如教材正文所述:「......接收到新樣本時,或是將其加入原數據集對圖進行重構並從新進行標記傳播,或是需引入額外的預測機制,例如將\(D_l\)和經標記傳播後獲得標記的\(D_u\)合併做爲訓練集,另外訓練一個學習器例如支持向量機來對新樣本進行預測。

對於前一種方法---從新進行標記傳播,若新樣本較少,對於結果影響應該很小。能夠基於前面的分析,計算新樣本與其他有標記和無標記樣本的「親和力(好比高斯函數值)」,將該親和力做爲權重來肯定新樣本的標記:\(\hat{y}_{new}=sign(\sum W_{x_{new}\,\,,x_i}\cdot y_i/\sum W_{x_{new}\,\,,x_i})\)

13.8 自訓練是一種比較原始的半監督學習方法:它先在有標記樣本上學習,而後用學得分類器對未標記樣本進行判別以得到其僞標記,再在有標記與僞標記樣本的合集上從新訓練,如此反覆。試析該方法有何缺陷。

:根據題乾的描述,自訓練與TSVM算法很相似,都是先在有標記樣本上訓練,而後指派僞標記,而後從新訓練。
不一樣點在於:TSVM算法中,未標記樣本的權重有個從小變大的過程,從新指派標記時每次經過交換標記的方式只調整一對標記。
自訓練方法有何缺陷呢? 貌似也不太看得出,嘗試在13.4題代碼的基礎上進行修改,實現自訓練算法,在人爲生成的兩簇沒法明顯線性分離的數據集上進行試驗,觀察運行結果:
在這裏插入圖片描述

上圖實現了自訓練算法,基學習器爲SVM。與TSVM不一樣,這裏未標記樣本與有標記樣本權重相同,每次從新擬合後,對全部樣本從新指派僞標記,而再也不是一次只交換一對。
在這裏插入圖片描述
上圖在前面自訓練的基礎上引入了Cu由小變大的機制,相似於TSVM。
在這裏插入圖片描述
做爲對比,上圖是TSVM算法的運行結果。
觀察上面的運行結果,從運行效果上看,暫時沒看出來自訓練方法有什麼明顯的缺陷。

13.9 給定一個數據集,假設其屬性集包含兩個視圖,但事先並不知道哪些屬性屬於哪一個視圖,試設計一個算法將這兩個視圖分離出來。

:我能想到的一個思路是:爲了確保不一樣視圖間的獨立性,先計算每一對屬性之間的相關性,而後將彼此相關性較高的屬性聚爲同一個視圖下的屬性,這個過程有點像聚類,只不過這裏不是對樣本聚類,而是對屬性聚類。

13.10 試爲圖13.7算法的第10行寫出違約檢測算法(用於檢測是否有約束未被知足)。

\[[(x_i\in {\Bbb{M}} ) ∧\exists\{x_j|(x_j\in \Bbb{M})∧(x_j\in C_s)∧(s\neq r)\}]\\ or \,\,[(x_i\in {\Bbb{C}} ) ∧\exists\{x_j|(x_j\in \Bbb{C})∧(x_j\in C_r)\}]\]


附:編程代碼

ex13.4 代碼(python)

# -*- coding: utf-8 -*-
"""
Created on Sat Jul 25 23:45:32 2020

@author: Administrator

ex13.4
"""

from sklearn.svm import SVC
from sklearn import datasets
from sklearn.model_selection import train_test_split as split
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.animation as animation

#==================================
#         編寫實現TSVM算法的函數
#==================================
def TSVM(Dl,Du,Cl,Cu,gifname=None):
    '''
    # 該函數實現TSVM算法,其中支持向量機算法基於sklearn中的SVC類的線性支持向量機實現
    # 
    # 輸入參數:
    #     Dl:有標記樣本數據,格式爲元祖形式:(Xl,yl),其中yl取值爲{1,-1}
    #     Du:未標記樣本數據,僅Xu
    #     Cl,Cu:初始折中參數,Cu<<Cl
    #     gifname:若要將TSVM算法過程保存爲gif動畫,則傳入文件名,默認不保存動畫
    # 輸出:
    #     clf:基於sklearn的支持向量機SVM分類器
    '''
    
    Xl,yl=Dl
    Xu=Du
    X_mix=np.r_[Xl,Xu]
    clf=SVC(C=Cl,kernel='linear').fit(Xl,yl)  #基於有標記樣本的初始SVM分類器
    yu=clf.predict(Xu)                        #向未標記樣本指派僞標記
    #acts用於後續繪製動畫所用,其中儲存了相應的事件動做的關鍵參數,
    #好比:從新擬合後的權重w和偏置b、從新分派僞標記後的僞標記yu等
    acts=[{'w':clf.coef_.reshape(-1),'b':clf.intercept_,'text':'初始模型(僅有標記樣本)'}]
    acts.append({'assign':yu.copy(),'text':'分派僞標記'})
    while Cu<Cl:
        #樣本權重,傳入clf.fit()函數可實現對於不一樣樣本不一樣的權重值
        sample_weight=[1.0]*len(yl)+[Cu/Cl]*len(yu)
        clf.fit(X_mix,np.r_[yl,yu],sample_weight=sample_weight)
        acts.append({'w':clf.coef_.reshape(-1),'b':clf.intercept_,'text':'調整Cu爲%.3E後從新擬合'%Cu})
        while True:
            f=clf.decision_function(Xu)  #計算f(x)=wx+b的結果
            xi=np.fmax(1-f*yu,0)         #計算ξ值,基於y(wx+b)≥1-ξ,ξ≥0
            y1_index=np.where(yu==1)[0]  #僞標記爲+1的索引號
            y0_index=np.where(yu==-1)[0] #僞標記爲-1的索引號
            max1=max(xi[yu==1])          #僞標記爲+1的樣本中的最大ξ值
            max0=max(xi[yu==-1])         #僞標記爲-1的樣本中的最大ξ值
            #只需分別考慮僞正負樣本中最大ξ值的兩個樣本便可,
            #由於若這兩個最大ξ值的樣本不知足條件(ξi>0,ξj>0,ξi+ξj>2),
            #那麼其餘樣本對也必然沒法知足了。
            if (max1>0)&(max0>0)&(max1+max0>2):
                print('交換僞標記:ξ_+1=%.3f,ξ_-1=%.3f'%(max1,max0))
                i=y1_index[np.argmax(xi[yu==1])]   #僞標記爲+1的樣本中的最大ξ值對應的樣本索引號
                j=y0_index[np.argmax(xi[yu==-1])]  #僞標記爲-1的樣本中的最大ξ值對應的樣本索引號
                yu[i]*=-1
                yu[j]*=-1
                acts.append({'exchanging':[i,j],'text':'交換僞標記中...'})
                acts.append({'assign':yu.copy(),'text':'完成交換'})
                clf.fit(X_mix,np.r_[yl,yu],sample_weight=sample_weight)
                acts.append({'w':clf.coef_.reshape(-1),'b':clf.intercept_,'text':'交換標記後從新擬合'})
            else:
                break
        Cu=min(2*Cu,Cl)
    acts.append({'text':'TSVM算法執行完畢!'})
    
    if gifname!=None:
        #設置繪圖中顯示中文
        plt.rcParams['font.sans-serif']=['SimHei']
        plt.rcParams['axes.unicode_minus'] = False
        
        fig=plt.figure()
        
        #繪製有標記樣本,用顏色區分正負樣本
        plt.scatter(Xl[yl==1,0],Xl[yl==1,1],s=40,c='r',marker='+',edgecolors='r')
        plt.scatter(Xl[yl==-1,0],Xl[yl==-1,1],s=40,c='g',marker='_',edgecolors='g')
        #繪製有標記樣本,所有顯示爲黑色小點
        plt.scatter(Xu[:,0],Xu[:,1],s=10,c='k')
        #設置座標軸上下限
        x1min,x1max=min(X_mix[:,0]),max(X_mix[:,0])
        x2min,x2max=min(X_mix[:,1]),max(X_mix[:,1])
        plt.xlim([x1min-(x1max-x1min)*0.2,x1max+(x1max-x1min)*0.2])
        plt.ylim([x2min-(x2max-x2min)*0.2,x2max+(x2max-x2min)*0.2])
        
        #分類器決策線
        decision_line,=plt.plot([],[],c='k')
        #無標記樣本之+1樣本指派結果,顏色與有標記樣本對應顏色相同
        unlabel_points1,=plt.plot([],[],marker='.',linestyle='',c='r')
        #無標記樣本之-1樣本指派結果,顏色與有標記樣本對應顏色相同
        unlabel_points0,=plt.plot([],[],marker='.',linestyle='',c='g')
        #繪製交換標記操做的牽引線
        exchange,=plt.plot([0,0],[0,0],linestyle='',c='m',linewidth=2)  #初始,任意位置,設置爲不顯示
        #顯示當前操做狀態的文字說明
        state=plt.text((x1min+x1max)/2,x2max+(x2max-x2min)*0.1,'',fontsize=12)
        
        def update(num):
            # 更新動畫幀的函數,num爲幀數
            act=acts[num]
            if 'w' in act:
                decision_line.set_data([x1min,x1max],
                                       [-(x1min*act['w'][0]+act['b'])/act['w'][1],
                                    -(x1max*act['w'][0]+act['b'])/act['w'][1]])
                exchange.set_linestyle('')
                state.set_text(act['text'])
            elif 'exchanging' in act:
                i,j=act['exchanging']
                exchange.set_linestyle('--')
                exchange.set_data([Xu[i][0],Xu[j][0]],[Xu[i][1],Xu[j][1]])
                state.set_text(act['text'])
            elif 'assign' in act:
                yu=act['assign']
                unlabel_points1.set_data(Xu[yu==1,0],Xu[yu==1,1])
                unlabel_points0.set_data(Xu[yu==-1,0],Xu[yu==-1,1])
                state.set_text(act['text'])
            else:
                state.set_text(act['text'])
            
            return [decision_line,unlabel_points1,unlabel_points0,exchange,state]
        
        #動畫生成函數animation.FuncAnimation(),其中參數intervel爲每幀的持續時間,單位爲ms
        ani=animation.FuncAnimation(fig,update,frames=range(len(acts)),interval=1000)
        #關於保存gif動畫,有些電腦可能直接能夠正常運行,
        #有些電腦則會報錯,這是由於電腦系統中缺乏了某些組件,
        #能夠根據提示以及參考網絡上一些案例進行安裝,
        #好比,我參考了下列網址中的方法成功地解決了問題:
        #https://blog.csdn.net/weixin_41957054/article/details/107280246
        #https://blog.csdn.net/qq_21905401/article/details/103023074
        ani.save(str(gifname)+'.gif',writer='imagemagick')
        plt.show()
    return clf

#==========================================
#     生成簡單二維數據集,
#     明顯線性可分離的兩類數據,
#     試驗並觀察TSVM算法過程
#     計算過程經過gif動畫的形式進行演示
#==========================================
#X1和X2爲生成的兩類數據
X1=np.random.random([50,2])
X2=np.random.random([50,2])+[2,0]
X1=X1[np.argsort(X1[:,1])]
X2=X2[np.argsort(X2[:,1])]
#在X1和X2中各取五個樣本組成有標記樣本
Xl=np.r_[X1[:5],X2[-5:]]
yl=np.array([1]*5+[-1]*5)
#其他的樣本做爲無標記樣本
Xu=np.r_[X1[5:],X2[:-5]]
TSVM((Xl,yl),Xu,1,0.0001,'demo1')

#==========================================
#     一樣生成簡單二維數據集,
#     可是兩類數據有重合,沒法明顯線性劃分
#==========================================
#X1和X2爲生成的兩類數據
X1=np.random.random([50,2])
X2=np.random.random([50,2])+[1,0]
X1=X1[np.argsort(X1[:,1])]
X2=X2[np.argsort(X2[:,1])]
#在X1和X2中各取五個樣本組成有標記樣本
Xl=np.r_[X1[:5],X2[-5:]]
yl=np.array([1]*5+[-1]*5)
#其他的樣本做爲無標記樣本
Xu=np.r_[X1[5:],X2[:-5]]
TSVM((Xl,yl),Xu,1,0.0001,'demo2')

#==========================================
#    在鶯尾花數據集上進行試驗
#==========================================
print('-------在鶯尾花數據集上進行試驗-------')
iris=datasets.load_iris()
X=iris['data']
y=(iris['target']==1)*2-1  #將第1類設爲y=+1,第二、3類設爲y=-1

#劃分數據集:X_test:Xu:Xl樣本比例爲:3:6:1
X_train,X_test,y_train,y_test=split(X,y,test_size=0.3,random_state=12)
Xu,Xl,yu,yl=split(X_train,y_train,test_size=1/7,random_state=12)

#單獨有標記樣本進行訓練和預測
Cl=1
clf0=SVC(C=Cl,kernel='linear').fit(Xl,yl)
y_pre0=clf0.predict(X_test)
acc0=(y_pre0==y_test).mean()
print('僅用有標記樣本進行訓練的模型的預測精度爲:',acc0)

#利用無標記樣本的半監督模型
Cl,Cu=1,0.0001
clf1=TSVM((Xl,yl),Xu,Cl,Cu)
y_pre1=clf1.predict(X_test)
acc1=(y_pre1==y_test).mean()
print('利用無標記樣本的半監督模型的預測精度爲:',acc1)
print('預測精度提升了%.2f%%'%((acc1-acc0)/acc0*100))

#==========================================
#    在手寫數據集上進行試驗
#==========================================
print('-------在手寫數據集上進行試驗-------')
digits=datasets.load_digits()
X=digits['data']
y=(digits['target']<5)*2-1  #將0~4設爲y=+1,第5~9設爲y=-1

#劃分數據集:X_test:Xu:Xl樣本比例爲:3:6:1
X_train,X_test,y_train,y_test=split(X,y,test_size=0.3,random_state=12)
Xu,Xl,yu,yl=split(X_train,y_train,test_size=1/7,random_state=12)

#單獨有標記樣本進行訓練和預測
Cl=1
clf0=SVC(C=Cl,kernel='linear').fit(Xl,yl)
y_pre0=clf0.predict(X_test)
acc0=(y_pre0==y_test).mean()
print('僅用有標記樣本進行訓練的模型的預測精度爲:',acc0)

#利用無標記樣本的半監督模型
Cl,Cu=1,0.0001
clf1=TSVM((Xl,yl),Xu,Cl,Cu)
y_pre1=clf1.predict(X_test)
acc1=(y_pre1==y_test).mean()
print('利用無標記樣本的半監督模型的預測精度爲:',acc1)
print('預測精度提升了%.2f%%'%((acc1-acc0)/acc0*100))

ex13.8 代碼(python)

修改TSVM函數中部分代碼實現自訓練算法,能夠只修改循環體「while Cu<Cl:」部分代碼爲:

def self_train(Dl,Du,Cl,Cu,gifname=None):
    '''
    ***********************
    前面部分與TSVM函數相同
    '''
    while Cu<=Cl:
        #樣本權重,傳入clf.fit()函數可實現對於不一樣樣本不一樣的權重值
        sample_weight=[1.0]*len(yl)+[Cu/Cl]*len(yu)
        
        clf.fit(X_mix,np.r_[yl,yu],sample_weight=sample_weight)
        yu=clf.predict(Xu)
        acts.append({'w':clf.coef_.reshape(-1),'b':clf.intercept_,'text':'加入帶僞標記的無標記樣本從新擬合'})
        acts.append({'assign':yu.copy(),'text':'從新分派僞標記'})
        while True:
            clf.fit(X_mix,np.r_[yl,yu],sample_weight=sample_weight)
            yu1=clf.predict(Xu)
            if (yu==yu1).all():
                break
            else:
                yu=yu1
                acts.append({'w':clf.coef_.reshape(-1),'b':clf.intercept_,'text':'從新擬合'})
                acts.append({'assign':yu.copy(),'text':'從新指派'})
        Cu=min(2*Cu,Cl+0.01)
        if Cu<=Cl:
            acts.append({'assign':yu.copy(),'text':'調整Cu爲%.3e'%Cu})
    acts.append({'text':'TSVM算法執行完畢!'})
    '''
    ***********************
    後面也與TSVM函數相同,不作變化
    '''

而後人爲生成的兩簇沒法明顯線性分離的數據集進行試驗,

#==========================================
#     生成簡單二維數據集,
#     兩類數據有重合,沒法明顯線性劃分
#==========================================
#X1和X2爲生成的兩類數據
X1=np.random.random([50,2])
X2=np.random.random([50,2])+[1,0]
X1=X1[np.argsort(X1[:,1])]
X2=X2[np.argsort(X2[:,1])]
#在X1和X2中各取五個樣本組成有標記樣本
Xl=np.r_[X1[:5],X2[-5:]]
yl=np.array([1]*5+[-1]*5)
#其他的樣本做爲無標記樣本
Xu=np.r_[X1[5:],X2[:-5]]
self_train((Xl,yl),Xu,1,1,'13.8_self_train_Cu=1')
self_train((Xl,yl),Xu,1,1E-4,'13.8_self_train_Cu=1E_4')
TSVM((Xl,yl),Xu,1,1E-4,'13.8_TSVM_Cu=1E_4')
相關文章
相關標籤/搜索