这份学习笔记断断续续改了三版。第一次只是抄了公式,第二次照葫芦画瓢跑通了案例,第三次才算真正想明白:层次分析法(AHP)这套东西,表面上是在算权重,本质上是逼着你把脑子里那团模糊的“我觉得”,拆成一个个能说清楚、能检验、能复现的判断。如果你正准备学数学建模,或者要处理那种“好几个方案、各有利弊、凭感觉定不下来”的决策问题,这篇文章应该能帮你省下不少弯路。我会从原理讲到一个能直接套用的完整案例,附上可复制的代码,最后聊聊我在实操里踩过的坑,比如一致性检验不通过到底怎么抢救。
1. 先搞清楚AHP到底要解决什么
很多人学AHP第一反应是背判断矩阵、背RI表,这其实搞反了顺序。AHP的核心不是计算,而是把“多准则决策”这个问题结构化。
1.1 凭空做决策为什么会翻车
假设你面前有三个旅游目的地,分别要考虑到花费、景色、交通、人多不多。大多数人的第一反应是纠结,而且越纠结越乱。我试过用一个很简单的办法试探自己:让朋友连续问五个“你到底更在意哪个因素”,结果发现回答前后矛盾。比如嘴上说“最看重风景”,可真让他多花一倍路费去远一点的地方,他又犹豫了。这种矛盾不是人品问题,是人的偏好本来就是非线性的,凭空比较五六个因素,大脑根本处理不过来。
AHP的破局思路很直接:既然一次性比五个因素会乱,那就两个两个比。任意两个因素之间哪个更重要、重要多少,这个判断大多数人都能给出。把全部两两比较的结果整理成一张矩阵,再通过数学手段把这张矩阵里的信息压缩成一组权重。这组权重不是算出来的“客观事实”,而是把你潜意识里的偏好给捞了出来,摊平在纸面上。
1.2 AHP的破局思路:两两比较
所以AHP的第一步永远是构造层次结构,第二步才是填判断矩阵。判断矩阵就是那个“两两比较”的载体,它长这样:
| 景色 | 门票 | 交通 | 拥挤度 | |
|---|---|---|---|---|
| 景色 | 1 | 3 | 2 | 5 |
| 门票 | 1/3 | 1 | 1/2 | 2 |
| 交通 | 1/2 | 2 | 1 | 3 |
| 拥挤度 | 1/5 | 1/2 | 1/3 | 1 |
矩阵里第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就等于n,CI=0。但人打分不可能做到完美,λmax总会比n大一点。CI越大说明越不一致。
然后算CR: CR = CI / RI
RI是随机一致性指标,它是一张查表得到的常数,代表“随机乱填一个正互反矩阵”,CI大概会是多少。n=3时RI约0.58,n=4时约0.90,n=5时约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个矩阵我直接给出:
单看景色:
| A | B | C | |
|---|---|---|---|
| A | 1 | 3 | 5 |
| B | 1/3 | 1 | 2 |
| C | 1/5 | 1/2 | 1 |
单看门票:
| A | B | C | |
|---|---|---|---|
| A | 1 | 1/3 | 1/5 |
| B | 3 | 1 | 1/2 |
| C | 5 | 2 | 1 |
单看交通:
| A | B | C | |
|---|---|---|---|
| A | 1 | 1/2 | 3 |
| B | 2 | 1 | 4 |
| C | 1/3 | 1/4 | 1 |
单看拥挤度:
| A | B | C | |
|---|---|---|---|
| A | 1 | 5 | 2 |
| B | 1/5 | 1 | 1/3 |
| C | 1/2 | 3 | 1 |
这些矩阵不是瞎编的,它们对应了很符合直觉的偏好: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而对称位置填了2,CR不通过完全不冤。这种错误属于低级但高频,我帮别人复查时至少一半的失败案例是倒数值抄错。
第二步,找到最“刺眼”的那对判断。可以对比判断矩阵和最终权重向量:把每个元素aij和wi/wj相除,如果某个比值明显偏离1很多,说明这个位置是你判断逻辑里最矛盾的点。比如权重比是2,但你填了5,那这个5大概率是整张矩阵里最大的不一致来源。
第三步,小幅度调整。改的时候不要大刀阔斧重填,一次只动一个数,幅度尽量控制在1到2个刻度以内,改完再算一次CR。我有一次把某个3改成2,CR就从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.33,1/5填成0.2,看起来差不多,但对高阶矩阵来说,这种舍入误差会逐层放大,本来CR刚好0.09算出来变0.12。建议要么输入分数然后统一计算,要么至少保留四到六位小数。
第二个细节是n=2时的一致性检验。二阶矩阵天然满足一致性,RI等于0的时候CR没有意义,所以不用算。有些工具会报除零错误,这不是bug,是数学上根本不需要这个检验。
第三个细节是判断矩阵的敏感度。权重对大的比值变化不敏感,比如某个位置从7改成8,最终权重可能只动一两个百分点。但对小比值,比如0.2改成0.3,也就是一个数从1/5变成3/10,权重的变动可能非常剧烈。所以如果要检查结果稳定性,优先审查那些数值很小的元素。这是很多人不知道的一个视角,多数人会盯着7、8、9这种大数猛调,其实往往是小数的细微变化在主导结果。
最后再分享一个我自己的习惯:填判断矩阵之前,我会先在心里明确一个优先级序列,比如“在这件事里,景色排第一,交通第二,门票第三,拥挤度第四”。然后才动手填数字。这个看似多余的准备动作,能极大降低后续一致性检验不通过的概率。因为一致性本质是你的内在逻辑,而不是勉强的数字拼凑。先把逻辑顺序想清楚,落到矩阵上只是把顺序翻译成数字,这时候就算还没有完全精确,也离合格线不远了。
学AHP最大的收获,是让我意识到所谓“决策”最难的部分不是数学,而是搞清楚自己到底想要什么。判断矩阵只是把那句“我想要”一笔一画地写了下来,并证明给你自己看。这个方法后续还可以往模糊AHP、群决策层次分析法这些方向延伸,比如加入三角模糊数来描述更复杂的不确定偏好,或者用网络层次分析法处理准则之间有互相依赖的情形。但不管走多远,根源都是那句“两两比较,再把偏好讲清楚”的思路。