D1 · AHP 层次分析法 + 熵权法¶
今天的目标:不是"看懂"这两个方法,而是能独立构造一个判断矩阵/数据表,手推出权重,用代码验证,并写出一段经得起追问的论文文字。
1. AHP 到底在解决什么问题¶
当你面对多个评价指标(比如"成本""时间""舒适度"),但它们量纲完全不同、没法直接相加时,AHP 让你通过两两比较的方式,把"我觉得成本比舒适度重要得多"这种主观判断,转换成可以直接乘进模型的数字权重。它的价值不在数学多复杂,而在于把说不清楚的"重要性"量化成了可追溯的过程——这也是为什么评委爱看:你不是拍脑袋给的权重,是有一套流程支撑的。
2. 五步流程¶
- 建层次结构:目标层 → 准则层(指标)→ 方案层。指标不要超过 7±2 个,太多两两比较会自相矛盾。
- 构造判断矩阵:对每一对指标,按 Saaty 1-9 标度打分(下表),aji = 1/aij。
- 计算权重:三种常见算法(选一种即可,特征值法最标准):
- 算术平均法:每列归一化后按行取平均 —— 手算最快,写论文可以说"简化处理"
- 几何平均法:每行元素连乘后开 n 次方再归一化 —— 对不一致矩阵更稳健
- 特征值法:取矩阵最大特征值对应的特征向量并归一化 —— 教材标准做法,代码里默认用这个
- 一致性检验:CI = (λmax − n)/(n − 1),CR = CI / RI,CR < 0.1 才算通过。
- 不通过怎么办:不是重新瞎猜,是回头检查哪一对比较和其他比较逻辑矛盾(比如你说 A 比 B 重要,B 比 C 重要,却说 C 比 A 重要),调整后重新算。
| 标度 | 含义 |
|---|---|
| 1 | 两者同等重要 |
| 3 | 前者比后者稍微重要 |
| 5 | 前者比后者明显重要 |
| 7 | 前者比后者强烈重要 |
| 9 | 前者比后者极端重要 |
| 2,4,6,8 | 相邻判断的中间值 |
关键概念
RI(随机一致性指标)是查表值,只和指标个数 n 有关,不用自己算:n=3 时 RI=0.58,n=4 时 0.90,n=5 时 1.12(完整表在代码里)。CR 本质是在问:"如果我是瞎填的,一致性会有多差?你实际填的比瞎填好多少?"
3. 例题精算(手推,不跳步)¶
场景:从成本、时间、舒适度三个指标比较三种出行方式的重要性,判断矩阵如下:
例子
成本 时间 舒适度
成本 1 3 5
时间 1/3 1 3
舒适度 1/5 1/3 1
- 列求和:成本列 1+1/3+1/5 = 1.5333;时间列 3+1+1/3 = 4.3333;舒适度列 5+3+1 = 9
- 每列归一化后按行平均,得权重:成本 w₁=0.633,时间 w₂=0.261,舒适度 w₃=0.106(三者相加=1)
- 用权重反乘回矩阵估算 λmax:算出三行的 (Aw)ᵢ/wᵢ 分别约为 3.071 / 3.033 / 3.012,取平均 λmax ≈ 3.039
- CI = (3.039 − 3) / (3 − 1) = 0.0194
- CR = CI / RI = 0.0194 / 0.58 = 0.033 —— 小于 0.1,通过一致性检验,权重可用
易错
很多人算完权重就直接用了,压根没做一致性检验——CR 没过关意味着你打的分自相矛盾,权重是不可信的,评委一眼能看出你根本没做这一步。
4. 代码逐行拆解¶
ahp_weight.py
import numpy as np
def ahp_weight(A):
n = A.shape[0]
eigvals, eigvecs = np.linalg.eig(A) # 求全部特征值/特征向量
idx = np.argmax(eigvals.real) # 取最大特征值的位置
w = eigvecs[:, idx].real # 对应的特征向量就是权重(未归一)
w = w / w.sum() # 归一化,使权重和为1
lam_max = eigvals[idx].real
CI = (lam_max - n) / (n - 1)
RI = {1:0,2:0,3:0.58,4:0.9,5:1.12,6:1.24,7:1.32,8:1.41,9:1.45}[n]
CR = CI / RI if RI else 0
return w, CR
注意:np.linalg.eig 返回的可能是复数(虚部通常是 0),所以要 .real 取实部;eigvecs[:, idx] 里正负号可能反过来,如果权重全是负数,整体取相反数即可。
5. 熵权法:让数据自己说话¶
AHP 靠人的主观判断;熵权法反过来,看一个指标在各方案之间差异有多大:差异越大,说明这个指标越能区分方案优劣,权重就该越高;如果所有方案在某个指标上几乎一样,这个指标就是"废话",权重趋近于 0。
易错
所有指标要先正向化(成本型指标,比如"价格",值越小越好,要先转换成"越大越好":常用 max−x 或取倒数),再归一化,才能算熵值——漏了这一步,算出来的权重会是反的。
6. 例题精算:为什么"没有差异的指标权重为0"¶
3 个方案 A/B/C,2 个已经正向化的指标:
例子
指标1(有差异) 指标2(无差异)
方案A 4 7
方案B 6 7
方案C 8 7
- 归一化(每列除以列和):指标1列和=18 → P=(0.222, 0.333, 0.444);指标2列和=21 → P=(0.333, 0.333, 0.333)
- 常数 k = 1/ln(3) = 0.9102
- 指标1 熵值 e₁ = −k·Σ(P·lnP) = 0.9657;指标2 熵值 e₂ = 1.0000(完全无差异时熵恒为1,这是理论最大值)
- 差异系数 d = 1 − e:d₁ = 0.0343,d₂ = 0
- 归一化得权重:w₁ = 1.000,w₂ = 0.000
关键概念
这个例子是刻意设计的极端案例:指标2 在三个方案里完全相同,携带的信息量为零,熵权法直接把它的权重判为 0——这就是"熵"在直觉上的意思:越"意外"(越有差异)的信息,权重越高。
7. 代码逐行拆解¶
entropy_weight.py
import numpy as np
def entropy_weight(X):
# X: n个方案 x m个指标,必须已经正向化 + 归一化到同一量纲
X = X + 1e-12 # 防止 log(0)
P = X / X.sum(axis=0) # 每列(每个指标)内部占比
k = 1 / np.log(len(X)) # len(X)=方案数 n
e = -k * (P * np.log(P)).sum(axis=0) # 每个指标的熵值
d = 1 - e # 差异系数:熵越低,差异系数越高
return d / d.sum() # 归一化为权重
+1e-12 是工程技巧:如果某方案在某指标上取值为 0,log(0) 会报错/得到 -inf,加一个极小值规避,不影响结果精度。
8. 进阶:组合赋权¶
实战中很少单用一种赋权法——AHP 有主观性,熵权法完全依赖数据、可能和常识相悖(比如碰巧本次样本里一个重要指标恰好差异很小)。常见做法是组合权重:
例子
w_combined = α · w_AHP + (1-α) · w_entropy
α 取 0.5 最简单(写论文可以说"等权重组合,兼顾主客观信息");更严谨的做法是用博弱组合赋权(求一组线性组合系数使组合权重与两组权重的离差平方和最小),属于加分项,时间够再做。
9. 写作表达¶
论文里"确定权重"这段的标准结构:为什么需要权重 → 用什么方法 → 关键结果(带数字)→ 结果为何合理。用今天例题的真实数字填一遍:
论文里可以这么写
由于成本、时间、舒适度三项指标难以直接量化比较,本文采用层次分析法确定各指标权重。通过构造两两比较判断矩阵,并计算一致性比率 CR = 0.033 < 0.1,通过一致性检验,得到权重向量为 (0.633, 0.261, 0.106),其中成本权重最高,符合出行决策中成本因素通常被优先考量的实际情况。
把方括号内容换成你自己任务的真实数字和场景描述,其余句式基本可以照搬。
10. 今日任务清单¶
- [ ]
任务1:跑通 AHP —
用本文的判断矩阵跑 ahp_weight,核对你的 CR 是否也在 0.03 附近(允许小数点后差异,特征值法和算术平均法结果会略有不同)
- [ ]
任务2:自己编一组熵权法数据 —
4 个方案 × 3 个指标,其中至少 1 个是成本型(记得先正向化),跑 entropy_weight,检查哪个指标权重最高,想一想是否符合你对"差异大小"的直觉
- [ ]
任务3:写一段权重确定的论文文字 —
套用第9节模板,用任务2的真实数字重写一遍
自查
自查:这4个问题答不上来,别进 D2¶
- CR 是用来检验什么的?如果 CR = 0.15 你会怎么处理?
- 熵权法为什么要求指标先"正向化"?不做会怎样?
- 如果某个指标在所有方案里数值都相同,熵权法算出的权重会是多少?为什么?
- AHP 和熵权法分别适合什么场景?能不能各举一个国赛题目里可能出现的例子?
参考答案
参考答案¶
-
CR 检验判断矩阵的一致性,即你的两两打分之间有没有逻辑矛盾(说 A>B、B>C,却又说 C>A)。CR = 0.15 > 0.1 不通过,需要修正矩阵。 定位问题元素的方法:完全一致时 aij = wi/wj,因此计算
a_ij · w_j / w_i − 1,绝对值最大的那个元素就是矛盾来源,把它往 wi/wj 拉近后重算。注意同步修改倒数位置 aji = 1/aij,否则矩阵不再是互反矩阵,后续计算全部失效。 -
正向化服务于综合评价的打分逻辑,不是为了修正权重方向。 熵权法量的是离散程度:一个成本型指标只要方案间差异大,无论正不正向化,算出的权重都高——所以指标权重的排序并不会翻。真正翻掉的是方案排序,因为加权求和默认"每列数值越大越好"。 用一组数据看后果(价格成本型,评分效益型):
价格(万元) 评分 方案A 10 8 方案B 50 7 方案C 90 6指标权重几乎不受影响:不正向化 (0.973, 0.027),正向化后 (0.985, 0.015),价格始终占主导。但综合得分完全不同:
方案 不正向化 正向化后 A(价10 / 评8) 0.075 0.663 ① B(价50 / 评7) 0.333 0.333 ② C(价90 / 评6) 0.591 ① 0.004 ③ 不正向化时最贵、评分最低的 C 排第一,因为 90 万的价格被当成了优点。 补充:正向化确实会让权重数值变化(0.973→0.985),因为
max−x改变了该列的占比结构 P,但这是副作用而非目的。 -
权重为 0。该指标各方案取值相同 → 归一化后 P 每项都是 1/n → 熵值 ej 达到理论最大值 1 → 差异系数 dj = 1 − ej = 0 → 权重为 0。含义是:这个指标对区分方案毫无贡献,信息量为零。
-
AHP 熵权法 前提 不需要数据,只要有领域判断 必须有多方案实测数据 国赛例子 "评价一项政策的社会效益",指标是安全性/公平性/可持续性——根本没有客观数据,只能靠专家两两比较 "给 30 个城市的宜居程度排名",已给出 GDP/绿化率/房价等实测表格,用数据定权更有说服力 失效模式 指标超过 7~9 个时人的判断必然自相矛盾,CR 难过关 样本依赖:公认重要的指标若碰巧在本次样本里差异很小,权重被压到接近 0,结论违背常识 熵权法的失效模式无法靠它自己修复,必须引入主观信息——这就是组合赋权存在的真正理由。论文里写
w = α·w_AHP + (1−α)·w_entropy时,理由应写成"避免客观赋权受样本分布影响导致关键指标失权",而不是"兼顾主客观"这种套话。
11. 把正向化写进函数签名¶
正向化是最容易漏的一步,别靠记性。把它做成熵权法函数的必填参数,漏写直接报错而不是静默出错:
entropy_weight_safe.py
import numpy as np
def positivize(X, kinds):
"""kinds: 每列一个, 'max'=效益型(越大越好), 'min'=成本型(越小越好)"""
X = np.asarray(X, dtype=float).copy()
for j, kind in enumerate(kinds):
if kind == 'min':
X[:, j] = X[:, j].max() - X[:, j]
return X
def entropy_weight(X, kinds):
X = positivize(X, kinds) # 从签名上就不可能"忘记"
X = X + 1e-12
P = X / X.sum(axis=0)
k = 1 / np.log(len(X))
e = -k * (P * np.log(P)).sum(axis=0)
d = 1 - e
return d / d.sum()
# w = entropy_weight(data, kinds=['min', 'max', 'max'])
设计意图:把易错步骤变成函数签名的必填参数,比在注释里写"记得正向化"可靠得多。后面每个模板都会沿用这个思路。