機器學習-幾種迴歸模型原理和實現

1. 什麼是迴歸?

分類的目標變量是標稱型數據,而回歸是對連續型數據的預測。迴歸分析是一種預測建模技術,研究因變量和自變量之間的關係,如銷售量預測或製造缺陷預測等,下圖中的紅線表示的就是迴歸曲線。

迴歸分析

迴歸不同於分類和聚類,他們的區別可以用下圖形象的表達出來。

迴歸-分類-聚類的區別

2. 迴歸模型

這裏使用sklearn進行代碼實現,如果想手動實現的話,可以看《機器學習實戰》,那本書有部分的算法實現,下面介紹的算法統一使用的函數如下

def load_data(file_path):
    num_feat = len(open(file_path).readline().split("\t")) - 1
    data_mat = list()
    lable_mat = list()
    fr = open(file_path)
    for line in fr.readlines():
        line_arr = list()
        cur_line = line.strip().split("\t")
        for i in range(num_feat):
            line_arr.append(float(cur_line[i]))
        data_mat.append(line_arr)
        lable_mat.append(float(cur_line[-1]))
    return data_mat, lable_mat
  • 繪製迴歸結果
def plot_regression(model, x_data, y_data):
    x_data = np.mat(x_data)
    y_data = np.mat(y_data).T
    x_train, y_train = x_data[:150,1:], y_data[:150,:]
    x_test, y_test = x_data[150:,1:], y_data[150:,:]
    model.fit(x_train, y_train)
    score = model.score(x_test, y_test)
    result = model.predict(x_train)
    plt.figure()
    srt_idx = x_train.argsort(0)
    plt.plot(x_train[srt_idx].reshape(-1,1), y_train[srt_idx].reshape(-1,1), 'go', label = "true value")
    plt.plot(x_train[srt_idx].reshape(-1,1), result[srt_idx].reshape(-1,1), 'ro-', label = "predict value")
    plt.title("score:%f" % score)
    plt.legend()
    plt.show()

2.1 線性迴歸

2.1.1 普通線性迴歸

提到迴歸,首先想到的肯定是線性迴歸(linear regression),因爲它是最容易理解,最簡單的迴歸方法。設待擬合的數據對象爲X={x1,x2,...,xm}X=\{x_1,x_2,...,x_m\},其對應的真實值爲y={y1,y2,...,ym}y=\{y_1,y_2,...,y_m\},線性模型可以寫爲
y^=Xw \hat{y}=Xw
其中,ww迴歸係數,我們用平方誤差來衡量擬合的誤差
L(X)=i=1m(yixiTw)2=(yXw)2 L(X)=\sum_{i=1}^{m}\left ( y_i-x_{i}^{T}w\right )^2=\left ( y-Xw\right )^2
上式對ww求導等於0可以得到
L(X)w=(yTywTXTyyTXwwTXTXw)w=2XT(yXw)=0 \frac{\partial L(X)}{\partial w}=\frac{\partial (y^Ty-w^TX^Ty-y^TXw-w^TX^TXw)}{\partial w}=2X^T\left ( y-Xw\right )=0
可以得到
w^=(XTX)1XTy \hat{w}=(X^TX)^{-1}X^Ty
上述方式容易對訓練數據欠擬合,一種好的解決方式是局部加權線性迴歸,爲每個誤差增加一個權重wiw_i(這裏的ww並不是上面的w^\hat{w}),此時誤差函數可以寫成
L(X)=i=1mwi(yixiTw)2=[W(yXw)]2 L(X)=\sum_{i=1}^{m}w_i\left ( y_i-x_{i}^{T}w\right )^2=[W( y-Xw)]^2
其中,WW是一個對角矩陣,也叫做核,核的類型可以自由選擇,最常見的就是高斯核,高斯覈對應的權重如下
W(j,j)=exp(xixj22k2) W(j,j)=\exp\left(\frac{\|x_{i}-x_{j}\|^{2}}{-2k^2}\right)
注意:這裏的xix_i是指的單個數據,每個數據對應的權重矩陣都不同。
同樣的,對新的誤差函數L(X)L(X)求導可以得到此時迴歸係數爲
w^=(XTWX)1XTWy \hat{w}=(X^TWX)^{-1}X^TWy
這裏的WW其實是WTWW^TW,但是使用WW代替具有同樣的意義並且簡便。

sklearn調用代碼:

x_data, y_data = load_data("ex0.txt")
from sklearn import linear_model
# 線性迴歸
model_linear_regression = linear_model.LinearRegression()
plot_regression(model_linear_regression, x_data, y_data)

繪製出的迴歸曲線如下圖所示

linear regression

2.1.2 嶺迴歸

