当前位置:   article > 正文

最小二乘法的曲线拟合_最小二乘法拟合曲线

最小二乘法拟合曲线

最小二乘法解决的问题:Ax=C 无解下的最优解
例子1:
一条过原点的直线OA,C是直线外一点,求C在OA上的投影点P

例子1

 

例子2:
已知三个不在一条直线上的点A,B,C,求一条直线,使A,B,C到直线的距离和最小

例子2

 

例子3:
已知三个不在一条直线上的点A,B,C,求一点,到A,B,C的距离和最小

例子3

其实这3个例子的本质都是一样的。都是求未知的数据,并使得这些求得的数据与实际数据之间误差的平方和为最小。
以第一个例子为例:

  1. Ax=C 无解
  2. 要求||Ax-C||^2最小
  3. A.TAx'=A.TC
  4. x'=(A.TA)^(-1)A.TC
  5. P=Ax'

公式推导

 

同理,例子2,3中都需要写成Ax=C 的形式,求最优解。
只是例子2中的最优解是直线y=ax+b中的a,b。例子3中的最优解是P的坐标P(xp,yp)。
使用程序求例子1:A(3,1),C(1,3)
CODE

  1. import numpy as np
  2. from matplotlib import pyplot as plt
  3. A = np.array([[3],[1]])
  4. C = np.array([[1],[3]])
  5. #x'=(A.TA)^(-1)A.TC
  6. B = A.T.dot(C)
  7. AA = np.linalg.inv(A.T.dot(A))#求A.T.dot(A)的逆
  8. l=AA.dot(B)
  9. #P=Ax'
  10. P=A.dot(l)
  11. x=np.linspace(-2,2,10)#x.shape=(10,)
  12. x.shape=(1,10)
  13. #画出直线y=ax
  14. xx=A.dot(x)
  15. fig = plt.figure() #figsize=(10,6)
  16. ax= fig.add_subplot(111)
  17. ax.plot(xx[0,:],xx[1,:])
  18. #画出A点
  19. ax.plot(A[0],A[1],'ko')
  20. #画出C点,P点
  21. ax.plot([C[0],P[0]],[C[1],P[1]],'r-o')
  22. #画出OC线
  23. ax.plot([0,C[0]],[0,C[1]],'m-o')
  24. #画出坐标轴x=0,y=0
  25. ax.axvline(x=0,color='black')
  26. ax.axhline(y=0,color='black')
  27. #标写每个点的字母
  28. margin=0.1
  29. ax.text(A[0]+margin, A[1]+margin, r"A",fontsize=20)
  30. ax.text(C[0]+margin, C[1]+margin, r"C",fontsize=20)
  31. ax.text(P[0]+margin, P[1]+margin, r"P",fontsize=20)
  32. ax.text(0+margin,0+margin,r"O",fontsize=20)
  33. ax.text(0+margin,4+margin, r"y",fontsize=20)
  34. ax.text(4+margin,0+margin, r"x",fontsize=20)
  35. plt.xticks(np.arange(-2,3))
  36. plt.yticks(np.arange(-2,3))
  37. ax.axis('equal')
  38. plt.show()

结果:

 

最小二乘法 拟合曲线

1.直线拟合

 

直线拟合


已知图中拟合数据的坐标,对图中的拟合数据进行直线拟合。
依旧使用最小二乘法求解
Ax=b——————1
无解下的最优解。已知点的个数为n,所求直线的方程为y1=ax1+b,A由方程右边的a,b的系数构成构成(nx2)的矩阵,每行为(x1,1),b由已知点的y1坐标构成矩阵(nx1)。方程1中的x为要求的列向量[a,b]。
A.TAx'=A.Tb
x'=(A.TA)^(-1)A.TC
求得x‘后,画出拟合曲线的yy=Ax'

 

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. #x的个数决定了样本量
  4. x = np.arange(-1,1,0.02)
  5. #y为理想函数
  6. y = 2*np.sin(x*2.3)+0.5*x**3
  7. #y1为离散的拟合数据
  8. y1 = y+0.5*(np.random.rand(len(x))-0.5)
  9. ##################################
  10. #主要程序
  11. one=np.ones((len(x),1))#len(x)得到数据量
  12. x=x.reshape(x.shape[0],1)
  13. A=np.hstack((x,one))#两个100x1列向量合并成100x2,(100, 1) (100,1 ) (100, 2)
  14. C=y1.reshape(y1.shape[0],1)
  15. #等同于C=y1.reshape(100,1)
  16. #虽然知道y1的个数为100但是程序中不应该出现人工读取的数据
  17. def optimal(A,b):
  18. B = A.T.dot(b)
  19. AA = np.linalg.inv(A.T.dot(A))#求A.T.dot(A)的逆
  20. P=AA.dot(B)
  21. print P
  22. return A.dot(P)
  23. #求得的[a,b]=P=[[ 2.88778507e+00] [ -1.40062271e-04]]
  24. yy = optimal(A,b)
  25. #yy=P[0]*x+P[1]
  26. ##################################
  27. plt.plot(x,y,color='g',linestyle='-',marker='',label=u'理想曲线')
  28. plt.plot(x,y1,color='m',linestyle='',marker='o',label=u'拟合数据')
  29. plt.plot(x,yy,color='b',linestyle='-',marker='.',label=u"拟合曲线")
  30. # 把拟合的曲线在这里画出来
  31. plt.legend(loc='upper left')
  32. plt.show()

