添加功能

This commit is contained in:
马宝龙
2026-07-02 23:55:30 +08:00
parent 648ccc9c77
commit b68322620b
20 changed files with 961 additions and 14 deletions

View File

@@ -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);
}
}