模糊算法是房地产专家评估系统中的另一个核心评估算法,基于模糊数学理论对建筑工程安全风险进行模糊评估。与打分算法不同,模糊算法通过隶属度矩阵和比较矩阵,结合外部模糊计算API,实现更加智能和灵活的风险评估。
flowchart TD
A[开始模糊评估] --> B[初始化问题映射表]
B --> C[构建模糊评估树]
C --> D[统计错误记录]
D --> E[标记参与评估节点]
E --> F[裁剪无用节点]
F --> G[更新隶属度和比较矩阵]
G --> H[调用模糊计算API]
H --> I[美化显示数据]
I --> J[返回评估结果]
subgraph "初始化阶段"
B1[获取专家配置]
B2[构建FuzzyValue树结构]
B3[初始化错误统计]
end
subgraph "统计阶段"
D1[遍历错误记录]
D2[累加错误数量]
D3[处理轮空项]
D4[向上累加错误统计]
D5[计算总错误数量]
end
subgraph "矩阵更新阶段"
G1[叶子节点:获取隶属度矩阵]
G2[父节点:获取比较矩阵]
G3[设置矩阵数据]
end
subgraph "API计算阶段"
H1[构建API请求]
H2[调用外部模糊API]
H3[解析API响应]
H4[更新节点数据]
end
B --> B1
B1 --> B2
B2 --> B3
D --> D1
D1 --> D2
D2 --> D3
D3 --> D4
D4 --> D5
G --> G1
G1 --> G2
G2 --> G3
H --> H1
H1 --> H2
H2 --> H3
H3 --> H4
var problemMap = initProblemMap(expert, expertService);
var result = initSysResult(expert, expertService);
构建逻辑:java private FuzzyResult initSysResult(Expert expert, ExpertService expertService) { var tree = expertService.getHierarchyTree(expert.getId()); var root = TreeHelper.<HierarchyData, FuzzyValue>convertTree(tree.root(), (node, newNode) -> FuzzyValue.builder() .build() ); return new FuzzyResult(root); }
count(problemMap, result, records, byPassPaths);
统计逻辑:
```java
private void count(TreeMap<Integer, Boolean> problemMap, FuzzyResult result, List records, List byPassPaths) {
// 遍历错误记录,将隐患数量累加到对应的节点上
if(records != null) {
records.forEach(errorRecord -> {
var problem = errorRecord.getProblem();
var ps = problemMap.get(problem.getId());
// 如果问题不在模型中,不计算
// 如果问题已经计算过,也不计算(同一问题的记录只计算一次)
if (ps == null || ps)
return;
problemMap.put(problem.getId(), true);
// 计算隐患数量
var node = result.get(problem.getHierarchyPath());
node.getData().addError(errorRecord.getLevel());
node.getData().setInclude(true);
});
}
}
```
步骤详解:
1. 遍历错误记录:对每个错误记录进行处理
2. 问题验证:检查问题是否在模型中且未被计算过
3. 错误累加:根据错误等级累加到对应节点
4. 节点标记:标记节点参与评估
// 轮空项,如果设置了,则需要参与计算
if(byPassPaths != null){
byPassPaths.forEach(path -> {
var node = result.get(path);
if(node == null) return;
var scoreValue = node.getData();
scoreValue.setInclude(true);
node.setData(scoreValue);
});
}
// 累加到上一级
TreeHelper.travel(result.root(), (node) -> {
var nodeData = node.getData();
for(var child : node.getChildren().values()) {
var childData = child.getData();
for(var i = 0; i < 4; i++) {
nodeData.getChildErrorCounts()[i] += childData.getErrorCounts()[i] + childData.getChildErrorCounts()[i];
}
}
});
// 更新totalErrorCounts
TreeHelper.travel(result.root(), (node) -> {
var nodeData = node.getData();
var t = new int[4];
for(var i = 0; i < 4; i++) {
t[i] = nodeData.getErrorCounts()[i] + nodeData.getChildErrorCounts()[i];
}
nodeData.setTotalErrorCounts(t);
});
mark(result);
标记逻辑:
```java
private void mark(FuzzyResult result) {
TreeHelper.travel(result.root(), (node) -> {
// 只去更新非叶子节点的include属性
if(node.getChildren().isEmpty())
return;
// 如果有子节点参与评分,当前节点也参与评分
boolean include = false;
for (var child : node.getChildren().values()) {
if(child.getData().isInclude())
include = true;
}
node.getData().setInclude(include);
});
}
```
result = prune(result);
裁剪逻辑:java private FuzzyResult prune(FuzzyResult result) { var root = TreeHelper.pruneTree(result.root(), (node) -> { return node.getData().isInclude() && node.getDepth() <= 3; }); return new FuzzyResult(root); }
update(result, expert, expertService);
更新逻辑:java private void update(FuzzyResult fuzzyResult, Expert expert, ExpertService expertService){ TreeHelper.travel(fuzzyResult.root(), (node) -> { var path = node.getPath(); var fuzzyValue = node.getData(); if(node.getChildren().isEmpty()) { // 从专家中获取隶属度矩阵 // 叶子节点,可以直接从专家中获取 // 非叶子节点,需要由下级节点计算得到 fuzzyValue.setMembershipList(expert.getMembershipMatrix().getData(fuzzyValue.getTotalErrorCounts())); fuzzyValue.setCompareMatrix(new CompareMatrix(new String[]{"空"})); }else{ // 从专家中获取判断矩阵 var indexCols = node.getChildren().values().stream().map(TreeNode::getName).toArray(String[]::new); var compareMatrix = expertService.getFuzzyMatrix(expert.getId(), path, indexCols); fuzzyValue.setCompareMatrix(compareMatrix); } }); }
矩阵类型:
1. 叶子节点:
- 获取隶属度矩阵:根据总错误数量查询
- 设置空比较矩阵:1x1矩阵
TreeHelper.travel(result.root(), this::computeNode);
计算逻辑:
```java
private void computeNode(TreeNode node) {
var fuzzyValue = node.getData();
var compareMatrix = fuzzyValue.getCompareMatrix();
float[][] membershipData;
if(node.getChildren().isEmpty()) {
membershipData = new float[][]{fuzzyValue.getMembershipList()};
}else {
membershipData = node.getChildren().values().stream()
.map(child -> child.getData().getResp().getLargeList())
.toArray(float[][]::new);
}
// 调用fuzzyAPI,计算检查得分
var request = FuzzyApiRequest.builder()
.n(compareMatrix.getN())
.membership_data(membershipData)
.index(compareMatrix.getIndexCols())
.compare_matrix_data(compareMatrix.getValues())
.num_experts(1)
.build();
var response = fuzzyApi.call(request);
fuzzyValue.setResp(response);
}
```
API请求构建:
1. 叶子节点:使用自身的隶属度矩阵
2. 父节点:使用子节点的计算结果(LargeList)
3. 请求参数:
- n:矩阵维度
- membership_data:隶属度数据
- index:索引列
- compare_matrix_data:比较矩阵数据
- num_experts:专家数量
prettyDisplay(result);
美化逻辑:
```java
private void prettyDisplay(FuzzyResult result) {
TreeHelper.travel(result.root(), (node) -> {
var fuzzyValue = node.getData();
fuzzyValue.setMembershipList(fuzzyValue.getResp().getLargeList());
fuzzyValue.setRiskLevel(FuzzyRiskLevel.values()[5 - fuzzyValue.getResp().getRiskInterval()]);
fuzzyValue.setScore(fuzzyValue.getResp().getRiskPoint());
// 更新权重显示
int i = 0;
var children = node.getChildren().values().stream().toList();
for(var child : children) {
child.getData().setWeight(fuzzyValue.getResp().getWeight()[i]);
i++;
}
});
}
```
美化内容:
1. 隶属度列表:从API响应中获取
2. 风险等级:根据风险区间计算
3. 风险得分:从API响应中获取
4. 权重更新:更新子节点的权重显示
| 特性 | 打分算法 | 模糊算法 |
|---|---|---|
| 计算方式 | 直接扣分计算 | 模糊数学计算 |
| 外部依赖 | 无 | 依赖外部API |
| 矩阵类型 | 权重矩阵 | 隶属度矩阵+比较矩阵 |
| 结果类型 | 具体分数 | 风险等级+风险得分 |
| 计算复杂度 | 较低 | 较高 |
| 适用场景 | 确定性评估 | 不确定性评估 |
模糊算法通过模糊数学理论和外部API调用,实现了更加智能和灵活的风险评估。相比打分算法,模糊算法能够更好地处理不确定性和模糊性,提供风险等级和风险得分的综合评估结果。该算法适用于需要处理复杂、不确定评估场景的建筑工程安全风险评估。