對于直線擬合
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(1, 10, 100)
X = np.ones((len(x), 2))
X[:, 0] = x
W_true = np.array([2, 3])
y = X.dot(W_true)
y_noise = y + np.random.randn(len(x))
fig = plt.figure(figsize=(8, 6))
plt.scatter(x, y_noise, s=10, c='r', marker='o')
plt.plot(x, y, label='true value', c='b')
plt.legend()
plt.show()

真實直線與噪聲點
真實的直線方程為y=2x+3,又由于添加了均值為0,方差為1的噪聲點,所以圖上的紅點便是我們要擬合的數(shù)據(jù)。

向量乘法
利用最小二乘法根據(jù)噪聲點求出擬合直線的a和b,即下列公式的w。y為我們真實觀察到的數(shù)據(jù),即對應代碼中的y_noise。

image.png
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(1, 10, 100)
X = np.ones((len(x), 2))
X[:, 0] = x
W_true = np.array([2, 3])
y = X.dot(W_true)
y_noise = y + np.random.randn(len(x))
# 求出擬合直線的權(quán)重
W_pred = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y_noise)
y_pred = X.dot(W_pred)
fig = plt.figure(figsize=(8, 6))
plt.scatter(x, y_noise, s=10, c='r', marker='o')
plt.plot(x, y, label='true value', c='b', zorder=1)
plt.plot(x, y_pred, label='pred value', c='g', zorder=2)
plt.legend()
plt.show()

直線擬合
擬合曲線
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(1, 10, 100)
X = np.ones((len(x), 2))
X[:, 0] = x
y = np.sin(0.5 * x) + 0.1 * x
y_noise = y + np.random.randn(len(x))
# 求出擬合直線的權(quán)重
W_pred = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y_noise)
y_pred = X.dot(W_pred)
fig = plt.figure(figsize=(8, 6))
plt.scatter(x, y_noise, s=10, c='r', marker='o')
plt.plot(x, y, label='true value', c='b', zorder=1)
plt.plot(x, y_pred, label='pred value', c='g', zorder=2)
plt.legend()
plt.show()

直線擬合曲線
真實的y=sin(0.5x)+0.1x,但我們還是用直線取擬合上面的數(shù)據(jù),效果顯然不太好?,F(xiàn)打算用多項式擬合數(shù)據(jù),公式如下:

多項式公式

向量化后
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(1, 10, 100)
y = np.sin(0.5 * x) + 0.1 * x
y_noise = y + np.random.randn(len(x))
# 設多項式最高次數(shù)為4
times = 4
X = np.ones((len(x), times))
for i in range(times):
X[:, i] = x ** (times - i)
# 求取參數(shù)W,即(a,b,...,d)
W_pred = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y_noise)
y_pred = X.dot(W_pred)
fig = plt.figure(figsize=(8, 6))
plt.scatter(x, y_noise, s=10, c='r', marker='o')
plt.plot(x, y, label='true value', c='b', zorder=1)
plt.plot(x, y_pred, label='pred value', c='g', zorder=2)
plt.legend()
plt.show()

image.png
當前設定的最高次數(shù)為5,擬合的還可以。當最高次數(shù)設置為1時,擬合曲線便成了直線,為欠擬合狀態(tài)。當最高次數(shù)為10時,為過擬合狀態(tài)。

最高次數(shù)為1,欠擬合狀態(tài)

最高次數(shù)為10,過擬合狀態(tài)
使用scipy.optimize擬合曲線
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import leastsq
# 多項式匹配,最高次數(shù)為p
def func(p, x):
f = np.poly1d(p)
return f(x)
# 誤差
def resudual(p, x, y):
error = y - func(p, x)
return error
x = np.linspace(1, 10, 100)
y = np.sin(0.5 * x) + 0.1 * x
y_noise = y + np.random.randn(len(x))
# 設多項式最高次數(shù)為4
times = 4
X = np.ones((len(x), times))
for i in range(times):
X[:, i] = x ** (times - i)
# 求取參數(shù)W,即(a,b,...,d)
p_init = np.random.randn(times)
para = leastsq(resudual, p_init, args=(x, y_noise))
y_pred = func(para[0], x)
fig = plt.figure(figsize=(8, 6))
plt.scatter(x, y_noise, s=10, c='r', marker='o')
plt.plot(x, y, label='true value', c='b', zorder=1)
plt.plot(x, y_pred, label='pred value', c='g', zorder=2)
plt.legend()
plt.show()

image.png