添加功能
This commit is contained in:
@@ -0,0 +1,293 @@
|
||||
package com.ruoyi.cms.util;
|
||||
|
||||
import com.ruoyi.cms.domain.dto.ModelWarningIndicatorDataResultDto;
|
||||
import com.ruoyi.cms.domain.vo.ModelResultDataVo;
|
||||
import com.ruoyi.cms.domain.vo.ModelResultIndicatorDataVo;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 模型指标工具类
|
||||
*
|
||||
* @author 马宝龙
|
||||
* @date 2026/7/2
|
||||
*/
|
||||
public class ModelIndicatorUtil {
|
||||
private ModelIndicatorUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 整理指标数据
|
||||
*
|
||||
* @param list 指标数据
|
||||
* @return 指标数据
|
||||
*/
|
||||
public static Tuple2<List<String>, List<ModelResultIndicatorDataVo>> organizeIndicator(
|
||||
List<ModelWarningIndicatorDataResultDto> list) {
|
||||
Set<String> timeSet = new HashSet<>();
|
||||
Map<String, List<ModelWarningIndicatorDataResultDto>> indicatorNameMap = new HashMap<>();
|
||||
for (ModelWarningIndicatorDataResultDto indicatorData : list) {
|
||||
timeSet.add(indicatorData.getYear() + "_" + String.format("%02d", indicatorData.getMonth()));
|
||||
List<ModelWarningIndicatorDataResultDto> indicatorDataList =
|
||||
indicatorNameMap.computeIfAbsent(indicatorData.getIndicatorName(), k -> new ArrayList<>());
|
||||
indicatorDataList.add(indicatorData);
|
||||
indicatorNameMap.put(indicatorData.getIndicatorName(), indicatorDataList);
|
||||
}
|
||||
List<String> timeTempList = new ArrayList<>(timeSet);
|
||||
Collections.sort(timeTempList);
|
||||
List<String> timeList = new ArrayList<>();
|
||||
for (String time : timeTempList) {
|
||||
String[] split = time.split("_");
|
||||
timeList.add(split[0] + "年" + Integer.parseInt(split[1]) + "月");
|
||||
}
|
||||
List<ModelResultIndicatorDataVo> indicatorList = new ArrayList<>();
|
||||
for (Map.Entry<String, List<ModelWarningIndicatorDataResultDto>> entry : indicatorNameMap.entrySet()) {
|
||||
|
||||
List<ModelWarningIndicatorDataResultDto> value = entry.getValue();
|
||||
ModelWarningIndicatorDataResultDto dataResultDto = value.get(0);
|
||||
BigDecimal maxValue = dataResultDto.getDataValue();
|
||||
BigDecimal minValue = dataResultDto.getDataValue();
|
||||
ModelResultIndicatorDataVo indicatorVo = ModelResultIndicatorDataVo.builder()
|
||||
.indicatorName(entry.getKey())
|
||||
.indicatorCode(dataResultDto.getIndicatorCode())
|
||||
.indicatorType(dataResultDto.getIndicatorType())
|
||||
.indicatorWeight(dataResultDto.getIndicatorWeight())
|
||||
.leadPeriod(dataResultDto.getLeadPeriod())
|
||||
.build();
|
||||
Map<String, ModelWarningIndicatorDataResultDto> valueMap = new HashMap<>();
|
||||
for (ModelWarningIndicatorDataResultDto indicatorData : value) {
|
||||
valueMap.put(indicatorData.getYear() + "_" + String.format("%02d", indicatorData.getMonth()),
|
||||
indicatorData);
|
||||
}
|
||||
List<ModelResultDataVo> dataList = new ArrayList<>();
|
||||
for (String time : timeTempList) {
|
||||
ModelWarningIndicatorDataResultDto indicatorData = valueMap.get(time);
|
||||
BigDecimal dataValue = null;
|
||||
if (Objects.nonNull(indicatorData)) {
|
||||
dataValue = indicatorData.getDataValue();
|
||||
maxValue = max(maxValue, indicatorData.getDataValue());
|
||||
minValue = min(minValue, indicatorData.getDataValue());
|
||||
}
|
||||
String[] split = time.split("_");
|
||||
dataList.add(ModelResultDataVo.builder()
|
||||
.time(split[0] + "年" + Integer.parseInt(split[1]) + "月")
|
||||
.value(dataValue)
|
||||
.build());
|
||||
}
|
||||
indicatorVo.setMaxValue(maxValue);
|
||||
indicatorVo.setMinValue(minValue);
|
||||
indicatorVo.setDataList(dataList);
|
||||
indicatorList.add(indicatorVo);
|
||||
}
|
||||
return Tuples.of(timeList, indicatorList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 就失业监测综合指数
|
||||
*
|
||||
* @param resultList 指标结果数据
|
||||
* @return 计算结果
|
||||
*/
|
||||
public static List<BigDecimal> calculateComposite(Tuple2<List<String>, List<ModelResultIndicatorDataVo>> resultList) {
|
||||
|
||||
List<ModelResultIndicatorDataVo> indicatorDataList = resultList.getT2();
|
||||
|
||||
// 预警指标值标准化
|
||||
for (ModelResultIndicatorDataVo indicatorData : indicatorDataList) {
|
||||
|
||||
BigDecimal maxValue = indicatorData.getMaxValue();
|
||||
BigDecimal minValue = indicatorData.getMinValue();
|
||||
BigDecimal denominator = null;
|
||||
if (Objects.nonNull(maxValue) && Objects.nonNull(minValue)) {
|
||||
denominator = maxValue.subtract(minValue);
|
||||
}
|
||||
List<ModelResultDataVo> dataList = indicatorData.getDataList();
|
||||
for (ModelResultDataVo dataVo : dataList) {
|
||||
if (Objects.nonNull(denominator) && denominator.compareTo(BigDecimal.ZERO) != 0) {
|
||||
// 正向指标 = (x-min)/(max-min)
|
||||
BigDecimal value;
|
||||
if (1 == indicatorData.getIndicatorType()) {
|
||||
value = (dataVo.getValue().subtract(minValue))
|
||||
.divide(denominator, 10, RoundingMode.HALF_UP);
|
||||
} else {
|
||||
// 负向指标 = (max-x)/(max-min)
|
||||
value = (maxValue.subtract(dataVo.getValue()))
|
||||
.divide(denominator, 10, RoundingMode.HALF_UP);
|
||||
}
|
||||
dataVo.setValue(value);
|
||||
} else {
|
||||
dataVo.setValue(BigDecimal.ZERO);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 预警指标加权平均值
|
||||
for (ModelResultIndicatorDataVo indicatorData : indicatorDataList) {
|
||||
BigDecimal indicatorWeight = indicatorData.getIndicatorWeight();
|
||||
if (Objects.isNull(indicatorWeight)) {
|
||||
indicatorWeight = BigDecimal.ZERO;
|
||||
}
|
||||
List<ModelResultDataVo> dataList = indicatorData.getDataList();
|
||||
for (ModelResultDataVo dataVo : dataList) {
|
||||
dataVo.setValue(dataVo.getValue().multiply(indicatorWeight));
|
||||
}
|
||||
}
|
||||
|
||||
// 每个月数据求和
|
||||
List<List<ModelResultDataVo>> dataList = new ArrayList<>();
|
||||
for (ModelResultIndicatorDataVo indicatorData : indicatorDataList) {
|
||||
dataList.add(indicatorData.getDataList());
|
||||
}
|
||||
List<String> timeList = resultList.getT1();
|
||||
BigDecimal[] sums = new BigDecimal[timeList.size()];
|
||||
for (List<ModelResultDataVo> innerList : dataList) {
|
||||
if (CollectionUtils.isEmpty(innerList)) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < innerList.size(); i++) {
|
||||
ModelResultDataVo vo = innerList.get(i);
|
||||
if (Objects.nonNull(vo) && Objects.nonNull(vo.getValue())) {
|
||||
sums[i] = sums[i].add(vo.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(Arrays.asList(sums));
|
||||
}
|
||||
|
||||
/**
|
||||
* 失业预警扩散指数
|
||||
*
|
||||
* @param resultList 指标结果数据
|
||||
* @param unemploymentRateData 失业率数据
|
||||
* @return 计算结果
|
||||
*/
|
||||
public static List<BigDecimal> calculateDiffusion(Tuple2<List<String>, List<ModelResultIndicatorDataVo>> resultList,
|
||||
ModelResultIndicatorDataVo unemploymentRateData) {
|
||||
|
||||
List<ModelResultIndicatorDataVo> indicatorDataList = resultList.getT2();
|
||||
if (Objects.nonNull(unemploymentRateData)) {
|
||||
indicatorDataList.add(unemploymentRateData);
|
||||
}
|
||||
|
||||
int maxLeadPeriod = 0;
|
||||
// 计算各个警兆指标的景气值
|
||||
for (ModelResultIndicatorDataVo indicatorData : indicatorDataList) {
|
||||
|
||||
Integer leadPeriod = indicatorData.getLeadPeriod();
|
||||
if (Objects.isNull(leadPeriod) || leadPeriod < 1) {
|
||||
leadPeriod = 1;
|
||||
}
|
||||
maxLeadPeriod = Math.max(maxLeadPeriod, leadPeriod);
|
||||
|
||||
List<ModelResultDataVo> dataList = indicatorData.getDataList();
|
||||
for (int i = dataList.size() - 1; i >= 0; i--) {
|
||||
ModelResultDataVo dataVo = dataList.get(i);
|
||||
if (i < leadPeriod) {
|
||||
dataVo.setValue(null);
|
||||
continue;
|
||||
}
|
||||
BigDecimal value;
|
||||
BigDecimal currentValue = dataVo.getValue();
|
||||
BigDecimal previousValue = dataList.get(i - 1).getValue();
|
||||
if (1 == indicatorData.getIndicatorType()) {
|
||||
// 正向指标
|
||||
value = currentValue.compareTo(previousValue) > 0 ? BigDecimal.ONE :
|
||||
(currentValue.compareTo(previousValue) == 0 ? new BigDecimal("0.5") : BigDecimal.ZERO);
|
||||
} else {
|
||||
// 负向指标
|
||||
value = currentValue.compareTo(previousValue) > 0 ? BigDecimal.ZERO :
|
||||
(currentValue.compareTo(previousValue) == 0 ? new BigDecimal("0.5") : BigDecimal.ONE);
|
||||
}
|
||||
dataVo.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
// 景气值加权值
|
||||
BigDecimal weight = BigDecimal.ONE.divide(new BigDecimal(indicatorDataList.size()), 10,
|
||||
RoundingMode.HALF_UP);
|
||||
for (ModelResultIndicatorDataVo indicatorData : indicatorDataList) {
|
||||
List<ModelResultDataVo> dataList = indicatorData.getDataList();
|
||||
for (int i = dataList.size() - 1; i >= 0; i--) {
|
||||
ModelResultDataVo dataVo = dataList.get(i);
|
||||
if (i < maxLeadPeriod) {
|
||||
dataVo.setValue(null);
|
||||
continue;
|
||||
}
|
||||
BigDecimal value = dataVo.getValue().multiply(weight).setScale(10, RoundingMode.HALF_UP);
|
||||
dataVo.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
// 每个月数据求和
|
||||
List<List<ModelResultDataVo>> dataList = new ArrayList<>();
|
||||
for (ModelResultIndicatorDataVo indicatorData : indicatorDataList) {
|
||||
dataList.add(indicatorData.getDataList());
|
||||
}
|
||||
List<String> timeList = resultList.getT1();
|
||||
BigDecimal[] sums = new BigDecimal[timeList.size() - maxLeadPeriod];
|
||||
for (List<ModelResultDataVo> innerList : dataList) {
|
||||
if (CollectionUtils.isEmpty(innerList)) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < innerList.size(); i++) {
|
||||
if (i < maxLeadPeriod) {
|
||||
continue;
|
||||
}
|
||||
ModelResultDataVo vo = innerList.get(i);
|
||||
if (Objects.nonNull(vo) && Objects.nonNull(vo.getValue())) {
|
||||
sums[i - maxLeadPeriod] = sums[i - maxLeadPeriod].add(vo.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(Arrays.asList(sums));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 求最大值
|
||||
*
|
||||
* @param a a
|
||||
* @param b b
|
||||
* @return 最大值
|
||||
*/
|
||||
public static BigDecimal max(BigDecimal a, BigDecimal b) {
|
||||
if (Objects.isNull(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Objects.isNull(b)) {
|
||||
return a;
|
||||
}
|
||||
return a.max(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* 求最小值
|
||||
*
|
||||
* @param a a
|
||||
* @param b b
|
||||
* @return 最小值
|
||||
*/
|
||||
public static BigDecimal min(BigDecimal a, BigDecimal b) {
|
||||
if (Objects.isNull(a)) {
|
||||
return b;
|
||||
}
|
||||
if (Objects.isNull(b)) {
|
||||
return a;
|
||||
}
|
||||
return a.min(b);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user