西瓜書習題試答-第10章-降維與度量學習


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



10.1 編程實現k近鄰分類器,在西瓜數據集3.0α上比較其分類邊界與決策樹邊界之異同。

:編程代碼附后。運行結果如下(考慮了k=1,3,5,以及分別采用曼哈頓(p=1),歐式(p=2)和切比雪夫(p=50)三種距離):
在這里插入圖片描述
上圖中,“+”和“-”離散點分別代表訓練數據樣本點,黑色線條為決策樹邊界,紅色線條為kNN邊界。
討論:

  1. 要說kNN邊界與決策樹邊界的異同,實在看不出來什么值得說道的地方,除了眾所周知的,決策樹邊界線段平行於坐標軸。
  2. 當k=1時訓練誤差為零;當k越來越大時,分類邊界趨向平緩,會出現訓練樣本誤分類的情況,此時為欠擬合。可見,k越小越容易過擬合,k越大越容易欠擬合。
  3. 不同p值的距離計算下,差別不太明顯。

10.2 令err、err*分別表示最近鄰分類器與貝葉斯最優分類器的期望錯誤率,試證明

\[err^\ast\leq err\leq err^\ast(2-\frac{|y|}{|y|-1}err^*)\tag{10.40} \]

證明:首先來理解一下這兩個期望錯誤率,它們都表示成“錯誤率=1-正確率”的形式,因此問題轉化成理解正確率。
對於預測樣本\(x\),貝葉斯最優分類器的決策結果\(c^*\),如果預測正確,意味着這個樣本的真實類別剛好也是\(c^*\),而該樣本以\(P(c^*|x)\)的概率屬於\(c^*\)類別,因此預測正確的概率即為\(P(c^*|x)\),而錯誤率\(err^*=1-P(c^*|x)\)
最近鄰分類器的決策結果等於近鄰樣本\(z\)相同的類別,假設這個共同的類別為\(c\),如果這個決策結果是正確的,意味着\(x\)樣本和\(z\)樣本剛好都屬於\(c\)類,這個事件發生的概率是\(P(c|x)P(c|z)\)。考慮各種不同的\(c\)值,把它們加起來便是總的期望正確率\(=\sum_c P(c|x)P(c|z)\),因此錯誤率\(err=1-\sum_c P(c|x)P(c|z)\)
接下來證明上面的不等式:

\[\begin{aligned} err&=1-\sum_cP(c|x)P(c|z)\\ &\geq 1-\sum_cP(c^*|x)P(c|z)\\ &=1-P(c^*|x)\cdot\sum_cP(c|z)\\ &=1-P(c^*|x)\\ &=err* \end{aligned}\]

第2行利用了關系\(P(c|x)\leq P(c^*|x)\),第4行利用了關系\(\sum_cP(c|z)=1\)
不等式左半邊得證。

\[\begin{aligned} err&=1-\sum_cP(c|x)P(c|z)\\ &≈1-\sum_cP^2(c^|x)\\ &=1-P^2(c^*|x)-\sum_{c\neq c^\ast}P^2(c|x)\\ &\leq 1-P^2(c^*|x)- \frac{[\sum_{c\neq c^\ast}P(c|x)]^2}{|y|-1}\\ &=1-(1-err^\ast)^2-\frac{(err^\ast)^2}{|y|-1} \\ &=err^\ast (2-\frac{|y|}{|y|-1}err^\ast) \end{aligned}\]

第4行利用了不等式關系:\(\frac{\sum a_i^2 }{n} \geq (\frac{\sum a_i}{n})^2, \ \ a_i\geq 0,\ i=1,2,\cdots ,n\);第5行利用了關系\(\sum_{c\neq c^\ast}P(c|x)=1-P(c^*|x)=err^*\)
不等式右半邊得證。

10.3 在對高維數據降維之前應先進行“中心化”,常見的是將協方差矩陣\(XX^T\)轉化為\(XHH^TX^T\),其中\(H=I-\frac{1}{m}11^T\),試析其效果。

