Quellcode durchsuchen

加权平均偏差归一化

zhangchenglong vor 1 Jahr
Ursprung
Commit
1325a61d4e

+ 6 - 1
src/main/java/com/syjy/calculate/entity/CalculationFormula.java

@@ -65,10 +65,15 @@ public class CalculationFormula extends PageReq {
     private String ruleFormula;
 
     /**
-     * 是否为百分比
+     * 是否为百分比  0:不是 1:是
      */
     private String isRate;
 
+    /**
+     * 是否限定结果最小最大值为[0,1]   0:不限制 1:限制
+     */
+    private String maxMinLimit;
+
 
     /**
      * 状态

+ 122 - 0
src/main/java/com/syjy/calculate/function/ManyDayThreeDayDeviationElectricity.java

@@ -0,0 +1,122 @@
+package com.syjy.calculate.function;
+
+import cn.hutool.json.JSONObject;
+import com.googlecode.aviator.AviatorEvaluator;
+import com.googlecode.aviator.runtime.function.AbstractFunction;
+import com.googlecode.aviator.runtime.type.*;
+import com.syjy.calculate.entity.FormulaParam;
+import lombok.extern.slf4j.Slf4j;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 将list 中的数据是按日期分组,list的格式是List<List<Map<String, Object>>>,最外层list的每一条是一天的数据
+ *
+ * @author zcl
+ * @version 1.0
+ * @since 2023/7/6 9:30
+ */
+@Slf4j
+public class ManyDayThreeDayDeviationElectricity extends AbstractFunction {
+    /**
+     * @param env  参数集合
+     * @param arg1 list 待计算数据
+     * @param arg2 偏差带阈值 0.2/0.15
+     * @param arg3 计算单点还是一段时间
+     * @return
+     */
+    @Override
+    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {
+        // 获取参数
+        FormulaParam formulaParam = CommonUtil.getFormulaParam(env, arg1, arg2, arg3, null, null);
+        // 获取list
+        Object first = arg1.getValue(env);
+        // 将参数转为集合
+        Sequence seq = CommonUtil.getSeq(first, env);
+        // 获取传入的数据
+        List<List<Map<String, Object>>> list = new ArrayList<>();
+        for (Object obj : seq) {
+            List<Map<String, Object>> listData = (List<Map<String, Object>>) obj;
+            list.add(listData);
+        }
+
+        // 数据校验
+        if (list == null || list.size() == 0) {
+            log.warn("入参列表为空");
+            return new AviatorString("入参列表为空");
+        }
+
+        // 判断是否传入的是三天数据
+        if (list.size() != 3) {
+            log.warn("入参数据不是三天的数据");
+            return new AviatorString("入参数据不是三天的数据,东北新短期准确率需前三日的预测数据");
+        }
+        int sum = 0;
+        // 循环求一共有多少条数据
+        for (List<Map<String, Object>> listMap : list) {
+            sum = sum + listMap.size();
+        }
+        // 如果数据总数!= 第一天数据*一共几天,则证明各天数据个数不一致
+        if (!(list.get(0).size() == list.get(1).size() && list.get(1).size() == list.get(2).size())) {
+            log.warn("各天数据个数不一致,需要每天96条完整数据");
+            return new AviatorString("各天数据个数不一致,需要每天96条完整数据");
+        }
+
+        BigDecimal agoOneRateResult;
+        BigDecimal agoTwoRateResult;
+        BigDecimal agoThreeRateResult;
+        BigDecimal deviationElectricityAvg;
+        // 偏差电量总和
+        BigDecimal sumDeviationElectricity = BigDecimal.ZERO;
+        BigDecimal deviationThreshold = new BigDecimal(formulaParam.getSecond());
+        String exp = formulaParam.getThird();
+        BigDecimal pointDeviationAvg = BigDecimal.ZERO;
+        // 循环列表中3天的数据
+        for (int i = 0; i < list.get(0).size(); i++) {
+            Map<String, Object> agoOneMap = list.get(0).get(i);
+            agoOneMap.put("deviationThreshold", deviationThreshold);
+            Map<String, Object> agoTwoMap = list.get(1).get(i);
+            agoTwoMap.put("deviationThreshold", deviationThreshold);
+            Map<String, Object> agoThreeMap = list.get(2).get(i);
+            agoThreeMap.put("deviationThreshold", deviationThreshold);
+
+            agoOneRateResult = getPointDeviation(exp, agoOneMap);
+            agoTwoRateResult = getPointDeviation(exp, agoTwoMap);
+            agoThreeRateResult = getPointDeviation(exp, agoThreeMap);
+
+            deviationElectricityAvg = (agoOneRateResult.add(agoTwoRateResult).add(agoThreeRateResult)).divide(new BigDecimal(3), 4, BigDecimal.ROUND_HALF_UP);
+            // 偏差电量求和
+            sumDeviationElectricity = sumDeviationElectricity.add(deviationElectricityAvg);
+            // 获取最后一条的点偏差均值
+            if (i == list.get(0).size() - 1) {
+                pointDeviationAvg = deviationElectricityAvg;
+            }
+        }
+        JSONObject resultJson = new JSONObject();
+        resultJson.set("pointDeviation", (BigDecimal.ONE.subtract(pointDeviationAvg).multiply(new BigDecimal(100))) + "%");
+        resultJson.set("sumDeviationElectricity", sumDeviationElectricity);
+        return new AviatorString(resultJson.toString());
+    }
+
+
+    /**
+     * 获取单点偏差电量
+     *
+     * @param exp
+     * @param dataInfo
+     * @return
+     */
+    public BigDecimal getPointDeviation(String exp, Map<String, Object> dataInfo) {
+        BigDecimal result;
+        result = new BigDecimal(String.valueOf(AviatorEvaluator.execute(exp, dataInfo)));
+        return result;
+    }
+
+    @Override
+    public String getName() {
+        return "manyDayThreeDayDeviationElectricity";
+    }
+
+}

+ 0 - 2
src/main/java/com/syjy/calculate/function/RootMeanSquaredErrorA.java

@@ -4,10 +4,8 @@ import com.googlecode.aviator.AviatorEvaluator;
 import com.googlecode.aviator.runtime.RuntimeUtils;
 import com.googlecode.aviator.runtime.function.AbstractFunction;
 import com.googlecode.aviator.runtime.type.AviatorDecimal;
-import com.googlecode.aviator.runtime.type.AviatorJavaType;
 import com.googlecode.aviator.runtime.type.AviatorObject;
 import com.googlecode.aviator.runtime.type.Sequence;
-import com.syjy.calculate.entity.CalculateResult;
 import com.syjy.calculate.entity.FormulaParam;
 
 import java.math.BigDecimal;

+ 1 - 1
src/main/java/com/syjy/calculate/listener/ApplicationListenerImpl.java

@@ -44,7 +44,7 @@ public class ApplicationListenerImpl implements ApplicationListener<ApplicationS
         AviatorEvaluator.addFunction(new SumDifferenceAbsolute());
         AviatorEvaluator.addFunction(new SumDifferenceSquare());
         AviatorEvaluator.addFunction(new DevianceElectric());
-
+        AviatorEvaluator.addFunction(new ManyDayThreeDayDeviationElectricity());
 
         // |预测-可用|/预测
         AviatorEvaluator.defineFunction("errorBandwidth", "lambda (a,b) -> math.abs((a - b)/a) end");

+ 45 - 20
src/main/java/com/syjy/calculate/service/AccuracyPassRateCalculateService.java

@@ -9,9 +9,10 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cglib.beans.BeanMap;
 import org.springframework.stereotype.Service;
-
 import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 计算准确率、合格率
@@ -68,7 +69,11 @@ public class AccuracyPassRateCalculateService {
             if (groupingList == null || groupingList.size() == 0) {
                 return CalculateResult.error(CalculateResult.MSG_CALCULATE_DATA_NULL);
             }
-        } else {
+            // 如果是多日数据,将数据按照日期分组
+        } else if(calculationFormula.getFormula().contains("manyDay")){
+            List<List<Map<String, Object>>> manyDaysList = groupingDaysList(checkedData,"genTime");
+            env.put(CalculateResult.LIST, manyDaysList);
+        }else {
             env.put(CalculateResult.LIST, checkedData);
         }
 
@@ -86,19 +91,12 @@ public class AccuracyPassRateCalculateService {
         }
         env.put(CalculateResult.MAX_OPEN_CAPACITY, maxOpenCapacity);
 
-//        Map<String, Object> calculateRequestMap = new HashMap<>();
-//        // bean 转map
-//        BeanMap beanMap = BeanMap.create(calculateRequest);
-//        for (Object key : beanMap.keySet()) {
-//            calculateRequestMap.put(String.valueOf(key), beanMap.get(key));
-//        }
-
         // 执行计算并得出结果
         try {
             // 获取计算结果
             Object executeResult = AviatorEvaluator.getInstance().getCachedExpressionByKey(scriptName).execute(env);
             // 过滤计算结果
-            String result = filterResult(executeResult, calculationFormula.getIsRate());
+            String result = filterResult(executeResult, calculationFormula.getIsRate(),calculationFormula.getMaxMinLimit());
             return CalculateResult.success(CalculateResult.MSG_CALCULATE_SUCCESS, result);
         } catch (Exception e) {
             e.printStackTrace();
@@ -112,7 +110,7 @@ public class AccuracyPassRateCalculateService {
      * @param result 过滤前的结果
      * @return 过滤后的结果
      */
-    private String filterResult(Object result, String type) {
+    private String filterResult(Object result, String type ,String maxMinLimit) {
         // 如果是map类型,转为jsonString
         if (result instanceof HashMap) {
             String jsonStr = JSONObject.toJSONString(result);
@@ -123,15 +121,18 @@ public class AccuracyPassRateCalculateService {
             return String.valueOf(result);
         }
         BigDecimal resultBig = new BigDecimal(String.valueOf(result));
-        //当结果为负数时,说明偏差过大,准确率为0
-        if (resultBig.compareTo(BigDecimal.ZERO) == -1 || resultBig.compareTo(BigDecimal.ZERO) == 0) {
-            log.warn("结果为负数:" + resultBig + "自动转换为0%");
-            resultBig = BigDecimal.ZERO;
-        }
-        // 如果结果大于1,则准确率设为100
-        if (resultBig.compareTo(BigDecimal.ONE) == 1) {
-            log.warn("结果大于100%:" + resultBig + "自动转换为100%");
-            resultBig = BigDecimal.ONE;
+        // 判断计算结果是否限定上下限
+        if(maxMinLimit != null && maxMinLimit.equals(CalculateResult.STR_TRUE)){
+            //当结果为负数时,说明偏差过大,准确率为0
+            if (resultBig.compareTo(BigDecimal.ZERO) == -1 || resultBig.compareTo(BigDecimal.ZERO) == 0) {
+                log.warn("结果为负数:" + resultBig + "自动转换为0%");
+                resultBig = BigDecimal.ZERO;
+            }
+            // 如果结果大于1,则准确率设为100
+            if (resultBig.compareTo(BigDecimal.ONE) == 1) {
+                log.warn("结果大于100%:" + resultBig + "自动转换为100%");
+                resultBig = BigDecimal.ONE;
+            }
         }
 
         // 如果公式结果为带百分号
@@ -274,6 +275,9 @@ public class AccuracyPassRateCalculateService {
      */
     private List<Map<String, Object>> getCalculationInfoList(List<CalculationInfo> calculationInfoList, BigDecimal electricCapacity) {
         List<Map<String, Object>> resultList = new ArrayList<>();
+        long time;
+        Date timeDate;
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         // 循环每条数据
         for (CalculationInfo calculationInfo : calculationInfoList) {
             // 将bean BeanMap
@@ -282,6 +286,11 @@ public class AccuracyPassRateCalculateService {
             // 将beanMap转为Map
             for (Object key : beanMap.keySet()) {
                 map.put(String.valueOf(key), beanMap.get(key));
+                if("time".equals(key.toString())){
+                    time = (long)beanMap.get(key);
+                    timeDate = new Date(time);
+                    map.put("timeStr", sdf.format(timeDate));
+                }
             }
             map.put("electricCapacity", electricCapacity);
             resultList.add(map);
@@ -341,6 +350,22 @@ public class AccuracyPassRateCalculateService {
 
         return groupingList;
     }
+    /**
+     * 将多日数据分成多组,并放入list中
+     *
+     * @param list
+     * @return
+     */
+    private List<List<Map<String, Object>>> groupingDaysList(List<Map<String, Object>> list,String groupBy) {
+        List<List<Map<String, Object>>> groupingList = new ArrayList<>();
 
+        Map<String, List<Map<String, Object>>> groupedMap = list.stream()
+                .collect(Collectors.groupingBy(map -> map.get(groupBy).toString().substring(0,10)));
+
+        for (Map.Entry<String, List<Map<String, Object>>> entry : groupedMap.entrySet()) {
+            groupingList.add(entry.getValue());
+        }
+        return groupingList;
+    }
 }