---
# System prepended metadata

title: 簡單線性迴歸（Simple Linear Regression）以及目標函數
tags: [regression, machine learning, linear regression]

---

---
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()
```

範例圖
![線性關係圖](https://hackmd.io/_uploads/rkhbyKkSex.png)


計算$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，才不會導致線亂折
:::

範例圖
![線性關係圖(迴歸線)](https://hackmd.io/_uploads/BymfkF1Sgl.png)

得到結果應該非常接近原來的斜率(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()
```
![線性關係圖(迴歸線和損失函數)](https://hackmd.io/_uploads/SkkkxFyHxl.png)

:::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_)
```



