1. 程式人生 > >斯坦福大學機器學習筆記——特徵和多項式迴歸以及正規方程

斯坦福大學機器學習筆記——特徵和多項式迴歸以及正規方程

我們可以舉一個例子來引入多項式迴歸:
比如我們之前遇到的房價問題,對於房價的影響我們假設有兩個特徵,一個是房子的寬度x1,另外一個是房子的長度x2,這針對房價的估測我們可以建立下面形式的假設:
hθ(x)=θ0+θ1x1+θ2x2
但是我們可以換一個角度思考,我們完全可以用房子的面積x3作為特徵來對房價進行估計,則房子的價格估計可以建立下面的假設:
hθ(x)=θ0+θ1x3
所以我們在建立模型時,可以對一些特徵進行選擇,選擇特徵的不同所構建的假設不同。
但是我們經常見到的問題,並不是都是能夠線性擬合的,比如下面的資料型別:
這裡寫圖片描述
顯然上面的資料使用線性擬合,擬合的效果不是特別好,同時若是我們選擇下面形式的擬合方式:
h

θ(x)=θ0+θ1x+θ2x2
這個形式的擬合方式是二次函式,二次函式擬合上面的資料時,會在對稱軸的右方出現下降的趨勢,所以這種擬合方式也是不合理的,所以我們想到了用到的擬合方式為:
hθ(x)=θ0+θ1x+θ2x2+θ3x3
這種假設能夠很好的擬合該資料型別。
對於使用什麼形式的假設比較合適,通常我們需要先觀察資料然後確定準備嘗試怎樣的模型,也就是說模型的確定是由資料來決定的。
上面提到的二次函式和三次函式擬合方式都可以稱為多項式迴歸。
對於多項式的迴歸我們可以將其轉化為線性迴歸的方式進行擬合,若我們另x1=x,x2=x2,x3=x3,則:
hθ(x)=θ0+θ1x+θ2x2+θ
3
x3=θ0+θ1x1+θ2x2+θ3x3

通過上述方式,我們將多項式迴歸問題轉化為線性問題來求解。
注意:我們採用多項式迴歸時,前面部落格講到的特徵縮放仍然是有必要的。

正規方程:
對於上面的線性迴歸演算法我們都是採用的梯度下降法,使得損失函式最小,而對於線性迴歸演算法還有另外一種使得損失函式最小的方法,那就是正規方程。
正規方程式通過求解下面的方程來找出使得代價函式最小的引數:
J(θj))θj=0
假設我們的訓練集特徵矩陣為X(包含x0=1)並且訓練集結果為向量y,利用正規方程可以解得引數θ=XTX1XTy
其中,T代表矩陣的轉置,上標-1代表矩陣的逆運算。
舉例來看一下正規方式的使用:
這裡寫圖片描述


這就是上述每個矩陣的構建方式,然後帶入公式就可以求得待求引數(一般針對矩陣化的程式語言,求逆一般都有現成的函式可以呼叫)。
從求取引數的式子中我們不難發現,當求待求的引數θ時,需要一個求逆的過程,但是不是所有的矩陣都有逆矩陣的,一般當出現下列情況四,矩陣不可逆:

  1. 特徵之間不獨立,比如在描述身高時,選取的兩個特徵為米和英尺,因為這兩個之間存在著一種換算關係:1米(m)=3.2808399英尺(ft),所以這兩個特徵不是獨立的,這種情況下,矩陣是不可逆的。
  2. 當特徵的數量大於訓練集的數量時,正規方程也是不能用的。

當使用正規方程時:
1.首先確定是否有相關的特徵,如果存在相關的特徵,則去除相關特徵;
2.當特徵的數目較多時,可以去除一些不重要的特徵,用少量的特徵表示儘可能多的內容。
下面來比較一下梯度下降法和正規方程的優劣:
梯度下降法的優勢:
1.當特徵的數量比較大時(特徵的數量超過10000),也能夠很好的實現損失函式最小化,同時時間複雜度不是很高;而當特徵的數量比較大時,使用正規方程求解逆運算是非常耗時的,所以此時使用梯度下降法比較合適。
2.梯度下降法適用於所有型別的模型,而正規方程的方法一般只適用於線性模型,不適合邏輯迴歸等其他模型。
正規方程的優勢:
1.當特徵點的數量不是很大時,使用正規方程更加簡答,不需要像梯度下降演算法一樣迭代實現,一次計算就可以得出最優引數。
2.對於梯度演算法來說,效能的好壞還與學習率的設定有關,學習率設定不合適,時間消耗較長,甚至得不到最優解,而正規方程的方法不需要學習率的設定。

基於python的正規方程實現如下所示:

import numpy as np

#從資料集中得到特徵矩陣和標籤向量
def loadDataSet(fileName):

    num_fea=len(open(fileName).readline().split(','))-1 #獲得特徵的數量
    fr=open(fileName)   #開啟檔案
    featureArr=[]
    labelArr=[]
    # 讀取每一行的資料
    for line in fr.readlines():
        line_fea=[]
        line_data=line.strip().split(',')   #將每一行的資料按照','分隔開(使用什麼分隔開看資料本身的構成)
        line_data.insert(0,'1') #將特徵進行擴充,將特徵矩陣轉化為增廣矩陣的形式
        for i in range(num_fea+1):
            line_fea.append(float(line_data[i]))    #得到每一行的特徵

        featureArr.append(line_fea)
        labelArr.append(float(line_data[-1]))   #得到每一行的標籤

    return featureArr,labelArr



def normalEquation(featureArr, labelArr):
    featureArr=np.mat(featureArr)
    labelArr=np.mat(labelArr).T

    xTx = featureArr.T*featureArr
    if np.linalg.det(xTx)==0:
        print("This matrix is singular, it can't do inverse")
        return
    ws=(xTx.I)*(featureArr.T*labelArr)
    return ws


#主程式
featureArr,labelArr=loadDataSet('ex1data2.txt')
ws=normalEquation(featureArr,labelArr)

print(ws)

matlab實現正規方程的程式碼如下:

clear;
close all;

%% 資料處理和初始化

data = load('ex1data2.txt'); % ex1data.txt中第一列是特徵,第二列是標籤
feature = data(:,1:end-1);    % 取出特徵資料
result = data(:,end);  % 出標籤資料  

[num_sample, num_feature] = size(feature);
feature = [ones(num_sample,1) feature];  % 將特徵進行擴充套件,在原來的基礎上增加一列全為1的矩陣

xTx = feature' * feature;

if det(xTx)==0
    sprintf('the matric is a singular, it can not do inverse!')
else
    theta = pinv(xTx) * feature' * result;
end

% 測試資料
test_data = [1520 4;5551 3];   %測試資料

[num_test_sample, num_test_feature] = size(test_data);  %測試資料的個數  
test_data = [ones(num_test_sample,1) test_data];  %測試資料的擴充
test_result = test_data * theta;    %測試資料的預測結果

test = feature * theta;

本人菜鳥一枚,有什麼問題歡迎指正。