【高等数学笔记】彻底弄懂最小二乘法(Least Squares Method)
seh_sjlj
已于 2022-03-14 18:58:16 修改
阅读量8.2k
收藏
15
点赞数
3
CC 4.0 BY-SA版权
分类专栏:
高等数学
文章标签:
最小二乘法
python
机器学习
经验分享
学习
于 2022-03-11 22:06:30 首次发布
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qaqwqaqwq/article/details/123434241
高等数学
专栏收录该内容
19 篇文章
订阅专栏
这篇博客介绍了最小二乘法在拟合一元线性函数时的作用,通过数学推导展示了如何找到使得偏差平方和最小的参数值。以一次函数为例,详细阐述了计算过程,并提供了Python代码实现,实现了从数据点中求解最佳拟合直线的斜率和截距。最后,讨论了算法的时间复杂度为线性。
摘要生成于
C知道
,由 DeepSeek-R1 满血版支持,
前往体验 >
假设我们要拟合一个一元函数,目前我们知道的自变量及因变量的值是(x1,y1),(x2,y2),⋯ ,(xn,yn)(x_1,y_1),(x_2,y_2),\cdots,(x_n,y_n)(x1,y1),(x2,y2),⋯,(xn,yn),而我们要求y=f(x)y=f(x)y=f(x),使得用它作为近似函数时,函数值与真实值的偏差ri=f(xi)−yir_i=f(x_i)-y_iri=f(xi)−yi的平方和∑i=1nri2=∑i=1n(f(xi)−yi)2\sum\limits_{i=1}^nr_i^2=\sum\limits_{i=1}^n(f(x_i)-y_i)^2i=1∑nri2=i=1∑n(f(xi)−yi)2最小。
假如我们已经选定了一类函数(模型)去拟合,现在要确定其中参数的值。比如我们选择了f(x)=eax+bf(x)=e^{ax+b}f(x)=eax+b这种模型(一般用于拟合人口增长),就要确定参数a,ba,ba,b的值。设参数为a1,a2,⋯ ,ama_1,a_2,\cdots,a_ma1,a2,⋯,am,将fff表示为f(x,a1,a2,⋯ ,am)f(x,a_1,a_2,\cdots,a_m)f(x,a1,a2,⋯,am)。损失函数,即偏差的平方和为Q(a1,a2,⋯ ,am)=∑i=1n(f(xi,a1,a2,⋯ ,am)−yi)2Q(a_1,a_2,\cdots,a_m)=\sum\limits_{i=1}^n(f(x_i,a_1,a_2,\cdots,a_m)-y_i)^2Q(a1,a2,⋯,am)=i=1∑n(f(xi,a1,a2,⋯,am)−yi)2。注意,这里QQQ是参数a1,a2,⋯ ,ama_1,a_2,\cdots,a_ma1,a2,⋯,am的函数,而不是x,yx,yx,y的函数。让QQQ取得极值,就需要让QQQ对a1,a2,⋯ ,ama_1,a_2,\cdots,a_ma1,a2,⋯,am的偏导数都为000。对于参数aka_kak,QQQ对它的偏导数为∂Q∂ak=2∑i=1n[(f(xi,a1,a2,⋯ ,am)−yi)∂f∂ak∣xi]\frac{\partial Q}{\partial a_k}=2\sum\limits_{i=1}^n\left[\left(f(x_i,a_1,a_2,\cdots,a_m)-y_i\right)\left.\frac{\partial f}{\partial a_k}\right|_{x_i}\right]∂ak∂Q=2i=1∑n[(f(xi,a1,a2,⋯,am)−yi)∂ak∂f∣∣∣∣xi]让它等于000,就是要使得∀k=1,2,⋯ ,m,∑i=1n[(f(xi,a1,a2,⋯ ,am)−yi)∂f∂ak∣xi]=0\forall k=1,2,\cdots,m,\\\sum\limits_{i=1}^n\left[\left(f(x_i,a_1,a_2,\cdots,a_m)-y_i\right)\left.\frac{\partial f}{\partial a_k}\right|_{x_i}\right]=0∀k=1,2,⋯,m,i=1∑n[(f(xi,a1,a2,⋯,am)−yi)∂ak∂f∣∣∣∣xi]=0
下面以一次函数拟合为例。设f(x)=ax+bf(x)=ax+bf(x)=ax+b,要通过已知的数据点(x1,y1),(x2,y2),⋯ ,(xn,yn)(x_1,y_1),(x_2,y_2),\cdots,(x_n,y_n)(x1,y1),(x2,y2),⋯,(xn,yn)来确定参数a,ba,ba,b的值。损失函数Q(a,b)=∑i=1n(axi+b−yi)2Q(a,b)=\sum\limits_{i=1}^n(ax_i+b-y_i)^2Q(a,b)=i=1∑n(axi+b−yi)2,∂Q∂a=2∑i=1n(axi+b−yi)xi=0①∂Q∂b=2∑i=1n(axi+b−yi)=0②\begin{aligned}\frac{\partial Q}{\partial a}&=2\sum\limits_{i=1}^n(ax_i+b-y_i)x_i=0\qquad&①\\\frac{\partial Q}{\partial b}&=2\sum\limits_{i=1}^n(ax_i+b-y_i)=0&②\end{aligned}∂a∂Q∂b∂Q=2i=1∑n(axi+b−yi)xi=0=2i=1∑n(axi+b−yi)=0①②由②②②得a∑i=1nxi+nb=∑i=1nyia\sum\limits_{i=1}^nx_i+nb=\sum\limits_{i=1}^ny_iai=1∑nxi+nb=i=1∑nyi令x‾=∑i=1nxin\overline x=\frac{\sum\limits_{i=1}^n x_i}{n}x=ni=1∑nxi,y‾=∑i=1nyin\overline y=\frac{\sum\limits_{i=1}^n y_i}{n}y=ni=1∑nyi(分别为x,yx,yx,y的平均值),则有ax‾+b=y‾③a\overline x+b=\overline y\qquad ③ax+b=y③由①①①得a∑i=1nxi2+b∑i=1nxi=∑i=1nxiyia\sum\limits_{i=1}^n x_i^2+b\sum\limits_{i=1}^n x_i=\sum\limits_{i=1}^n x_iy_iai=1∑nxi2+bi=1∑nxi=i=1∑nxiyi令x2‾=∑i=1nxi2n,xy‾=∑i=1nxiyin\overline{x^2}=\frac{\sum\limits_{i=1}^n x_i^2}{n},\overline{xy}=\frac{\sum\limits_{i=1}^n x_iy_i}{n}x2=ni=1∑nxi2,xy=ni=1∑nxiyi,则有ax2‾+bx‾=xy‾④a\overline{x^2}+b\overline{x}=\overline{xy}\qquad④ax2+bx=xy④③×x‾③\times\overline x③×x得ax‾2+bx‾=xˉyˉ⑤a{\overline x}^2+b\overline x=\bar x\bar y\qquad⑤ax2+bx=xˉyˉ⑤⑤−④⑤-④⑤−④得a(x‾2−x2‾)=xˉyˉ−xy‾a({\overline x}^2-\overline{x^2})=\bar x\bar y-\overline{xy}a(x2−x2)=xˉyˉ−xy由此算出直线的斜率a=xˉyˉ−xy‾x‾2−x2‾a=\frac{\bar x\bar y-\overline{xy}}{{\overline x}^2-\overline{x^2}}a=x2−x2xˉyˉ−xy由③③③得b=y‾−ax‾b=\overline y-a\overline xb=y−ax
一次函数拟合的Python代码实现:
# Least Squares Method (Linear)
# Author: seh_sjij
import matplotlib.pyplot as plt
import numpy as np
class LeastSquareMethod(object):
def __init__(self, x, y):
self.x = x
self.y = y
self.n = len(self.x)
if len(self.y) != self.n:
raise Exception(
'LeastSquareMethod: len(x) != len(y)')
def Calculate(self):
self.xmean = self.xsquaremean = 0
# average of x and x^2
for x_i in self.x:
self.xmean += x_i
self.xsquaremean += x_i * x_i
self.xmean /= self.n
self.xsquaremean /= self.n
self.ymean = 0
# average of y
for y_i in self.y:
self.ymean += y_i
self.ymean /= self.n
self.xymean = 0
# average of xy
for i in range(0, self.n):
self.xymean += self.x[i] * self.y[i]
self.xymean /= self.n
a = (self.xmean * self.ymean - self.xymean) \
/ (self.xmean * self.xmean - self.xsquaremean)
b = self.ymean - a * self.xmean
return (a, b) # y = ax + b
if __name__ == '__main__':
x = [1, 2, 4, 6, 7, 9, 10, 12]
y = [0.7, 2.25, 4.64, 5.69, 7.40, 8.57, 10.72, 11.64]
lsm = LeastSquareMethod(x, y)
a, b = lsm.Calculate()
plt.scatter(x, y)
plt.plot(x, [a * x_i + b for x_i in x])
plt.title('Least Squares Method: y = %fx + %f' % (a, b))
plt.show()
执行结果:
时间复杂度:Θ(n)\Theta(n)Θ(n)。