曲线拟合最小二乘法算法设计及Scala和C++代码实现

2017-01-10 10:02:52来源:oschina作者:安艳青人点击

第七城市

一、曲线拟合最小二乘原理


设实验数据集为,构造的拟合曲线为,则在插值节点处产生的误差为,若想使能够描述原曲线,则应使最小。常使用下列三种标准来度量误差的大小:



曲线拟合最小二乘法选择的是使用向量2-范数最为总体误差的度量标准。


具体地,对给定一组实验数据拟构造的曲线为,其中是基函数是当为极小值时的解。


设多元函数,令 ,具体如下:




,则上式可以写为:把它改写成矩阵形式为:



这是关于系数的线性方程组,也称为正则方程。由于线性无关,故上述线性方程组的系数矩阵行列式不为零,因此方程组有唯一解


二、算法设计


曲线拟合最小二乘法算法设计主要分成两部分,首先应得到线性方程组系数的增广矩阵,然后再求解线性方程组,方程组的求解可用高斯消去法得到。


多项式型经验公式的计算步骤:


(1)输入实验数据:


(2)构造正则方程:


右端项:


系数矩阵:


(3)用高斯消去法求解正则方程;


(4)输出经验公式。


具体算法描述如下图:



其中,n为插值节点下标上限,m为拟合曲线最高次方,X,Y为插值节点向量。


三、Scala实现


在IDEA里实现这个算法,具体代码如下:


package com.hzznv.ls
import breeze.numerics.pow
/**
* Created by YanqingAn on 2017/1/6.
*/
object LeastSquare_2 {
def main(args: Array[String]): Unit = {
val x = new Array[Double](20)
val y = new Array[Double](20)
val a = Array.ofDim[Double](20, 20)
var t: Double = 0
var m: Int = 0
var n: Int = 0
n = readLine("请输入n:").toInt
val xy:String = readLine("请输入xy:")
for(i <- 0 to 2*n-1){
if(i % 2 == 0){
x(i/2) = xy.split(" ")(i).toDouble
}else if(i % 2 == 1) {
y((i-1)/2) = xy.split(" ")(i).toDouble
}
}
m = readLine("请输入m:").toInt
println("输入的插值节点是:")
for(i <- 0 to n-1){
print(x(i) + " ")
}
println()
for(i <- 0 to n-1){
print(y(i) + " ")
}
println()
for(i <- 0 to m){
for(j <- 0 to m){
for(k <- 0 to n-1){
a(i)(j) += pow(x(k), i+j)
}
}
for(k <- 0 to n-1){
a(i)(m+1) += y(k) * pow(x(k), i)
}
}
println("增广矩阵是:")
for(i <- 0 to m){
for(j <- 0 to m+1){
print(" " + a(i)(j))
}
println()
}
for(k <- 0 to m-1){
for(i <- k+1 to m){
t = -a(i)(k) / a(k)(k)
for(j <- k+1 to m+1){
a(i)(j) += a(k)(j) * t
}
}
}
for(i <- (0 to m).reverse){
for(j <- i+1 to m){
a(i)(m+1) -= a(i)(j) * a(j)(m+1)
}
a(i)(m+1) /= a(i)(i)
a(i)(m+1) = f"${a(i)(m+1)}%1.5f".toDouble
}
print("拟合曲线是: y=" + a(0)(m+1))
for(i <- 1 to m){
if(a(i)(m+1) >= 0){
print("+")
}
print(a(i)(m+1))
for(j <- 0 until i){
print("*x")
}
}
}
}

执行过程和结果如下:



四、附C++代码


3 C++实现 在 Vi s ua l c++6. 0里实现这个算法 ,具体代码 如下:#i ncl ude #i ncl ude” mat h. h”int main (){ double x[ 20], y[ 20], a[ 20] [ 20]= { 0}, t ; int i , j, m, n, k; cout <<”请输入 n”<>n;cout <<”请输入 X Y”<>x[ i ]>>y[ i ]; cout <<”请输入 m”<>m; cout <=0;i--){


for(j=i+1;j<=m;j++)


a[i][m+1] -= a[i][j] * a[j][m+1];


a[i][m+1] /= a[i][i];}


cout<

cout<<" y="<

for(i=1;i<=m;i++){


if(a[i][m+1]>0) cout<<" +";


cout<

for(j=0;j

cout<<" *x";


}


五、结束语


曲线拟合最小二乘算法在插值问题的数值算法中是比较经典的算法,它应用的领域也比较宽泛,比如在轨道曲线拟合、人口预测、煤矿瓦斯预警等问题上都有突出贡献。


第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台