我們看線性迴歸中的輸入集X={x1,x2,...,xm}X=\{x_1,x_2,...,x_m\},假設其維度爲nn,當n>mn>m的時候,XX不是滿秩矩陣,無法求解逆矩陣,這時候就需要用到**嶺迴歸(ridge regression)**了,在矩陣XTXX^TX上加上一個λI\lambda I讓其成爲滿秩矩陣,那麼這個時候的迴歸係數爲
w^=(XTX+λI)1XTy \hat{w}=(X^TX+\lambda I)^{-1}X^Ty

sklearn調用代碼:

x_data, y_data = load_data("ex0.txt")
from sklearn import linear_model
# Ridge迴歸
model_ridge = linear_model.Ridge(alpha = 0.01)
plot_regression(model_ridge, x_data, y_data)

繪製出的迴歸曲線如下圖所示

ridge regression

2.2 決策樹迴歸

決策樹學習常用的算法有ID3、C4.5、CART(classification and regression tree),這介紹用於迴歸的決策樹CART,具體的方法理論參考李航的《統計學習方法》。

我們考慮輸入的訓練數據D={X,y}={(x1,y1),(x1,y1),...,(xm,ym)}D=\{X,y\}=\{(x_1,y_1),(x_1,y_1),...,(x_m,y_m)\},一個迴歸樹對應着輸入空間(即特徵空間)的一個劃分以及在劃分的單元上的輸出值,假設已將輸入空間劃分爲MM個單元R1,R2,...,RMR_1,R_2,...,R_M,並且在每一個單元上都有一個固定的輸出值cmc_m,那麼迴歸樹模型可以表示爲
f(x)=m=1McmI(xRm) f(x)=\sum_{m=1}^{M}c_mI(x \in R_m)
其中,函數II對應着0-1函數。當輸入空間的劃分確定時,可以用平方誤差xiRm(yif(xi))\sum_{x_i \in R_m}(y_i-f(x_i))來表示迴歸樹對於訓練數據的預測誤差,用平方誤差最小的準則求解每個單元上的最優輸出值,那麼單元RmR_m上的最優值cm^\hat {c_m}RmR_m上的所有輸入實例xix_i對應的輸出yiy_i的均值,即
cm^=ave(yixiRm) \hat {c_m} = ave(y_i|x_i \in R_m)
上面是整個樹的輸出形式,關鍵的問題來了,怎麼對輸入空間進行劃分?這裏採用啓發式的算法,選擇第jj個變量和它取的值ss作爲切分變量(spliting variable)和切分點(spliting point),並定義兩個區域
R1(j,s)={xxjs}R2(j,s)={xxj>s} R_1(j,s)=\{x|x_j≤s\} \quad R_2(j,s)=\{x|x_j>s\}
然後尋找最優切分變量和最優切分點,即
m(s)=minj,s[minc1xiRj(j,s)(yic1)2+minc2xiRj(j,s)(yic2)2] m(s)=\min_{j,s}\left[\min_{c_1}\sum_{x_i \in R_j(j,s)}(y_i-c_1)^2+\min_{c_2}\sum_{x_i \in R_j(j,s)}(y_i-c_2)^2\right]
簡單的理解,就是在要求切分點ss兩邊的區域的均方差都儘量小的同時,保證兩個區域的最小均方差和是最小的。

對每一對(j,s)(j,s),均值表示爲
c1^=ave(yixiR1(j,s))c2^=ave(yixiR2(j,s)) \hat {c_1} = ave(y_i|x_i \in R_1(j,s))\quad \hat {c_2} = ave(y_i|x_i \in R_2(j,s))
遍歷所有輸入變量,找到最優的對(j,s)(j,s),從而將輸入空間切分爲兩個區域,接着對切分的兩個區域重複上述劃分過程,直到滿足停止條件爲止,這樣一個迴歸樹的生成就完成了。

舉個🌰,輸入數據DD如下表所示。

xix_i 1 2 3 4 5 6
yiy_i 5.56 5.70 5.91 6.40 6.90 7.95

對上述連續型變量,只有一個切分變量,那麼考慮切分點爲1.5, 2.5, 3.5, 4.5, 5.5。對切分點依次求解R1,R2,c1,c2,m(s)R_1,R_2,c_1,c_2,m(s),例如當切分點爲2.5時,R1={1,2},R2={3,4,5,6}R_1=\{1,2\},R_2=\{3,4,5,6\},其他的計算如下
c1=1N1xiR1(j,s)yi=12(5.56+5.70)=5.63c2=1N2xiR2(j,s)yi=14(5.91+6.40+6.90+7.95)=6.79sm=minj,s[minc1xiR1(j,s)(yic1)2+minc2xiR2(j,s)(yic2)2]=2.294 c_1=\frac{1}{N_1}\sum_{x_i \in R_1(j,s)}y_i=\frac{1}{2}(5.56+5.70)=5.63 \\ c_2=\frac{1}{N_2}\sum_{x_i \in R_2(j,s)}y_i=\frac{1}{4}(5.91+6.40+6.90+7.95)=6.79 \\ s_m=\min_{j,s}\left[\min_{c_1}\sum_{x_i \in R_1(j,s)}(y_i-c_1)^2+\min_{c_2}\sum_{x_i \in R_2(j,s)}(y_i-c_2)^2\right]=2.294
第一次切分時,對象爲全體輸入,計算出來的sms_m值如下表所示。

