一、拟合函数常用工具:
Apache Commons Math3
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
2、二维曲线拟合查看工具
http://tools.jb51.net/jisuanqi/fun_draw
3、三维曲线绘制工具
https://echarts.apache.org/examples/zh/editor.html?c=line3d-orthographic&gl=1
二、线性拟合:
拟合公式:
定义:拟合就是把平面上一系列的点,用一条光滑的曲线连接起来的过程。找到一条最符合这些散点的曲线,使得尽可能多的落在曲线上。常用的方法是最小二乘法。也就是最小二乘问题(采用线性代数的计算对残差最小值进行逼近)
**方法:**线性拟合比较简单,主要是 SimpleRegression 类的 regress() 方法,默认使用 最小二乘法优化器
2.1 RegressionResults 常用参数
RegressionResults 中是拟合的结果
其中重要的几个参数如下:
parameters:
按照次数从低到高,由索引获取;
getParameterEstimate()
globalFitInfo
0: getErrorSumSquares 平方误差之和, SSE
1: getTotalSumSquares 平方和, SST
2: getRSquared R 平方, RSQ
3: getMeanSquareError 均方误差, MSE
4: getAdjustedRSquared调整后的 R 平方, adjRSQ
2.2拟合代码
public static String linearFit(double[][] data) {
SimpleRegression regression = new SimpleRegression();
//导入原始数据集
regression.addData(data);
//使用回归结果类接受数据
RegressionResults results = regression.regress();
//按照序号获取估计参数
DecimalFormat df = new DecimalFormat("#0.0000");
double b = results.getParameterEstimate(0);
double k = results.getParameterEstimate(1);
//保留精度
b = Double.parseDouble(df.format(b));
k = Double.parseDouble(df.format(k));
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 func.toString();
}
2.3 拟合结果
f(x) = 1.2742 + 1.4149x
三、n次/曲线拟合:
非线性函数:
3.1 方法一:
Step1. 创建多项式:
ParametricUnivariateFunction function = new PolynomialFunction.Parametric();
Step2. 初始化多项式:
SimpleCurveFitter curveFitter = SimpleCurveFitter.create(function,guess);
Step3. 输入Fit函数需要的List类型参数List**:**
double[] best = curveFitter.fit(observedPoints.toList());
public static String curveFit(double[][] data) {
//参数单变量函数 多项式函数
ParametricUnivariateFunction function = new PolynomialFunction.Parametric();
//按所需次数依次为 常数项、1次项、二次项......
double[] guess = {0,1,2,3};
// 初始化多项式
SimpleCurveFitter curveFitter = SimpleCurveFitter.create(function,guess);
// 添加数据点 可以设置个点权重,默认平均权重
WeightedObservedPoints observedPoints = new WeightedObservedPoints();
for (double[] point : data) {
observedPoints.add(point[0], point[1]);
}
//List<WeightedObservedPoint> weightedObservedPoints = observedPoints.toList();
//拟合结果:依次为 常数项、1次项、二次项.......
double[] best = curveFitter.fit(observedPoints.toList());
String fun = "f(x) = ";
for (int i = best.length - 1; i >= 0; i--) {
String add = best[i] > 0 ? "+" : "";
String x = i > 0 ? "x^" + i : "";
if (i == best.length - 1) {
fun += (best[i] + x);
} else {
fun += (add + best[i] + x);
}
}
return fun;
}
3.2 方法二:多项式回归拟合
https://alvinalexander.com/java/jwarehouse/commons-math3-3.6.1/src/main/java/org/apache/commons/math3/fitting/PolynomialCurveFitter.java.shtml
Step1. 数据放入加权点对象中:
WeightedObservedPoints points = new WeightedObservedPoints();
Step2. 初始化多项式设置阶数:
SimpleCurveFitter curveFitter = SimpleCurveFitter.create(function,guess);
Step3. 输入数据进行拟合:
double[] result = fitter.fit(points.toList());
public double[] calculatePolynomial(List<Map<String, Object>> list) {
//创建加权点对象
WeightedObservedPoints points = new WeightedObservedPoints();
for (int i = 0; i < list.size(); i++) {
//把数据点加入观察的序列 参数的格式注意一下***
points.add(Double.valueOf(list.get(i).get("x").toString()), Double.valueOf(list.get(i).get("y").toString()));
}
//指定多项式阶数 可以放到参数里
PolynomialCurveFitter fitter = PolynomialCurveFitter.create(3);
// 曲线拟合完成后,结果保存于数组
double[] result = fitter.fit(points.toList());
}
四、信号拟合:
→当数据震荡时,例如去拟合一个设备的采集站,总不可能时单调的,或者在一个大范围内不能是单调的,统计学中总是正太分布的,就决定了数据总是在一个范围内震动的;
→那么联想到了正弦、余弦函数;
→但是在数据拟合不方便对正弦、余弦函数进行拟合,那么对变量进行处理就可以实现了;
多重线性回归
Step1. 数据初始化:
Step2. 创建多重线性回归对象:
OLSMultipleLinearRegression ols = new OLSMultipleLinearRegression();
Step3. 输入数据进行拟合:
ols.newSampleData(YArray,XArray);
double[] ct = ols.estimateRegressionParameters();
//获取x 将单变量的数据转为多变量的数据;
List<double[]> data = new ArrayList<>();
for (double i = 1; i <= leng; i++) {
double x1 = Math.cos(i);
double x2 = Math.sin(i);
data.add(new double[]{x1, x2});
}
double[][] XArray= data.stream().toArray(double[][]::new);
//获取y
double[] YArray = new double[leng];
for (int i = 0; i < leng; i++) {
YArray[i] = stringList.get(i);
}
OLSMultipleLinearRegression ols = new OLSMultipleLinearRegression();
ols.newSampleData(YArray,XArray);
double[] ct = ols.estimateRegressionParameters();
f(x) = 0.0403-1.4025Math.cos(x)-1.3236Math.sin(x)
for (var t = 0; t < 25; t += 1) {
var x = Math.cos(t);
var y = Math.sin(t);
var z = 0.0403-1.4025*Math.cos(x)-1.3236*Math.sin(y);
data.push([x, y, z]);
}