香港中文大學數學系
2026年5月16日
最小二乘法 (Least-squares method) 是獲取代表數據模式的最佳擬合曲線的最直觀方法。
讓我們探討如何利用最小二乘法(曲線擬合)來求得最佳解。
考慮 \(xu\) 平面上的 4 個點(二維數據): \[ (0,1),\ (1,3),\ (2,4),\ (3,4) \]
我們可以從下圖中看到包含 \(x\) 和 \(u\) 的圖表。我們可以透過畫一條直線來建立 \(x\) 和 \(u\) 之間的關係。這非常直觀。
最小二乘法可用於找出一條最能代表給定數據的直線。所求得的直線稱為最小二乘法直線或最佳擬合直線。
import numpy as np
import matplotlib.pyplot as plt
# 定義原始數據點(與 LaTeX 座標完全相符)
x = [0, 1, 2, 3]
u = [1, 3, 4, 4]
# 產生繪製最小二乘法直線所需的 x 值
x_fit = np.linspace(-0.5, 3.5, 100)
# 定義最小二乘法直線方程式:u = x + 1.5
u_fit = x_fit + 1.5
# 建立尺寸與 LaTeX 圖表一致的圖形 (8cm x 6cm)
plt.figure(figsize=(8, 6))
# 繪製紅色的實心數據點
plt.scatter(x, u, color='red', s=60, zorder=3)
# 繪製藍色的最小二乘法擬合粗直線
plt.plot(x_fit, u_fit, color='blue', linewidth=2)
# 繪製置中的 x 與 y 軸(匹配 TikZ 座標軸樣式)
plt.axhline(0, color='black', linewidth=1)
plt.axvline(0, color='black', linewidth=1)
# 設定帶有數學符號的坐標軸標籤
plt.xlabel(r'$x$', fontsize=12)
plt.ylabel(r'$u$', fontsize=12)
# 設定與 LaTeX 相同的坐標軸極限
plt.xlim(-0.5, 3.5)## (-0.5, 3.5)
## (0.0, 5.0)
## (array([-0.5, 0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5]), [Text(-0.5, 0, '−0.5'), Text(0.0, 0, '0.0'), Text(0.5, 0, '0.5'), Text(1.0, 0, '1.0'), Text(1.5, 0, '1.5'), Text(2.0, 0, '2.0'), Text(2.5, 0, '2.5'), Text(3.0, 0, '3.0'), Text(3.5, 0, '3.5')])
## (array([0., 1., 2., 3., 4., 5.]), [Text(0, 0.0, '0'), Text(0, 1.0, '1'), Text(0, 2.0, '2'), Text(0, 3.0, '3'), Text(0, 4.0, '4'), Text(0, 5.0, '5')])
# 設定圖形標題(與 LaTeX 標題相符)
plt.title("Figure 1: Data points and least-squares line", fontsize=12)
# 調整排版以呈現整潔外觀
plt.tight_layout()
# 顯示最終圖表
plt.show()讓我們考慮最簡單的情況:解出最佳直線 \(u = a + bx\) 來描述給定數據 \((x_i, u_i)\)。這即是尋找最適合 \((x_i, u_i)\) 的線性函數。理想情況是找到能使所有數據 \((x_i, u_i)\) 皆滿足 \(u_i = a + bx_i\) 的 \(u\) 截距 \(a\) 及斜率 \(b\)。
我們可以透過以下含有兩個未知數 \(a\) 和 \(b\) 的矩陣形式線性方程組來求出解答。
建構最小二乘法問題
\[ \begin{array}{cccccccccccc} \hline \textrm{數據} ~(x, u) & \textrm{線性函數} ~u = a + bx & \textrm{線性方程組} & \textrm{矩陣形式} \\ \hline (0, 1) & 1 = a + b \cdot 0 & & \\ (1, 3) & 3 = a + b \cdot 1 & \begin{cases} a = 1 \\ a + b = 3 \\ a + 2b = 4 \\ a + 3b = 4 \end{cases} & A\mathbf{u} = \mathbf{y} \\ (2, 4) & 4 = a + b \cdot 2 & & \textrm{其中} ~A = \begin{bmatrix} 1 & 0 \\ 1 & 1 \\ 1 & 2 \\ 1 & 3 \end{bmatrix}, ~\mathbf{u} = \begin{bmatrix} a \\ b \end{bmatrix}, ~\mathbf{y} = \begin{bmatrix} 1 \\ 3 \\ 4 \\ 4 \end{bmatrix} \\ (3, 4) & 4 = a + b \cdot 3 & & \\ \hline \end{array} \]
當我們只有兩個數據點時,很容易就能求出 \(u = a + bx\) 中的 \(a\) 和 \(b\)。如果我們有超過兩個數據點,這個建模便需要我們使用線性方程組。我們通常會使用較大量的數據來尋求最佳的曲線擬合。
因此,我們最終得到的方程式數量會多於未知數的數量。在這種情況下,我們無法期望 \(A\mathbf{u} = \mathbf{y}\) 存在(唯一的)解 \(\mathbf{u}\)。
所以,我們嘗試尋找一個近似值 \(\hat{\mathbf{u}}\),使得 \(A\mathbf{u}\) 與 \(\mathbf{y}\) 之間的距離最小化, \[ \min_{\mathbf{u}} \| A\mathbf{u} - \mathbf{y} \| \]
儘管無法穿過所有四個點,我們仍會嘗試得出誤差最小的直線。在數學上,這意味著要讓 \(\| A\mathbf{u} - \mathbf{y} \| = 0\)。
這個問題被稱為最小二乘法問題,而 \(\hat{\mathbf{u}}\) 則被稱為最佳解(或最小二乘解)。雖然 \(\hat{\mathbf{u}}\) 是一個近似值(\(A\hat{\mathbf{u}} \approx \mathbf{y}\)),即使 \(\hat{\mathbf{u}}\) 可能無法完美滿足 \(A\mathbf{u} = \mathbf{y}\)。
令 \(\hat{y}_i\) 為將各數據點 \((x_i, y_i)\) 中的 \(x_i\) 代入 \(y = a + bx\) 所得的值。當 \(y_i\) 與 \(\hat{y}_i\) 不相等時,對某些 \(i\) 而言便存在誤差。
如果對所有 \(i\),\(y_i\) 和 \(\hat{y}_i\) 都相等,那麼直線 \(y = a + bx\) 便具有唯一解。既然存在 \(y_i\) 和 \(\hat{y}_i\) 不相等的情況,換句話說,\((y_i - \hat{y}_i)^2\) 並非全部為零,我們便會嘗試尋找能使誤差最小化的 \(a\) 和 \(b\)。將所有給定數據的誤差平方相加,可得出以下的誤差函數 \(E(\mathbf{u})\)。
\[ E(\mathbf{u}) = E(a,b) = (a-1)^2 + (a+b-3)^2 + (a+2b-4)^2 + (a+3b-4)^2 = \|A\mathbf{u} - \mathbf{y}\|^2 \] \[ \min E(\mathbf{u}) \]
誤差 \(E(\mathbf{u})\) 最終等於 \(A\mathbf{u}\) 與 \(\mathbf{y}\) 之間距離的平方。我們很容易就能看出範數與內積是如何與誤差產生關聯的。
解決最小二乘法問題,就是在解決尋找能使誤差函數最小化 \(\min E(\mathbf{u})\) 的 \(\hat{\mathbf{u}}\) 的問題。這個問題的最佳解就是最小二乘解 \(\hat{\mathbf{u}}\)。為了解出最小二乘解,我們需要投影 (projection) 的概念。
\[ \begin{array}{cccccccccccc} \hline \textbf{組成部分} & \textbf{定義} \\ \hline \textrm{數據} & (0,1),\ (1,3),\ (2,4),\ (3,4) \\ \textrm{模型} & y = a + bx \\ \textrm{預測值} & \hat{y}_i = a + bx_i \\ \textrm{誤差項} & (y_i - \hat{y}_i)^2 \\ \textrm{誤差函數} & E(a,b) = \sum_{i=1}^4 (y_i - (a+bx_i))^2 \\ \textrm{矩陣形式} & E(\mathbf{u}) = \|A\mathbf{u} - \mathbf{y}\|^2 , \textrm{其中}~ A = \begin{bmatrix}1 & 0 \\ 1 & 1 \\ 1 & 2 \\ 1 & 3\end{bmatrix} , \mathbf{u} = \begin{bmatrix}a \\ b\end{bmatrix} , \mathbf{y} = \begin{bmatrix}1 \\ 3 \\ 4 \\ 4\end{bmatrix} \\ \textrm{最小二乘法問題} & \displaystyle \min_{\mathbf{u}} E(\mathbf{u}) \\ \textrm{最佳解} & \textrm{最小二乘解} ~\hat{\mathbf{u}} \\ \hline \end{array} \]
為理解最小二乘法問題,我們需要了解投影。讓我們考慮尋找滿足以下條件的 \(t\) 的問題: \[ \min \| t\mathbf{a} - \mathbf{x} \| \] 其中 \(t\) 為實數。
換句話說,這就是尋找 \(t\) 以最小化向量 \(\mathbf{x}\) 與包含 \(\mathbf{a}\) 的直線之間距離的問題,其中 \(t\) 為純量。
import matplotlib.pyplot as plt
import numpy as np
# ==============================================
# 設定圖形和坐標軸
# ==============================================
fig, ax = plt.subplots(figsize=(8, 5))
# 隱藏所有軸線、刻度和標籤,以匹配簡潔的圖表樣式
ax.set_xlim(-0.2, 3.2)## (-0.2, 3.2)
## (-0.2, 2.2)
## []
## []
for spine in ax.spines.values():
spine.set_visible(False)
# ==============================================
# 定義匹配圖表的關鍵座標
# ==============================================
start_ta = (0, 0) # ta 線段的起點
proj_point = (1.5, 0) # 垂足 (ta 的終點)
top_point = (1.5, 2) # 三角形的頂點
end_a = (3, 0) # 完整向量 a 直線的終點
# ==============================================
# 繪製水平線 (向量 a) 線段
# ==============================================
# 1. 黑色線段:ta (帶箭頭)
ax.annotate(
'', # 空白文字 (我們只需要箭頭)
xy=proj_point, # 箭頭終點
xytext=start_ta, # 箭頭起點
arrowprops=dict(
arrowstyle='->', # 簡單箭頭樣式
color='black',
linewidth=2
)
)
# 2. 藍色線段:向量 a 的其餘部分
ax.plot([proj_point[0], end_a[0]], [proj_point[1], end_a[1]],
color='blue', linewidth=2)
# ==============================================
# 繪製向量 x (紫色線)
# ==============================================
ax.plot([start_ta[0], top_point[0]], [start_ta[1], top_point[1]],
color='purple', linewidth=2)
# ==============================================
# 繪製垂直虛線 (最小距離)
# ==============================================
ax.plot([proj_point[0], top_point[0]], [proj_point[1], top_point[1]],
color='gray', linestyle='--', linewidth=1.5)
# 在垂足處加上直角符號
right_angle_size = 0.1
ax.plot([proj_point[0], proj_point[0]+right_angle_size],
[proj_point[1], proj_point[1]], color='gray', linewidth=1)
ax.plot([proj_point[0]+right_angle_size, proj_point[0]+right_angle_size],
[proj_point[1], proj_point[1]+right_angle_size], color='gray', linewidth=1)
# ==============================================
# 繪製其他 t 值的淺灰色線條
# (匹配圖表中從頂點出發的多條線)
# ==============================================
other_t_points = [0.5, 1.0, 2.0, 2.5] # a 直線上的其他點
for t_x in other_t_points:
ax.plot([t_x, top_point[0]], [0, top_point[1]],
color='gray', alpha=0.4, linewidth=1)
# ==============================================
# 加上與圖表相符的標籤
# ==============================================
# 向量 x 的標籤 (紫色)
ax.text(0.4, 1.0, r'$x$', fontsize=18, color='purple')
# ta 的標籤 (在黑色線段下方)
ax.text(0.6, -0.15, r'$ta$', fontsize=16, color='black')
# 向量 a 的標籤 (在藍色線段末端)
ax.text(2.6, -0.15, r'$a$', fontsize=16, color='blue')
# 距離 ||ta - x|| 的標籤
ax.text(1.8, 1.0, r'$\| ta - x \|$', fontsize=16, color='black')
# --------------------------
# 最終圖形設定
# --------------------------
# 加入整體標題 (對應 LaTeX 圖形標題)
fig.suptitle('Figure 2a: Projection of a vector onto a line', fontsize=12)
plt.tight_layout() # 調整排版
plt.show() # 顯示圖表import matplotlib.pyplot as plt
import numpy as np
# ==============================================
# 初始化圖形並清理坐標軸
# ==============================================
fig, ax = plt.subplots(figsize=(8, 5))
# 隱藏所有軸線/刻度以匹配簡潔的圖表樣式
ax.set_xlim(-0.2, 3.2)## (-0.2, 3.2)
## (-0.2, 2.2)
## []
## []
for spine in ax.spines.values():
spine.set_visible(False)
# ==============================================
# 定義匹配您圖表的關鍵座標
# ==============================================
left_p = (0, 0) # p 線段的左端點
proj_point = (1.5, 0) # p 的右端點 / 垂足
top_point = (1.5, 2) # 三角形的頂點
end_a = (3, 0) # 完整 a 向量的右端點
# ==============================================
# 繪製水平線段
# ==============================================
# 1. 紅色線段:p (投影的底部)
ax.plot([left_p[0], proj_point[0]], [left_p[1], proj_point[1]],
color='red', linewidth=3)
# 2. 藍色線段:a (向量直線的其餘部分,帶箭頭)
ax.annotate(
'',
xy=end_a, xycoords='data',
xytext=proj_point, textcoords='data',
arrowprops=dict(arrowstyle='->', color='blue', linewidth=2)
)
# 3. 黑色箭頭表示 ta (位於 p 線段上方)
ax.annotate(
'',
xy=proj_point, xycoords='data',
xytext=left_p, textcoords='data',
arrowprops=dict(arrowstyle='->', color='black', linewidth=2)
)
# ==============================================
# 繪製向量 x (紫色線)
# ==============================================
ax.plot([left_p[0], top_point[0]], [left_p[1], top_point[1]],
color='purple', linewidth=2)
# ==============================================
# 繪製垂直虛線 + 直角符號
# ==============================================
# 虛線垂線 (最小距離)
ax.plot([proj_point[0], top_point[0]], [proj_point[1], top_point[1]],
color='gray', linestyle='--', linewidth=1.5)
# 垂足處的小直角標記
right_angle_size = 0.1
ax.plot([proj_point[0], proj_point[0]+right_angle_size],
[proj_point[1], proj_point[1]], color='gray', linewidth=1)
ax.plot([proj_point[0]+right_angle_size, proj_point[0]+right_angle_size],
[proj_point[1], proj_point[1]+right_angle_size], color='gray', linewidth=1)
# ==============================================
# 繪製其他 t 值的淺灰色線條
# (匹配圖表中從頂點出發的多條線)
# ==============================================
other_t_points = [0.8, 1.2, 2.2, 2.6] # 水平線上的其他點
for t_x in other_t_points:
ax.plot([t_x, top_point[0]], [0, top_point[1]],
color='gray', alpha=0.4, linewidth=1)
# ==============================================
# 加上與您的圖表相符的標籤 (搭配對應顏色)
# ==============================================
# 向量 x 的標籤 (紫色)
ax.text(0.3, 1.0, r'$x$', fontsize=18, color='purple')
# ta 的標籤 (黑色,在紅色線段上方)
ax.text(0.6, 0.1, r'$ta$', fontsize=16, color='black')
# p 的標籤 (紅色,在紅色線段下方)
ax.text(0.6, -0.15, r'$p$', fontsize=16, color='red')
# 向量 a 的標籤 (藍色,在藍色線段下方)
ax.text(2.1, -0.15, r'$a$', fontsize=16, color='blue')
# 距離 ||ta - x|| 的標籤
ax.text(1.8, 1.0, r'$\| ta - x \|$', fontsize=16, color='black')
# --------------------------
# 最終圖形設定
# --------------------------
# 加入整體標題 (對應 LaTeX 圖形標題)
fig.suptitle('Figure 2b: Projection of a vector onto a line', fontsize=12)
plt.tight_layout() # 調整排版
plt.show() # 顯示圖表如圖 2 所示,我們可以看出 \(\| t\mathbf{a} - \mathbf{x} \|\) 代表 \(t\mathbf{a}\) 與 \(\mathbf{x}\) 之間的距離。直觀上,當 \(\mathbf{p} = t\mathbf{a}\) 且 \((\mathbf{x} - t\mathbf{a}) \perp \mathbf{a}\) 時,可以獲得最短距離。這樣的 \(t\) 即為 \(\min \| t\mathbf{a} - \mathbf{x} \|\) 的解,而向量 \(\mathbf{p} = t\mathbf{a}\) 被稱為 \(\mathbf{x}\) 在 \(\mathbf{a}\) 上的投影。
由於 \((\mathbf{x} - t\mathbf{a}) \perp \mathbf{a}\),這個 \(t\) 可以透過以下方式求得: \[ \mathbf{a} \cdot (\mathbf{x} - t\mathbf{a}) = 0 \implies t(\mathbf{a} \cdot \mathbf{a}) = \mathbf{a} \cdot \mathbf{x} \implies t = \frac{\mathbf{a} \cdot \mathbf{x}}{\mathbf{a} \cdot \mathbf{a}} = (\mathbf{a}^T\mathbf{a})^{-1}\mathbf{a}^T\mathbf{x} \]
給定 \(\mathbf{x} = (2, -1, 3)\),\(\mathbf{y} = (4, -1, 2)\),求 \(\mathbf{y}\) 在 \(\mathbf{x}\) 上的投影。
解答
# 匯入 NumPy 庫以進行數值計算和向量運算
import numpy as np
# 定義原始向量 x 和 y (如範例所給)
x = np.array([2, -1, 3]) # 向量 x = (2, -1, 3)
y = np.array([4, -1, 2]) # 向量 y = (4, -1, 2)
# 計算 y 和 x 的內積:y · x
yx = np.inner(y, x)
# 計算 x 自己與自己的內積:x · x
xx = np.inner(x, x)
# 計算 y 在 x 上的投影向量 p
# 公式:p = ( (y·x)/(x·x) ) * x
p = (yx / xx) * x
# 輸出最終的投影結果
print("Projection vector p of y onto x =", p)## Projection vector p of y onto x = [ 2.14285714 -1.07142857 3.21428571]
我們求解最小二乘法問題 \(\min \| A\mathbf{u} - \mathbf{y} \|\) 的方式,與我們決定能使(\(\mathbf{x}\) 在 \(\mathbf{a}\) 上的)投影與向量 \(\mathbf{x}\) 差異最小的 \(t\) 的問題類似。為此,令 \(A_1, A_2\) 分別為 \(A\) 的第一與第二行向量 (column vector)。那麼,我們有 \(A\mathbf{u} = aA_1 + bA_2\)。 \[ \min \| A\mathbf{u} - \mathbf{y} \| = \min \| (aA_1 + bA_2) - \mathbf{y} \| \]
因此,最小二乘法問題與 \(A\) 的行向量所構成的行空間 (column space) 有關。最小二乘問題可以被解釋為一個尋找投影的問題。
平面 \(A\mathbf{u} = aA_1 + bA_2\) 是由 \(A\mathbf{x}\) 產生的一組映射。如圖所示,這可被理解為尋求 \(a\) 和 \(b\),使得包含 \(A_1\) 和 \(A_2\) 的平面與向量 \(\mathbf{y}\) 之間的距離最小化的問題。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# --------------------------
# 設定 3D 圖形
# --------------------------
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
# 設定視角以符合圖解透視
ax.view_init(elev=25, azim=45)
# 隱藏坐標軸刻度和標籤 (呈現簡潔圖解外觀)
ax.set_xticks([])## []
## []
## []
ax.set_axis_off()
# --------------------------
# 繪製平面 (行空間)
# --------------------------
# 定義平面角落坐標 (z=0 平面)
plane_corners = np.array([
[-1, -1, 0],
[ 2, -1, 0],
[ 2, 1, 0],
[-1, 1, 0]
])
# 繪製半透明的灰色平面
ax.plot_trisurf(plane_corners[:,0], plane_corners[:,1], plane_corners[:,2],
color='gray', alpha=0.3)
# --------------------------
# 定義並繪製向量
# --------------------------
# 向量從原點 (0,0,0) 出發
origin = np.array([0, 0, 0])
# 向量 A1 (藍色,基底向量 1)
A1 = np.array([1, -0.5, 0])
ax.quiver(*origin, *A1, color='blue', linewidth=2, arrow_length_ratio=0.1)
ax.text(A1[0], A1[1], A1[2], r'$A_1$', fontsize=16, color='blue')
# 向量 A2 (綠色,基底向量 2)
A2 = np.array([0.5, 1, 0])
ax.quiver(*origin, *A2, color='green', linewidth=2, arrow_length_ratio=0.1)
ax.text(A2[0], A2[1], A2[2], r'$A_2$', fontsize=16, color='green')
# 投影向量 p (紅色,y 在平面上的正交投影)
p = np.array([0.75, 0.25, 0])
ax.quiver(*origin, *p, color='red', linewidth=2, arrow_length_ratio=0.1)
ax.text(p[0]+0.1, p[1], p[2], r'$p$', fontsize=16, color='red')
# 線性組合向量 aA1 + bA2 (黑色,平面上的任意點)
comb = 0.5*A1 + 0.5*A2
ax.quiver(*origin, *comb, color='black', linewidth=2, arrow_length_ratio=0.1)
ax.text(comb[0]+0.1, comb[1], comb[2], r'$aA_1 + bA_2$', fontsize=14, color='black')
# 目標向量 y (紫色,被投影的平面外向量)
y = np.array([0.75, 0.25, 1.5])
ax.quiver(*origin, *y, color='purple', linewidth=2, arrow_length_ratio=0.1)
ax.text(y[0], y[1], y[2]+0.1, r'$y$', fontsize=16, color='purple')
# --------------------------
# 繪製垂直虛線 (誤差向量 y-p)
# --------------------------
error_vector = y - p
ax.plot([y[0], p[0]], [y[1], p[1]], [y[2], p[2]],
color='black', linestyle='--', linewidth=1)
# --------------------------
# 調整繪圖極限並顯示
# --------------------------
ax.set_xlim(-1, 2)## (-1.0, 2.0)
## (-1.0, 1.0)
## (-0.1, 1.6)
# ==============================================
# 加上標題並顯示圖表
# ==============================================
plt.title("Figure 3: Projection of vector $\mathbf{y}$ onto the column space of $A$", fontsize=12)
plt.tight_layout()
plt.show()如圖 3 所示,\(\| (aA_1 + bA_2) - \mathbf{y} \|\) 代表對於給定的 \(a\) 和 \(b\) 值所標示實線的長度。我們很容易看出,當 \((A\mathbf{u} - \mathbf{y}) \perp A_1\) 且 \((A\mathbf{u} - \mathbf{y}) \perp A_2\) 時,可由 \(\mathbf{p} = aA_1 + bA_2\) 求得從 \(\mathbf{y}\) 到 \(aA_1 + bA_2\) 距離最短的向量。
這樣的 \(a\) 和 \(b\) 給出了 \(\min \| A\mathbf{u} - \mathbf{y} \| = \min \| (aA_1 + bA_2) - \mathbf{y} \|\) 的解。條件 \((A\mathbf{u} - \mathbf{y}) \perp A_1\) 及 \((A\mathbf{u} - \mathbf{y}) \perp A_2\) 意味著 \(A^T(A\mathbf{u} - \mathbf{y}) = \mathbf{0}\),並得出 \(\hat{\mathbf{u}} = (A^TA)^{-1}A^T\mathbf{y}\)。 \[ \begin{cases} A_1 \cdot (A\mathbf{u} - \mathbf{y}) = 0 \\ A_2 \cdot (A\mathbf{u} - \mathbf{y}) = 0 \end{cases} \iff \begin{bmatrix} A_1 \cdot (A\mathbf{u} - \mathbf{y}) \\ A_2 \cdot (A\mathbf{u} - \mathbf{y}) \end{bmatrix} = \begin{bmatrix} 0 \\ 0 \end{bmatrix} \] \[ \iff \begin{bmatrix} A_1^T \\ A_2^T \end{bmatrix}(A\mathbf{u} - \mathbf{y}) = \begin{bmatrix} 0 \\ 0 \end{bmatrix} \iff A^T(A\mathbf{u} - \mathbf{y}) = \mathbf{0} \] \[ \iff A^TA\mathbf{u} = A^T\mathbf{y} \iff \hat{\mathbf{u}} = (A^TA)^{-1}A^T\mathbf{y} \]
備註
如果對於數據集 \(\{(x_i, y_i)\}\) 存在 \(x_i \neq x_j\),則 \(A^TA\) 必定是可逆的 (Vandermonde 決定式),且 \(\hat{\mathbf{u}} = (A^TA)^{-1}A^T\mathbf{y}\)。
投影與最小二乘法概念總結
\[ \begin{array}{cccccccccccc} \hline \textbf{概念} & \textbf{定義 / 公式} \\ \hline \textrm{直線投影問題} & \min \| t\mathbf{a} - \mathbf{x} \| \\ \textrm{最佳純量}~ t & t = \frac{\mathbf{a} \cdot \mathbf{x}}{\mathbf{a} \cdot \mathbf{a}} = (\mathbf{a}^T\mathbf{a})^{-1}\mathbf{a}^T\mathbf{x} \\ \textrm{最小二乘法問題} & \min \| A\mathbf{u} - \mathbf{y} \| = \min \| aA_1 + bA_2 - \mathbf{y} \| \\ \textrm{正交條件} & (A\mathbf{u} - \mathbf{y}) \perp A_1,\ (A\mathbf{u} - \mathbf{y}) \perp A_2 \\ \textrm{正規方程式} & A^T(A\mathbf{u} - \mathbf{y}) = \mathbf{0} \implies A^TA\mathbf{u} = A^T\mathbf{y} \\ \textrm{最小二乘解} & \hat{\mathbf{u}} = (A^TA)^{-1}A^T\mathbf{y} \\ \hline \end{array} \]
從給定數據中找出 \(A\mathbf{u} = \mathbf{y}\) 的最小二乘解。 \[ A = \begin{bmatrix} 1 & 0 \\ 1 & 1 \\ 1 & 2 \\ 1 & 3 \end{bmatrix}, \quad \mathbf{u} = \begin{bmatrix} a \\ b \end{bmatrix}, \quad \mathbf{y} = \begin{bmatrix} 1 \\ 3 \\ 4 \\ 4 \end{bmatrix} \]
解答
\(A\mathbf{u} = \mathbf{y}\) 的最小二乘解為 \[ \hat{\mathbf{u}} = (A^T A)^{-1} A^T \mathbf{y} \] 該解能最小化 \(\|A\mathbf{u} - \mathbf{y}\|\)。
計算: \[ \hat{\mathbf{u}} = \begin{bmatrix} a \\ b \end{bmatrix} = (A^T A)^{-1} A^T \mathbf{y} = \begin{bmatrix} \frac{7}{10} & -\frac{3}{10} \\ -\frac{3}{10} & \frac{2}{10} \end{bmatrix} \begin{bmatrix} 1 & 1 & 1 & 1 \\ 0 & 1 & 2 & 3 \end{bmatrix} \begin{bmatrix} 1 \\ 3 \\ 4 \\ 4 \end{bmatrix} = \begin{bmatrix} \frac{3}{2} \\ 1 \end{bmatrix} = \begin{bmatrix} 1.5 \\ 1 \end{bmatrix} \]
# 匯入所需庫:NumPy 進行計算,Matplotlib 進行繪圖
import numpy as np
import matplotlib.pyplot as plt
# --------------------------
# 步驟 1:定義給定的矩陣 A 和向量 y
# --------------------------
# 來自線性迴歸問題的設計矩陣 A
A = np.array([[1, 0], [1, 1], [1, 2], [1, 3]])
# 目標輸出向量 y
y = np.array([1, 3, 4, 4])
# --------------------------
# 步驟 2:計算最小二乘解
# 公式:û = (AᵀA)⁻¹ Aᵀ y
# --------------------------
# 計算 A 轉置矩陣乘以 A
ATA = A.T @ A
# 計算 ATA 的反矩陣
ATA_inv = np.linalg.inv(ATA)
# 計算 A 轉置矩陣乘以 y
ATy = A.T @ y
# 計算最小二乘解向量 û (包含 a 和 b)
u_hat = ATA_inv @ ATy
# 從解答中提取截距 (a) 和斜率 (b)
intercept = u_hat[0]
slope = u_hat[1]
# --------------------------
# 步驟 3:列印結果
# --------------------------
print("Least-squares solution u* =", u_hat)## Least-squares solution u* = [1.5 1. ]
## Fitted line equation: y = 1.5 + 1.0x
# --------------------------
# 步驟 4:繪製數據和擬合直線 (對應 TikZ 圖形)
# --------------------------
# 從數據的第一列提取 x 值
x_data = np.array([0, 1, 2, 3])
y_data = y
# 產生用來繪製擬合直線的 x 值
x_line = np.linspace(-0.5, 4, 100)
y_line = intercept + slope * x_line
# 建立具有相符尺寸的圖形
plt.figure(figsize=(8, 6))
# 繪製紅色的數據點 (精確座標)
plt.scatter(x_data, y_data, color='red', s=60, zorder=5)
# 繪製藍色的擬合粗直線
plt.plot(x_line, y_line, color='blue', linewidth=2)
# 繪製置中的座標軸
plt.axhline(0, color='black', linewidth=1)
plt.axvline(0, color='black', linewidth=1)
# 設定標籤和坐標軸極限 (與 LaTeX 完全相同)
plt.xlabel(r'$x$', fontsize=12)
plt.ylabel(r'$y$', fontsize=12)
plt.xlim(-0.5, 4)## (-0.5, 4.0)
## (0.0, 5.0)
# 加上標題 (圖形說明)
plt.title("Fig. 4: Least-squares line fitting the data", fontsize=12)
# 顯示網格和刻度
plt.xticks()## (array([-0.5, 0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. ]), [Text(-0.5, 0, '−0.5'), Text(0.0, 0, '0.0'), Text(0.5, 0, '0.5'), Text(1.0, 0, '1.0'), Text(1.5, 0, '1.5'), Text(2.0, 0, '2.0'), Text(2.5, 0, '2.5'), Text(3.0, 0, '3.0'), Text(3.5, 0, '3.5'), Text(4.0, 0, '4.0')])
## (array([0., 1., 2., 3., 4., 5.]), [Text(0, 0.0, '0'), Text(0, 1.0, '1'), Text(0, 2.0, '2'), Text(0, 3.0, '3'), Text(0, 4.0, '4'), Text(0, 5.0, '5')])
最小二乘法直線為 \[ y = a + bx = \frac{3}{2} + x \] 其中 \[ \hat{\mathbf{u}} = \begin{bmatrix} a \\ b \end{bmatrix} = \begin{bmatrix} 1.5 \\ 1 \end{bmatrix}. \]
我們稍後將會在統計學章節中,學習這個尋找最小二乘法曲線(直線)的過程,這稱為線性迴歸。
範例 2 最小二乘解總結
\[ \begin{array}{cccccccccccc} \hline \textbf{組成部分} & \textbf{數值} \\ \hline \textrm{矩陣}~ A & \begin{bmatrix} 1 & 0 \\ 1 & 1 \\ 1 & 2 \\ 1 & 3 \end{bmatrix} \\ \textrm{向量}~ \mathbf{y} & \begin{bmatrix} 1 \\ 3 \\ 4 \\ 4 \end{bmatrix} \\ \textrm{正規方程式} & A^T A \mathbf{u} = A^T \mathbf{y} \\ \textrm{最小二乘解} & \hat{\mathbf{u}} = (A^T A)^{-1} A^T \mathbf{y} = \begin{bmatrix} 1.5 \\ 1 \end{bmatrix} \\ \textrm{擬合直線} & y = 1.5 + x \\ \hline \end{array} \]
考慮 \(xu\) 平面上的 4 個點(二維數據): \[ (0,1),\ (1,3),\ (2,4),\ (3,4) \]
讓我們找出最佳擬合曲線(\(u = a + bx + cx^2\) 的二次近似值)來描述 \((x_i, u_i)\)。由於所有 4 個數據點都應滿足二次方程式 \(u = a + bx + cx^2\),因此它們可以表示為以下的矩陣形式。
# 匯入數值和繪圖庫
import numpy as np
import matplotlib.pyplot as plt
# =============================================================================
# 步驟 1:定義給定的數據點 (x, u)
# 數據: (0,1), (1,3), (2,4), (3,4)
# =============================================================================
x_data = np.array([0, 1, 2, 3])
u_data = np.array([1, 3, 4, 4])
# =============================================================================
# 步驟 2:建立用於二次擬合的設計矩陣 A (u = a + bx + cx²)
# 每一列為:[1, x, x²]
# =============================================================================
A = np.array([
[1, 0, 0], # x=0 → 1, 0, 0²
[1, 1, 1], # x=1 → 1, 1, 1²
[1, 2, 4], # x=2 → 1, 2, 2²
[1, 3, 9] # x=3 → 1, 3, 3²
])
# 目標向量 y (觀測到的 u 值)
y = np.array([1, 3, 4, 4])
# =============================================================================
# 步驟 3:計算最小二乘解
# 公式:û = (Aᵀ A)⁻¹ Aᵀ y
# =============================================================================
# 計算 A 轉置矩陣乘以 A
ATA = A.T @ A
# 計算 ATA 的反矩陣
ATA_inv = np.linalg.inv(ATA)
# 計算 A 轉置矩陣乘以 y
ATy = A.T @ y
# 求解係數 [a, b, c]
u_hat = ATA_inv @ ATy
# 提取二次係數
a, b, c = u_hat[0], u_hat[1], u_hat[2]
# =============================================================================
# 步驟 4:列印結果
# =============================================================================
print("Least-squares solution u* =", u_hat)## Least-squares solution u* = [ 1. 2.5 -0.5]
## Quadratic curve: u = 1.0 + 2.5x + -0.5x²
# =============================================================================
# 步驟 5:繪製數據點和擬合的二次曲線
# (與 LaTeX TikZ 圖形完全相符)
# =============================================================================
# 產生用於繪製平滑曲線的 x 值
x_curve = np.linspace(-0.5, 4, 100)
# 使用二次方程式計算 u 值
u_curve = a + b * x_curve + c * x_curve**2
# 建立具有相符尺寸的圖形
plt.figure(figsize=(8, 6))
# 繪製紅色的數據點 (實心圓)
plt.scatter(x_data, u_data, color='red', s=60, zorder=5)
# 繪製藍色的二次擬合粗曲線
plt.plot(x_curve, u_curve, color='blue', linewidth=2)
# 繪製置中的 x 與 y 軸
plt.axhline(0, color='black', linewidth=1)
plt.axvline(0, color='black', linewidth=1)
# 設定坐標軸標籤 (數學符號)
plt.xlabel(r'$x$', fontsize=12)
plt.ylabel(r'$u$', fontsize=12)
# 設定坐標軸極限 (與 LaTeX 完全相同)
plt.xlim(-0.5, 4)## (-0.5, 4.0)
## (0.0, 5.0)
# 加上圖形標題 (與 LaTeX 標題相符)
plt.title("Fig. 5: Quadratic least-squares curve fitting the data", fontsize=12)
# 清理排版並顯示圖表
plt.tight_layout()
plt.show()建構二次最小二乘法問題
\[ \begin{array}{cccccccccccc} \hline \textrm{數據}~(x, u) & \textrm{二次函數}~u = a + bx + cx^2 & \textrm{線性方程組} & \textrm{矩陣表示} \\ \hline (0, 1) & 1 = a + b\cdot 0 + c\cdot 0^2 & & \\ (1, 3) & 3 = a + b\cdot 1 + c\cdot 1^2 & \begin{cases} a = 1 \\ a + b + c = 3 \\ a + 2b + 4c = 4 \\ a + 3b + 9c = 4 \end{cases} & A\mathbf{u} = \mathbf{y} \\ (2, 4) & 4 = a + b\cdot 2 + c\cdot 2^2 & & \textrm{其中}~A = \begin{bmatrix} 1 & 0 & 0 \\ 1 & 1 & 1 \\ 1 & 2 & 4 \\ 1 & 3 & 9 \end{bmatrix}, ~\mathbf{u} = \begin{bmatrix} a \\ b \\ c \end{bmatrix}, ~\mathbf{y} = \begin{bmatrix} 1 \\ 3 \\ 4 \\ 4 \end{bmatrix} \\ (3, 4) & 4 = a + b\cdot 3 + c\cdot 3^2 & & \\ \hline \end{array} \]
簡單來說,我們只需要找出 \(u = a + bx + cx^2\) 的向量 \(\hat{\mathbf{u}} = (a, b, c)\),使其最小化 \(\|A\mathbf{u} - \mathbf{y}\|\)。為了從數據集中得出這個二次函數,我們將會得到一個沒有唯一解的方程組。因此,我們需要解決一個最小二乘法問題 \(\min \|A\mathbf{u} - \mathbf{y}\|\)。
以下的函數 \(E(\mathbf{u})\) 代表了這個問題的誤差: \[ E(\mathbf{u}) = E(a,b,c) = (a-1)^2 + (a+b+c-3)^2 + (a+2b+4c-4)^2 + (a+3b+9c-4)^2 = \|A\mathbf{u} - \mathbf{y}\|^2 \]
我們可以求得 \[ \hat{\mathbf{u}} = \begin{bmatrix} a \\ b \\ c \end{bmatrix} = (A^T A)^{-1} A^T \mathbf{y} = \begin{bmatrix} 1 \\ \frac{3}{2} \\ -\frac{1}{2} \end{bmatrix} \]
# 匯入 NumPy 庫
import numpy as np
# 二次擬合的設計矩陣
A = np.array([[1, 0, 0],
[1, 1, 1],
[1, 2, 4],
[1, 3, 9]])
# 目標值
y = np.array([1, 3, 4, 4])
# 使用標準矩陣運算計算最小二乘解
u_hat = np.linalg.inv(A.T @ A) @ A.T @ y
# 列印結果
print("u* =", u_hat)## u* = [ 1. 2.5 -0.5]
所以最小二乘法曲線為 \[ u = 1 + \frac{3}{2}x - \frac{1}{2}x^2. \]