【機器學習】算法原理詳細推導與實現(一):線性回歸


【機器學習】算法原理詳細推導與實現(一):線性回歸

今天我們這里要講第一個有監督學習算法,他可以用於一個回歸任務,這個算法叫做 線性回歸

房價預測

假設存在如下 m 組房價數據:

面積(m^2) 價格(萬元)
82.35 193
65.00 213
114.20 255
75.08 128
75.84 223
... ...

通過上面的數據,可以做出如下一個圖。橫坐標是 面積(m^2),縱坐標是 價格(萬元)

那么問題來了,給你這樣一組數據,或者給你這樣一個訓練數據的集合,能否預測房屋的面積大小和房價之間的關系?

構建函數

存在如下符號假設:

m 為訓練數據
x 為輸入特征,即房子的大小
y 為輸出結果,即房子的價格
(x, y) 為一個樣本,即表格中一行代表一個訓練樣本
\((x^{(i)}, y^{(i)})\) 為第 i 個訓練樣本

在監督學習中,我們一般會這樣做:

  1. 首先找到一個訓練集合
  2. 提供樣本 m 給算法構建學習函數
  3. 算法會生成一個學習函數,用 \(h(x)\) 表示
  4. 給學習函數提供足夠的樣本\(x\),由此輸出結果\(y\)

學習函數

graph TD A[訓練集合]--"樣本m"-->B[學習函數] B[學習函數]--"生成"-->C["h(x)"]

訓練函數

graph LR A[輸入]--"面積(m^2)"-->B["h(x)"] B["h(x)"]--"價格(萬元)"-->C[輸出]

為了設計學習算法(學習函數),假設存在如下函數:

\[h(x)=\theta_0+\theta_1x \]

其中 \(x\) 是一個輸入函數,這里代表輸入的面積(m^2),\(h(x)\) 是一個輸出函數,這里代表 輸出的價格(萬元),\(\theta\) 是函數的參數,是需要根據樣本學習的參數。對於如上的學習函數只是一個簡單的二元一次方程,只需要兩組樣本 \((x_0,y_0),(x_1,y_1)\) 就能將 \(\theta_0,\theta_1\) 學習出來,這是一個很簡單的函數,但是這樣在實際情況中並非很合理。

但是影響房子價格的因素不僅僅是房子的大小。除了房子的大小之外,假設這里還知道每個房子的房間數量:

面積(m^2) 房間(個) 價格(萬元)
82.35 2 193
65.00 2 213
114.20 3 255
75.08 2 128
75.84 2 223
... ... ...

那么我們的訓練集合將有第二個特征,\(x_1\)表示房子的面積(m^2),\(x_2\)表示房子的房間(個),這是學習函數就變成了:

\[h(x)=\theta_0+\theta_1x_1+\theta_2x_2=h_\theta(x) \]

\(\theta\)被稱為參數,決定函數中每個特征\(x\)的影響力(權重)。\(h_\theta(x)\) 為參數為 \(\theta\) 輸入變量為\(x\)的學習函數。如果令\(x_0=1\),那么上述方程可以用求和方式寫出,也可以轉化為向量方式表示:

\[\begin{split} h_\theta(x)&=\theta_0x_0+\theta_1x_1+\theta_2x_2 \\ &=\sum^2_{i=0}{\theta_ix_i} \\ &=\theta^Tx \\ \end{split} \]

假設存在\(m\)個特征\(x\),那么上述公式求和可以改成:

\[\begin{split} h_\theta(x)&=\sum^m_{i=0}{\theta_ix_i} \\ &=\theta^Tx \\ \end{split} \]

訓練參數

在擁有足夠多的訓練數據,例如上面的房價數據,怎么選擇(學習)出參數\(\theta\)出來?一個合理的方式是使學習函數\(h_\theta(x)\) 學習出來的預測值無限接近實際房價值 \(y\)。假設單個樣本誤差表示為:

\[j(\theta)=\frac{1}{2}(h_\theta(x^{(i)})-y^{(i)})^2 \]

我們把 \(j(\theta)\) 叫做單個樣本的誤差。至於為什么前面要乘\(\frac{1}{2}\),是為了后面計算方便。

為了表示兩者之間的接近程度,我們可以用訓練數據中所有樣本的誤差的和,所以定義了 損失函數 為:

\[\begin{split} J(\theta)&=j_1(\theta)+j_2(\theta)+...+j_m(\theta) \\ &=\frac{1}{2}\sum^m_{i=1}{(h_\theta(x^{(i)})-y^{(i)})^2} \\ \end{split} \]

而最終的目的是為了使誤差和 \(min(J(\theta))\) 最小,這里會使用一個搜索算法來選取 \(\theta\) 使其誤差和無限逼近 \(J(\theta)\) 最小,其流程是:

  1. 初始化一組向量 \(\vec{\theta}=\vec{0}\)
  2. 不斷改變 \(\theta\) 的值使其 \(J(\theta)\) 不斷減小
  3. 直到取得 \(J(\theta)\) 最小值,活得得到最優的參數向量 \(\vec{\theta}\)

