---
title: '簡單線性迴歸(Simple Linear Regression)以及目標函數'
disqus: hackmd
---
簡單線性迴歸(Simple Linear Regression)以及目標函數
===
## Table of Contents
[TOC]
## 簡單線性迴歸(Simple Linear Regression)
假設**只有一個x特徵**,即**簡單線性迴歸**,我們會希望**預測值**和**實際樣本點**差距越小越好,兩者差距稱為**誤差(Error)** 或 **殘差(Residual)**,想要評估模型的能力,就會需要用到迴歸的目標函數(Objective function)(又叫做損失函數(Loss function)或成本函數(Cost function))。
:::info
在訓練集:你算的是「殘差」,因為模型看過這些資料,模型是針對這些資料調整的。
在測試集:你算的是「誤差」,因為這些資料是模型從沒看過的,用來估計模型未來表現。
:::
## 目標函數及衡量指標
:::info
接下來程式碼主要會以SSE、MSE、OLS為主
:::
### SSE(Sum of Squared Errors,誤差平方和)
**SSE**(Sum of Squared Errors 或 Residual Sum of Squares)不僅用於訓練,也常被用於整個模型評估流程中,是預測時「**真實值 – 預測值**」的平方(避免正的誤差跟負的誤差抵銷)再相加:
$$
\mathrm{SSE} = \sum_{i=1}^{n} (y_i - \hat{y}_i)^2
$$
<!--
<details>
<summary>完整公式</summary>
套入簡單線性迴歸
$$
\mathrm{SSE} = \sum_{i=1}^{n} (y_i - w \cdot \text{x} - b)^2
$$
</details>
-->
目標就是希望SSE越小越好,也就是預測值跟真實質(答案)差距越小越好。
### MSE(Mean Squared Error,平均平方誤差)
MSE 是 SSE 的平均版本,用來衡量資料集上的平均預測誤差,**平均會讓誤差對不同樣本大小**(n)更清楚比較,也減少隨著n增加導致 SSE 過大的問題
$$
\mathrm{MSE} = \frac{1}{n}\mathrm{SSE}
$$
<!--
<details>
<summary>完整公式</summary>
$$
\mathrm{MSE} = \frac{1}{n} \sum_{i=1}^n \left(y_i - \hat{y}_i\right)^2
$$
$$
\mathrm{MSE} = \frac{1}{n} \sum_{i=1}^n \left(y_i - w \cdot \text{x} - b)\right)^2
$$
</details>
-->
### MAE(Mean Absolute Error,平均絕對誤差)
MAE 衡量預測值與真實值間的**平均「絕對」誤差,比 MSE 更不容易受極端值影響**,**適合關注穩定誤差表現**。
$$
\mathrm{MAE} = \frac{1}{n} \sum_{i=1}^n \left| y_i - \hat{y}_i \right|
$$
<!--
<details>
<summary>完整公式</summary>
* MAE:對每一筆誤差 \$e\_i\$,直接取絕對值,**線性懲罰**
* MSE/SSE:誤差平方,**誇大懲罰大誤差(離群點)**
$$
\mathrm{MAE} = \frac{1}{n} \sum_{i=1}^n \left| y_i - w \cdot \text{x} - b \right|
$$
</details>
-->
| 指標 | 優點 | 缺點 | 常見用途 |
| ------- | -------------- | -------- | ---------- |
| **MSE** | 平滑可導、適合優化、理論完備 | 對離群點過於敏感 | 機器學習、OLS推導 |
| **MAE** | 抗離群點干擾、直覺 | 不可導、無封閉解 | 醫療、金融、穩定預測 |
### RMSE(Root Mean Squared Error,均方根誤差)
RMSE 是 MSE 的平方根,**與原始資料單位尺度相同**,更容易解釋。
$$
\mathrm{RMSE} = \sqrt{ \frac{1}{n} \sum_{i=1}^n \left( y_i - \hat{y}_i \right)^2 } = \sqrt{\mathrm{MSE}}
$$
RMSE 與 MSE 本質相同,但更直觀易讀。
<!--
<details>
<summary>完整公式</summary>
$$
\mathrm{RMSE} =\sqrt{\mathrm{MSE}}
\mathrm{RMSE} = \sqrt{ \frac{1}{n} \sum_{i=1}^n \left( y_i - w \cdot \text{x} -b\right)^2 }
$$
</details>
-->
#### SST(Total Sum of Squares,總平方和)
**SST** 衡量的是「真實值相對於其平均值」的總變異量。可以理解為:
> **資料本身有多少變化?如果我們都不知道 X,只用平均值 $\bar{y}$ 來預測 Y,會錯多少?**
公式如下:
$$
\mathrm{SST} = \sum_{i=1}^{n} (y_i - \bar{y})^2
$$
### R2(決定係數,R-squared)
$R^{2}$ 衡量模型解釋資料變異的能力,值介於 0 到 1,越接近 1 表示模型擬合越好:
$$
R^2 = 1 - \frac{\mathrm{SSE}}{\mathrm{SST}} = 1 - \frac{\sum_{i=1}^n (y_i - \hat{y}_i)^2}{\sum_{i=1}^n (y_i - \bar{y})^2}
$$
* SST:總平方和,代表總變異量
* SSE:模型未解釋的變異量
直觀解釋
* $R^{2} = 0$:模型跟用平均值猜一樣爛
* $R^{2} = 1$:完美預測
#### COV(Covariance,協方差)
衡量兩變數 **同時變化的方向與程度**,常見於迴歸中的斜率計算:
$$
\mathrm{Cov}(X, Y) = \frac{1}{n} \sum_{i=1}^n (x_i - \bar{x})(y_i - \bar{y})
$$
* Cov > 0:同方向(X↑ ⇒ Y↑)
* Cov < 0:反方向(X↑ ⇒ Y↓)
* Cov ≈ 0:不相關(或更複雜的關係)
#### VAR(Variance,變異數)
衡量一組數值的**發散程度**,即離均值有多遠:
$$
\mathrm{Var}(X) = \frac{1}{n} \sum_{i=1}^n (x_i - \bar{x})^2
$$
* 單一變數的波動性
* 也是回歸中計算斜率的分母
:::success
### Covariance 與 Regression 的連結:
在簡單線性回歸中,斜率 $w$ 其實是:
$$
w = \frac{\mathrm{Cov}(X, Y)}{\mathrm{Var}(X)}
$$
這也顯示了線性回歸本質上是衡量「x 與 y 的共變動關係」(x 與 y 的共變動程度(Cov)➗x 自己的變化程度(Var))。
:::
## OLS(Ordinary Least Square,最小平方法)
OLS 是一種在**線性迴歸模型**中用來估計參數(w、b)好壞的方法,SSE 是 OLS 優化的核心目標,來求取最優参数。
:::info
根據**凸函數的性質(可以把它想像成一個「碗形」的圖像──中間最低,兩邊往上翹)**,
對 OLS 的目標函數(SSE)求**一階導函數=0(斜率=0)**
保證是全域的最小點,不會出現「局部最小但非全域最小」(local minimum)的情況。
:::
SSE分別對的斜率(w,slope)跟截距(b,bias/intercept)做**偏微分**,並且令一階導函數為0,就可得到SSE最小值(預測跟真實差距最小)。
<details>
<summary>微分與偏微分</summary>
#### 微分
給一個函數 $y = f(x)$,它的微分(導數)定義為:
$$
\frac{dy}{dx} = f'(x) = \lim_{\Delta x \to 0} \frac{f(x+\Delta x) - f(x)}{\Delta x}
$$
微分就是問:「當 $x$ 變動一點點($\Delta x$),$y$ 會怎麼跟著變?」
想像一條彎彎的曲線上的某一點,我們想知道那一點的「斜率」有多陡,這就是微分。
在OLS的情況,**我想知道當w、b只變動一點點時,我的SSE會如何變化?**
#### 偏微分
給一個多變數函數 $z = f(x, y)$,針對 $x$ 的偏微分記為:
$$
\frac{\partial z}{\partial x} = \lim_{\Delta x \to 0} \frac{f(x+\Delta x, y) - f(x, y)}{\Delta x}
$$
類似地,針對 $y$:
$$
\frac{\partial z}{\partial y} = \lim_{\Delta y \to 0} \frac{f(x, y+\Delta y) - f(x, y)}{\Delta y}
$$
偏微分就像在多個按鈕中,只轉動其中一個,看看輸出會怎麼改變。
在OLS的情況,**我想一次只變動w、b其中之一時,我的SSE會如何變化?**
</details>
給定模型:
$$
\hat{y} = wx + b
$$
定義 SSE(殘差平方和)為:
$$
SSE = \sum_{i=1}^{n} (y_i - wx_i - b)^2
$$
### 對 b 偏微分
因為:
$f(x)=g(x)g(x)$
$f'(x)=g'(x)g(x)+g(x)g'(x)=2g'(x)g(x)$
所以:
$$
\frac{d}{db}SSE =\sum_{i=1}^{n} 2(y_i - wx_i - b)(-1)= -2 \sum_{i=1}^{n} (y_i - wx_i - b) = 0
$$
兩邊同除 $-2$:
$$
\sum_{i=1}^{n} (y_i - wx_i - b) = 0
$$
展開:
$$
\sum_{i=1}^{n} y_i - \sum_{i=1}^{n} wx_i - \sum_{i=1}^{n} b = 0
$$
移項$b$:
$$
\sum_{i=1}^{n} y_i - w \sum_{i=1}^{n} x_i = \sum_{i=1}^{n} b
$$
同除$n$,整理後解得:
$$
\frac{1}{n} \sum_{i=1}^{n} y_i - w \cdot \frac{1}{n} \sum_{i=1}^{n} x_i=\frac{1}{n} \sum_{i=1}^{n} b
\quad \Rightarrow \quad
\bar{y} - w \bar{x}=b
$$
* $\bar{x}$: x的平均數
* $\bar{y}$: y的平均數
### 對 w 偏微分:
代入 $b = \bar{y} - w \bar{x}$:
$$
SSE = \sum_{i=1}^{n} (y_i - wx_i - \bar{y} + w \bar{x})^2
$$
$$
\frac{d}{dw}SSE = -2 \sum_{i=1}^{n} (y_i - wx_i - \bar{y} + w \bar{x})(x_i -\bar{x}) = 0
$$
消去 $-2$:
$$
\sum_{i=1}^{n} (y_i - wx_i - \bar{y} + w \bar{x})(x_i -\bar{x}) = 0
$$
整理括號:
$$
\sum_{i=1}^{n} (y_i - \bar{y} - w(x_i - \bar{x}))(x_i -\bar{x}) = 0
$$
$$
\sum_{i=1}^{n} (y_i - \bar{y})(x_i -\bar{x}) - w \sum_{i=1}^{n} (x_i - \bar{x})(x_i -\bar{x}) = 0
$$
兩邊移項:
$$
w \sum_{i=1}^{n} (x_i - \bar{x})(x_i -\bar{x}) = \sum_{i=1}^{n} (y_i - \bar{y})(x_i -\bar{x})
$$
$$
\quad \Rightarrow \quad
w = \sum_{i=1}^{n} (y_i - \bar{y})(x_i -\bar{x})/\sum_{i=1}^{n} (x_i - \bar{x})(x_i -\bar{x})
$$
得到:
$$
w = \frac{\sum_{i=1}^{n} (y_i - \bar{y})(x_i - \bar{x})}{\sum_{i=1}^{n} (x_i - \bar{x})^2}
$$
### 最後整理得到 OLS 解
\begin{aligned}
w &= \frac{\sum_{i=1}^{n} (x_i - \bar{x})(y_i - \bar{y})}{\sum_{i=1}^{n} (x_i - \bar{x})^2} \\
b &= \bar{y} - w \bar{x}
\end{aligned}
## numpy程式碼範例
:::info
以下範例建議在colab裡使用
:::
引入模組庫
```python=
import numpy as np
import matplotlib.pyplot as plt
```
產生隨機數據
```python=
# 設定隨機種子(讓每次執行結果一致)
np.random.seed(42)
# 產生自變數 x(例如 100 筆均勻分布的數據)
x = np.random.uniform(0, 10, 100)
# 定義線性關係:y = 2.5 * x + 3,加上一點隨機雜訊
noise = np.random.normal(0, 1, size=x.shape) # 標準差為 1 的正態分布雜訊
y = 2.5 * x + 3 + noise
```
繪圖觀察
```python=
# 繪製圖形觀察線性關係
plt.scatter(x, y)
plt.title("Linear Relationship with Noise")
plt.xlabel("x")
plt.ylabel("y")
plt.show()
```
範例圖