切分點 1.5 2.5 3.5 4.5 5.5
s(m)s(m) 3.23468 2.294 1.31373333 0.956725 1.21752

可以看到,當s=4.5s=4.5時,取得最小的s(m)s(m)值,此時的迴歸估計值爲全體輸入的均值6.403,遞歸求解左子樹和右子樹的迴歸估計值,最終求解的迴歸方程爲
f(x)={5.723x3.56.43.5<x4.56.94.5<x5.57.95x>5.5 f(x)=\begin{cases} 5.723 & x≤3.5 \\ 6.4 & 3.5<x≤4.5 \\ 6.9 & 4.5<x≤5.5 \\ 7.95 & x>5.5 \end{cases}

這個過程可以使用graphviz模塊顯示出來。

image-20191130004808546

使用本文一開始提到的數據,決策樹迴歸的代碼如下

# 決策樹迴歸
from sklearn import tree
model_decisiontree_regression = tree.DecisionTreeRegress(min_weight_fraction_leaf=0.01)
plot_regression(model_decisiontree_regression, x_data, y_data)

decision tree regression

2.3 SVM迴歸

先回顧一下在基本線性可分情況下的SVM模型:
err(xi,yi)={0yiwxibεyiwxibεyiwxib>ε \operatorname{err}\left(x_{i}, y_{i}\right)=\left\{\begin{array}{ll}{0} & {\left|y_{i}-w \cdot x_{i}-b\right| \leq \varepsilon} \\ {\left|y_{i}-w \cdot x_{i}-b\right|-\varepsilon} & {\left|y_{i}-w \cdot x_{i}-b\right|>\varepsilon}\end{array}\right.
分類SVM模型中要讓訓練集中的每個樣本儘可能遠離自己類別一側的支持向量,迴歸模型也一樣,沿用的是最大建哥分類器的思想。

對於迴歸模型,優化的目標函數和分類模型保持一致,依然是minw,b12w2\min_{w,b}\frac{1}{2}\|w\|^{2},但是約束條件不一樣,迴歸模型的目標是讓訓練集中的每個樣本點(xi,yi)(x_i,y_i)儘量擬合到一個線性模型yi=wxi+by_i=wx_i+b上,對於一般的迴歸模型使用均方誤差MSE作爲損失函數的,但是SVM迴歸不是這樣定義的。

SVM需要我們定義一個常量ε>0\varepsilon>0,對於某一個點(xi,yi)(x_i,y_i),如果yiwxibε\left|y_i-wx_i-b\right|≤\varepsilon,則完全沒有損失,如果yiwxib>ε\left|y_i-wx_i-b\right|>\varepsilon,則對應的損失爲yiwxibε\left|y_i-wx_i-b\right|-\varepsilon,這個和均方差損失不同,對於均方差,只要yiwxib0\left|y_i-wx_i-b\right|\neq 0就會有損失。

如下圖所示,在藍色條帶裏面的點是沒有損失的,但是在外面的點是有損失的,損失大小爲紅色線的長度。

SVM迴歸損失函數

總結下,我們的SVM迴歸模型的損失函數度量爲
err(xi,yi)={0yiwxibεyiwxibεyiwxib>ε \text{err}\left(x_{i}, y_{i}\right)=\left\{\begin{array}{ll}{0} & {\left|y_{i}-w \cdot x_{i}-b\right| \leq \varepsilon} \\ {\left|y_{i}-w \cdot x_{i}-b\right|-\varepsilon} & {\left|y_{i}-w \cdot x_{i}-b\right|>\varepsilon}\end{array}\right.
有了損失函數之後,我們就可以定義SVM迴歸的目標函數爲
min12w22 s.t yiwxibε(i=1,2,,m) \min \frac{1}{2}\|w\|_{2}^{2} \\ \text { s.t }\left|y_{i}-w \cdot x_{i}-b\right| \leq \varepsilon(i=1,2, \ldots,m)
這個模型的最優解求解過程這裏不再贅述,有興趣的可以看參考[2]或者[3]中的論述。

使用本文一開始提到的數據,SVM迴歸的代碼如下

# SVM迴歸
from sklearn import svm
model_svr = svm.SVR()
plot_regression(model_svr, x_data, y_data)

SVM regression

參考

[1] 李航. 統計學習方法, 清華大學出版社

[2] CSDN-SVM迴歸博客

[3] cnblog-SVM迴歸博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章