:相當於將\(X\)變為\(X^{\prime}\):

\[\begin{aligned} X^\prime&=XH\\ &=X(I-\frac{1}{m}11^T)\\ &=X-\frac{1}{m}X11^T\\ &=X-\frac{1}{m}\begin{bmatrix}x_1,&x_2,&\cdots\end{bmatrix}\begin{bmatrix}1\\1\\\vdots\end{bmatrix}\begin{bmatrix}1&1&\cdots\end{bmatrix}\\ &=X-\frac{1}{m}\sum_i x_i\begin{bmatrix}1&1&\cdots\end{bmatrix}\\ &=X-\bar{x}\begin{bmatrix}1&1&\cdots\end{bmatrix}\\ &=\begin{bmatrix}x_1-\bar{x},&x_2-\bar{x},&\cdots\end{bmatrix} \end{aligned}\]

其效果便是中心化\(x_i^{\prime}=x_i-\bar{x}\)

10.4 在實踐中,協方差矩陣\(XX^T\)的特征值分解常由中心化后的樣本矩陣X的奇異值分解代替,試述其原因。

:首先看一下,確實可以通過SVD(奇異值)分解得到協方差矩陣的特征值和特征向量。由附錄A.33式有,任意實矩陣\(A\in R^{m\times n}\)都可以分解為

\[A=U\Sigma V^T \]

其中U和V分別為m階和n階的酉矩陣,\(\Sigma\)是m×n矩陣,對角元以外元素均為零,於是有:

\[AA^T=U\Sigma V^TV\Sigma^TU^T=U\Sigma\Sigma^TU^T\\ A^TA=V\Sigma^TU^TU\Sigma V^T=V\Sigma^T\Sigma V^T\]

因此,\(U\)的列向量是\(AA^T\)的特征向量,\(V\)的列向量是\(A^TA\)的特征向量,\(\Sigma\)矩陣的非零對角元\(\sigma_{ii}\)的平方即為\(AA^T\)\(A^TA\)的共同非零特征值。

在前面原理介紹部分采用的10.2和10.4等圖中,數據維度d=2或3,而樣本數m遠大於數據維數,m>>d。然而在實際情況中,既然需要降維,通常維度d很大,比如對於100張100*100的圖片,m=100,d=10000,此時的協方差矩陣\(XX^T\)的shape為\(R^{10000\times10000}\),矩陣維度較大。而\(X\in R^{10000\times100}\),對其進行SVD(奇異值)分解的計算成本較低一些。

另外,參考博友Vic時代的解答:
其實對X進行奇異值分解,也要消耗與\(XX^T\)相同的10000×10000的存儲空間。
可以先求\(X^TX\in R^{100\times 100}\)的特征分解,得到特征值\(\lambda\)和特征向量\(\nu\),那么\(\lambda\)\(X\nu\)分別也是\(XX^T\)的特征值和特征向量。
因為\(X^TX\nu=\lambda\nu\),等式左右兩邊左乘\(X\)得到,\(XX^T(X\nu)=\lambda (X\nu)\)

10.5 降維中涉及的投影矩陣通常要求是正交的。試述正交、非正交投影矩陣用於降維的優缺點。

