ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

多属性决策MCDM实战:决策矩阵、熵权TOPSIS与方法验算

多属性决策MCDM实战:决策矩阵、熵权TOPSIS与方法验算 选型会开到第三个小时会议室里的人还在吵。采购说A家的设备故障率低生产说B家的交期更稳财务说C家的三年总成本最低工艺又补了一句D家的售后响应快。四个人四个维度各自都有数据支撑谁也说服不了谁。最后拍板的领导来了一句综合考虑一下吧然后综合考虑这四个字成了整个项目里最没有信息量的一句话。这类场景我遇到过太多次。多属性决策MCDMMulti-Criteria Decision Making干的活就是把这句综合考虑拆成一张能算、能验、能复盘的表。它不负责告诉你哪个方案绝对正确它负责把每个方案在多个互相冲突的指标上的表现压缩成一个可比较的排序并且告诉你这个排序对外界条件有多敏感。供应商选型、厂址选择、设备采购、人才评价、材料配方筛选、投资标的比选凡是指标多于一个、且指标之间打架的决策背后跑的都是MCDM这一套。这篇内容我会从一张决策矩阵开始把归一化、赋权、TOPSIS推演、方法族对比、结果验算、代码落地这条链路完整走一遍。适合两类人一类是刚接触评价模型、被熵权TOPSIS这类词砸晕的同学另一类是已经在用、但结果总被业务方质疑你这权重哪来的的从业者。1. 决策矩阵把会议室里的口水仗变成一张能算的表任何MCDM问题的起点都是同一件事——把方案和指标摆成矩阵。行是备选方案列是评价指标单元格里是每个方案在每个指标上的原始取值。这一步听起来平平无奇但它决定了后面所有计算的合法性。1.1 一次设备选型的矩阵长什么样假设我们要在四家供应商之间选一家定了六个指标采购单价、故障率、交期天数、三年运维成本、售后响应时长、产能冗余度。前四个里单价、故障率、交期、运维成本都是成本型指标——数值越小越好响应时长也是成本型只有产能冗余度是效益型指标——越大越好。摆出来是这样一张表方案采购单价(万)故障率(%)交期(天)三年运维(万)响应时长(h)产能冗余(%)A1202.14538815B983.430521225C1451.26022610D1082.83845430这张表一摆出来第一个反直觉的地方就出现了单位不统一数值尺度差了好几个量级。采购单价是百位数故障率是个位数小数。如果你直接拿原始值去做加权求和那么采购单价这个指标会凭借数值量级天然碾压其他所有指标你后面精心调的权重基本等于白调。所以归一化不是可选项是必选项。1.2 归一化的三套常用做法和各自代价归一化的目标是把所有指标拉到同一个尺度上同时把成本型指标的方向掰成越大越好。常见三套极差归一化min-max把每列映射到[0,1]。效益型用 $(x - x_{min})/(x_{max} - x_{min})$成本型用 $(x_{max} - x)/(x_{max} - x_{min})$。优点是结果直观、落到0到1缺点是对极值极其敏感。如果某一列里有一个离谱的离群值——比如某家供应商报价写成了1200万——整列的归一化结果会被这一个值压扁其他方案之间原本的差异全被抹平。向量归一化欧氏归一化每个元素除以该列的平方和开根号。这是TOPSIS的标准动作。它的好处是不依赖极值只依赖整列的分布抗离群值能力比极差法强。缺点是归一化后的值不再落在[0,1]某列最大值可能只有0.6看起来不够整齐但这对数学上没有影响。线性比例归一化max法效益型除以该列最大值 $x/x_{max}$成本型用 $x_{min}/x$。它保留了比例关系适合有明确零基准的指标比如产量。缺点同样怕极端值而且不保证非负。我的经验是先看有没有离群值再决定用哪套。如果数据分布比较均匀极差法最直观业务方也最容易接受如果有个别极端值优先用向量归一化。这中间还有一个经常被忽略的细节——极差归一化在成本和效益转换时如果某一列所有方案取值完全相同分母会是0程序直接报除零错误。这种情况在真实业务里比想象中常见比如所有供应商交期都是30天。工程上一般统一加个极小值1e-12兜底但在报告里必须说明这一列实际上没有区分度。1.3 MCDM不是最优化也不是简单加权求和这里必须把三个容易混淆的概念分清楚我见过太多人把它们当一回事。多目标优化MODM是在连续或离散的可行域里搜索最优解决策变量本身是可调的目标是找到一组帕累托最优解。典型场景是排产计划、投资组合权重优化。简单加权求和SAW是MCDM里最简单的一种聚合方式——归一化后直接和各列权重相乘再求和得分最高的胜出。它就是MCDM的一个特例思路直白但有个致命前提它默认指标之间完全可以线性补偿。意思是一个方案在采购成本上多花50万只要在售后响应上快3小时就能被完全抵消回来。现实里这种补偿关系往往不成立。MCDM的完整范畴覆盖了聚合方式的全部谱系从可以完全补偿的SAW、TOPSIS到部分补偿的VIKOR再到基于偏好关系而非绝对补偿的PROMETHEE、ELECTRE。你选哪一类本质上是在回答一个问题这些指标之间的替代关系允不允许一好遮百丑。注意在写评价报告时务必把归一化方法和指标方向两件事写清楚。我见过项目验收时被追问你们的成本型指标有没有取反结果翻代码发现极差归一化公式写反了整个排序全部倒置。这类错误不会报错只会安静地给你一个错答案。2. 权重才是真正让所有人抠头皮的环节矩阵搭好、归一化做完接下来是MCDM里争议最大的一步权重怎么定。你把权重从采购0.3、质量0.2、成本0.5改成采购0.2、质量0.3、成本0.5排序很可能整个翻过来。所以业务方质疑结果时第一句话永远是你这权重谁给的。权重的来源分三条路主观赋权、客观赋权、组合赋权。三条路没有绝对优劣只有适用场景。2.1 主观赋权AHP的判断矩阵和那个0.1的门槛层次分析法AHP是最经典的主观赋权方法。它的核心操作是对同一层级的指标两两比较用1到9的标度打分构成判断矩阵。1到9标度的含义是1表示同等重要3表示稍重要5表示明显重要7表示强烈重要9表示极端重要2、4、6、8是中间值。反过来就是倒数。举个例子采购、质量、交期三个指标如果我认为质量比采购稍重要3交期比采购明显重要5交期比质量稍重要3判断矩阵就是采购质量交期采购11/31/5质量311/3交期531这里有两个关键处理。第一要做一致性检验。人的判断很难完全自洽可能出现采购质量、质量交期、但交期采购这种循环。AHP用一致性比率CR来度量这种矛盾程度先算判断矩阵的最大特征值 $\lambda_{max}$再算一致性指标 $CI (\lambda_{max} - n)/(n - 1)$最后除以随机一致性指标RI得到CR。RI的取值随矩阵阶数变化常用的几个值是n3时0.58n4时0.90n5时1.12n6时1.24n7时1.32。工程上的硬门槛是CR 0.1。超过这个值判断矩阵就不能用必须让打分的人回头调整。我见过不少团队把这个检验直接跳过理由是业务方懒得改。跳过之后权重照样能算出来但它的数学含义已经站不住了后面所有结论都建在流沙上。第二权重的求解方式。理论上用最大特征值对应的特征向量实际工程里用几何平均法的近似解更常见——对判断矩阵每一行求几何平均再归一化。这个近似解和特征向量法结果通常非常接近但算起来快得多也好解释。AHP最大的价值不在数学在过程。它逼着打分的人把这个指标比那个指标重要多少这句话从模糊表态变成具体数字而且数字之间还要自洽。我在项目里用AHP很多时候真正的收获是发现两个部门对同一个指标的重要性认知差了整整五个标度——这种分歧如果不上矩阵永远暴露不出来。2.2 客观赋权熵权法的信息量逻辑和CRITIC的相关性修正客观赋权完全靠数据说话不打分。最常用的是熵权法。熵在这里衡量的是某一列数据的离散程度。如果某个指标下所有方案的取值几乎一样这个指标对区分方案几乎没有贡献信息量小熵值大权重就该低。反过来某列数据上下翻飞、区分度极高熵值小权重就高。具体步骤是先把归一化后的矩阵平移到正数区间因为有对数运算不能出现0或者负数然后按列算出每个元素占该列总和的比例 $p_{ij}$再算该列的熵 $E_j -\frac{1}{\ln m}\sum p_{ij}\ln p_{ij}$其中m是方案数。最后用 $d_j 1 - E_j$ 表示差异系数归一化后就是权重。熵权法的坑在于它只认数据不认业务。我遇到过一个真实案例某个指标数据收集时录入错误导致某列波动异常大熵权法直接给这个错误指标分配了最高权重。所以客观赋权的输出必须做一次常识体检——如果算出来的权重和业务直觉完全相反第一反应应该是查数据而不是信算法。CRITIC法是对熵权法的一个重要补充。它同时考虑两件事指标的对比强度用标准差衡量和指标之间的冲突性用相关系数衡量。两个指标如果高度相关说明它们携带的信息大量重叠CRITIC会降低它们的综合权重避免同一件事被重复计权。熵权法和CRITIC的差异可以这样理解熵权法关心这列数据散不散CRITIC还额外关心这列数据和别的列说的是不是一回事。如果指标之间存在明显共线性——比如采购单价和三年运维成本往往正相关——CRITIC更合适。2.3 组合赋权两种耦合方式和必须注意的一个细节主观和客观各有短板主观反映意图但可能拍脑袋客观尊重数据但可能违背业务逻辑。组合赋权就是取两者之长。最常见的两种耦合方式方式公式思路特点线性加权组合$w \alpha w_{sub} (1-\alpha) w_{obj}$直观α需要人为指定随意性大乘法归一化组合$w_j \frac{w_{sub,j} \cdot w_{obj,j}}{\sum_k w_{sub,k} \cdot w_{obj,k}}$均衡性强任一方法给出低权重都会拉低最终结果基于距离的优化最小化组合权重与两种权重的偏差平方和有明确优化目标可解释性好我个人更偏向乘法归一化或者基于偏差最小的优化模型因为线性组合里的那个α实在很难说清该取多少而业务方一定会问。乘法组合没有这个自由参数解释起来干净。一个必须注意的细节任何组合之后权重向量必须重新归一化到和为1。我见过把两个各自和为1的权重向量直接相加得到权重和等于2然后拿去乘归一化矩阵结果所有贴近度都被整体放大排序虽然没变但输出的分值完全没法解释。排序不变是运气好如果后续要做阈值判断这个错误就会直接致命。3. TOPSIS完整推演从加权矩阵到贴近度TOPSIS逼近理想解排序法大概是MCDM里出镜率最高的方法几乎所有熵权TOPSIS的论文和项目都能看到它。它的核心思想一句话概括最好的方案应该离正理想解最近、离负理想解最远。这个思想本身非常符合直觉。想象你在挑房子你心里有个完美房的画像——价格最低、面积最大、通勤最短、学区最好同时也有个最差房的画像。每套真实房源都在这两个极端之间离完美房越近、离最差房越远的那套综合分就越高。3.1 向量归一化与加权决策矩阵TOPSIS的第一步是向量归一化每个元素除以该列的平方和开根号。得到的矩阵记为R。然后把权重向量逐列乘上去得到加权决策矩阵 $V R \cdot diag(w)$。为什么要先加权再找理想解而不是先找理想解再加权这是TOPSIS里一个容易搞混的地方。理想解是在加权空间里定义的因为权重本身就代表了指标的重要性一个权重极低的指标它的最好值不应该对理想解产生和权重高的指标一样的影响。先加权理想解的位置才反映真实的偏好结构。3.2 正负理想解、距离与贴近度的计算加权矩阵V里逐列取最优值构成正理想解 $V^$逐列取最差值构成负理想解 $V^-$。注意这里的方向效益型指标取最大值成本型指标取最小值。然后算每个方案到两个理想解的欧氏距离$$d_i^ \sqrt{\sum_j (v_{ij} - v_j^)^2}, \quad d_i^- \sqrt{\sum_j (v_{ij} - v_j^-)^2}$$最后算贴近度 $C_i \frac{d_i^-}{d_i^ d_i^-}$。这个值落在0到1之间越大越好等于1表示这个方案在所有指标上都是最优。这里有个数学上的必然结果如果一个方案在所有指标上都是最优它同时就是正理想解$d_i^ 0$贴近度恰好等于1。反之为0。这个边界性质可以用来验证代码写得对不对。3.3 逆序现象TOPSIS最容易被忽略的软肋TOPSIS有一个著名的性质叫逆序rank reversal当你往方案集里增加一个新方案或者删掉一个方案原来两个方案之间的相对排序可能发生翻转。这个现象不只在TOPSIS里出现AHP、VIKOR等也有类似问题只是TOPSIS因为引入了理想解这种全局参照物表现得格外明显。原因不难理解理想解是由整个方案集里的最优值决定的。加进来一个新方案它如果在某个指标上特别突出正理想解的位置就被拉走了其他所有方案到理想解的距离都要重算排序自然可能变。这在工程上意味着什么如果你打算分批次评估供应商或者中途淘汰掉几个方案一定要把最终入围的方案放在一次完整的TOPSIS计算里重跑。我见过一个项目前期用20家供应商排名筛出前5然后用这5家再跑一次排名结果前两名换了位置汇报时被问得下不来台。规避思路有几种一是在报告里明确说明排序仅在当前方案集内有效二是改用对逆序不敏感的方法比如PROMETHEE这类基于成对比较的方法三是在关键决策上同时跑两三种方法做交叉验证如果结论一致可信度就高得多。3.4 手写一版TOPSIS把流程跑通理论讲完直接上代码。这套实现不依赖任何第三方MCDM库纯numpy便于你理解每一步在干什么。import numpy as np def topsis(X, w, benefit): X: m x n 决策矩阵行是方案列是指标 w: 长度为n的权重向量元素和应为1 benefit: 长度为n的布尔数组True表示效益型指标 返回贴近度数组越大越优 X np.asarray(X, dtypefloat) w np.asarray(w, dtypefloat) benefit np.asarray(benefit, dtypebool) m, n X.shape assert len(w) n, 权重维度与指标数不一致 assert abs(w.sum() - 1.0) 1e-8, 权重之和必须为1 # 1. 向量归一化 denom np.sqrt((X ** 2).sum(axis0)) denom[denom 0] 1e-12 # 防御全零列 R X / denom # 2. 加权决策矩阵 V R * w # 3. 正负理想解 best np.where(benefit, V.max(axis0), V.min(axis0)) worst np.where(benefit, V.min(axis0), V.max(axis0)) # 4. 欧氏距离 d_best np.sqrt(((V - best) ** 2).sum(axis1)) d_worst np.sqrt(((V - worst) ** 2).sum(axis1)) # 5. 贴近度 return d_worst / (d_best d_worst)用第1章那张供应商表验证一下。六个指标前五个是成本型最后一个是效益型。假设权重先用一个主观设定[0.2, 0.15, 0.15, 0.2, 0.1, 0.2]。X np.array([ [120, 2.1, 45, 38, 8, 15], [ 98, 3.4, 30, 52, 12, 25], [145, 1.2, 60, 22, 6, 10], [108, 2.8, 38, 45, 4, 30], ]) w np.array([0.2, 0.15, 0.15, 0.2, 0.1, 0.2]) benefit np.array([False, False, False, False, False, True]) score topsis(X, w, benefit) print(np.round(score, 4)) # 输出大致为: [0.3582 0.4407 0.4466 0.6903]D方案综合得分最高C紧随其后。这个结果符合直觉D虽然采购价不是最低、交期不最短但它在响应时长和产能冗余上都很突出而这两个指标正好权重不低。这就是MCDM的价值——它能明确告诉你为什么D赢了而不是一句模糊的综合考虑。提醒贴近度只在同一批方案内可比不同批次的贴近度数值之间没有绝对意义。0.69不代表69分合格它只是一个相对位置的表达。汇报时千万别把它说成综合评分很容易误导听众。4. 方法族横向对比VIKOR、PROMETHEE和灰色关联各自适合什么场景TOPSIS不是唯一选择也不总是最优选择。方法选错结论可能完全反着来。这一章把几个主流方法摊开讲重点说清各自的补偿机制和适用边界。4.1 VIKOR当决策者不愿接受一好遮百丑VIKOR的核心思路和TOPSIS不同。它算出两个指标群体效用S和个体遗憾R。$S_i \sum_j w_j \cdot \frac{f_j^* - f_{ij}}{f_j^* - f_j^-}$ 衡量的是这个方案整体上离理想状态差多少相当于平均表现。$R_i \max_j \left[ w_j \cdot \frac{f_j^* - f_{ij}}{f_j^* - f_j^-} \right]$ 衡量的是这个方案最差的那一项指标有多差相当于短板程度。然后综合成一个Q值$Q_i v \cdot \frac{S_i - S^}{S^- - S^} (1-v) \cdot \frac{R_i - R^}{R^- - R^}$其中v是决策机制系数通常取0.5v大于0.5表示偏向群体效用最大化小于0.5表示偏向个体遗憾最小化。VIKOR最大的特点是它能识别折衷解而不只是最优解而且配套有两个接受条件一是可接受优势条件二是可接受决策可靠性条件。只有同时满足Q值最小的方案才是唯一最优否则要给出一个折衷方案集。什么时候用VIKOR当决策者明确表达了我不希望某个方案在某一项上烂到没法看这种偏好时。比如选医疗器械供应商价格可以谈但灭菌合格率这一项不能有任何妥协这种场景VIKOR比TOPSIS更贴切。4.2 PROMETHEE基于成对比较的净流排序PROMETHEE走的是完全不同的路子——它不做全局归一化而是对每一对方案在每个指标上做两两比较用偏好函数把差值转换成一个0到1之间的偏好度再加权汇总成流入和流出。对方案a正流 $\phi^(a)$ 表示它相对其他所有方案的优势总和负流 $\phi^-(a)$ 表示它相对其他方案的劣势总和净流 $\phi(a) \phi^(a) - \phi^-(a)$ 就是最终的排序依据。偏好函数有好几种形态通常型差值大于0就算完全偏好、U型差值超过某个阈值才算偏好、V型偏好度随差值线性增长、高斯型平滑过渡等等。这个设计让PROMETHEE在处理有明确无所谓区间的指标时特别自然。比如交期30天和31天在实际业务里没区别差值1天不该产生任何偏好差异用U型函数设个阈值就能把这个逻辑表达出来。PROMETHEE还有个副产品特别实用它可以直接画出方案之间的关系图你能清楚看到哪些方案处于支配地位、哪些方案之间互有胜负。这种可视化在向管理层汇报时比一张干巴巴的分数表有说服力得多。4.3 灰色关联分析小样本、信息不全时的务实选择灰色关联分析GRA来自灰色系统理论解决的问题是数据量少、信息不完整。它的核心是算每个方案和参考序列之间的关联系数。$$\xi_{ij} \frac{\min_i \min_j \Delta_{ij} \rho \max_i \max_j \Delta_{ij}}{\Delta_{ij} \rho \max_i \max_j \Delta_{ij}}$$其中 $\Delta_{ij}$ 是方案i在指标j上与参考值的绝对差$\rho$ 是分辨系数一般取0.5。最后按权重聚合得到关联度。GRA的好处是对数据量要求低四五个方案、六七个指标就能算而且不需要严格的统计分布假设。我们做早期技术路线预研时用过很多次那时候连方案都还没定型能拿到的就是几个专家估的区间值根本没法做复杂的统计分析GRA这种能算就行的方法反而最合适。缺点也很明显分辨率系数ρ的取值会影响最终排序虽然通常取0.5但它确实是一个人为参数需要做敏感性分析来验证结论稳不稳。4.4 一张表看清方法选型方法补偿机制数据要求抗逆序典型场景SAW完全补偿低弱快速初筛、指标独立性好TOPSIS完全补偿中弱通用评价、论文常见VIKOR部分补偿中中存在不可妥协的硬指标PROMETHEE部分补偿中高强需要成对关系可视化ELECTRE部分补偿高强存在明显不可比方案GRA完全补偿低中小样本、早期预研选型的经验法则指标之间可以互相补偿、数据量充足用TOPSIS有绝对不能踩的红线指标用VIKOR需要向非技术背景的听众解释清楚谁压过谁用PROMETHEE数据少得可怜用GRA。拿不准的时候跑两三个方法对比结论一致的排序基本可以放心用。5. 结果可信度的三道验算关卡算出排序不等于交付。真正拉开专业度差距的是你有没有对结果做过稳健性检验。业务方问换个权重会不会变你答不上来整个报告的权威性就没了。5.1 权重扰动给每个权重±20%看排序稳不稳最简单也最有效的敏感性分析方法对每个权重单独做扰动比如上下浮动20%同时保证权重向量重新归一化到和为1然后重跑排序看前几名的顺序有没有变化。具体做法是逐一处理把第一个权重乘以1.2其余按比例压缩使总和保持为1重跑TOPSIS再把第一个权重乘以0.8重跑。对每个权重都做一遍记录排序变化情况。判断标准很直接如果前两名的相对顺序在绝大多数扰动下都保持不变那这个结论就相当稳固。如果稍微动一下权重第一名就换人了说明这两个方案本质上难分伯仲这时候正确的做法不是硬选一个而是向决策者说明这两个方案在现有指标体系下等价把选择权交回去同时建议补充新的区分性指标。我在一个产业园选址项目里就用过这招。前两个地块的综合分差了不到0.01做敏感性分析发现权重只要动5%排序就翻转。最后我们没有强行给结论而是补了一个周边配套成熟度的定性指标重新评估反而让整个决策过程更扎实。5.2 换方法交叉验证从单一证据变成多重证据权重扰动检验的是数据层面的稳定性方法交叉验证检验的是模型层面的稳定性。操作很朴素同一份归一化数据、同一组权重分别用TOPSIS、VIKOR、PROMETHEE跑一遍比较排序结果。如果三种方法给出的第一名一致前几名顺序也大体吻合这个结论的可信度就远超单一方法。如果三种方法结果差异很大那不是坏事反而说明方案之间的差异本身就是多维的。这时候要具体分析是某个方案在某一两个指标上极端突出导致某些方法偏爱它还是方法本身的补偿机制差异导致的把这个原因分析清楚往往比给一个标准答案更有价值。5.3 决策报告怎么写才站得住脚一份能经得起追问的MCDM报告我一般会包含这几块第一指标体系的来源。每个指标为什么入选是文献支撑、行业标准还是访谈共识必须写清楚。指标体系一旦被质疑后面全废。第二权重的确定过程和一致性检验结果。如果用了AHP把判断矩阵和CR值贴出来如果用了熵权法把各列的信息熵和差异系数贴出来。让读者能复现你的权重。第三归一化方法及离群值处理说明。有没有剔除异常值用的什么规则剔除前后结果差异多大。第四排序结果和敏感性分析。不只给最终排名还要给权重扰动下排名的稳定区间。第五结论的适用边界。明确说明这个排序在什么条件下成立超出这个条件需要重新评估。我最常提醒团队的一句话MCDM产出的是在当前指标体系、当前权重、当前方案集下的一个有理有据的建议不是客观真理。把边界说清楚反而比宣称绝对最优更能赢得信任。6. 工程落地代码骨架、常见报错与那个绕不开的复用问题前面讲的是方法和逻辑这一章聊落地。真实项目里MCDM的代码往往不是写一次就扔而是要在多轮评审中反复跑、反复改。所以代码的组织方式很重要。6.1 把归一化、赋权、评价拆成三层我习惯把代码分成三个独立模块各自职责单一第一层数据层负责读入决策矩阵、校验维度、处理缺失值和异常值。这一层输出的应该是干净的、方向已统一的数值矩阵外加一个指标方向的元数据。第二层赋权层包含AHP、熵权法、CRITIC、组合赋权几个函数。每个函数输入矩阵输出权重向量并且都做和为1的断言。第三层评价层包含TOPSIS、VIKOR、PROMETHEE等方法函数。每个函数输入归一化后的矩阵和权重输出排序结果。这样分层的好处是改权重方法不用动评价逻辑换评价方法不用动权重方法做敏感性分析时只要在外层套个循环。熵权法的实现给一份参考import numpy as np def entropy_weight(X, benefit, eps1e-6): X: m x n 原始决策矩阵 benefit: 长度为n的布尔数组 返回熵权法权重向量和为1 X np.asarray(X, dtypefloat) m, n X.shape Z np.zeros_like(X) # 极差归一化并统一方向全部转为效益型 for j in range(n): col X[:, j] rng col.max() - col.min() if rng 0: Z[:, j] 1.0 # 该列无区分度赋相同值 continue if benefit[j]: Z[:, j] (col - col.min()) / rng else: Z[:, j] (col.max() - col) / rng # 平移避免对数为负无穷 Z Z eps P Z / Z.sum(axis0) # 计算信息熵 E -(P * np.log(P)).sum(axis0) / np.log(m) d 1.0 - E if d.sum() 0: return np.full(n, 1.0 / n) return d / d.sum()CRITIC的实现稍微复杂一点核心是多算一步相关系数矩阵def critic_weight(X, benefit, eps1e-6): CRITIC法综合对比强度与指标冲突性 X np.asarray(X, dtypefloat) m, n X.shape Z np.zeros_like(X) for j in range(n): col X[:, j] rng col.max() - col.min() if rng 0: Z[:, j] 1.0 continue Z[:, j] (col - col.min()) / rng if benefit[j] else (col.max() - col) / rng # 对比强度标准差 sigma Z.std(axis0, ddof1) # 冲突性1 - 相关系数之和对角为1 corr np.corrcoef(Z, rowvarFalse) corr np.nan_to_num(corr, nan0.0) conflict (1.0 - corr).sum(axis1) info sigma * conflict if info.sum() 0: return np.full(n, 1.0 / n) return info / info.sum()AHP一致性检验也补上def ahp_weight(A): A: 判断矩阵返回(权重向量, CR值) A np.asarray(A, dtypefloat) n A.shape[0] RI {1: 0.0, 2: 0.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} # 几何平均法求权重 geo np.prod(A, axis1) ** (1.0 / n) w geo / geo.sum() # 一致性检验 lam_max (A w / w).mean() CI (lam_max - n) / (n - 1) if n 1 else 0.0 CR CI / RI[n] if RI.get(n, 0) 0 else 0.0 return w, CR6.2 那些不会报错但会给你错答案的坑我把这些年踩过和见别人踩过的坑整理成一张清单。它们的共同特点是程序不报错结果看起来正常但结论是错的。现象根因排查方式某个指标权重异常高该列存在录入错误导致的极端离群值逐列打印min/max和业务方核对排序和直觉完全相反成本型指标方向没取反或取反写反用只有一个最优方案的玩具数据验证贴近度全部接近0.5权重和为1的断言没做权重整体偏大打印 w.sum()极差归一化报除零某列所有取值相同检查方差对零方差列单独处理分批次评估后排序大变TOPSIS逆序现象把入围方案合并重跑一次AHP的CR值超过0.1判断矩阵存在逻辑矛盾定位矛盾的三元组请打分人调整相关系数矩阵出现NaN某列零方差导致相关系数无定义用np.nan_to_num兜底组合权重之和等于2两个权重向量直接相加未归一化组合后强制重新归一化有一条我特别想说始终用玩具数据验证你的实现。构造一个3方案2指标的矩阵其中方案1在两个指标上都是最优方案2都是中等方案3都是最差。正确的TOPSIS输出应该是贴近度严格递减方案1接近1。如果跑出来不是这个结果说明归一化或者理想解的方向有问题。这个自检花不了五分钟但能挡住绝大部分低级错误。另外指标之间的方向判断错误是最难发现的因为它不影响程序运行只影响结论。我的做法是在数据层要求每个指标显式声明direction字段取值benefit或cost代码里任何地方用到方向都从这个字段读不允许在函数内部硬编码。这样至少保证方向信息只有一个来源不会出现两处逻辑打架。6.3 关于工具库的取舍Python生态里现成的MCDM库主要有pymcdm和scikit-criteria两个。它们封装了TOPSIS、VIKOR、PROMETHEE、COPRAS、MARCOS等一大批方法接口比较统一适合快速验证想法。但我的建议是核心生产代码还是自己写。原因有三个。第一这类库的更新频率和周边生态远不如numpy、pandas长期维护有风险。第二方法实现里的细节——比如归一化用哪一种、理想解怎么定义——不同库的处理可能不一样一旦结果对不上排查成本很高。第三MCDM的每一步计算量都不大自己实现几十行就能搞定掌控感完全不同。库的最佳用法是当参照物自己实现完TOPSIS拿库跑一遍同样的数据如果结果一致说明实现没问题如果不一致正好是个深入理解方法细节的机会。我最初学PROMETHEE的时候就是这么干的发现自己在偏好函数阈值设置上和库默认值不同才真正搞懂了那几种偏好函数的实际含义。最后一个实操建议把归一化后的矩阵、权重向量、中间距离、最终贴近度全部落盘保存。MCDM项目一定会被追问评审现场临时重跑代码很尴尬。留一份完整的中间结果追问什么就翻什么这个习惯帮我省过很多次事。关于MCDM这一整套东西我的整体感受是它的数学门槛其实不高真正难的是把这些数字和业务判断对齐。指标体系选得对不对权重定得合不合理结论的边界说不说得清这些决定了你的结果是被采纳还是被推翻。工具和方法都在其次把每一步的为什么讲明白比用多花哨的算法都管用。
返回列表