專欄【機器學習】
【機器學習】《機器學習》周志華西瓜書 筆記/習題答案 總目錄
——————————————————————————————————————————————————————
習題
-
試想一下,擬合曲線時,如果不考慮偏置項,則只能擬合一條過原點的曲線。在多元線性迴歸中也同理,如果不考慮偏置項,那麼擬合的超平面就只能過原點,但現實中數據點的分佈並不是這樣的。使用一個不依賴於屬性的的偏置項能夠讓權重向量所描述的超平面更好地擬合數據點的分佈。如果輸出值的期望(均值)爲0就不需要考慮偏置項了,或者說偏置項此時就等於0。
-
或者可以用變量歸一化(max-min或z-score)來消除偏置。
-
再或者可以用任意兩個線性模型實例進行相減,以此消除了偏置,然後對新的樣本做線性迴歸,只需要用模型 。
式1:
式2:
一種方法 筆記中已經提到了,檢驗一個函數是否凸函數,可以看其二階導數是否在區間上恆大於0。
目標函數(也即sigmoid函數):
顯然,sigmoid的二階導數在自變量大於0處取值小於0,所以它不是凸函數。
對數似然函數:
可以看到這個函數在區間上恆大於0(兩邊無限延伸),符合凸函數的要求。
另一種證明方法是利用 如果一個多元函數是凸的,那麼它的Hessian矩陣是半正定的。
對於式1,這裏 理解爲標量,而 爲 的列向量。
則其一階導:
其二階導:
(即海森矩陣)
其中 秩爲1,非零特徵值只有一個,其正負號取決於 ,顯然當在(0,1)之間變化時,特徵值正負號會發生變化,於是式1關於 的海森矩陣非半正定,因此非凸。
對於式2,關於 的二階導有 (原書p60)
其中第一個等號是原書中的,第二個等號中 爲 矩陣,每一列對應一個樣本, 爲對角矩陣, 。
關於 ,對於任意向量 都有:
因此其海森矩陣爲半正定。
西瓜數據集3.0α:
編號 | 密度 | 含糖率 | 好瓜 |
---|---|---|---|
1 | 0.697 | 0.460 | 是 |
2 | 0.774 | 0.376 | 是 |
3 | 0.634 | 0.264 | 是 |
4 | 0.608 | 0.318 | 是 |
5 | 0.556 | 0.215 | 是 |
6 | 0.403 | 0.237 | 是 |
7 | 0.481 | 0.149 | 是 |
8 | 0.437 | 0.211 | 是 |
9 | 0.666 | 0.091 | 否 |
10 | 0.243 | 0.0267 | 否 |
11 | 0.245 | 0.057 | 否 |
12 | 0.343 | 0.099 | 否 |
13 | 0.639 | 0.161 | 否 |
14 | 0.657 | 0.198 | 否 |
15 | 0.36 | 0.37 | 否 |
16 | 0.593 | 0.042 | 否 |
17 | 0.719 | 0.103 | 否 |
把這個數據集轉換爲csv表格,並且注意要把 標記轉換爲0、1,注意不是-1、+1!!邏輯迴歸的二分類標記必須是0、1,對應於sigmoid函數的值域。
代碼:
%matplotlib inline
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
#讀入csv文件數據
df = pd.read_csv('../watermelon3.0alpha.csv')
df['intercept'] = 1.0
df
dataMat = np.array(df[['density','Sugar_content','intercept']].values[:,:])
labelMat = np.mat(df['label'].values[:]).transpose()
def sigmoid(z):
return 1.0 / (1 + np.exp(-z))
def LogisticRegression(dataMat,labelMat):
m,n = np.shape(dataMat)
alpha = 0.05 # 步長
iterations = 2000 # 最大迭代次數
weights = np.array(np.array(np.ones((n,1)))) # 初始權重
# 用梯度上升法更新權重
for k in range(iterations):
z = np.dot(dataMat,weights)
error = labelMat - sigmoid(z)
weights = weights + alpha * np.dot(dataMat.transpose(),error)
return weights
def DrawResult(weights):
m = np.shape(dataMat)[0]
xcord1, ycord1, zcord1= [], [], []
xcord2, ycord2, zcord2= [], [], []
xcord3, ycord3, zcord3= [], [], []
xcord4, ycord4, zcord4= [], [], []
# 按照類別劃分數據點
for i in range(m):
if labelMat[i]==1:
z = sigmoid(dataMat[i, :] * weights)
if z>= 0.5:
xcord1.append(dataMat[i, 0])
ycord1.append(dataMat[i, 1])
zcord1.append(z)
else:
xcord2.append(dataMat[i, 0])
ycord2.append(dataMat[i, 1])
zcord2.append(z)
else:
z = sigmoid(dataMat[i, :] * weights)
if z< 0.5:
xcord3.append(dataMat[i, 0])
ycord3.append(dataMat[i, 1])
zcord3.append(z)
else:
xcord4.append(dataMat[i, 0])
ycord4.append(dataMat[i, 1])
zcord4.append(z)
# 創建三維圖表
fig = plt.figure()
ax = Axes3D(fig)
# 畫出判決平面
x = np.arange(0.2, 1.0, 0.1)
y = np.arange(0.0, 0.6, 0.1)
X, Y = np.meshgrid(x, y)
z = np.array([0.5 for x,y in zip(np.ravel(X), np.ravel(Y))])
Z = z.reshape(X.shape)
ax.plot_surface(X, Y, Z, rstride=10, cstride=10, color=(0, 0.6, 0.6, 0.1))
# 按類別畫出數據點
ax.scatter(xcord1, ycord1, zcord1, s=30, c='red')
ax.scatter(xcord2, ycord2, zcord2, s=30, c='red', marker='x')
ax.scatter(xcord3, ycord3, zcord3, s=30, c='green')
ax.scatter(xcord4, ycord4, zcord4, s=30, c='green', marker='x')
ax.set_xlim(0.0, 1.0)
ax.set_ylim(-0.1, 0.7)
ax.set_zlim(-0.2, 1.2)
ax.set_xlabel('density')
ax.set_ylabel('Sugar content')
ax.set_zlabel('Logit')
plt.title('Gradient ascent logistic regression')
plt.show()
weights = LogisticRegression(dataMat, labelMat)
DrawResult(weights)
用了梯度上升法來更新權值,步長0.05,最大迭代次數2000次。上圖中紅色爲好瓜,綠色爲壞瓜,圓形標記表示預測正確,叉號標記表示預測錯誤。可以看到有一個好瓜被預測爲壞瓜,有兩個壞瓜被預測爲好瓜。事實上,在200次迭代後,已經基本定型了,權值並沒有太大的變化。
參考博客——https://blog.csdn.net/snoopy_yuan/article/details/64131129
參考博客——https://blog.csdn.net/snoopy_yuan/article/details/64443841
給出兩種思路:
- 參考書p57,採用廣義線性模型,如 y-> ln(y)。
- 參考書p137,採用核方法將非線性特徵空間隱式映射到線性空間,得到KLDA(核線性判別分析)。
原書對很多地方解釋沒有解釋清楚,把原論文看了一下《Solving Multiclass Learning Problems via Error-Correcting Output Codes》。
先把幾個涉及到的理論解釋一下。
首先原書中提到:
對同等長度的編碼,理論上來說,任意兩個類別之間的編碼距離越遠,則糾錯能力越強。因此,在碼長較小時可根據這個原則計算出理論最優編碼。
其實這一點在論文中也提到,“假設任意兩個類別之間最小的海明距離爲 ,那麼此糾錯輸出碼最少能矯正 位的錯誤。
拿上圖論文中的例子解釋一下,上圖中,所有類別之間的海明距離都爲4,假設一個樣本正確的類別爲 ,那麼codeword應該爲 ‘0 0 1 1 0 0 1 1’,若此時有一個分類器輸出錯誤,變成‘0 0 0 1 0 0 1 1’,那麼此時距離最近的仍然爲 ,若有兩個分類輸出錯誤如‘0 0 0 0 0 0 1 1’,此時與 的海明距離都爲2,無法正確分類。即任意一個分類器將樣本分類錯誤,最終結果依然正確,但如果有兩個以上的分類器錯誤,結果就不一定正確了。這是 的由來。
此外,原論文中提到,一個好的糾錯輸出碼應該滿足兩個條件:
- 行分離。任意兩個類別之間的codeword距離應該足夠大。
- 列分離。任意兩個分類器 的輸出應相互獨立,無關聯。這一點可以通過使分類器 編碼與其他分類編碼的海明距離足夠大實現,且與其他分類編碼的反碼的海明距離也足夠大(有點繞)。
第一點其實就是原書提到的,已經解釋過了,說說第二點:
如果兩個分類器的編碼類似或者完全一致,很多算法(比如C4.5)會有相同或者類似的錯誤分類,如果這種同時發生的錯誤過多,會導致糾錯輸出碼失效。(翻譯原論文)
個人理解就是:若增加兩個類似的編碼,那麼當誤分類時,就從原來的1變成3,導致與真實類別的codeword海明距離增長。極端情況,假設增加兩個相同的編碼,此時任意兩個類別之間最小的海明距離不會變化依然爲 ,而糾錯輸出碼輸出的codeword與真實類別的codeword的海明距離激增(從1變成3)。所以如果有過多同時發出的錯誤分類,會導致糾錯輸出碼失效。
另外,兩個分類器的編碼也不應該互爲反碼,因爲很多算法(比如C4.5,邏輯迴歸)對待0-1分類其實是對稱的,即將0-1類互換,最終訓練出的模型是一樣的。也就是說兩個編碼互爲補碼的分類器是會同時犯錯的。同樣也會導致糾錯輸出碼失效。
當然當類別較少時,很難滿足上面這些條件。如上圖中,一共有三類,那麼只有 中可能的分類器編碼( ),其中後四種( )是前四種的反碼,都應去除,再去掉全爲0的 ,就只剩下三種編碼選擇了,所以很難滿足上述的條件。事實上,對於 種類別的分類,再去除反碼和全是0或者1的編碼後,就剩下 中可行的編碼。
原論文中給出了構造編碼的幾種方法。其中一個是:
回到題目上,在類別爲4時,其可行的編碼有7種,按照上述方法有:
當碼長爲9時,那麼 [公式] 之後加任意兩個編碼,即爲最優編碼,因爲此時再加任意的編碼都是先有編碼的反碼,此時,類別之間最小的海明距離都爲4,不會再增加。
條件分解爲兩個:一是出錯的概率相當,二是出錯的可能性相互獨立。
先看第一個把,其實就是每個一位上的分類器的泛化誤差相同,要滿足這個條件其實取決於樣本之間的區分難度,若兩個類別本身就十分相似,即越難區分,訓練出的分類器出錯的概率越大,原書p66也提到:
將多個類拆解爲兩個"類別子集“,所形成的兩個類別子集的區分難度往往不同,即其導致的二分類問題的難度不同。
所以每個編碼拆解後類別之間的差異越相同(區分難度相當),則滿足此條件的可能性越大。在實際中其實很難滿足。
第二個,相互獨立。在3.7中也提到過,原論文中也提出一個好的糾錯輸出碼應該滿足的其中一個條件就是各個位上分類器相互獨立,當類別越多時,滿足這個條件的可能性越大,在3.7中也解釋了當類別較少時,很難滿足這個條件。
至於產生的影響。西瓜書上也提到:
一個理論糾錯牲質很好、但導致的三分類問題較難的編碼,與另一個理論糾錯性質差一些、但導致的二分類問題較簡單的編碼,最終產生的模型性能孰強孰弱很難說。
因爲OvR或者MvM在輸出結果階段,是對各個二分類器的結果進行彙總,彙總的這個過程就會消除不平衡帶來的影響(因爲總和總是1)
p66 其實已經給出答案了:
對 OvR 、 MvM 來說,由於對每個類進行了相同的處理,其拆解出的二分類任務中類別不平衡的影響會相互抵消,因此通常不需專門處理.
題目提到僅考慮類別分類的誤分類代價,那麼就默認正確分類的代價爲0。 於是得到分類表,(假設爲3類)
對於二分類而言,將樣本爲正例的後驗概率設爲是p,那麼預測爲正的代價是 , 預測爲負的代價是 。當 樣本會被預測成正例,因爲他的代價更小。當不等式取等號時,得到了最優劃分,這個閥值 ,這表示正例與反例的劃分比例應該是初始的 倍。假設分類器預設的閥值是 ,不考慮代價敏感時,當 時取正例。當考慮代價敏感,則應該是 。
推廣到對於多分類,任意兩類的最優再縮放係數,然而所有類別的最優縮放係數並不一定能同時滿足。當代價表滿足下面條件時,能通過再縮放得到最優解。
設 ,則 對所有 成立,假設有 類,共 個等式,此時代價表中 個數,最少只要知道 2 就能推出整張表。