正交有兩個好處:

  1. 降維和重構變換計算方便。比如,在PCA中,設新坐標系中基矢為\(\{w_1,w_2,\cdots,w_{d^\prime}\}\),樣本\(x\)在新坐標系中的坐標為\(z\),通過\(z\)重構的樣本坐標為\(\hat{x}=Wz\)。現在假設\(\{w_i\}\)是一組線性無關的基矢,但是未必正交歸一,那么為了滿足“最近重構”,需要\(\min_z|\hat{x}-x|=min_z|Wz-x|\),該問題有解析解:\(z^*=(W^TW)W^Tx\)。如果\(\{w_i\}\)彼此正交歸一,便有\(W^TW=I\),於是\(z^*=W^Tx\)
  2. 變換后的Z的不同坐標之間是“去相關”的。我們已經知道,在PCA中,變換后,在新的特征空間中,不同特征之間是“不相關”的,也就是協方差矩陣\(ZZ^T\)是對角化的,非對角元素為零。現在,假設有一組基矢\(\{w_i^\prime\}\)不是正交化的,設為\(W^\prime\),它可以由正交化的\(W\)線性表出:\(W^\prime=WA\),從“最近重構”的角度,兩者的重構效果應該等同:\(W^{\prime }z'=Wz\),於是\(z^\prime=A^{-1}z\)\(Z^\prime Z^{\prime T}=A^{-1}ZZ^T{A^{-1}}^T\),此時協方差的非對角元就未必為零了。

其實至於不同特征之間“去相關”有什么好處,現在沒有相關的實踐應用,不好體會,留待以后有所體會的時候再回來補充吧。
關於正交的缺點方面,大概也就是“去相關”后的缺點吧,某些情況下也許特征之間完全去相關未必是好事。同樣需要慢慢實踐、體會。現在想到的例子,比如:一個人的身高和體重是正相關的,通過PCA方法大概可以得到“身體年齡”和“肥瘦度”兩個相互獨立的特征,但是,或許在一個特定任務中,直接用身高和體重兩個特征更容易一些。

10.6 試使用MATLAB中的PCA函數對Yale人臉數據集進行降維,並觀察前20個特征向量所對應的圖像。

  1. Yale人臉數據集在vision.uscd.edu這個地址不太好下載,可以從這里下載,提取碼:uuae 。Yale人臉數據有15人,每人11張照片。原始照片如下:
    在這里插入圖片描述
  2. 詳細編程代碼附后。這里采用Python語言編寫,PCA利用sklearn中的PCA類實現。
    圖片文件數據讀取可以參考這篇博文
  3. PCA前20個特征向量可視化效果:
    在這里插入圖片描述
    利用這20個特征向量來重構回去的樣本圖片效果:
    在這里插入圖片描述

10.7 試述核化線性降維與流形學習之間的聯系及優缺點。(暫缺)

10.8 k近鄰圖與ε近鄰圖存在的短路和斷路問題會給Isomap造成困擾,試設計一個方法緩解該問題。(暫缺)

10.9 試設計一個方法為新樣本找到LLE降維后的低維坐標。(暫缺)

10.10 試述如何確保度量學習產生的距離能滿足距離度量的四條基本性質。(暫缺)


附:編程代碼

習題10.1(Python)

# -*- coding: utf-8 -*-
"""
Created on Mon Apr 27 11:04:11 2020

@author: Administrator
"""

import numpy as np
import matplotlib.pyplot as plt

#設置繪圖時顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False

def kNN(X,Y,Xpre,k,p=2):
    # k近鄰算法
    # X:樣本數據
    # Y:樣本標記
    # Xpre:待預測樣本
    # k:k近鄰的k值
    # p:計算距離所采用的閔可夫斯基距離的p值
    mt,n=X.shape             #訓練樣本數和特征數
    Xpre=np.array(Xpre).reshape(-1,n)
    mp=Xpre.shape[0]         #預測樣本數
    dist=np.zeros([mp,mt])   #存儲預測樣本和訓練樣本之間的距離
    for i in range(mt):
        dist[:,i]=(((abs(Xpre-X[i]))**p).sum(axis=1))**(1/p)
    neighbor=np.argsort(dist,axis=1)   #訓練樣本按距離遠近排序的索引號
    neighbor=neighbor[:,:k]            #只取前k個作為最近鄰
    Ypre=Y[neighbor]
    return (Ypre.sum(axis=1)>=0)*2-1   #西瓜3.0α僅兩類,故可如此計算

# 西瓜3.0α 樣本數據
X=np.array([[0.697,0.46],[0.774,0.376],[0.634,0.264],[0.608,0.318],[0.556,0.215],
   [0.403,0.237],[0.481,0.149],[0.437,0.211],[0.666,0.091],[0.243,0.267],
   [0.245,0.057],[0.343,0.099],[0.639,0.161],[0.657,0.198],[0.36,0.37],
   [0.593,0.042],[0.719,0.103]])
Y=np.array([1,1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1])

# 執行kNN算法
# 嘗試 k=1,3,5,p=1,2,30的不同情況
ks=[1,3,5]
ps=[1,2,50]  #p=1為曼哈頓距離,p=2為歐式距離,p=50(→∞)為切比雪夫距離
for i,k in enumerate(ks):
    for j,p in enumerate(ps):
        # kNN算法預測結果
        x0=np.linspace(min(X[:,0]),max(X[:,0]),60)
        x1=np.linspace(min(X[:,1]),max(X[:,1]),60)        
        X0,X1=np.meshgrid(x0,x1)
        Xpre=np.c_[X0.reshape(-1,1),X1.reshape(-1,1)]
        Ypre=kNN(X,Y,Xpre,k,p).reshape(X0.shape)
        # 畫圖
        plt.subplot(len(ks),len(ps),i*len(ps)+j+1)
        #plt.axis('equal')
        plt.title('k=%d,p=%d'%(k,p))
        plt.xlabel('密度')
        plt.ylabel('含糖率')
        # 畫樣本點
        plt.scatter(X[Y==1,0],X[Y==1,1],marker='+',s=30,label='好瓜')
        plt.scatter(X[Y==-1,0],X[Y==-1,1],marker='_',s=30,label='壞瓜')
        # 畫決策樹邊界 (直接根據教材上圖4.10和4.11確定邊界曲線坐標)
        plt.plot([0.381,0.381,0.56,0.56,max(X[:,0])],
                  [max(X[:,1]),0.126,0.126,0.205,0.205],'k',label='決策樹邊界')
        # 畫kNN邊界
        plt.contour(X0,X1,Ypre,1,colors='r',s=2)
plt.show()                

習題10.6(Python)

# -*- coding: utf-8 -*-
"""
Created on Sat May 16 21:03:47 2020

@author: Administrator
"""
import numpy as np
from PIL import Image
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

#==========讀取Yale圖片數據===========
#Yale人臉數據為15人,每人11張照片
#下載到的Yale文件存儲規律是:
#    Yale文件夾下有名稱分別為1~15的15個子文件夾,
#    每個子文件夾下有s1.bmp~s11.bmp的11張圖片

rootpath='Yale'  #Yale根文件夾所在路徑,我這里將Yale文件夾放在當前目錄下,若其他位置,改成相應路徑即可
X=[]             #存儲圖片數據
for person in range(15):
    for num in range(11):
        path=rootpath+'/'+str(person+1)+'/s'+str(num+1)+'.bmp'
        img=Image.open(path)
        X.append(np.array(img).reshape(-1))
X=np.array(X)

#==========觀察這15人的圖片============
#只顯示第一張圖片s1
for i in range(3):
    for j in range(5):
        plt.subplot(3,5,i*5+j+1)
        plt.imshow(X[(i*5+j)*11,:].reshape(100,100),cmap='gray')
        plt.axis('off')
        plt.title('%d'%(i*5+j+1))
plt.show()

#========PCA主成分分析(d'=20)==========
pca=PCA(n_components=20)
Z=pca.fit_transform(X)   #輸入X的shape為m×d,與教材中相反
W=pca.components_        #特征向量W,shape為d'×d,與教材中相反

#====可視化觀察特征向量所對應的圖像======
for i in range(5):
    for j in range(4):
        plt.subplot(4,5,i*4+j+1)
        plt.imshow(W[i*4+j,:].reshape(100,100),cmap='gray')
        plt.axis('off')
        plt.title('w%d'%(i*4+j+1))
plt.show()

#========觀察重構后的15人圖片===========
#只顯示第一張圖片s1
X_re=pca.inverse_transform(Z)
for i in range(3):
    for j in range(5):
        plt.subplot(3,5,i*5+j+1)
        plt.imshow(X_re[(i*5+j)*11,:].reshape(100,100),cmap='gray')
        plt.axis('off')
        plt.title('%d'%(i*5+j+1))
plt.show()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM