1.java进行实现需要导入
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
2.模拟数据进行曲线生成,进行四次曲线拟合,然后进行二分递归获取最优数据
public Map fitting(@RequestParam(value = "sum") Integer sum) {
List<Map<String,Double>> params = new ArrayList<>();
for (int i = 0; i <= sum; i++) {
Map<String,Double> xy = new HashMap<>();
xy.put("x",Double.valueOf(i) * 10);
xy.put("y",Math.random() * 100);
params.add(xy);
}
List<Map> stringObjectMap = modifyMonitorDataService.fittingRecursion(params);
Map<String,Object> resultList = new HashMap<>();
resultList.put("stringObjectMap",stringObjectMap);
resultList.put("params",params);
return resultList;
}
/**
* 获取最优拟合结果
*
* @param params
* @return
*/
public List<Map> fittingRecursion(List<Map<String, Double>> params) {
double[] fittingValue = getFittingValue(params);
double fittingDifference = getFittingDifference(params, fittingValue);
int numberOfCycles = 0;
List<Map> resultList = new ArrayList<>();
dichotomousRecursion(params, fittingDifference, fittingValue, numberOfCycles, resultList);
List<Map> doubles = new ArrayList<>();
if (resultList.size() > 0) {
log.info("\r\n拟合结果集:{}", JSONUtil.toJsonStr(resultList));
Map<String, Object> map = resultList.get(0);
int half = Integer.parseInt(map.get("half").toString());
double floor = Math.floor(params.size() / half);
int start = 0;
int end = half;
for (int i = 0; i < floor; i++) {
List<Map<String, Double>> maps = params.subList(start, end);
double[] fittingDouble = getFittingValue(maps);
Map<String,Object> obj = new HashMap<>();
obj.put("fittingDouble",fittingDouble);
obj.put("sum",half);
doubles.add(obj);
start = end;
end = start + half;
}
return doubles;
}
Map<String,Object> obj = new HashMap<>();
obj.put("fittingDouble",fittingValue);
obj.put("sum",params.size());
doubles.add(obj);
return doubles;
}
/**
* 获取参数拟合
*
* @param params
* @return
*/
private double[] getFittingValue(List<Map<String, Double>> params) {
WeightedObservedPoints points = new WeightedObservedPoints();
for (int i = 0; i < params.size(); i++) {
points.add(params.get(i).get("x"), params.get(i).get("y"));
}
PolynomialCurveFitter fitter = PolynomialCurveFitter.create(3);
return fitter.fit(points.toList());
}
/**
* 获取拟合误差值
*
* @param params
* @param result
* @return
*/
private double getFittingDifference(List<Map<String, Double>> params, double[] result) {
double difference = 0.0;
for (int i = 0; i < params.size(); i++) {
double yv = (result[3] * Math.pow(params.get(i).get("x"), 3)) + ((result[2] * Math.pow(params.get(i).get("x"), 2))) + (result[1] * params.get(i).get("x")) + result[0];
difference += Math.abs(yv - params.get(i).get("y"));
}
return difference;
}
/**
* 递归二分拟合
*
* @param params
* @param fittingDifference
* @param fittingValue
* @param numberOfCycles
* @param resultList
*/
private void dichotomousRecursion(List<Map<String, Double>> params, double fittingDifference, double[] fittingValue, int numberOfCycles, List<Map> resultList) {
Map<String, Object> resultParams = new HashMap<>();
if (params.size() >= 20) {
numberOfCycles += 1;
int half = (int) Math.floor(params.size() / 2);
List<Map<String, Double>> anterior = params.subList(0, half);
List<Map<String, Double>> rearSection = params.subList(half, params.size());
double[] resultHalf = getFittingValue(anterior);
double differenceHalf = getFittingDifference(anterior, resultHalf);
double[] resultSection = getFittingValue(rearSection);
double differenceSection = getFittingDifference(rearSection, resultSection);
if (differenceHalf < fittingDifference || differenceSection < fittingDifference) {
if (differenceHalf <= differenceSection) {
dichotomousRecursion(anterior, differenceHalf, resultHalf, numberOfCycles, resultList);
}
if (differenceSection <= differenceHalf) {
dichotomousRecursion(rearSection, differenceSection, resultSection, numberOfCycles, resultList);
}
}
resultParams.put("numberOfCycles", numberOfCycles);
resultParams.put("fittingValue", fittingValue);
resultParams.put("fittingDifference", fittingDifference);
resultParams.put("half", half);
resultList.add(resultParams);
}
}