該搜索算法為 梯度下降,算法的思想是這樣的,下圖看到顯示了一個圖形和坐標軸,圖像的高度表示誤差和 \(J(\theta)\),而下面的兩條坐標表示不同的參數 \(\theta\) ,這里為了方便看圖只是顯示了 \(\theta_0\)\(\theta_1\) ,即變化參數 \(\theta_0\)\(\theta_1\) 使其誤差和 \(J(\theta)\) 在最低點,即最小值。

首先隨機選取一個點 \(\vec{\theta}\) ,它可能是 \(\vec{0}\) ,也可能是隨機的其他向量。最開始的 + 字符號表示開始,搜索使其 \(J(\theta)\) 下降速度最快的方向,然后邁出一步。到了新的位置后,再次搜索下降速度最快的方向,然后一步一步搜索下降,梯度下降算法是這樣工作的:

梯度下降的核心就在於每次更新 \(\theta\) 的值,公式為:

\[\theta_j:=\theta_j-\alpha\frac{\partial J(\theta)}{\partial\theta_j}\tag{1} \]

上面公式代表:\(\theta_j\) 每次都按照一定的 學習速率 \(\alpha\) 搜索使誤差和 \(J(\theta)\) 下降最快的方向更新自身的值。而 \(\frac{\partial J(\theta)}{\partial\theta_j}\)\(J(\theta)\) 的偏導值,求偏導得到極值即是下降最快的方向。假設在房價的例子中,只存在一組訓練數據 \((x,y)\),那么可以推導如下公式:

\[\begin{split} \frac{\partial J(\theta)}{\partial\theta_j}&=\frac{\partial}{\partial\theta_j}\frac{1}{2}(h_{\theta}(x)-y)^2 \\ &=2\frac{1}{2}(h_{\theta}(x)-y)\frac{\partial}{\partial\theta_j}(h_{\theta}(x)-y) \\ &=(h_{\theta}(x)-y)\frac{\partial}{\partial\theta_j}(\sum^m_{i=0}{\theta_ix_i}-y) \\ &=(h_{\theta}(x)-y)\frac{\partial}{\partial\theta_j}(\theta_0x_0+\theta_1x_1+...+\theta_mx_m-y) \\ &=(h_{\theta}(x)-y)x_j \\ \end{split}\tag{2} \]

結合 \((1)(2)\) 可以得到:

\[\theta_j:=\theta_j-\alpha(h_{\theta}(x)-y)x_j\tag{3} \]

對於存在 \(m\) 個訓練樣本,\((1)\) 轉化為:

\[\theta_j:=\theta_j-\sum^m_{i=1}\alpha(h_{\theta}(x^{(i)})-y^{(i)})x_j\tag{4} \]

學習速率 \(\alpha\) 是梯度下降的速率,\(\alpha\) 越大函數收斂得越快,\(J(\theta)\) 可能會遠離最小值,精度越差;\(\alpha\) 越小函數收斂得越慢,\(J(\theta)\) 可能會靠近最小值,精度越高。下面就是下降尋找最小值的過程,在右圖 \(J(\theta)\) 越來越小的時候,左邊的線性回歸越來准:

代碼

選取得到的 150條二手房 數據進行預測和訓練,擬合情況如下:

計算損失函數:

# 損失函數
def computeCost(X, y, theta):
    inner = np.power(((X * theta.T) - y), 2)
    return np.sum(inner) / (2 * len(X))

梯度下降函數為:

# 梯度下降函數
def gradientDescent(X, y, theta, alpha, iters):
    temp = np.matrix(np.zeros(theta.shape))
    parameters = int(theta.ravel().shape[1])
    cost = np.zeros(iters)

    for i in range(iters):
        error = (X * theta.T) - y

        for j in range(parameters):
            term = np.multiply(error, X[:, j])
            temp[0, j] = theta[0, j] - ((alpha / len(X)) * np.sum(term))

        theta = temp
        cost[i] = computeCost(X, y, theta)

    return theta, cost

訓練迭代1000次后得到參數 \(\theta\)

# 訓練函數
def train_function():
    X, y, theta = get_training_dataset()
    # 有多少個x就生成多少個theta
    theta = np.matrix(np.zeros(X.shape[-1]))
    # 查看初始誤差
    # first_cost=computeCost(X, y, theta)
    # print(first_cost)
    # 設置參數和步長
    alpha = 0.01
    iters = 1000

    # 訓練得到theta和每一次訓練的誤差
    g, cost = gradientDescent(X, y, theta, alpha, iters)
    computeCost(X, y, g)
    return g, cost

數據和代碼下載請關注公眾號【 機器學習和大數據挖掘 】,后台回復【 機器學習 】即可獲取


免責聲明!

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



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