【高等数学笔记】彻底弄懂最小二乘法(Least Squares Method)

【高等数学笔记】彻底弄懂最小二乘法(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∑n​ri2​=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∑n​xi​+nb=i=1∑n​yi​令x‾=∑i=1nxin\overline x=\frac{\sum\limits_{i=1}^n x_i}{n}x=ni=1∑n​xi​​,y‾=∑i=1nyin\overline y=\frac{\sum\limits_{i=1}^n y_i}{n}y​=ni=1∑n​yi​​(分别为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∑n​xi2​+bi=1∑n​xi​=i=1∑n​xi​yi​令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∑n​xi2​​,xy​=ni=1∑n​xi​yi​​,则有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)。