1. 什么是最小二乘法?
最小二乘法(Ordinary Least Squares)是一种常用的数据拟合方法,它通过最小误差的平方和来找到一组数据的最佳函数匹配。
很多软件中都包含最小二乘法功能的模块,比如python里scipy库中的leastsq方法。但是本着应用之前知晓其原理的理念,我们来简单了解一下最小二乘法背后的数学设计。
这里暂时考虑最线性的拟合情况。
2. 线性拟合数学原理
假设在一个二维平面内,我们有一堆无序且有一定趋势的散点 [(x1,y1), (x2,y2),…,(xn,yn)],若想通过一条直线来描述这些散点的分布情况,那我们的期望是每个散点离直线的距离加起来应该是最短的。那么,我们期望的效果是下图中的哪一种描述呢?
如果想要更方便地从数学角度研究这个问题,选择第二个方法无疑是更加取巧的。因为第一种情况下算点到直线距离的公式相对复杂。同时,由于点相对与直线的位置有上有下,d 值有正有负,因此只能用 delta y 的绝对值来代表距离d。那么干脆将距离进行平方,去除绝对值,简化数学表达。
假设需要拟合的直线函数表达式为: y=ax+b
那么距离的平方和可以表示为:
为了找到最合适的a, b值,使得上式结果最小,因此需要将上式对参数a, b求偏导,找出偏置数为0对应的 a, b值。
令两式均等于0,求得:
3. 代码实现
import matplotlib.pyplot as plt
def ordinary_least_square(list1,list2):
x_sum = sum(list1)
y_sum = sum(list2)
x_mean = sum(list1)/len(list1)
y_mean = sum(list2)/len(list2)
x_square_sum = sum(x**2 for x in list1)
x_sum_square = (sum(x for x in list1))**2
mul = [m*n for m,n in zip(list1,list2)]
mul_sum = sum(mul)
# 求解线性方程的系数
a = (len(list1)*mul_sum-x_sum*y_sum)/(len(list1)*x_square_sum-x_sum_square)
b = y_mean - a*x_mean
# 拟合直线开始和结束的y值
line_str_y = a*list1[0] + b
line_end_y = a*list1[-1] + b
fit_x = [list1[0],list1[-1]]
fit_y = [line_str_y,line_end_y]
plt.scatter(list1,list2)
plt.plot(fit_x,fit_y)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
if __name__ == "__main__":
list1 = [1,2,3,4,5,6,7,8]
list2 = [2,3,8,8,11,15,30,25]
ordinary_least_square(list1,list2)
这里用了两个List来观察最小二乘法的拟合情况,效果如下。