
这份学习笔记断断续续改了三版。第一次只是抄了公式第二次照葫芦画瓢跑通了案例第三次才算真正想明白层次分析法AHP这套东西表面上是在算权重本质上是逼着你把脑子里那团模糊的“我觉得”拆成一个个能说清楚、能检验、能复现的判断。如果你正准备学数学建模或者要处理那种“好几个方案、各有利弊、凭感觉定不下来”的决策问题这篇文章应该能帮你省下不少弯路。我会从原理讲到一个能直接套用的完整案例附上可复制的代码最后聊聊我在实操里踩过的坑比如一致性检验不通过到底怎么抢救。1. 先搞清楚AHP到底要解决什么很多人学AHP第一反应是背判断矩阵、背RI表这其实搞反了顺序。AHP的核心不是计算而是把“多准则决策”这个问题结构化。1.1 凭空做决策为什么会翻车假设你面前有三个旅游目的地分别要考虑到花费、景色、交通、人多不多。大多数人的第一反应是纠结而且越纠结越乱。我试过用一个很简单的办法试探自己让朋友连续问五个“你到底更在意哪个因素”结果发现回答前后矛盾。比如嘴上说“最看重风景”可真让他多花一倍路费去远一点的地方他又犹豫了。这种矛盾不是人品问题是人的偏好本来就是非线性的凭空比较五六个因素大脑根本处理不过来。AHP的破局思路很直接既然一次性比五个因素会乱那就两个两个比。任意两个因素之间哪个更重要、重要多少这个判断大多数人都能给出。把全部两两比较的结果整理成一张矩阵再通过数学手段把这张矩阵里的信息压缩成一组权重。这组权重不是算出来的“客观事实”而是把你潜意识里的偏好给捞了出来摊平在纸面上。1.2 AHP的破局思路两两比较所以AHP的第一步永远是构造层次结构第二步才是填判断矩阵。判断矩阵就是那个“两两比较”的载体它长这样景色门票交通拥挤度景色1325门票1/311/22交通1/2213拥挤度1/51/21/31矩阵里第i行第j列的数代表“因素i比因素j重要多少”。3就是稍微重要5就是明显重要取倒数就表示反过来。这个矩阵最好记的特性是对角线上全是1因为自己和自己比当然一样重要。而且a12和a21必须是倒数关系如果你觉得景色比门票重要3倍那门票比景色就自动是1/3这是逻辑自洽问题不是数学问题。这套方法在数学建模里应用非常广尤其是评价类问题。比如某个城市空气质量评价、供应商选择、岗位应聘者排序本质都是“给定几个方案按一组指标排出优序”。AHP最拿手的就是这种场景方案数量有限准则数量适中而且判断主要依赖主观经验。1.3 AHP适合用在哪些场景不是所有决策问题都适合AHP。我自己用下来觉得它适合以下三种场景第一种是指标权重需要“讲道理”的。比如写论文要确定几个一级指标各占多少分没有任何历史数据支撑时AHP可以用专家打分的形式把权重确定下来并且还能有一致性检验作为质量把关的证明。第二种是团队决策出现分歧时。大家吵来吵去没有统一标准干脆把每个人的判断矩阵收集起来算一个群体权重。第三种是建模竞赛里的评价题。AHP作为主观赋权法常和熵权法等客观赋权法结合一个提供主观偏好一个提供数据波动信息两个一结合论文的评价维度就立体起来了。反过来如果指标之间本身就是客观数据比如三种芯片的功耗、价格、性能都有实测值那直接归一化加权就行硬套AHP反而显得画蛇添足。AHP解决的是“没有权威客观值”的那类问题它的价值恰恰在于主观判断也可以做得很有条理。2. 手把手搭一遍AHP四步走完整流程清楚了AHP解决什么问题下面就是可操作的步骤。我把它拆成四步每一步都说明原理和容易踩的坑。2.1 第一步画一张三层结构图AHP的标准结构就三层目标层、准则层、方案层。目标层就是你要回答的最终问题比如“选出最佳旅游地”。准则层是判断好坏的角度比如景色、门票、交通、拥挤度。方案层就是待选对象比如A地、B地、C地。这里有个经验准则层的指标数量控制在4到7个之间最舒服。太少体现不出多准侧决策的价值太多就会造成判断矩阵阶数过高填表时脑子不够用一致性大概率不通过。我记得最开始练习时贪心列了9个指标结果判断矩阵填到一半就疯了不是忘了倒数就是前后矛盾最后CR值直接爆炸。还有一个小技巧准则一定要选“相互独立”的维度。比如“风景”和“拍照出片率”其实高度相关这种相关性过高的指标放在一起会让判断矩阵的一贯性天然就差。选准则的时候先想想能不能把某个指标删掉或合并这一步比后面所有计算都重要。2.2 第二步1到9标度给判断矩阵打分判断矩阵的标度用的是1到9不是0到1也不是百分制。这套标度的含义有一个很值得玩味的设定1代表两因素同样重要3代表前者稍微重要5代表明显重要7代表强烈重要9代表极端重要2、4、6、8是中间值。为什么上限只到9因为心理学研究表明人在同一尺度下能稳定区分的重要等级最多在9个左右。超过9个等级判断质量会急剧下降。我第一次学的时候嫌这个标度太粗糙后来发现它粗糙得恰到好处——既然判断本来就是模糊的非要人家分到37级反而制造幻觉。填表的时候记住三件事。第一对角线填1。第二aij和aji互为倒数。第三不要试图做到完美的逻辑一致。所谓完美的逻辑一致意味着如果景色比门票重要3倍、门票比交通重要2倍那么景色就必须比交通重要6倍。但实际上你填的是2倍或者4倍都很正常。AHP的高明之处在于它不要求绝对一致只要不一致的程度在容忍范围内即可这个“容忍范围”就是后面要讲的一致性检验。2.3 第三步三种方法把权重算出来判断矩阵填好后就要从矩阵里提炼出权重向量。主流做法有三种。算术平均法最直观把矩阵的每一列做归一化也就是每个元素除以所在列的和得到一张新表。然后按行求平均这个平均值就是每个因素的权重。它的思路等于把所有列的意见拿来平权投票。几何平均法稍有不同把每一行的元素做乘积然后开n次方根n是矩阵阶数得到一组数值后归一化。这两种方法计算简单但严格来说都是对特征值法的近似。特征值法才是AHP的标准做法求判断矩阵的最大特征值所对应的特征向量归一化之后就是权重向量。从数学上讲判断矩阵是正互反矩阵时理想情况下的权重应该让矩阵能写成w_i/w_j的形式而最大特征值对应的特征向量最接近这个理想结构。我在实际做论文时一般只报特征值法的结果因为理解成本最低、认可度也最高。2.4 第四步一致性检验必须过计算权重之后还要回答一个问题这个判断矩阵内部逻辑到底乱成什么样一致性检验就是把这个“乱的程度”量化。首先算CI CI (λmax - n) / (n - 1)λmax是判断矩阵最大特征值。理论上如果矩阵完全一致λmax就等于nCI0。但人打分不可能做到完美λmax总会比n大一点。CI越大说明越不一致。然后算CR CR CI / RIRI是随机一致性指标它是一张查表得到的常数代表“随机乱填一个正互反矩阵”CI大概会是多少。n3时RI约0.58n4时约0.90n5时约1.12规模越大RI越大因为矩阵越大越容易不一致。判断标准CR 0.1时认为一致性可以接受。如果CR大于等于0.1就需要回头调整判断矩阵。这一步在建模论文里一定要写因为它既是科学性的体现也是逻辑闭环的关键。我第一次跑案例时CR在0.08左右心里还有点慌后来发现只要填表的时候不是随手乱写大多数情况下都能过。3. 用一个旅游案例把全流程跑通含可直接复制的代码前面讲了一堆原理这里用一个完整的案例把流程串起来。案例就是我前面提到过的“选旅游地”目标是对比A、B、C三个目的地。3.1 案例数据准则与方案怎么打分准则层一共4个景色、门票、交通、拥挤度。我给出的判断矩阵就是前文那张。然后是方案层的判断矩阵。这里要特别说明有多少个准则就要针对每个准则再建立一个方案层判断矩阵。也就是说我要分别回答“单看景色A、B、C谁更好”、“单看门票谁更好”、“单看交通谁更好”“单看拥挤度谁更好”一共4个3乘3矩阵。这4个矩阵我直接给出单看景色ABCA135B1/312C1/51/21单看门票ABCA11/31/5B311/2C521单看交通ABCA11/23B214C1/31/41单看拥挤度ABCA152B1/511/3C1/231这些矩阵不是瞎编的它们对应了很符合直觉的偏好A在景色和避拥挤上占优C在门票便宜上占优B在交通便利上占优。打分的时候最好头脑里先有一版“排序叙事”再去填数这样一致性能高很多。3.2 一段Python代码算完所有权重手算也能算但矩阵一多容易出错。我用Python写了一个通用的AHP计算函数把矩阵丢进去就能得到权重、CI、CR。import numpy as np def ahp_cal(matrix): n matrix.shape[0] # 特征值法求主特征向量 eig_val, eig_vec np.linalg.eig(matrix) idx np.argmax(eig_val.real) max_eig eig_val[idx].real weight eig_vec[:, idx].real weight weight / weight.sum() # 一致性检验 CI (max_eig - n) / (n - 1) RI_dict {1: 0, 2: 0, 3: 0.58, 4: 0.90, 5: 1.12, 6: 1.24, 7: 1.32, 8: 1.41, 9: 1.49} RI RI_dict[n] CR CI / RI if RI ! 0 else 0.0 return weight, CI, CR, max_eig # 准则层判断矩阵 matrix_criteria np.array([ [1, 3, 2, 5], [1/3, 1, 1/2, 2], [1/2, 2, 1, 3], [1/5, 1/2, 1/3, 1] ]) w_criteria, ci_c, cr_c, lam ahp_cal(matrix_criteria) print(准则层权重, w_criteria) print(准则层CI, round(ci_c, 4), CR, round(cr_c, 4)) # 方案层判断矩阵 w_scheme {} matrix_scenery np.array([[1, 3, 5], [1/3, 1, 2], [1/5, 1/2, 1]]) matrix_ticket np.array([[1, 1/3, 1/5], [3, 1, 1/2], [5, 2, 1]]) matrix_transport np.array([[1, 1/2, 3], [2, 1, 4], [1/3, 1/4, 1]]) matrix_crowd np.array([[1, 5, 2], [1/5, 1, 1/3], [1/2, 3, 1]]) for name, mat in zip([景色, 门票, 交通, 拥挤度], [matrix_scenery, matrix_ticket, matrix_transport, matrix_crowd]): w, ci, cr, _ ahp_cal(mat) w_scheme[name] w print(f方案层-{name} 权重, w, CI, round(ci, 4), CR, round(cr, 4))代码看起来很简洁但有几个细节容易忽略。例如np.linalg.eig返回的可能是复数虽然我们的矩阵特征值理论上是实数但数值计算会有虚部所以要取real。再用argmax定位最大特征值的索引才能提取对应的特征向量。如果直接取第一个特征向量结果一般来说是错的。3.3 权重结果怎么解读跑上面的代码会得到这样一组结果准则层权重大约是[0.483, 0.157, 0.272, 0.088]也就是景色占比最高48.3%交通27.2%门票15.7%拥挤度8.8%。这说明在这套主观偏好里景色是压倒性的决定因素。CR约0.006远小于0.1矩阵一致性非常好。各方案在单准则下的局部权重为景色权重[0.648, 0.230, 0.122]门票权重[0.110, 0.309, 0.581]交通权重[0.320, 0.558, 0.122]拥挤度权重[0.582, 0.109, 0.309]。最后一步是算综合得分把每个方案在所有准则下的局部权重用准则层权重加权求和方案A 0.483×0.648 0.157×0.110 0.272×0.320 0.088×0.582 ≈ 0.469方案B 0.483×0.230 0.157×0.309 0.272×0.558 0.088×0.109 ≈ 0.321方案C 0.483×0.122 0.157×0.581 0.272×0.122 0.088×0.309 ≈ 0.210结论是方案A综合最优。这个结论完全是由你打的判断矩阵决定的如果换一个人认为门票价格远比景色重要结果可能完全反过来。这就是AHP的本质它不是给你一个客观答案而是把你内心里原本模糊的偏好翻译成一个可比较的数字。代码跑完之后别忘了把总排序的一致性也看一遍不过在这个案例里单层CR都远低于0.1总排序结果可信度很高。4. 常见坑点与排查心得这部分是我最想写的因为公式和步骤你在任何教材上都能找到但实际操作中的坑往往才是决定你能不能顺利跑通一个案例的关键。4.1 一致性检验老是不通过怎么办这是我被问过最多的问题CR跑到0.3了怎么办首先别慌这不是说你的判断没价值而是矩阵内部有逻辑矛盾。排查思路分三步。第一步检查倒数关系。看每个aij与aji是不是互为倒数。如果某个位置填了3而对称位置填了2CR不通过完全不冤。这种错误属于低级但高频我帮别人复查时至少一半的失败案例是倒数值抄错。第二步找到最“刺眼”的那对判断。可以对比判断矩阵和最终权重向量把每个元素aij和wi/wj相除如果某个比值明显偏离1很多说明这个位置是你判断逻辑里最矛盾的点。比如权重比是2但你填了5那这个5大概率是整张矩阵里最大的不一致来源。第三步小幅度调整。改的时候不要大刀阔斧重填一次只动一个数幅度尽量控制在1到2个刻度以内改完再算一次CR。我有一次把某个3改成2CR就从0.15降到了0.07。记住AHP允许一定程度的不一致不需要追求CR等于0那本来就是不可能的。另外如果矩阵阶数很高而且实在调不过也可以回退一步看看是不是准则选得太多太杂。4.2 同一个矩阵为什么不同工具算出来权重不一样这个问题也有很多人遇到过。同一张判断矩阵用网上的计算器、手算、代码算结果往往有细微差别甚至在第三四位上不同。原因主要有三个。第一计算路径不同。算术平均法、几何平均法、特征值法三种算法的结果天然就有差异尤其是矩阵一致性较差的场景差异更明显。所以用规范工具之前先确认它用的哪种方法。论文里最好明确写出用特征值法并附上代码。第二约数精度不同。手算经常只保留三到四位小数代码算可以保留到十几位。第三RI表的版本不同。不同教材对于随机一致性指标RI的模拟次数不一样导致同一n对应的RI有微小差异进而CR值有一点偏差。但这不影响权重结果只影响一个0.01级别的CR小数位。我的习惯是固定用一份RI表并且在论文里注明出处口径这事就没有歧义了。4.3 打分太主观会被质疑怎么把过程写严谨AHP被诟病最多的一点就是主观性你的判断矩阵是自己填的凭什么别人要信我的答案不是“你信我”而是“我把怎么填的每一步都写清楚让这个填法可以复现、可以讨论、可以修改”。实操上我有三个习惯。第一引入多人打分结构。如果条件允许找三到五个人分别填同一套判断矩阵然后把所有打分做几何平均得到一个群体判断矩阵。为什么用几何平均而不是算术平均因为判断矩阵里的数是比率型的几何平均在数学上更匹配这种乘性结构。第二把判断依据写进文章的附录或说明里。比如“景色比门票重要因为本次旅行以摄影创作为主要目的”这样哪怕主观也是有论据的主观。第三如果是竞赛或论文场景可以做一个敏感性分析比如给权重加5%的扰动看最终排名是否稳定。排名稳定说明结论可靠也间接回应了“主观性”的攻击。我在实际写建模论文时用的组合是AHP加熵权法AHP算主观权重熵权法算客观权重各取50%加权得到最终权重。论文里解释起来很顺既尊重了专家经验也吸收了数据信息差异整体结构一下就完整了。4.4 判断矩阵里容易忽略的三个小细节第一个细节是四舍五入。有人图省事把1/3直接填成0.331/5填成0.2看起来差不多但对高阶矩阵来说这种舍入误差会逐层放大本来CR刚好0.09算出来变0.12。建议要么输入分数然后统一计算要么至少保留四到六位小数。第二个细节是n2时的一致性检验。二阶矩阵天然满足一致性RI等于0的时候CR没有意义所以不用算。有些工具会报除零错误这不是bug是数学上根本不需要这个检验。第三个细节是判断矩阵的敏感度。权重对大的比值变化不敏感比如某个位置从7改成8最终权重可能只动一两个百分点。但对小比值比如0.2改成0.3也就是一个数从1/5变成3/10权重的变动可能非常剧烈。所以如果要检查结果稳定性优先审查那些数值很小的元素。这是很多人不知道的一个视角多数人会盯着7、8、9这种大数猛调其实往往是小数的细微变化在主导结果。最后再分享一个我自己的习惯填判断矩阵之前我会先在心里明确一个优先级序列比如“在这件事里景色排第一交通第二门票第三拥挤度第四”。然后才动手填数字。这个看似多余的准备动作能极大降低后续一致性检验不通过的概率。因为一致性本质是你的内在逻辑而不是勉强的数字拼凑。先把逻辑顺序想清楚落到矩阵上只是把顺序翻译成数字这时候就算还没有完全精确也离合格线不远了。学AHP最大的收获是让我意识到所谓“决策”最难的部分不是数学而是搞清楚自己到底想要什么。判断矩阵只是把那句“我想要”一笔一画地写了下来并证明给你自己看。这个方法后续还可以往模糊AHP、群决策层次分析法这些方向延伸比如加入三角模糊数来描述更复杂的不确定偏好或者用网络层次分析法处理准则之间有互相依赖的情形。但不管走多远根源都是那句“两两比较再把偏好讲清楚”的思路。