- 機器學習:使用OpenCV、Python和scikit-learn進行智能圖像處理(原書第2版)
- (印)阿迪蒂亞·夏爾馬 維什韋什·拉維·什里馬利 (美)邁克爾·貝耶勒
- 3393字
- 2020-11-24 18:13:01
3.4 使用回歸模型預測連續的結果
現在,讓我們把注意力轉向回歸問題。我相信你現在已經熟記了,回歸是對連續結果的預測,而不是對離散的類標簽的預測。
3.4.1 理解線性回歸
最簡單的回歸模型稱之為線性回歸。線性回歸隱含的思想是用特征的一個線性組合來描述一個目標變量(例如,波士頓房價——我們在第1章中學習過的各種數據集)。
為了簡單起見,讓我們只關注兩個特征。假設我們想用兩個特征預測(今天的股票價格和昨天的股票價格)明天的股票價格。我們將今天的股票價格作為第一個特征f1,昨天的股票價格作為第二個特征f2。然后,線性回歸的目標是學習兩個權重系數:w1和w2,這樣我們就可以預測明天的股票價格,如下所示:
?=w1f1+w2f2
(3.1)
這里,?是明天的真實股票價格y的預測。
注意
只有一個特征變量的特例稱為簡單線性回歸(simple linear regression)。
根據更多過去的股票價格樣本,我們可以很容易擴展特征。如果我們有M個特征值,而不是兩個特征值的話,我們可以把方程(3.1)擴展到M個乘積的和,這樣每個特征都有一個權重系數。我們可以把方程結果寫成這樣:

我們先從幾何角度看一下方程(3.2)。在只有一個特征f1的情況下,方程(3.2)中的?將變成? = w1f1,這實際上是一條直線。在有兩個特征的情況下,? = w1f1+ w2 f2可以描述特征空間中的一個平面,如圖3-7所示。

圖3-7 兩個特征構成特征空間中的一個平面
注意
在N維空間中,這就是一個超平面。如果一個空間是N維的,那么它的超平面有N–1維。
如圖3-7所示,所有這些直線和平面都相交于原點。但是如果我們想要估計的真實的y值沒有經過原點會怎么樣?
要從原點抵消?,習慣上是添加另一個不依賴于任何特征值的權重系數,因此它就充當一個偏置項。在一維情況下,將該項當作?截距。在實踐中,這通常是通過設置f0 = 1實現的,這樣可以將w0作為偏置項:

這里,我們可以保持f0 = 1。
最后,線性回歸的目標是學習一組權重系數,這些權重系數使得預測盡可能準確地逼近真實值。與我們在分類器中顯式地獲取一個模型的準確率不同,回歸中的評分函數通常采用所謂代價函數(或者損失函數)的形式。
如在3.2節中所述,我們有許多評分函數可以用于度量回歸模型的性能。最常用的代價函數可能就是均方誤差了,它通過比較預測值?i與目標輸出值yi,然后取平均,計算每個數據點i的一個誤差(yi–?i)2:

這里,N是數據點數。
因此,回歸問題成為一個優化問題——我們的任務是找到使代價函數最小的權重設置。
注意
這通常是通過一個迭代算法(逐個數據點應用迭代算法)來實現的,因此可以逐步降低代價函數。我們會在第9章中更深入地討論這類算法。
理論已經講得足夠多了——讓我們來編碼吧!
3.4.2 OpenCV中的線性回歸
在對實際數據集嘗試線性回歸之前,先讓我們來了解一下如何使用cv2.fitLine函數用一條直線擬合二維或三維點集:
1)讓我們從生成一些點開始。通過向直線y = 5x + 5上的點添加噪聲來生成這些點:

2)使用下列代碼,我們還可以可視化這些點:

結果如圖3-8所示,直線是真實的函數。

圖3-8 生成數據點的可視化圖
3)接下來,我們將這數據些點拆分成訓練集和測試集。這里,我們根據70:30的比例拆分數據,70%的數據點用于訓練,30%的數據點用于測試:

4)現在,讓我們借助cv2.fitLine用一條線擬合這個二維點集。該函數取下列參數:
- points:這是一條直線必須擬合的點集。
- distType:這是M-估計所使用的距離。
- param:這是數值參數(C),用于某些類型的距離。我們將其保持為0,這樣就可以選擇一個最優值。
- reps:這是原點到直線的距離準確率。0.01是reps的一個不錯的默認值。
- aeps:這是角度的準確率。0.01是aeps的一個不錯的默認值。
注意
更多信息參見documentation。
5)讓我們來看看使用不同的距離類型選項會得到什么樣的結果?

6)我們還將使用scikit-learn的LinearRegression擬合訓練點,然后使用predict函數來預測這些點的y值:

7)我們使用reshape(–1, 1)和reshape(1, –1),將NumPy數組轉換成一個列向量,然后回到一個行向量:

上面這段冗長的代碼實現的唯一目標是創建一個圖,它可以用來比較使用不同距離測量得到的結果。
得到的結果如圖3-9所示。