計算$w$、$b$
```python=
w=np.sum((x-x.mean())*(y-y.mean()))/np.sum((x-x.mean())*(x-x.mean()))
b=y.mean()-w*x.mean()
```
繪圖觀察預測結果
```python=
x_sorted = np.sort(x)
plt.plot(x_sorted,x_sorted*w+b, color='red', linestyle='--', linewidth=2, label=f'y={w:.2f}*x+{b:.2f}')
plt.scatter(x, y)
plt.title("Linear Relationship with Noise")
plt.xlabel("x")
plt.ylabel("y", rotation=0, labelpad=20)
plt.legend()
plt.show()
```
:::info
matplotlib.pyplot.plot() **是「按順序」畫線,不是按大小**,因為x隨機生成沒按照大小排序,因此先排序產生x_sorted,才不會導致線亂折
:::
範例圖

得到結果應該非常接近原來的斜率(2.5)和截距(3)
觀察MSE和SSE
```python=
SSE=np.sum((y-x*w-b)**2)
MSE=SSE/len(y)
print(f'SSE:{SSE},MSE:{MSE}')
```
統整程式碼
```python=
import numpy as np
import matplotlib.pyplot as plt
# 產生資料
np.random.seed(0)
x = np.random.uniform(0, 10, 100)
noise = np.random.normal(0, 1, size=x.shape)
y = 2.5 * x + 3 + noise
# 線性回歸(手動)
w = np.sum((x - x.mean()) * (y - y.mean())) / np.sum((x - x.mean()) ** 2)
b = y.mean() - w * x.mean()
y_pred = w * x + b
# SSE 與 MSE
SSE = np.sum((y - y_pred) ** 2)
MSE = SSE / len(y)
# 建立子圖(1 列 2 欄)
fig, axs = plt.subplots(1, 2, figsize=(14, 6))
# 子圖1:線性回歸圖
axs[0].scatter(x, y, label='Data Points')
axs[0].plot(np.sort(x), y_pred[np.argsort(x)], color='red', linestyle='--', label=f'y = {w:.2f}x + {b:.2f}')
axs[0].set_title("Linear Regression")
axs[0].set_xlabel("x")
axs[0].set_ylabel("y", rotation=0, labelpad=20)
axs[0].legend()
axs[0].grid(True)
# 子圖2:顯示公式與誤差
formula_text = (
r"$\mathbf{Linear\ Regression\ Formula}$" "\n\n"
r"$y = wx + b$" "\n"
rf"$w = \frac{{\sum (x_i - \bar{{x}})(y_i - \bar{{y}})}}{{\sum (x_i - \bar{{x}})^2}} = {w:.2f}$" "\n"
rf"$b = \bar{{y}} - w \bar{{x}} = {b:.2f}$" "\n\n"
r"$\mathbf{Error\ Metrics}$" "\n"
rf"$SSE = \sum (y_i - \hat{{y}}_i)^2 = {SSE:.2f}$" "\n"
rf"$MSE = \frac{{SSE}}{{n}} = {MSE:.2f}$"
)
axs[1].axis('off')
axs[1].text(0.05, 0.95, formula_text, fontsize=18, va='top', linespacing=1.5)
plt.tight_layout()
plt.show()
```

:::info
matplotlib 支援的格式,它內建的是簡化版的 LaTeX 渲染器(稱為 mathtext)
| 調整 | 原因 |
| --------------------- | ---------------------- |
| `r"..."` | 使用 raw 字串避免跳脫錯誤 |
| `\mathbf{}` | 支援、取代 `\textbf{}` |
| `\hat{y}` `\bar{x}` 等 | 可以正確渲染 |
| 換行用 `"\n"`,非 `\\` | `text()` 不能直接用 `\\` 換行 |
:::
## scikit-Learn LinearRegression範例
```python=
import numpy as np
from sklearn.linear_model import LinearRegression
# 設定隨機種子(讓每次執行結果一致)
np.random.seed(42)
# 產生自變數 x(例如 100 筆均勻分布的數據)
x = np.random.uniform(0, 10, 100)
# 定義線性關係:y = 2.5 * x + 3,加上一點隨機雜訊
noise = np.random.normal(0, 1, size=x.shape) # 標準差為 1 的正態分布雜訊
y = 2.5 * x + 3 + noise
x=x.reshape(-1,1)
lr=LinearRegression()
lr.fit(x,y)
print(lr.coef_,lr.intercept_)
```