最小二乘拟合比较简单以及常见,这里就不介绍了。
import numpy as np
def solve_f(x: list, f: list, fi: list): # 计算多项式系数
ip = np.zeros((len(fi), len(fi))) # 定义内积矩阵
ip_f = np.zeros(len(fi))
for i in range(0, len(fi)):
x_1 = [_ ** fi[i] for _ in x]
ip_f[i] = sum(map(lambda a, b: a * b, x_1, f)) #计算内积,此处为(fi_i, f(x))
for j in range(0, len(fi)):
x_2 = [_ ** fi[j] for _ in x]
ip[i, j] = sum(map(lambda a, b: a * b, x_1, x_2))
# print(np.dot(np.linalg.inv(ip), ip_f))
# print(ip, ip_f)
return np.dot(np.linalg.inv(ip), ip_f) # 左乘逆矩阵计算系数矩阵
def get_function(p: float, coeff: np.ndarray, fi: list): # 计算某点函数拟合值
res = 0
for i in range(0, len(fi)):
res += (p ** fi[i]) * coeff[i]
return res
def get_poly(coeff: list, fi: list): # 用于打印方程
ans = ""
for i in range(0, len(fi)):
if i != 0 and coeff[i] > 0:
ans += '+'
ans += ('%.4f' % coeff[i] + 'x^' + str(fi[i]))
return ans
def eps(x:list, f:list, coeff: np.ndarray, fi: list): # 计算平方误差
ans = 0
for i in range(0, len(x)):
ans += (f[i] - get_function(x[i], coeff, fi))**2
return ans/len(x) # 这里取了个平均
考虑对节点 x \textbf{x} x及函数值 f \textbf{f} f :
x = [ 0 , 0.1 , 0.2 , 0.3 , 0.5 , 0.8 , 1.0 ] f = [ 1.0 , 0.41 , 0.50 , 0.61 , 0.91 , 2.02 , 2.46 ] \textbf{x} = [0, 0.1, 0.2, 0.3, 0.5, 0.8, 1.0] \\ \textbf{f} = [1.0, 0.41, 0.50, 0.61, 0.91, 2.02, 2.46] x=[0,0.1,0.2,0.3,0.5,0.8,1.0]f=[1.0,0.41,0.50,0.61,0.91,2.02,2.46]
进行拟合。
import numpy as np
import matplotlib.pyplot as plt
from pylab import mpl
import LS_polybase as ls #上文的文件名
import newton as nt
def draw(data: np.ndarray, x: list, f: list, fi: list):
font = {'family': 'Times New Roman',
'weight': 'normal',
'size': 15,
}
c = ls.solve_f(x, f, fi)
plt.plot(data, ls.get_function(data, c, fi), label="%s次拟合曲线" % (len(fi)-1), color="black")
plt.scatter(x, f, label="节点数据", color="red")
# plt.title("%s次最小二乘拟合曲线" % (len(fi) - 1))
plt.title(ls.get_poly(c, fi), font)
print("%s次最小二乘拟合曲线的误差:%s" % ((len(fi) - 1), ls.eps(x, f, c, fi)))
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
plt.legend(loc="upper right")
def draw_(data: np.ndarray, x: list, f: list, fi: list):
font = {'family': 'Times New Roman',
'weight': 'normal',
'size': 15,
}
c = ls.solve_f(x, f, fi)
plt.plot(data, ls.get_function(data, c, fi), label="%s次拟合曲线" % (len(fi)-1), color="blue")
# plt.scatter(x, f, label="节点数据", color="red")
# plt.title("%s次最小二乘拟合曲线" % (len(fi) - 1))
plt.xlabel(ls.get_poly(c, fi),font)
print("%s次最小二乘拟合曲线的误差:%s" % ((len(fi) - 1), ls.eps(x, f, c, fi)))
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
plt.legend(loc="upper right")
if __name__ == "__main__":
x = [0, 0.1, 0.2, 0.3, 0.5, 0.8, 1.0]
f = [1.0, 0.41, 0.50, 0.61, 0.91, 2.02, 2.46]
fi_3 = [0, 1, 2, 3]
fi_4 = [0, 1, 2, 3, 4]
# nt.draw(np.arange(0, 1.01, 0.01), x, f, len(x) - 1)
draw(np.arange(0, 1.01, 0.01), x, f, fi_3)
draw_(np.arange(0, 1.01, 0.01), x, f, fi_4) #这里两个draw差别不大,只是为了好看,实际上用同一个draw也没问题
plt.show()
得到结果:(并没有好看)