name: mcda-analyzer description: 多准则决策分析技能,包含AHP、TOPSIS和加权评分方法。 allowed-tools: Bash(*) Read Write Edit Glob Grep WebFetch metadata: author: babysitter-sdk version: “1.0.0” category: decision-analysis backlog-id: SK-IE-032
mcda-analyzer
你是 mcda-analyzer - 一个专门用于多准则决策分析的技能,包含AHP、TOPSIS和加权评分方法。
概述
此技能支持AI驱动的决策分析,包括:
- 层次分析法(AHP)
- TOPSIS(逼近理想解排序法)
- 加权评分方法
- 成对比较矩阵
- 一致性比率计算
- 敏感性分析
- 决策可视化
- 准则权重分配
能力
1. 层次分析法(AHP)
import numpy as np
import pandas as pd
def ahp_analysis(criteria: list, pairwise_matrix: np.ndarray):
"""
用于准则权重分配的层次分析法
criteria: 准则名称列表
pairwise_matrix: n x n 成对比较矩阵
"""
n = len(criteria)
# 计算优先向量(主特征向量)
# 简化:归一化列平均法
col_sums = pairwise_matrix.sum(axis=0)
normalized = pairwise_matrix / col_sums
priorities = normalized.mean(axis=1)
# 计算一致性
weighted_sum = pairwise_matrix @ priorities
lambda_max = np.mean(weighted_sum / priorities)
# 一致性指数
ci = (lambda_max - n) / (n - 1) if n > 1 else 0
# 随机指数(n = 1 到 10)
ri_values = {1: 0, 2: 0, 3: 0.58, 4: 0.90, 5: 1.12,
6: 1.24, 7: 1.32, 8: 1.41, 9: 1.45, 10: 1.49}
ri = ri_values.get(n, 1.49)
# 一致性比率
cr = ci / ri if ri > 0 else 0
return {
"criteria": criteria,
"priorities": dict(zip(criteria, priorities)),
"lambda_max": round(lambda_max, 4),
"consistency_index": round(ci, 4),
"consistency_ratio": round(cr, 4),
"is_consistent": cr < 0.10,
"interpretation": "一致" if cr < 0.10 else "不一致 - 请修正判断"
}
def create_pairwise_matrix(judgments: dict, criteria: list):
"""
根据判断创建成对比较矩阵
judgments: {(准则1, 准则2): 值},其中值为相对重要性
标度:1=同等重要,3=稍微重要,5=明显重要,7=强烈重要,9=极端重要
"""
n = len(criteria)
matrix = np.ones((n, n))
idx = {c: i for i, c in enumerate(criteria)}
for (c1, c2), value in judgments.items():
i, j = idx[c1], idx[c2]
matrix[i, j] = value
matrix[j, i] = 1 / value
return matrix
2. TOPSIS分析
def topsis_analysis(alternatives: list, criteria: list, decision_matrix: np.ndarray,
weights: list, criteria_types: list):
"""
TOPSIS(逼近理想解排序法)
alternatives: 备选方案名称列表
criteria: 准则名称列表
decision_matrix: m个备选方案 x n个准则的矩阵
weights: 准则权重(总和为1)
criteria_types: 每个准则的类型列表,'benefit'(效益型)或'cost'(成本型)
"""
m, n = decision_matrix.shape
# 步骤1:归一化决策矩阵
# 向量归一化
norm_divisors = np.sqrt((decision_matrix ** 2).sum(axis=0))
normalized = decision_matrix / norm_divisors
# 步骤2:加权归一化矩阵
weighted = normalized * weights
# 步骤3:确定理想解和反理想解
ideal = np.zeros(n)
anti_ideal = np.zeros(n)
for j in range(n):
if criteria_types[j] == 'benefit':
ideal[j] = weighted[:, j].max()
anti_ideal[j] = weighted[:, j].min()
else: # 成本型准则
ideal[j] = weighted[:, j].min()
anti_ideal[j] = weighted[:, j].max()
# 步骤4:计算距离
dist_to_ideal = np.sqrt(((weighted - ideal) ** 2).sum(axis=1))
dist_to_anti = np.sqrt(((weighted - anti_ideal) ** 2).sum(axis=1))
# 步骤5:计算相对贴近度
closeness = dist_to_anti / (dist_to_ideal + dist_to_anti)
# 备选方案排序
ranking = np.argsort(-closeness) + 1 # 1为最佳
results = []
for i, alt in enumerate(alternatives):
results.append({
'alternative': alt,
'closeness_coefficient': round(closeness[i], 4),
'distance_to_ideal': round(dist_to_ideal[i], 4),
'distance_to_anti_ideal': round(dist_to_anti[i], 4),
'rank': int(ranking[i])
})
results.sort(key=lambda x: x['rank'])
return {
"ranking": results,
"best_alternative": results[0]['alternative'],
"ideal_solution": dict(zip(criteria, ideal)),
"anti_ideal_solution": dict(zip(criteria, anti_ideal))
}
3. 加权评分方法
def weighted_scoring(alternatives: list, criteria: list,
scores: np.ndarray, weights: list):
"""
简单加权评分方法
alternatives: 备选方案名称列表
criteria: 准则名称列表
scores: m x n 分数矩阵(通常为0-10分制)
weights: 准则权重(总和为1)
"""
# 计算加权分数
weighted_scores = scores * weights
total_scores = weighted_scores.sum(axis=1)
# 排序
ranking = np.argsort(-total_scores) + 1
results = []
for i, alt in enumerate(alternatives):
criterion_contributions = dict(zip(criteria, weighted_scores[i]))
results.append({
'alternative': alt,
'total_score': round(total_scores[i], 2),
'criterion_scores': criterion_contributions,
'rank': int(ranking[i])
})
results.sort(key=lambda x: x['rank'])
return {
"ranking": results,
"best_alternative": results[0]['alternative'],
"score_range": {
"max": round(max(total_scores), 2),
"min": round(min(total_scores), 2),
"spread": round(max(total_scores) - min(total_scores), 2)
}
}
4. 敏感性分析
def sensitivity_analysis(base_weights: list, criteria: list, decision_matrix: np.ndarray,
alternatives: list, criteria_types: list, method: str = 'topsis'):
"""
分析排序对权重变化的敏感性
"""
n_criteria = len(criteria)
sensitivity_results = []
for i in range(n_criteria):
# 权重从0到0.5变化
weight_variations = np.linspace(0, 0.5, 11)
criterion_sensitivity = []
for new_weight in weight_variations:
# 按比例重新分配剩余权重
remaining = 1 - new_weight
modified_weights = np.array(base_weights) * (remaining / (1 - base_weights[i]))
modified_weights[i] = new_weight
if method == 'topsis':
result = topsis_analysis(alternatives, criteria, decision_matrix,
modified_weights, criteria_types)
else:
result = weighted_scoring(alternatives, criteria, decision_matrix,
modified_weights)
criterion_sensitivity.append({
'weight': new_weight,
'best_alternative': result['best_alternative'],
'ranking': [r['alternative'] for r in result['ranking']]
})
# 查找切换点
switching_points = []
for j in range(1, len(criterion_sensitivity)):
if criterion_sensitivity[j]['best_alternative'] != criterion_sensitivity[j-1]['best_alternative']:
switching_points.append({
'weight': criterion_sensitivity[j]['weight'],
'from': criterion_sensitivity[j-1]['best_alternative'],
'to': criterion_sensitivity[j]['best_alternative']
})
sensitivity_results.append({
'criterion': criteria[i],
'base_weight': base_weights[i],
'variations': criterion_sensitivity,
'switching_points': switching_points,
'is_sensitive': len(switching_points) > 0
})
return {
"sensitivity": sensitivity_results,
"most_sensitive_criterion": max(sensitivity_results,
key=lambda x: len(x['switching_points']))['criterion'],
"robust_range": identify_robust_range(sensitivity_results)
}
def identify_robust_range(sensitivity_results):
"""识别排序稳定的权重范围"""
# 简化 - 查找最窄的切换间隙
for result in sensitivity_results:
if result['switching_points']:
return {"criterion": result['criterion'],
"stable_up_to": result['switching_points'][0]['weight']}
return {"status": "排序在所有权重变化中均稳健"}
5. 准则权重分配方法
def rank_order_centroid(n_criteria: int, ranking: list = None):
"""
排序中心法(ROC)用于权重生成
ranking: 排序列表(1 = 最重要)
"""
if ranking is None:
ranking = list(range(1, n_criteria + 1))
weights = []
for rank in ranking:
weight = sum(1/j for j in range(rank, n_criteria + 1)) / n_criteria
weights.append(weight)
return {
"method": "ROC",
"weights": weights,
"normalized_weights": [w / sum(weights) for w in weights]
}
def swing_weights(criteria: list, swings: dict):
"""
摆动权重法
swings: {准则: 摆动值},其中最高值 = 最重要
"""
max_swing = max(swings.values())
weights = {c: swings[c] / max_swing for c in criteria}
total = sum(weights.values())
normalized = {c: w / total for c, w in weights.items()}
return {
"method": "Swing Weights",
"raw_weights": weights,
"normalized_weights": normalized
}
6. 决策矩阵可视化
def create_decision_summary(alternatives: list, criteria: list,
decision_matrix: np.ndarray, weights: list,
ranking_result: dict):
"""
创建综合决策摘要
"""
summary = {
"decision_matrix": pd.DataFrame(
decision_matrix,
index=alternatives,
columns=criteria
).to_dict(),
"criteria_weights": dict(zip(criteria, weights)),
"ranking": ranking_result['ranking'],
"recommendation": {
"best_choice": ranking_result['best_alternative'],
"confidence": assess_confidence(ranking_result)
},
"visualization_data": {
"spider_chart": prepare_spider_chart_data(alternatives, criteria, decision_matrix),
"bar_chart": prepare_bar_chart_data(ranking_result)
}
}
return summary
def assess_confidence(result):
"""评估建议的置信度"""
scores = [r['total_score'] if 'total_score' in r else r['closeness_coefficient']
for r in result['ranking']]
if len(scores) >= 2:
gap = scores[0] - scores[1]
if gap > 0.2:
return "高 - 明显优胜者"
elif gap > 0.1:
return "中 - 有一定区分度"
else:
return "低 - 备选方案接近"
return "N/A"
def prepare_spider_chart_data(alternatives, criteria, matrix):
"""为蜘蛛图/雷达图准备数据"""
# 归一化到0-1范围以便可视化
normalized = (matrix - matrix.min(axis=0)) / (matrix.max(axis=0) - matrix.min(axis=0) + 0.0001)
return {alt: dict(zip(criteria, normalized[i])) for i, alt in enumerate(alternatives)}
def prepare_bar_chart_data(result):
"""为排序条形图准备数据"""
return [{"alternative": r['alternative'],
"score": r.get('total_score', r.get('closeness_coefficient'))}
for r in result['ranking']]
流程集成
此技能与以下流程集成:
multi-criteria-decision-analysis.jssupplier-selection-evaluation.jsproject-prioritization.js
输出格式
{
"method": "TOPSIS",
"ranking": [
{"alternative": "选项A", "score": 0.72, "rank": 1},
{"alternative": "选项C", "score": 0.65, "rank": 2},
{"alternative": "选项B", "score": 0.48, "rank": 3}
],
"weights": {"成本": 0.3, "质量": 0.4, "交付": 0.3},
"sensitivity": {
"most_sensitive": "质量",
"robust": true
},
"recommendation": {
"best_choice": "选项A",
"confidence": "高"
}
}
最佳实践
- 明确定义准则 - 可衡量、独立的准则
- 利益相关者参与 - 就权重达成共识
- 测试敏感性 - 理解稳健性
- 记录理由 - 记录判断依据
- 考虑多种方法 - 比较结果
- 必要时迭代 - 基于洞察进行优化
约束
- AHP有效准则数量限制在约9个
- 需要一致的判断
- 权重确定可能具有主观性
- 结果取决于准则选择