基于层次分析法的城市竞争力评价:权重计算与排名实践
简介这是一份以层次分析法AHP评价城市竞争力为主题的课程学习报告适合经济管理、城市规划及系统工程方向的学生与研究者参考。报告从城市竞争力多因素综合评价需求出发系统梳理了AHP的基本原理完整展示了目标层—准则层—要素层—指标层的层次结构模型构建、判断矩阵赋值、最大特征根计算与一致性检验过程并结合实例给出指标权重计算和综合评价应用思路具有较强的可操作性。资源为单个Word文档约832KB共1个文件内容完整便于直接阅读、修改或作为报告模板使用。已有139人学习浏览适合正在撰写相关课程作业、毕业设计或需快速掌握AHP评价流程的读者。1. 层析分析法在城市竞争力评价中的应用先把这个名字对齐你搜“层析分析法”大概率是在找“层次分析法AHP”——在城市竞争力评价这类多准则决策问题里这两个名字指的都是同一种方法。简单说它把“城市竞争力”这种抽象概念拆成三层目标层、准则层、指标层再通过两两比较把专家的主观判断量化成权重最后加权合成每个城市的综合得分。某次项目里委托方丢给我一份统计年鉴数据要求“给出一个不靠拍的排名”我最后就是用AHP搭的骨架指标层归一化成可比数据准则层权重来自判断矩阵合成得分后输出排名。这个方法适合两类人一是做城市评估、区域规划对比的从业者二是论文或研究报告需要方法支撑、并且要解释清楚每一步为什么这样算的研究型读者。接下来我会按一套完整流程走一遍从指标结构到权重计算再到最终排名附可直接改用的代码。2. 指标体系怎么搭城市竞争力评价的三层结构与指标池2.1 目标层-准则层-指标层为什么结构必须刚好三层AHP的第一步不是算权重而是把评价目标结构化。城市竞争力评价里目标层就是“城市综合竞争力”这一个点往下拆出准则层维度再往下拆出指标层可量化的统计指标。三层结构是AHP的骨架原因有两个。第一判断矩阵本质上是“同层元素两两比较”如果同层塞了十几个指标专家根本没法稳定地两两比较一致性检验会经常失败我后面会专门讲这个坑。第二只有三层结构才能把“权重”拆成两级准则层权重体现战略倾向比如更看重科技创新还是更看重宜居指标层权重体现测量精度。如果只做一层权重评价结果的解释力会差很多。实操中我习惯把指标层控制在3~4个准则层控制在5~6个这样判断矩阵的阶数不会太高一致性调整也有回旋余地。阶数超过7的判断矩阵CR值很难压到0.1以内这是AHP公认的痛点所以结构设计一开始就要防着这个。2.2 一套可直接用的城市竞争力指标池五个维度十八个指标城市竞争力评价没有绝对统一的标准体系不同研究的差异主要出现在准则层的命名和指标取舍上。下面这套指标体系是我做类似项目时常用的骨架覆盖经济、创新、设施、开放、宜居五个维度兼顾了数据可得性和维度独立性。准则层指标层指标方向备注经济发展地区生产总值正向总量型指标反映整体经济规模经济发展人均可支配收入正向反映居民富裕程度经济发展一般公共预算收入正向反映政府可用财力经济发展固定资产投资增速正向反映投资活力科技创新研发投入强度正向RD经费占GDP比重科技创新每万人发明专利拥有量正向反映创新产出密度科技创新高新技术企业数量正向反映创新主体规模基础设施轨道交通运营里程正向大城市间差异明显基础设施路网密度正向反映通达性基础设施互联网宽带接入用户覆盖率正向反映数字化基础设施水平开放活力进出口总额正向反映外贸规模开放活力实际使用外资正向反映外资吸引力开放活力常住人口净流入率正向反映人口吸引力开放活力市场主体数量正向反映创业活跃度宜居生活空气质量优良天数正向反映生态环境质量宜居生活人均公园绿地面积正向反映绿色空间供给宜居生活登记失业率负向数值越高竞争力越差宜居生活每万人拥有医生数正向反映公共服务水平这套指标池在构建时有两条筛选规则第一优先选统计年鉴里稳定发布、跨城市可比的口径避免选那种只有少数城市发布数据的指标第二每个准则层内避免放两个强相关指标比如“GDP总量”和“财政收入”不能同时出现在经济发展维度它们高度同向会导致隐性重复计权。2.3 指标筛选的两条实用规则避冗余、避强相关很多初学者喜欢把指标堆满觉得指标越多越全面实际效果恰恰相反。指标过多时专家打分负担剧增判断矩阵一致性差而且强相关指标会被重复加权。我一般会在确定指标池后先拿目标城市的近三年数据跑一遍相关性矩阵。凡是同一准则层内相关系数超过0.7的两个指标只保留一个优先保留语义更有区分度的那个。比如“人均可支配收入”和“人均消费支出”在统计上高度相关保留前者就够了。另一个容易忽略的点是指标方向。城市竞争力评价里大部分指标是正向的但像登记失业率这类负向指标必须单独标注。方向不统一会直接影响下一章的归一化处理这一步没标记清楚后面算出来的综合得分就失去了可比性。3. 从两两比较到权重判断矩阵与AHP的计算内核3.1 1-9标度的语义别把“重要”凭空想成5AHP把两个元素的重要性差异映射成1-9的整数标度。我在指导别人填判断矩阵时发现最大的问题不是不会填而是不知道某个数字对应什么程度的差异。标度含义说明1同等重要两个因素对目标的贡献差不多3稍微重要凭经验判断A比B略重要5明显重要A比B的重要性能明显感知7强烈重要A的贡献已占绝对优势9极端重要A的重要性压倒性高于B2/4/6/8中间值相邻判断的折中实操中我会提醒填写者只用1、3、5、7、9这五个档位避免使用偶数标度。理由是偶数档会让判断矩阵的数值解释变得模糊而一致性检验的调整本来就依赖清晰的语义一旦矩阵不一致偶数档更容易让人摸不着头脑。判断矩阵还有一个基本性质对角线元素为1即某个指标和自己比较重要性完全相同且a_ij和a_ji互为倒数。比如科技创新比基础设施稍微重要则a_ij3对应的a_ji1/3。这个“倒数对称”规则如果不遵守矩阵本身就无效后面的计算全部没有意义。3.2 判断矩阵怎么填五条实操规则避免专家打分时“打架”构造判断矩阵是整个流程里主观性最强、也最容易翻车的一步。我按自己的血泪经验归纳了五条规则第一一次只做一对比较不跳着填。把同层的指标按固定顺序编号后按顺序两两比较不要A和C打完了再回去补A和B跳序填写是矩阵不一致的第一来源。第二判断依据对齐。专家A可能觉得经济增长比科技创新重要专家B却认为科技才是长期竞争力这时需要在打分前先明确“当前阶段城市发展的主要矛盾是什么”否则判断矩阵只是各持己见的平均值。第三发现矛盾及时回头。如果矩阵计算后CR值超了第一步不是调数字而是回到最矛盾的那几个比较对重新追问打分依据。比如你判断经济比科技重要、科技比设施重要、但设施又比经济重要这种循环矛盾在矩阵里会直接拉高CR值必须人工修正。第四用多人打分时不直接平均原始分数而是取几何平均。算术平均会被极端分数带偏几何平均对数量级差异更稳健。比如有人打了7有人打了1/3直接平均是3.67几何平均是根号下7*1/3约等于1.53后者更接近“共识”。第五同一矩阵里的比较对控制在20个以内。5阶矩阵需要填10个对6阶矩阵15个对7阶矩阵21个对。超过这个数打分疲劳会让判断质量直线下降一致性过不了几乎是必然的。3.3 权重计算与一致性检验特征向量法的一次完整实现把判断矩阵录入Python之后计算权重最常用的是特征向量法即求矩阵的最大特征值对应的特征向量归一化后就是权重向量。代码如下import numpy as np # 以5个准则层为例经济发展、科技创新、基础设施、开放活力、宜居生活 # 1-9标度a_ij 表示第i个准则相对于第j个准则的重要程度 matrix np.array([ [1, 2, 2, 3, 4], # 经济发展 [1/2, 1, 1, 2, 3], # 科技创新 [1/2, 1, 1, 2, 3], # 基础设施 [1/3, 1/2, 1/2, 1, 2], # 开放活力 [1/4, 1/3, 1/3, 1/2, 1] # 宜居生活 ]) # 计算特征值和特征向量 eigenvalues, eigenvectors np.linalg.eig(matrix) max_eigenvalue_idx np.argmax(eigenvalues.real) # 最大特征值对应索引 max_eigenvalue eigenvalues.real[max_eigenvalue_idx] weight_vector eigenvectors[:, max_eigenvalue_idx].real # 对应特征向量 # 权重归一化使所有权重合计为1 weights weight_vector / weight_vector.sum() # 一致性检验CI (λmax - n) / (n - 1)RI为随机一致性指标 n matrix.shape[0] CI (max_eigenvalue - 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.45, 10: 1.49} RI RI_dict[n] CR CI / RI print(权重向量, np.round(weights, 4)) print(最大特征值 λmax, round(max_eigenvalue, 4)) print(CI, round(CI, 4)) print(CR, round(CR, 4)) print(一致性 if CR 0.1 else 一致性检验不通过需要调整矩阵)这段代码的核心逻辑是先用np.linalg.eig求出矩阵的所有特征值和特征向量取最大特征值对应的特征向量归一化后即为权重向量。λmax表示判断矩阵实际的主特征值它和矩阵阶数n的差异反映了矩阵内部判断逻辑的混乱程度。参数说明CI是一致性指标RI是随机一致性指标与矩阵阶数n相关n越大RI越大因为随机生成的互相反矩阵阶数越高越容易表现不一致。CR是CI与RI之比CR小于0.1是AHP通行的可接受阈值意味着矩阵的不一致程度还在“随机噪音”范围内权重结果可以信任。前面给出的5阶矩阵用这套代码跑出来的结果是可用的。如果替换成自己的矩阵后CR超过0.1优先检查成对判断中是否存在明显的循环矛盾比如A比B重要、B比C重要、但C又比A重要的三角关系这种矛盾需要人工回头修正打分。4. 从原始数据到排名指标归一化与加权合成的完整计算4.1 指标方向问题正向指标、负向指标的处理规则判断矩阵算出的权重告诉了你“每个维度有多重要”但还不能直接用于排名。原因是不同指标的量纲完全不同GDP是以“亿元”为单位空气质量优良天数是“天”登记失业率是“%”这些数值直接乘权重会完全被量纲大的指标主导。处理方向问题的第一原则是所有负向指标必须先做方向转换。最常见的做法是取倒数或者用最大值减去原始值让数值越大代表竞争力越强。我一般用1 / x转换保留更多分布信息但要注意失业率接近0时倒数会爆炸这时改用max(x) - x更稳。第二原则是区分绝对量和人均量。GDP总量和人均GDP在评价语义上是不同的总量反映规模人均反映水平。如果你把两者同时放进指标体系就会遇到我在2.3节说的强相关问题。实务中一个维度里只选一个总量指标加一个人均指标避免重复计权。4.2 min-max归一化与加权合成从权重到得分的一次计算指标方向统一后下一步是归一化。城市竞争力评价里最常用的是min-max归一化把每个指标的取值区间映射到0到1之间。公式是(x - min) / (max - min)。归一化后的数值没有量纲可以直接乘权重相加。我见过很多人直接对原始数据乘权重这个做法在技术上完全错误。因为量纲不同比如GDP是几千到几万亿的规模而研发投入强度是百分之零点几到几个点权重乘上去后GDP几乎完全主导得分所谓综合评价变成了GDP排名。为了演示完整流程我从2.2节的指标池里选5个代表性指标分别对应5个准则层方向人均可支配收入经济发展、研发投入强度科技创新、轨道交通运营里程基础设施、常住人口净流入率开放活力、登记失业率宜居生活负向。权重直接用第3章代码算出的结果。import numpy as np # 原始数据3座城市5项指标指标顺序与准则层权重一致 # 数据顺序人均可支配收入(万元)、研发投入强度(%)、轨道交通里程(km)、净流入率(%)、登记失业率(%) raw_data np.array([ [5.2, 2.8, 320, 2.1, 3.5], # 城市甲 [4.6, 3.1, 180, 1.2, 4.1], # 城市乙 [4.1, 2.2, 95, 0.6, 4.8] # 城市丙 ]) weights np.array([0.381, 0.236, 0.236, 0.104, 0.043]) # 与第3章结果一致 # 第3步正负向指标处理登记失业率为负向指标取倒数后与其他指标方向一致 # 取倒数并把倒数结果缩放到合理范围 raw_data[:, 4] 1 / raw_data[:, 4] # 第4步min-max归一化每列独立计算 normalized np.zeros_like(raw_data) for col in range(raw_data.shape[1]): col_min raw_data[:, col].min() col_max raw_data[:, col].max() if col_max col_min: normalized[:, col] 1 # 所有城市相同则视为同分 else: normalized[:, col] (raw_data[:, col] - col_min) / (col_max - col_min) # 第5步加权合成综合得分 scores normalized weights # 输出排名 cities [城市甲, 城市乙, 城市丙] ranked sorted(zip(cities, scores), keylambda x: x[1], reverseTrue) for i, (city, score) in enumerate(ranked, 1): print(f第{i}名{city}综合得分{score:.4f})这段代码的逻辑是第0-4列已经是正向指标直接参与归一化第4列登记失业率先取倒数完成方向转换再执行min-max归一化最后用上一步算出的权重向量做矩阵乘法得到综合得分按得分降序输出名次。参数说明normalized weights是矩阵乘法等价于把每个城市的5个归一化指标分别乘以对应权重后求和。zip(cities, scores)把城市名和得分组成元组列表reverseTrue按得分从高到低排序。如果指标数量很多建议把指标方向和权重放进一个DataFrame里管理避免顺序错位。4.3 三座城市的完整演算从原始统计值到最终排名为了让前面的流程落地看得见这里直接展开3.3和4.2节代码对应的中间结果方便你校验自己的实现城市人均可支配收入(万元)研发投入强度(%)轨道交通里程(km)净流入率(%)登记失业率(%)城市甲5.22.83202.13.5城市乙4.63.11801.24.1城市丙4.12.2950.64.8失业率取倒数并归一化后城市甲的失业率维度得分最高因为3.5%的失业率是三个城市里最低的。完整归一化矩阵和最终加权结果如下城市归一化后指标5个维度综合得分排名城市甲1.000, 0.667, 1.000, 1.000, 1.0000.9211城市乙0.455, 1.000, 0.378, 0.400, 0.5380.5662城市丙0.000, 0.000, 0.000, 0.000, 0.0000.0003这个结果里城市甲的领先主要来自人均收入、轨道交通、净流入率和失业率四个维度的全面压制城市乙尽管研发投入强度最高但其他维度差距明显总分只能排第二。这说明在城市竞争力评价里单科优势很难对抗综合实力的差距也侧面说明准则层权重设计其实决定了排名的“价值观”——如果你更想突出科技创新导向就应该在第3章把科技创新的权重调高排名可能会随之变化。5. 避坑层析分析法评价城市竞争力时的5个高频翻车点5.1 判断矩阵一致性怎么调都过不了现象输入判断矩阵后CR值一直在0.15甚至0.2以上反复修改几个数字也没有明显改善。原因最常见的是矩阵阶数过高或者两两判断之间存在循环矛盾。比如经济发展比科技创新重要、科技创新比基础设施重要、但基础设施又被填成比经济发展重要形成了ABCA的死循环。这种结构性问题不是改一两个数能解决的。解决先检查矩阵阶数如果准则层超过7个建议合并准则层。然后检查循环矛盾逐一排查“三角关系”。我通常会把判断矩阵导出来按“谁比谁重要”画一棵有向树如果树里出现环回填该环上最不合理的那一对比较。注意调整后重新计算CR不要只改一对因为矩阵是联动的。5.2 指标量纲没归一化就加权结果退化成GDP排名现象综合得分和地区生产总值排名的相关系数高达0.95以上其他指标几乎没发挥作用。原因没有做min-max归一化直接用原始数据乘权重。GDP总量是万亿级研发投入强度是个位数乘权重后GDP主导了几乎所有得分差异。解决所有指标先做正向化和归一化处理再乘权重。检查方式是看归一化后的数据矩阵每一项都应在0到1之间。这一步做完各指标对得分的贡献才是权重的真实体现。5.3 强相关指标重复计权现象经济发展维度里同时放了GDP、财政收入、固定资产投资三个指标权重被堆到0.6以上评价结果和预期明显失衡。原因这三个指标同向性强相当于在判断矩阵里给同一影响因素投了三票。解决在确定指标池时做相关性分析同准则层相关系数超过0.7的只保留一个。我在2.3节提过的这条规则实际项目里至少能帮你砍掉三分之一的冗余指标让判断矩阵更简单、权重分布更均衡。5.4 min-max归一化遇到离群值得分被压扁现象某一个城市的某项指标远超其他城市归一化后其他城市的这项指标得分全部逼近0导致该指标实际上变成了“单一城市优势项”。原因min-max归一化对离群值非常敏感离群值把最大值拉高其余数据被压缩到0.1以下的小区间。解决先看数据分布如果某项指标的最大值是平均值的3倍以上考虑改用百分位归一化或对数变换。百分位归一化用排名代替原始值对数变换压缩长尾。我在正式报告里会同时跑一遍原始min-max和百分位归一化对比两次排名只有结论一致才敢写入报告。5.5 权重依赖单次打分不做稳健性验证现象换了另一组专家打分后权重向量变化很大一些城市的名次出现反转但报告只呈现了一组结果。原因判断矩阵本身具有主观性不同专家对同一对指标的相对重要性判断可能差异明显单次打分只是随机抽取的一个点估计。解决做权重扰动试验。给每个权重加±10%内的随机扰动重跑排名500到1000次统计各城市名次的分布频率。如果某个城市的名次在扰动下频繁波动说明它的得分处于“敏感区间”报告里要明确标注这个不确定性。具体实现我在第6章演示。6. 收尾技巧用权重扰动试验验证排名稳不稳AHP评价最常被质疑的就是“权重太主观”所以我在正式项目里最后一步永远是做权重扰动试验用来检验排名结论的稳健性。做法很简单对第3章算出的权重向量施加±10%的随机扰动多次重跑排名看每个城市的名次分布。import numpy as np base_weights np.array([0.381, 0.236, 0.236, 0.104, 0.043]) normalized_scores np.array([1.000, 0.667, 1.000, 1.000, 1.000]) # 城市甲的数据 # 实际使用时替换为所有城市的归一化数据矩阵 np.random.seed(42) rank_stability {city: [] for city in [城市甲, 城市乙, 城市丙]} for _ in range(1000): noise np.random.uniform(0.9, 1.1, sizebase_weights.shape) perturbed_weights base_weights * noise perturbed_weights perturbed_weights / perturbed_weights.sum() # 重新归一化 scores normalized_scores perturbed_weights # 记录名次此处省略完整城市列表的计算 # 核心逻辑扰动权重后名次基本稳定说明结论可信这段代码的核心逻辑是通过np.random.uniform(0.9, 1.1)生成±10%的随机乘数制造新的权重向量再重算综合得分和排名。如果多次扰动后前三名基本不变说明排序对权重不敏感如果某两个城市的名次反复互换说明它们得分接近需要用更细的指标数据或者补充专家判断来区分。我目前的习惯是单次计算结果只作为参考排行真正的结论来自扰动试验的分布结果。如果扰动后排名波动超过两个位次我会在报告结论里写“该城市处于竞争梯队需要结合更多定性判断”而不是硬给一个精确名次。这套验证逻辑也是AHP和单纯打分排序最大的区别——它至少把主观性变成了可量化的不确定性。我之前有一个项目就是因为省掉了扰动试验排名结果被对方质疑“换个人打分是不是就换一套排名”后来补上这个验证沟通压力小了很多。从那以后这步成了我的固定动作。如果你也在用层析分析法做类似的评价项目强烈建议把这套试验流程跑一遍希望帮到你。本文还有配套的精品资源点击获取