Java 使⽤Apachecommons-math3线性拟合、⾮线性拟合实例(带效果图)Java 使⽤ CommonsMath3 的线性和⾮线性拟合实例,带效果图例⼦查看运⾏src/main/java/org/wfw/chart/Main.java  即可查看效果
src/main/java/org/wfw/math  包下是简单的使⽤版本说明JDK:1.8
commons-math:3.6.1⼀些基础知识线性:两个变量之间存在⼀次⽅函数关系,就称它们之间存在线性关系。也就是如下的函数:⾮线性:除了线性其他的都是⾮线性,例如:矩阵:矩阵(Matrix)是⼀个按照长⽅阵列排列的复数或实数集合,可以理解为平⾯或者空间的坐标点。
看⼤佬怎么说之>>微分、积分:互为逆过程,⼀句话概括,微分就是求导,求某个点的极⼩变化量的斜率。积分是求⼀些列变化点的和,⼏何意义是⾯积看⼤佬怎么说之>>
拟合:形象的说,拟合就是把平⾯上⼀系列的点,⽤⼀条光滑的曲线连接起来的过程。到⼀条最符合这些散点的曲线,使得尽可能多的落在曲线上。常⽤的⽅法是最⼩⼆乘法。也就是最⼩⼆乘问题
添加依赖
Maven 中添加依赖
<!-- mvnrepository/artifact/org.apachemons/commons-math3 -->
<dependency >
<groupId >org.apachemons </groupId >
<artifactId >commons-math3</artifactId >
<version >3.6.1</version >
</dependency >
如果你是 Gradle
// mvnrepository/artifact/org.apachemons/commons-math3
compile group : 'org.apachemons', name : 'commons-math3', version : '3.6.1'
如何使⽤和验证
f (x )=kx +b
f (x )=e x
1. 假设函数已知
2. 根据函数并添加随机数R ⽣成⼀系列散点数据(蓝⾊)
3. 进⾏拟合,根据拟合结果⽣成拟合曲线
4. 对⽐结果曲线(绿⾊)和散点曲线
例如:
⾸先根绝函数⽣成  取任意实数时的以及所对应的  得到数据集 然后对这组数据进⾏拟合,然后和已知函数  对⽐斜率  以及截距 1. 线性拟合
线性函数:
假设函数为:
⽣成数据集合:
/**
*
* y = kx + b
* f(x) = 1.5x + 0.5
*
* @return
*/
public  static  double [][] linearScatters () {
List <double []> data = new  ArrayList <>();
for  (double  x = 0; x <= 10; x += 0.1) {
double  y = 1.5 * x + 0.5;
y += Math .random () * 4 - 2; // 随机数
double [] xy = {x , y };
data .add (xy );
}
return  data .stream ().toArray (double [][]::new );
}
进⾏拟合
f (x )=2x +3
x f (x )xy
f (x ,y )=(0,3)∗R ,(1,5)∗R ,(2,7)∗R ...(n ,2n +3)∗R
f (x )k b
f (x )=kx +b
f (x )=1.5x +0.5
public static Result linearFit(double[][] data){
List<double[]> fitData =new ArrayList<>();
SimpleRegression regression =new SimpleRegression();
regression.addData(data);// 数据集
/*
* RegressionResults 中是拟合的结果
* 其中重要的⼏个参数如下:
*  parameters:
*      0: b
*      1: k
*  globalFitInfo
*      0: 平⽅误差之和, SSE
*      1: 平⽅和, SST
*      2: R 平⽅, RSQ
*      3: 均⽅误差, MSE
*      4: 调整后的 R 平⽅, adjRSQ
*
* */
RegressionResults results = ss();
double b = ParameterEstimate(0);
double k = ParameterEstimate(1);
double r2 = RSquared();
/
/ 重新计算⽣成拟合曲线
for(double[] datum : data){
double[] xy ={datum[0], k * datum[0]+ b};
fitData.add(xy);
}
StringBuilder func =new StringBuilder();
func.append("f(x) =");
func.append(b >=0?" ":" - ");
func.append(Math.abs(b));
func.append(k >0?" + ":" - ");
func.append(Math.abs(k));
func.append("x");
return new Result(fitData.stream().toArray(double[][]::new), String());
}
拟合效果
线性拟合⽐较简单,主要是 SimpleRegression 类的 regress() ⽅法,默认使⽤ 最⼩⼆乘法优化器2. ⾮线性(曲线)拟合(⼀元多项式)
⾮线性函数
假设函数为
⽣成数据集合:f(x)=a+bx+cx+
2dx+
<+mx n
f(x)=1+2x+3x2
/**
*
* f(x) = 1 + 2x + 3x^2
*
* @return
*/
public static double[][]curveScatters(){
List<double[]> data =new ArrayList<>();
for(double x =0; x <=20; x +=1){
double y =1+2* x +3* x * x;
y += Math.random()*60-10;// 随机数
double[] xy ={x, y};
jdk怎么使用data.add(xy);
}
return data.stream().toArray(double[][]::new);
}
进⾏拟合
public static Result curveFit(double[][] data){
ParametricUnivariateFunction function =new PolynomialFunction.Parametric();/*多项式函数*/ double[] guess ={1,2,3};/*猜测值依次为常数项、1次项、⼆次项*/
// 初始化拟合
SimpleCurveFitter curveFitter = ate(function,guess);
// 添加数据点
WeightedObservedPoints observedPoints =new WeightedObservedPoints();
for(double[] point : data){
observedPoints.add(point[0], point[1]);
}
/*
* best 为拟合结果
* 依次为常数项、1次项、⼆次项
* 对应 y = a + bx + cx^2 中的 a, b, c
* */
double[] best = curveFitter.List());
/
*
* 根据拟合结果重新计算
* */
List<double[]> fitData =new ArrayList<>();
for(double[] datum : data){
double x = datum[0];
double y = best[0]+ best[1]* x + best[2]* x * x;// y = a + bx + cx^2
double[] xy ={x, y};
fitData.add(xy);
}
StringBuilder func =new StringBuilder();
func.append("f(x) =");
func.append(best[0]>0?" ":" - ");
func.append(Math.abs(best[0]));
func.append(best[1]>0?" + ":" - ");
func.append(Math.abs(best[1]));
func.append("x");
func.append(best[2]>0?" + ":" - ");
func.append(Math.abs(best[2]));
func.append("x^2");
return new Result(fitData.stream().toArray(double[][]::new), String());
}
拟合效果⼀元多项式曲线的拟合多了⼀些步骤。但是总归也是不难的。主要是 SimpleCurveFitter  类以及 ParametricUnivariateFunction  接⼝。
3. ⾃定义函数拟合(⼀元多项式)
总得来说,貌似线性和⼀元多项式都不难。不过,实际⼯作或者学术中,⼀般都是⾃定义的函数。假设有⼀元多项式函数:
需要拟合出 a,b,c,d 四个参数的值。
⽅法:
1. 实现 ParametricUnivariateFunction  接⼝
2. ⾃定义函数,实现 value  ⽅法
3. 解偏微分⽅程,实现 gradient  ⽅法
4. 设置需要拟合的点
5. 调⽤SimpleCurveFitter#fit  ⽅法进⾏拟合不着急写代码,先看ParametricUnivariateFunction 这个接
⼝的源码:
/**
* An interface representing a real function that depends on one independent
* variable plus some extra parameters.
*
* @since 3.0
*/
public  interface  ParametricUnivariateFunction {
/**
* Compute the value of the function.
* 计算函数的值
* @param x Point for which the function value should be computed.
* @param parameters Function parameters.
* @return the value.
*/
double  value (double  x , double  ... parameters );
/**
* Compute the gradient of the function with respect to its parameters.
* 计算函数相对于某个参数的导数
* @param x Point for which the function value should be computed.
* @param parameters Function parameters.
* @return the value.
*/
double [] gradient (double  x , double  ... parameters );}
value  ⽅法很简单,就是说计算函数  的值。说⼈话就是⾃定义函数的
gradient  ⽅法为返回⼀个数组,其实意思就是求偏微分⽅程,对每⼀个要拟合的参数求导就⾏不会偏微分⽅程?
按格式输⼊你的⽅程=>输⼊⾃变量=>输⼊求导阶数(⼀般都是 1 阶)=>计算f (x )=d +1+()
c x b a −
d F (x )

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。