圖3-9 使用不同距離度量得到的比較結果
我們可以清楚地看到,scikit-learn的LinearRegression模型比OpenCV的fitLine函數執行結果更好。現在,讓我們使用scikit-learn的API來預測波士頓的房價。
3.4.3 使用線性回歸預測波士頓房價
為了更好地理解線性回歸,我們想構建一個簡單模型,可應用于一個最著名的機器學習數據集:波士頓房價數據集(Boston housing prices dataset)。這里的目標是利用犯罪率、房產稅率、到就業中心的距離和高速公路可達性等信息預測20世紀70年代波士頓一些社區的房價。
1. 加載數據集
我們再次感謝scikit-learn,讓我們能夠輕松訪問數據集。就像我們之前做的那樣,首先導入所有必要的模塊:

然后,加載數據集只需一行程序:

正如在前面的命令中討論過的那樣,boston對象的結構與iris對象相同。在'DESCR'中我們可以獲取關于數據集的更多信息,在'data'中找到所有的數據,在'feature_names'中找到所有的特征名稱,在'filename'中找到波士頓CSV數據集的物理位置,并在'target'中找到所有的目標值:

數據集共包含506個數據點,每個數據點有13個特征:

當然,我們只有一個目標值,那就是房價:

2. 訓練模型
現在,讓我們創建一個LinearRegression模型,然后我們將在該訓練集上進行訓練:

在上面的命令中,我們希望將數據拆分成訓練集和測試集。我們可以根據自己認為合適的方式自由地拆分數據,但是通常預留10%到30%的數據用于測試是最好的。這里,我們選擇10%,使用test_size參數:

在scikit-learn中,train函數命名為fit,但是在其他方面,它的行為與在OpenCV中是完全一樣的:

通過比較真實房價y_train和我們的預測linreg.predict(X_train),我們可以看看預測的均方誤差:

linreg對象的score方法返回決定系數(R平方):

3. 測試模型
為了測試模型的泛化性能,我們計算測試數據的均方誤差:

我們注意到,測試集的均方誤差略低于訓練集的均方誤差。這很不錯,因為我們主要關心的是測試誤差。但是,從這些數據中,我們真的很難理解這個模型到底有多好。也許繪制數據圖會更好:

生成的圖如圖3-10所示。

圖3-10 生成的測試數據的預測結果
這更有意義!這里,我們看到所有測試樣本的ground truth房價用紅色表示(圖中淺色曲線),predicted房價用藍色表示(圖中深色曲線)。如果你問我的話,我覺得挺接近的。可是,值得注意的是,對于非常高或者非常低的房價,比如數據點12、18、42的峰值,該模型往往偏離得較遠。我們通過計算R平方來形式化數據的方差:

x軸是ground truth價格y_test,y軸是predicted價格y_pred。我們還繪制了一條對角線作為參考(用黑色虛線'k--'),這我們很快就能看到。可是我們還希望在文本框中顯示R2得分和均方誤差:

這將生成圖3-11,這是繪制模型擬合的一種專業方式。

圖3-11 模型擬合結果
如果我們的模型是完美的,那么所有的數據點都應該位于虛線對角線上,因為y_pred總是等于y_true。對角線上的偏差表明模型存在一定的誤差,或者數據中存在一些模型無法解釋的偏差。實際上,R2表明我們能夠解釋76%的數據分散,均方誤差是14.996。這些是我們可以用來比較線性回歸模型和一些更復雜的模型的性能指標。
3.4.4 Lasso回歸和嶺回歸的應用
機器學習中一個常見的問題是,一個算法在訓練集上可能工作得很好,但是在應用到未知數據時,就會產生很多錯誤。你可以明白這是有問題的,通常因為我們最感興趣的是模型對新數據的泛化能力。一些算法(如決策樹)比其他算法更容易受到這種現象的影響,但是即使是線性回歸也可能會受到影響。
注意
這種現象也被稱為過擬合(overfitting),在第5章和第11章中,我們將對過擬合進行詳細的討論。
降低過擬合的一種常見技術是正則化(regularization),該技術涉及向代價函數中添加另一個與所有特征值無關的約束。常用的兩個正則化項如下所述:
- L1正則項:這將向評分函數中添加一項,該項與所有絕對權值的和成正比。或者說,這是基于權值向量的L1范數(也稱為直角距離、蛇距,或者曼哈頓距離)。因為曼哈頓街道的網格布局,L1范數類似于一個度量紐約出租車司機從A點到B點的距離。由此得到的算法使這個距離最小化,也稱為Lasso回歸。
- L2正則項:這將向評分函數中添加一項,該項與所有權重平方值的和成正比。或者說,這是基于權值向量的L2范數(也稱之為歐氏距離,Euclidean distance)。因為L2范數涉及一個平方運算,因此它對權重向量中的強異常值的懲罰要比L1范數嚴很多。由此得到的算法也稱為嶺回歸。
這個過程與前面的過程完全相同,只是我們替換了初始化命令,并加載了Lasso或者RidgeRegression對象。具體來說,我們需要替換以下命令:

對于Lasso回歸算法,我們可以將上面這行代碼修改為:

對于ridge回歸算法,我們可以將上面這行代碼修改為:

建議你用波士頓數據集代替傳統的線性回歸測試這兩種算法。泛化誤差(In [25])是如何變化的呢?預測圖(In [27])是如何變化的呢?你認為性能上有改進嗎?