【教程地址】:
数学建模导论
https://datawhalechina.github.io/intro-mathmodel/#/
搭配以下内容食用效果更佳:
Python科学计算
https://datawhalechina.github.io/scientific-computing/#/
7.1 层次分析法
7.1.1 层次分析法原理
基本步骤:
** 1.选择指标,建立递阶层次结构模型**
选择指标。在面对评价类问题,选择指标往往需要依据文献研究或社会调查来确定。若缺少明确指标,可通过发放问卷、运用德尔菲法等手段,结合专家意见来构建评价准则。
构造层次模型图。从结构上看,层次分析法将模型大致分为目标层、准则层和方案层。目标层是评价目标,准则层是评价指标体系,方案层是多个对比方案。
** 2.对目标层到准则层之间和准则层到方案层之间构造判断矩阵**
对指标重要性重要性进行两两比较,构造判断矩阵。两个相邻的层次之间是需要构建成对比较矩阵的。矩阵元素 aij 意义:第 i 个指标对第 j 个指标的重要程度。
表中描述的重要性是因素 i 比因素 j 重要的情况下描述的。如果是因素 j 比因素 i 重要,由表中得到的“相对不重要程度”那就用 1~9 的倒数描述即可。
注意:通常来说,对重要性的取值都是取奇数,也就是 1、3、5、7、9,偶数是当不太确定,即认为介于两个奇数程度之间时再取偶数。
在目标层和准则层之间就需要构建第一层比较矩阵。除了准则层外,方案层也需要构建成对比较矩阵。但不同的是,假如有 m 个准则 n 个样本,需要构建的矩阵数量为 m,矩阵大小为(n,n)。每个成对比较矩阵是需要我们自己手动确定的。
** 3.层次单排序和一致性检验**
在层次分析法中构建的判断矩阵是正互反矩阵,方阵中每个元系满足:
若同时,正互反矩阵也满足:
则称其为一致矩阵。
目的:确定构建的判断矩阵是否存在逻辑问题。
原理:检验构子的判断矩阵和一致矩阵是否有太大差别。
步骤:
** 4.计算权重向量**
进行权重计算之前要先对判断矩阵进行一致性检验。
权重的计算有三种方法:
①算数平均法求权重
②几何平均法求权重
③特征值法求权重
求出矩阵A的最大特征值以及其对应的特征向量,对求出的特征向量进行归一化即可得到权重。
** 5.层次总排序和一致性检验**
计算某一层次所有因素对于最高层(目标层)相对重要性的权值,称为层次总排序。该过程是从最高层次向最低层次依次进行的。
设上一层次(A层)包含A1,...,Am共m个因素,它们的层次总排序权重分别为 a1,...,am。又设其后的下一层次(B层)包含n个因素B1,...,Bn,它们关于Aj的层次单排序权重分别为b1j,...,bnj。
对层次总排序也需作一致性检验,检验仍像层次总排序那样由高层到低层逐层进行。这是因为当综合考察时,各层次的非一致性仍有可能积累起来, 引起最终分析结果较严重的非一致性。
** 6.求权重后进行评价**
根据权重和方案的评分进行综合评价。
7.1.2 层次分析法案例
为了更好地理解层次分析法的应用,我们来看一个具体的案例——水质评价。
例 7.1 某日从三条河流的基站处抽检水样,得到了水质的四项检测指标如表 5.1 所示。请根据提供数据对三条河流的水质进行评价。其中,DO 代表水中溶解氧含量,越大越好;CODMn 表示水中高锰酸盐指数,NH3-N 表示氨氮含量,这两项指标越小越好;pH 值没有量纲,在 6~9 区间内较为合适。
例 7.1数据
地点名称pH*DOCODMnNH3-N四川攀枝花龙洞7.949.471.630.077重庆朱沱8.1591.40.417湖北宜昌南津关8.068.452.830.203
首先,构建一个层次结构模型。该评价问题一共有三个样本,四个评价指标,根据所给评价指标,构建层次模型图:
接下来,需对准则层的各因素进行成对比较,构建成对比较矩阵。对目标层到准则层构建一个大小为 4 的方阵,准则层到方案层构建 4 个大小为 3 的方阵。例如:
变量pHDOCODMnNH3-NpH1.001/51/31DO5.00135CODMn3.001/313NH3-N1.001/51/31
通过特征值分解的方法,计算出成对比较矩阵的最大特征值和对应的特征向量,进而得到权重向量,代码如下:
import numpy as np
# 构建矩阵
A=np.array([[1,1/5,1/3,1],[5,1,3,5],[3,1/3,1,3],[1,1/5,1/3,1]])#获得指标个数
m=len(A)
n=len(A[0])
RI=[0,0,0,0.58,0.90,1.12,1.24,1.32,1.41,1.45,1.49,1.51]#求判断矩阵的特征值和特征向量,V为特征值,D为特征向量
V,D=np.linalg.eig(A)
list1=list(V)#求矩阵的最大特征值
B=np.max(list1)
index=list1.index(B)
C=D[:,index]
计算一致性指标(CI)和一致性比率(CR),检验成对比较矩阵的一致性。
CI=(B-n)/(n-1)
CR=CI/RI[n]
if CR<0.10:
print("CI=",CI)
print("CR=",CR)
print("对比矩阵A通过一致性检验,各向量权重向量Q为:")
C_sum=np.sum(C)
Q=C/C_sum
print(Q)
else:
print("对比矩阵A未通过一致性检验,需对对比矩阵A重新构造")
结果输出如下:
CI= (0.014497820535966117+0j)
CR= (0.0161086894844068+0j)
对比矩阵A通过一致性检验,各向量权重向量Q为:
[0.09546368-0.j 0.55958606-0.j 0.24948658-0.j 0.09546368-0.j]
分解出来的权重向量为什么是个复数?python 进行矩阵分解的时候是在复数域内进行分解,所得到的向量也是复数向量。虚部为 0 的情况下想要单独分析实部,通过 Q.real 即可达成取实部的效果。
计算出目标层到准则层的 1 个权重向量和 4 个准则层到方案层的权重向量以后,可以列出下表将权重向量进行排布。
例 7.1 中 4 个权重向量的排布
地点名称pH*DOCODMnNH3-N得分0.09550.55960.24950.0955四川攀枝花龙洞0.41660.53960.2970.6370.4767重庆朱沱0.32750.2970.53960.10470.3421湖北宜昌南津关0.25990.16340.16340.25830.1817
将准则层到方案层得到的 7 个成对比较矩阵对应的权重向量排列为一个矩阵,矩阵的每一行表示对应的方案,矩阵的每一列代表评价准则。将这一方案权重矩阵与目标层到准则层的权重向量进行数量积,得到的分数就是最终的评分。最终得到的一个结论是:在评价过程中水中溶解氧含量与钴金属含量占评价体系比重最大,而四川攀枝花龙洞的水质虽然含钴元素比另外两个更高,但由于溶解氧更多,NH3-N 的含量更小,水体不显富营养化。就整体而言,四川攀枝花龙洞得分高于重庆朱沱和湖北宜昌南津关。
将一个成对比较矩阵的 AHP 过程封装为函数,完整函数如下。
def AHP(A):
m = len(A) # 获取指标个数
n = len(A[0])
RI = [0,0, 0, 0.58, 0.90, 1.12, 1.24, 1.32, 1.41, 1.45, 1.49, 1.51]
R = np.linalg.matrix_rank(A) # 求判断矩阵的秩
V, D = np.linalg.eig(A) # 求判断矩阵的特征值和特征向量,V特征值,D特征向量;
list1 = list(V)
B = np.max(list1) # 最大特征值
index = list1.index(B)
C = D[:, index] # 对应特征向量
CI = (B - n) / (n - 1) # 计算一致性检验指标CI
CR = CI / RI[n]
if CR < 0.10:
print("CI=", CI.real)
print("CR=", CR.real)
print('对比矩阵A通过一致性检验,各向量权重向量Q为:')
sum = np.sum(C)
Q = C / sum # 特征向量标准化
print(Q.real) # 输出权重向量
return Q.real
else:
print("对比矩阵A未通过一致性检验,需对对比矩阵A重新构造")
return 0
7.1.3层次分析法代码
例7.1
import numpy as np
# 准则层和方案层的成对比较矩阵
criteria_matrix = np.array([
[1, 1/5, 1/3, 1],
[5, 1, 3, 5],
[3, 1/3, 1, 3],
[1, 1/5, 1/3, 1]
])
# 方案层的原始数据
data = np.array([
[7.94, 9.47, 1.63, 0.077], # 四川攀枝花龙洞
[8.15, 9.00, 1.40, 0.417], # 重庆朱沱
[8.06, 8.45, 2.83, 0.203] # 湖北宜昌南津关
])
# 计算权重的函数
def calculate_weights(matrix):
eigenvalues, eigenvectors = np.linalg.eig(matrix)
max_index = np.argmax(eigenvalues)
eigenvector = eigenvectors[:, max_index] / np.sum(eigenvectors[:, max_index])
return eigenvector
# 一致性检验的函数
def consistency_check(matrix):
eigenvalues, _ = np.linalg.eig(matrix)
max_eigenvalue = np.max(eigenvalues)
CI = (max_eigenvalue - matrix.shape[0]) / (matrix.shape[0] - 1)
RI_values = [0,0, 0, 0.58, 0.90, 1.12, 1.24, 1.32, 1.41, 1.45, 1.49, 1.51] # 根据矩阵阶数选择
RI = RI_values[matrix.shape[0]]
CR = CI / RI
return CI, CR
# 标准化处理数据的函数
def normalize_data(data):
max_values = np.max(data, axis=0)
min_values = np.min(data, axis=0)
normalized_data = (data - min_values) / (max_values - min_values)
# 对CODMn和NH3-N进行逆极差标准化
normalized_data[:, 2] = 1 - normalized_data[:, 2]
normalized_data[:, 3] = 1 - normalized_data[:, 3]
return normalized_data
# 计算方案得分的函数(修正后)
def calculate_scores(normalized_data, weights):
return np.dot(normalized_data, weights)
# 主程序
def main():
# 计算准则层权重
criteria_weights = calculate_weights(criteria_matrix)
print("准则层权重:", criteria_weights.real)
# 进行一致性检验
CI, CR = consistency_check(criteria_matrix)
print("一致性指标CI:", CI.real)
print("一致性比率CR:", CR.real)
# 标准化处理数据
normalized_data = normalize_data(data)
# 计算方案的综合得分
scores = calculate_scores(normalized_data, criteria_weights)
print("各方案的综合得分:")
for i, score in enumerate(scores):
print(f"方案 {i+1}: {score.real}") # Ensure to print real part of complex numbers
# 根据得分对方案进行排序
sorted_indices = scores.argsort()[::-1]
print("方案排序(水质从好到差):", sorted_indices + 1) # 将索引转换为实际方案编号
if __name__ == "__main__":
main()
输出结果:
准则层权重: [0.09546368 0.55958606 0.24948658 0.09546368]
一致性指标CI: 0.014497820535966117
一致性比率CR: 0.0161086894844068
各方案的综合得分:
方案 1: 0.8644091087319299
方案 2: 0.6466878399762959
方案 3: 0.1146366370978105
方案排序(水质从好到差): [1 2 3]
版权归原作者 moon(ight 所有, 如有侵权,请联系我们删除。