試答系列:“西瓜書”-周志華《機器學習》習題試答
系列目錄
[第01章:緒論]
[第02章:模型評估與選擇]
[第03章:線性模型]
[第04章:決策樹]
[第05章:神經網絡]
[第06章:支持向量機]
第07章:貝葉斯分類器
第08章:集成學習
第09章:聚類
第10章:降維與度量學習
第11章:特征選擇與稀疏學習
第12章:計算學習理論(暫缺)
第13章:半監督學習
第14章:概率圖模型
(后續章節更新中...)
- 13.1 試推導出式(13.5)~(13.8).
- 13.2 試基於朴素貝葉斯模型推導出生成式半監督學習算法.
- 13.3 假設數據由混合專家(mixture of experts)模型生成,即數據是基於k個成分混合而得的概率密度生成:
- 13.4 從網上下載或自己編程實現TSVM算法,選擇兩個UCI數據集,將其30%的樣例用作測試樣本,10%的樣本用作有標記樣本,60%的樣本用作無標記樣本,分別訓練出無標記樣本的TSVM以及僅利用有標記樣本的SVM,並比較其性能。
- 13.5 對未標記樣本進行標記指派與調整的過程中有可能出現類別不平衡問題,試給出考慮該問題后的改進TSVM算法。
- 13.6 TSVM對未標記樣本進行標記指派與調整的過程涉及很大的計算開銷,試設計一個高效的改進算法。
- 13.7 試設計一個能對新樣本進行分類的圖半監督學習方法。
- 13.8 自訓練是一種比較原始的半監督學習方法:它先在有標記樣本上學習,然后用學得分類器對未標記樣本進行判別以獲得其偽標記,再在有標記與偽標記樣本的合集上重新訓練,如此反復。試析該方法有何缺陷。
- 13.9 給定一個數據集,假設其屬性集包含兩個視圖,但事先並不知道哪些屬性屬於哪個視圖,試設計一個算法將這兩個視圖分離出來。
- 13.10 試為圖13.7算法的第10行寫出違約檢測算法(用於檢測是否有約束未被滿足)。
- 附:編程代碼
13.1 試推導出式(13.5)~(13.8).
答:首先,我們進行一些約定和分析:
約定和分析:
- 原教材中用\(y\)代表類別標記,用\(\Theta\)表示(樣本)所隸屬的高斯成分,同時假定第\(i\)個類別對應於第\(i\)個高斯成分。這里我們將兩者視為同一個東西,統一用\(y\)來表示,不再區分。
- 將(13.1)式改寫為
- 目標函數\(LL\)中,對於有標記樣本項為似然項,對於無標記樣本項則為邊際似然項,原(13.4)實際上可以表達為:
其中對於無標記樣本的求和項中存在\(\ln[\sum(\cdot)]\)的形式,若直接求取\(\max_{\{\alpha,\mu,\Sigma\}}LL\)會比較困難,通常采用\(EM\)算法來求取。
EM算法求解:
- E步:計算未標記樣本所屬類別標記的后驗概率:
該結果與 (13.5) 式等同(盡管看起來不一樣)。
- M步:計算目標函數LL的期望,並最大化:
1.計算\(LL\)的期望。
2.最大化\(E(LL)\)。
首先介紹一下高斯函數關於均值和協方差的梯度結果:
最后一式應用了關系:\(\nabla_A|A|=|A|(A^{-1})^T\)
下面正式最大化似然函數的期望:\(\max_{\{\alpha,\mu,\Sigma\}}E(LL)\)
此即 (13.6) 式,其中\(I(\cdot)\)為指示函數。
此即 (13.7) 式。
對於\(\{\alpha_i\}\),還要考慮約束\(\sum_i \alpha_i=1\),利用拉格朗日方法來求解該約束問題:
由約束\(\sum_i \alpha_i=1\)可得\(\lambda=-m\),所以:
此即 (13.8) 式。
13.2 試基於朴素貝葉斯模型推導出生成式半監督學習算法.
答:完全與基於混合高斯模型的生成式算法類似,下面試推導一番。
這里同樣假設樣本類別數等於朴素貝葉斯模型的類別數,而且第i個樣本類別對應於第i個模型類別,同樣不再區分\(y\)和\(\Theta\)。
另外,假設樣本中每個特征取值為離散值。
- 朴素貝葉斯模型
其中\(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\)。
- 似然函數
其中\(x_{jf}\)表示樣本\(\boldsymbol{x}_j\)的第\(f\)個特征取值。
- EM算法求解參數
---E步---
對於無標記樣本:
似然函數的期望:
---M步---
極大化期望似然函數,得到:
其中\(l_i\)表示標記樣本中屬於第i類的數目,\(l_{i,f,k}\)表示標記樣本中屬於第\(i\)類,而且第\(f\)個特征取值為\(k\)的樣本數目。
13.3 假設數據由混合專家(mixture of experts)模型生成,即數據是基於k個成分混合而得的概率密度生成:
其中\(\theta=\{\theta_1,\theta_2,\cdots,\theta_k\}\)是模型參數\(p(x|\theta_i)\)是第\(i\)個混合成分的概率密度,混合系數\(\alpha_i\geq0,\sum_i^k\alpha_i=1\).假定每個混合成分對應一個類別,但每個類別可包含多個混合成分.試推導相應的生成式半監督學習算法。
答:
1. 一些認識
對於生成式方法的半監督學習,試借用貝葉斯網中的表示方法來表達各變量間的依賴關系,用以幫助理解:
根據上圖可寫出聯合概率密度:
其中\(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,其余取值為零。
我們可以將這個條件概率表達為:
其中\(C_y\)表示類別\(y\)所包含的混合成分的序號的集合。
2. 對於“每個混合成分對應於一個類別”的情況下,求解參數\(\{\alpha_i, \theta_i\}\)
將這種對應關系視為固定不變,求解參數。如果同時也想學習這種對應關系,可以嘗試不同組合方式,取其最佳組合。
與前面混合高斯模型和朴素貝葉斯模型中的方法完全類似,寫出似然函數,然后應用EM算法:
注意,由於似然函數的\(D_l\)和\(D_u\)項都有\(\ln[\sum(\cdot)]\)的形式,因此,E步需要針對兩項都要求取隱變量\(\Theta\)的后驗概率:
---E步--
---M步--
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}\),此時,它也將是可學習的參數。
此時,似然函數為:
在應用EM算法求解參數時,論文中介紹了兩者處理方法:
EM-I:對於有標記和無標記樣本,隱變量都只是\(\Theta\).
EM-II:對於有標記,隱變量為\(\Theta\),對於無標記樣本,隱變量為\(\Theta,y\).
兩種方法計算得到的\(\alpha_i,\theta_i\)完全一樣,但是\(\beta_{y|i}\)不一樣:
其中,\(\gamma_{ji}\)的含義與前相同,而\(\gamma_{jiy}=p(\Theta=i,y|x_j)\)
13.4 從網上下載或自己編程實現TSVM算法,選擇兩個UCI數據集,將其30%的樣例用作測試樣本,10%的樣本用作有標記樣本,60%的樣本用作無標記樣本,分別訓練出無標記樣本的TSVM以及僅利用有標記樣本的SVM,並比較其性能。
答:詳細編程代碼附后。
- TSVM算法實現
TSVM算法基於教材圖13.4所示,其中SVM功能基於sklearn.svm.SVC實現。
在尋找滿足條件,需要交換偽標記的樣本\(x_i,x_j\)時,分別對偽正例樣本和偽負例樣本按\(\xi\)值進行排序,取其最大者分別作為待交換樣本\(x_i,x_j\),然后考察它們是否滿足交換條件。只需要考慮這兩個\(\xi\)值最大的樣本即可,因為,如果它們都不滿足條件的話,那么其余樣本對也都無法滿足條件。 - 運行結果
首先為了觀察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行寫出違約檢測算法(用於檢測是否有約束未被滿足)。
答:
附:編程代碼
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,第2、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')