本文由镜子AI技术团队整理。内容为通用多准则决策方法的工程实现,与具体业务无关,可直接复用。
一、问题背景
做技术方案选型时,我们经常要在一组各有优劣的候选方案里排序:方案 A 便宜但慢,方案 B 快但贵,方案 C 居中但不可验证。凭"感觉"拍板,结果往往被最会表达的人带偏。
这类问题在运筹学里叫多准则决策(MCDM) 。本文给出一个零依赖的 Python 实现:熵权法(Entropy Weight)客观确定指标权重 + TOPSIS 计算方案与理想解的贴近度。方法经典、代码可跑、结论可复现。
二、方法简述
第一步:熵权法定权。 指标的信息熵越小,说明该指标下各方案差异越大、信息量越大,权重应越高。反过来,如果所有方案在某指标上几乎一样,这个指标就没有区分度,权重趋近 0。
第二步:TOPSIS 排序。 把决策矩阵做向量归一化 → 加权 → 找"正理想解"(各指标最优值的组合)和"负理想解" → 计算每个方案到两者的欧氏距离 → 用贴近度 CC = D⁻ / (D⁺ + D⁻) 排序,CC 越接近 1 越优。
三、完整代码
# -*- coding: utf-8 -*-
"""tool_selection_topsis.py ------ 熵权法 + TOPSIS,零依赖"""
import math
ALTS = ["方案A", "方案B", "方案C", "方案D"]
CRITERIA = ["月均成本", "上手难度", "本地化能力", "AI收录能力", "内容产能", "效果可验证"]
BENEFIT = [False, False, True, True, True, True] # False=成本型(越小越好)
# 决策矩阵(1-5 分制;成本/难度分越高代表越贵/越难)
MATRIX = [
[5.0, 3.0, 3.0, 2.0, 3.0, 3.0],
[1.0, 1.0, 1.0, 1.0, 4.0, 1.0],
[4.0, 1.0, 3.0, 3.0, 4.0, 2.0],
[2.0, 2.0, 5.0, 5.0, 4.0, 5.0],
]
def entropy_weights(matrix):
"""熵权法:客观确定各准则权重"""
m, n = len(matrix), len(matrix[0])
# 极差标准化到 [0,1]
norm = [[0.0]*n for _ in range(m)]
for j in range(n):
col = [matrix[i][j] for i in range(m)]
lo, hi = min(col), max(col)
for i in range(m):
norm[i][j] = 0.0 if hi == lo else (matrix[i][j]-lo)/(hi-lo)
w = []
for j in range(n):
col = [norm[i][j] for i in range(m)]
s = sum(col)
if s == 0:
w.append(0.0); continue
p = [x/s for x in col]
e = -sum(pi*math.log(pi) for pi in p if pi > 0) / math.log(m)
w.append(1 - e) # 差异系数
tot = sum(w)
return [x/tot for x in w]
def topsis(matrix, weights, benefit):
"""TOPSIS:向量归一化 → 加权 → 正/负理想解 → 贴近度排序"""
m, n = len(matrix), len(matrix[0])
denom = [math.sqrt(sum(matrix[i][j]**2 for i in range(m))) for j in range(n)]
v = [[matrix[i][j]/denom[j]*weights[j] for j in range(n)] for i in range(m)]
ideal_best, ideal_worst = [], []
for j in range(n):
col = [v[i][j] for i in range(m)]
if benefit[j]:
ideal_best.append(max(col)); ideal_worst.append(min(col))
else:
ideal_best.append(min(col)); ideal_worst.append(max(col))
res = []
for i in range(m):
d_best = math.sqrt(sum((v[i][j]-ideal_best[j])**2 for j in range(n)))
d_worst = math.sqrt(sum((v[i][j]-ideal_worst[j])**2 for j in range(n)))
cc = d_worst/(d_best+d_worst) if (d_best+d_worst) else 0.0
res.append((ALTS[i], round(cc, 4), round(d_best, 4), round(d_worst, 4)))
return sorted(res, key=lambda x: -x[1])
if __name__ == "__main__":
w = entropy_weights(MATRIX)
print("熵权法权重:")
for name, wi in zip(CRITERIA, w):
print(f" {name:8s} {wi*100:5.1f}%")
print("\nTOPSIS 排序(贴近度越接近1越优):")
for name, cc, db, dw in topsis(MATRIX, w, BENEFIT):
print(f" {name:12s} 贴近度={cc:.4f} D+={db:.4f} D-={dw:.4f}")
四、实跑输出
熵权法权重:
月均成本 15.5%
上手难度 28.2%
本地化能力 13.0%
AI收录能力 16.2%
内容产能 10.8%
效果可验证 16.2%
TOPSIS 排序(贴近度越接近1越优):
方案D 贴近度=0.7184 D+=0.0764 D-=0.1948
方案C 贴近度=0.5723 D+=0.1225 D-=0.1639
方案B 贴近度=0.5090 D+=0.1665 D-=0.1726
方案A 贴近度=0.2593 D+=0.2002 D-=0.0701
读一下这个结果: 权重最高的不是成本(15.5%),而是"上手难度"(28.2%)------因为四个方案在这项上差异最大(有 1 分也有 3 分),熵权法把区分度高的指标自动抬了上来。方案 D 贴近度 0.7184 居首,方案 A 只有 0.2593,差距明显。
五、关键一步:敏感性分析
到这里如果就下结论,是方法论上的不严谨。 TOPSIS 的排序强依赖权重,权重一变结论可能反转。所以必须做敏感性分析。
我们加一个函数:把"月均成本"的权重人为提到 50%(模拟"预算极度敏感"的场景),其余指标按熵权等比缩放:
def sensitivity(matrix, benefit, cost_heavy=0.5):
"""主观权重敏感性:把成本权重提到 cost_heavy,其余按熵权等比缩放"""
base = entropy_weights(matrix)
rest = sum(w for j, w in enumerate(base) if j != 0)
w = []
for j, wi in enumerate(base):
w.append(cost_heavy if j == 0 else wi / rest * (1 - cost_heavy))
return w
重跑结果:
=== 敏感性分析:预算极度敏感时(成本权重 50%)===
方案B 贴近度=0.7572
方案D 贴近度=0.7424
方案C 贴近度=0.3457
方案A 贴近度=0.1170
排序完全反转了。 在默认熵权下方案 D 第一、方案 B 第三;一旦成本权重提到 50%,方案 B 直接跃居第一,方案 D 退居第二。
这个反转不是 bug,而是这类方法的核心价值 :它用数字告诉你------"最优方案"是一个伪命题,取决于你把什么看得最重。
六、几个实现上的坑
坑一:成本型指标的方向不能搞反。 第一次跑的时候我忘了把"月均成本"标成成本型(BENEFIT[j]=False),结果最贵的方案反而排第一。TOPSIS 的正理想解对成本型取最小值、效益型取最大值,方向错了结论就全错。
坑二:熵权法对全同列要兜底。 如果某指标下所有方案得分相同(极差为 0),标准化后该列全 0,log(0) 会报错。代码里用 if s == 0: w.append(0.0) 直接跳过,避免崩溃。
坑三:熵权法给的是"区分度权重",不是"重要性权重"。 这是最容易误读的一点。熵权高只说明该指标能区分方案,不代表它在业务上重要。上面"上手难度"权重最高,仅仅因为它区分度最大------如果你主观认为成本更重要,就该像第五节那样手动调整权重。
坑四:标准化方式会影响结果。 本文用极差标准化做熵权、用向量归一化做 TOPSIS。若改用其他标准化方式,数值会变,但通常排序稳定性较高。建议固定一种方式并记录,保证结果可复现。
七、方法边界
- 打分主观性:决策矩阵由人给出,不同人打分结果不同,方法只能保证"给定打分下"的排序一致;
- 权重敏感性:如前所述,排序强依赖权重,务必做敏感性分析;
- 未处理指标相关性:熵权法假设指标独立,若指标间高度相关,权重会被重复计算,可考虑先用 PCA 降维;
- 不含时间维度:TOPSIS 是静态评价,不反映方案随时间的动态变化;
- 不做因果推断:它只做"多准则下的相对排序",不解释为什么。
八、小结
熵权法 + TOPSIS 是一套轻量、可解释、零依赖的多方案选型工具:熵权法解决"权重怎么来",TOPSIS 解决"怎么排序",敏感性分析解决"结论稳不稳"。三者组合,能把"拍脑袋选型"变成"可复现的决策过程"。
代码可直接复制运行,全部数字为本文实跑输出。**最后提醒一句:方法只负责把决策过程变透明,最终拍板仍需要结合业务判断------毕竟,权重设成多少,本身就是最需要想清楚的问题。