多元線性迴歸(一)


在〈多項式迴歸〉中想求得的迴歸函式是 x -> fΘ(x),只有一個變數 x,如果想求得的迴歸函式不只有一個變數,這個任務稱為多元線性迴歸,也就是函式的形式會是 fΘ(x1, x2, x3, …) = Θ1 * x1 + Θ2 * x2 + Θ3 * x3

遇到多元函式時,腦袋或許會一時當機,然而先從兩個變數開始,也就是 fΘ(x1, x2) = Θ1 * x1 + Θ2 * x2,如果兩個變數各表示空間的 x 與 y,而計算結果代表 z,不就是平面方程式嗎?

也就是說,若空間中散佈著一組點:

[
    [180.81382149   2.01912626 444.75446169]
    [ 29.38946937 180.38776789 431.49013503]
    [ 68.19346217 157.16977084 503.50527714]
    [ 77.42914051  74.85384854 334.95642501]
    [ 13.15090257  77.22469551 122.27877554]
    [119.07045075  87.30218615 522.81495852]
    [184.35629535 200.15363538 702.41205539]
    [ 73.01474307  85.12155386 372.027134  ]
    [ 77.90825066  79.74688831 352.30507521]
    ....
]

使用散佈圖畫出來是這樣:

多元線性迴歸(一)

觀察點的散佈,大致上呈現某個線性趨勢,若打算求得多元線性迴歸,結果會是個平面函式,畫出來會像是:

多元線性迴歸(一)

想要透過程式庫來求多元線性迴歸,可以使用 sklearnsklearn.linear_model.LinearRegression 物件,以下直接列出程式碼作為參考:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from sklearn.linear_model import LinearRegression

def points(start, end, step, noise, f):
    n = (end - start) // step
    x = np.arange(start, end, step) + np.random.rand(n) * noise
    y = np.arange(start, end, step) + np.random.rand(n) * noise
    z = f(x, y) + np.random.rand(n) * noise
    return np.dstack((x, y, z))[0]

# 用來產生資料的平面函式
def f(x, y):
    return 2 * x + y + 10

# 資料來源
data = points(0, 100, 1, 200, f)

xy = data[:,0:2]   # 包含 [x, y] 的清單
z = data[:,2]      # 包含 z 的清單

linreg = LinearRegression()    # 負責線性迴歸
linreg = linreg.fit(xy, z)     # 擬合

t1, t2 = linreg.coef_          # 係數
intercept = linreg.intercept_  # 截距

# 畫平面需要的資料
arange = np.arange(0, 300)
X, Y = np.meshgrid(arange, arange)
Z = X * t1 + Y * t2 + intercept    # 平面方程式

ax = plt.axes(projection='3d')

ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.set_box_aspect((1, 1, 1))

ax.scatter(data[:,0], data[:,1], data[:,2])
ax.plot_surface(X, Y, Z, cmap = cm.Reds) 

plt.show()

若有一組 x、y 資料,想求得對應的 z 值,除了自行組合係數與截距之外,也可以透過 LinearRegressionpredict 方法,例如:

# z_lt 是 [172.21473337 143.75287361 331.28569312 318.98911371]
z_lt = linreg.predict([[10, 20], [3, 3], [100, 2], [50, 99]])