Files
CalWay_Python/按方法整理/拟合-最小二乘法.py
2025-06-19 00:08:48 +08:00

143 lines
4.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import math
# 列主元高斯消元法
def SovleRowMain(A,b):
ks = 0.00000001
n = len(A)
if len(A[0]) != n:
print("A要为方阵")
return None,None,None,None
if len(b) != n:
print("b与A的行数不匹配")
return None,None,None,None
p = list(range(n))
for i in range(n):
row_max = abs(A[i][i])
row_max_index = i
for j in range(i + 1, n):
if abs(A[j][i]) > row_max:
row_max = abs(A[j][i])
row_max_index = j
A[i], A[row_max_index] = A[row_max_index], A[i]
b[i], b[row_max_index] = b[row_max_index], b[i]
p[i], p[row_max_index] = p[row_max_index], p[i]
if abs(A[i][i]) < ks:
print("A矩阵奇异无法进行高斯消元")
return None,None,None,None
for j in range(i + 1, n):
m = A[j][i] / A[i][i]
A[j][i] = m
for k in range(i + 1, n):
A[j][k] -= m * A[i][k]
b[j] -= m * b[i]
if abs(A[n - 1][n - 1]) < ks:
print("A矩阵奇异无法进行高斯消元")
return None,None,None,None
# 回代求解
b[n - 1] /= A[n - 1][n - 1]
for i in range(n - 2, -1, -1):
for j in range(i + 1, n):
b[i] -= A[i][j] * b[j]
b[i] /= A[i][i]
return b
# 最小二乘法拟合
def LeastSquares(list_x,list_y,n):
m = len(list_x)
for i in range(2*n):
tl = [list_x[j]**(i+1) for j in range(m)]
print(f"x^{i+1} :",tl)
print("sum:", sum(tl))
for i in range(n+1):
tl = [list_y[j]*list_x[j]**i for j in range(m)]
print(f"y*x^{i}: ",tl)
print("sum:", sum(tl))
x_n = []
b = []
for i in range(2*n+1):
x_n.append(0)
b.append(0)
for j in range(m):
x_n[i]+=(list_x[j]**i)
b[i]+=(list_y[j]*list_x[j]**i)
b = b[:n+1]
A = []
for i in range(n+1):
tmp = []
for j in range(n+1):
tmp.append(x_n[i+j])
A.append(tmp)
print("A:", A)
print("b:", b)
result = SovleRowMain(A, b)
print("result:", result)
return result
# 计算多项式在给定x值上的值
def CalculateY(list_x, coeff):
re = []
for i in range(len(list_x)):
re.append(0)
for j in range(len(coeff)):
re[i] += coeff[j]*list_x[i]**j
print("y预测:", re)
return re
# 计算均方根误差
def MeanSquareErr(list_y,list_y_approx):
m = len(list_y)
err = 0
print("y差值: ")
for i in range(m):
print(f"y-y测={list_y[i] - list_y_approx[i]}, (y-y测)^2={(list_y[i] - list_y_approx[i])**2}")
err += (list_y[i] - list_y_approx[i])**2
return err**0.5
# 计算最大误差
def MaxErr(list_y,list_y_approx):
m = len(list_y)
err = 0
for i in range(m):
if abs(list_y[i] - list_y_approx[i]) > err:
err = abs(list_y[i] - list_y_approx[i])
return err
# 打印拟合方程
def PrintEquation(coeff):
n = len(coeff)
str_ = str(coeff[0]) + "+"
for i in range(0,n-1):
str_ += str(coeff[i+1])
str_ += "*x^"+str(i+1)+"+"
str_ = str_[0:len(str_)-1]
print(str_)
if __name__ == "__main__":
##########################################################################
# 下面的数值根据题意改成适合的比如要取对数就先取对数下面的x和y是直接用于拟合的
list_x = [2,4,6,8] # 已给出的x数值与y数值对应
list_y = [2,11,28,40] # 已给出的y数值与x数值对应
# 记得改下面最后一个参数,为拟合阶数
print("一次拟合")
coeff = LeastSquares(list_x,list_y,1)
PrintEquation(coeff)
y_approx = CalculateY(list_x, coeff)
print("均方根误差:",MeanSquareErr(list_y,y_approx))
print("最大误差:",MaxErr(list_y,y_approx))
print()
print("二次拟合")
coeff = LeastSquares(list_x,list_y,2)
PrintEquation(coeff)
y_approx = CalculateY(list_x, coeff)
print("均方根误差:",MeanSquareErr(list_y,y_approx))
print("最大误差:",MaxErr(list_y,y_approx))