直线拟合结果

 

从结果中可以看出,直线拟合并不能对拟合数据达到很好的效果,下面我们介绍一下曲线拟合

2.曲线拟合

 

曲线拟合


图中的拟合数据如果用直线进行拟合效果会更差,曲线能更好的表达数据的特征。这里我们使用多项式函数进行拟合。
拟合函数:
y=axn+bx(n-1)+cx^(n-2)+...+d
假设拟合数据共有100个
Ax=b
A=[x1^n x1^(n-1) x1^(n-2) ...... 1]
[x2^n x2^(n-1) x2^(n-2) ...... 1]
......
[x100^n x100^(n-1) x100^(n-2) . 1]

 

b=[y1]
[y2]
......
[y100]

解得拟合函数的系数[a,b,c.....d]
CODE:

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. x = np.arange(-1,1,0.02)
  4. y = ((x*x-1)**3+1)*(np.cos(x*2)+0.6*np.sin(x*1.3))
  5. y1 = y+(np.random.rand(len(x))-0.5)
  6. ##################################
  7. ### 核心程序
  8. #使用函数y=ax^3+bx^2+cx+d对离散点进行拟合,最高次方需要便于修改,所以不能全部列举,需要使用循环
  9. #A矩阵
  10. m=[]
  11. for i in xrange(7):#这里选的最高次为x^7的多项式
  12. a=x**(i)
  13. m.append(a)
  14. A=np.array(m).T
  15. b=y1.reshape(y1.shape[0],1)
  16. ##################################
  17. def projection(A,b):
  18. AA = A.T.dot(A)#A乘以A转置
  19. w=np.linalg.inv(AA).dot(A.T).dot(b)
  20. print w#w=[[-0.03027851][ 0.1995869 ] [ 2.43887827] [ 1.28426472][-5.60888682] [-0.98754851][ 2.78427031]]
  21. return A.dot(w)
  22. yw = projection(A,b)
  23. yw.shape = (yw.shape[0],)
  24. plt.plot(x,y,color='g',linestyle='-',marker='',label=u"理想曲线")
  25. plt.plot(x,y1,color='m',linestyle='',marker='o',label=u"已知数据点")
  26. plt.plot(x,yw,color='r',linestyle='',marker='.',label=u"拟合曲线")
  27. plt.legend(loc='upper left')
  28. plt.show()

结果

 

根据结果可以看到拟合的效果不错。
我们可以通过改变

  • 拟合函数类型
  • 样本数(此处为x的个数)

来调整拟合效果。
如果此处我们把拟合函数改为最高次为x^20的多项式

  1. m=[]
  2. for i in xrange(20):
  3. a=x**(i)
  4. m.append(a)

所得结果如下:

 

x^20 样本数100


这种现象称为过拟合现象

 

  • 可以通过增加样本数数,
  • 降低拟合函数的次数

矫正过拟合现象
在保持拟合函数改为最高次为x^20的多项式的条件下,增大样本数:

x = np.arange(-1,1,0.005) #原来是x = np.arange(-1,1,0.02)  

x^20 样本数400

通过结果可以看出,过拟合现象得到了改善。

 

 

概念

最小二乘法多项式曲线拟合,根据给定的m个点,并不要求这条曲线精确地经过这些点,而是曲线y=f(x)的近似曲线y= φ(x)。

 

原理

[原理部分由个人根据互联网上的资料进行总结,希望对大家能有用]

     给定数据点pi(xi,yi),其中i=1,2,…,m。求近似曲线y= φ(x)。并且使得近似曲线与y=f(x)的偏差最小。近似曲线在点pi处的偏差δi= φ(xi)-y,i=1,2,...,m。 

常见的曲线拟合方法:

     1.使偏差绝对值之和最小

     

 

     2.使偏差绝对值最大的最小

     

 

     3.使偏差平方和最小

 

     

 

     按偏差平方和最小的原则选取拟合曲线,并且采取二项式方程为拟合曲线的方法,称为最小二乘法。

