数值计算 利用Python实现多项式最小二乘拟合(不调用函数库)

最小二乘拟合介绍

最小二乘拟合比较简单以及常见,这里就不介绍了。

代码实现

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

得到结果:(并没有好看)

数值计算 利用Python实现多项式最小二乘拟合(不调用函数库)_第1张图片

你可能感兴趣的:(数值计算,python,numpy,线性代数,矩阵)