推导过程:

     1. 设拟合多项式为:

          

     2. 各点到这条曲线的距离之和,即偏差平方和如下:

          

     3. 为了求得符合条件的a值,对等式右边求ai偏导数,因而我们得到了: 

          

          

                         .......

          

 

     4. 将等式左边进行一下化简,然后应该可以得到下面的等式:

          

          

                     .......

          

 

     5. 把这些等式表示成矩阵的形式,就可以得到下面的矩阵:

          

     6. 将这个范德蒙得矩阵化简后可得到:

          

     7. 也就是说X*A=Y,那么A = (X'*X)-1*X'*Y,便得到了系数矩阵A,同时,我们也就得到了拟合曲线。

 

经验证 5,与 6 的 结果一致,所以 一般用 6的方式更简单。

 

 

验证代码:

  1. # coding=utf-8
  2. '''
  3. 作者:Jairus Chan
  4. 程序:多项式曲线拟合算法
  5. '''
  6. import matplotlib.pyplot as plt
  7. import math
  8. import numpy
  9. import random
  10. fig = plt.figure()
  11. ax = fig.add_subplot(111)
  12. # 阶数为9
  13. order = 9
  14. # 生成曲线上的各个点
  15. x = numpy.arange(-1, 1, 0.02)
  16. y = [((a * a - 1) * (a * a - 1) * (a * a - 1) + 0.5) * numpy.sin(a * 2) for a in x]
  17. # ax.plot(x,y,color='r',linestyle='-',marker='')
  18. # ,label="(a*a-1)*(a*a-1)*(a*a-1)+0.5"
  19. # 生成的曲线上的各个点偏移一下,并放入到xa,ya中去
  20. i = 0
  21. xa = []
  22. ya = []
  23. for xx in x:
  24. yy = y[i]
  25. d = float(random.randint(60, 140)) / 100
  26. # ax.plot([xx*d],[yy*d],color='m',linestyle='',marker='.')
  27. i += 1
  28. xa.append(xx * d)
  29. ya.append(yy * d)
  30. '''for i in range(0,5):
  31. xx=float(random.randint(-100,100))/100
  32. yy=float(random.randint(-60,60))/100
  33. xa.append(xx)
  34. ya.append(yy)'''
  35. ax.plot(xa, ya, color='m', linestyle='', marker='.')
  36. # 进行曲线拟合 验证 5
  37. matA = []
  38. for i in range(0, order + 1):
  39. matA1 = []
  40. for j in range(0, order + 1):
  41. tx = 0.0
  42. for k in range(0, len(xa)):
  43. dx = 1.0
  44. for l in range(0, j + i):
  45. dx = dx * xa[k]
  46. tx += dx
  47. matA1.append(tx)
  48. matA.append(matA1)
  49. print(len(matA))
  50. print(len(matA[0]))
  51. print(matA[0])
  52. print(matA[1])
  53. print(matA[2])
  54. # print(len(xa))
  55. # print(matA[0][0])
  56. matA = numpy.array(matA)
  57. matB = []
  58. for i in range(0, order + 1):
  59. ty = 0.0
  60. for k in range(0, len(xa)):
  61. dy = 1.0
  62. for l in range(0, i):
  63. dy = dy * xa[k]
  64. ty += ya[k] * dy
  65. matB.append(ty)
  66. matB = numpy.array(matB)
  67. matAA = numpy.linalg.solve(matA, matB)
  68. print(matAA.shape)
  69. # 画出拟合后的曲线
  70. # print(matAA)
  71. xxa = numpy.arange(-1, 1.06, 0.03)
  72. yya = []
  73. for i in range(0, len(xxa)):
  74. yy = 0.0
  75. for j in range(0, order + 1):
  76. dy = 1.0
  77. for k in range(0, j):
  78. dy *= xxa[i]
  79. dy *= matAA[j]
  80. yy += dy
  81. yya.append(yy)
  82. ax.plot(xxa, yya, color='g', linestyle='', marker='.')
  83. # 多项式 拟合 验证 6
  84. def projection(A, b):
  85. AA = A.T.dot(A)
  86. w = numpy.linalg.inv(AA).dot(A.T).dot(b)
  87. return w
  88. array_xa = numpy.array(xa)
  89. array_ya = numpy.array(ya)
  90. m = []
  91. for i in range(10):
  92. a = array_xa**(i)
  93. m.append(a)
  94. A = numpy.array(m).T
  95. b = array_ya.reshape(array_ya.shape[0], 1)
  96. w = projection(A, b)
  97. print("w:", w.shape)
  98. print("xxa", xxa.shape)
  99. array_xxa = numpy.array(xxa)
  100. mm = []
  101. for i in range(10):
  102. a = xxa**(i)
  103. mm.append(a)
  104. AA = numpy.array(mm).T
  105. print("AA:", AA.shape)
  106. new_y = AA.dot(w)
  107. ax.plot(array_xxa, new_y, color='b', linestyle='-', marker='')
  108. # 5 曲线 与 6 曲线 重合。
  109. ax.legend()
  110. plt.show()

运行效果:

 

 

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号