基础理论介绍:层次分析法(AHP)和模糊层次分析法(FAHP)-CSDN博客
本篇博客用来记录层次分析法(AHP)和模糊层次分析法(FAHP)实现过程,进一步学习两种方法的求解过程,体会两种算法的不同之处。
一、层次分析法(AHP)
以这篇博文中所提出的案例作为待决策事件。
大体步骤主要包括四个:层次结构模型的构建;构造判断矩阵;层次单排序及其一致性检验;层次总排序及其一致性检验(没有决策层的话可以省略此步骤)。
推荐工具SPSSPRO
1.层次结构模型的构建
将此待决策事件分解为:
- 目标层:选择旅行地
- 准则层:选择旅行目的地考虑的因素(景色、费用、居住、饮食、旅途)
- 方案层:旅游目的地(苏杭、北戴河、桂林)
2.构造判断矩阵
景色 | 费用 | 居住 | 饮食 | 旅途 | |
景色 | 1 | 5 | 5 | 1/3 | 8 |
费用 | 1/5 | 1 | 1/4 | 1/6 | 2 |
居住 | 1/5 | 4 | 1 | 1/5 | 3 |
饮食 | 3 | 6 | 5 | 1 | 6 |
旅途 | 1/8 | 1/2 | 1/3 | 1/6 | 1 |
对角线上是各个指标对自己的判断,自身对标自身均是1:1,其他相对重要性的判断依据下表进行判别。
3.层次单排序及其一致性检验
层次单排序是指针对上一层某元素将本层中所有元素两两评比,并开展层次排序, 进行重要顺序的排列。计算方法在基础理论介绍中有详细解释,这里就不再赘述。
4.层次总排序及其一致性检验
层次总排序是指计算某一层次所有因素对于最高层(目标层)相对重要性的权值,称为层次总排序。该过程是从最高层次向最低层次依次进行。
专业性解释:
设B层对A层中因素的层次排序一致性指标为CIi,随机性一致性指标为RIi,则层次总排序的一致性比率为:
同样也是通过看CR是否小于0.1判断是否满足一致性检验 。
通俗来说,就是将准则层的步骤再重复一遍,即:
景色 | 苏杭 | 北戴河 | 桂林 |
苏杭 | 1 | 2 | 5 |
北戴河 | 1/2 | 1 | 2 |
桂林 | 1/5 | 1/2 | 1 |
费用 | 苏杭 | 北戴河 | 桂林 |
苏杭 | 1 | 1/3 | 1/8 |
北戴河 | 3 | 1 | 1/3 |
桂林 | 8 | 3 | 1 |
居住 | 苏杭 | 北戴河 | 桂林 |
苏杭 | 1 | 1 | 3 |
北戴河 | 1 | 1 | 3 |
桂林 | 1/3 | 1/3 | 1 |
饮食 | 苏杭 | 北戴河 | 桂林 |
苏杭 | 1 | 3 | 4 |
北戴河 | 1/3 | 1 | 1 |
桂林 | 1/4 | 1 | 1 |
旅途 | 苏杭 | 北戴河 | 桂林 |
苏杭 | 1 | 1 | 1/4 |
北戴河 | 1 | 1 | 1/4 |
桂林 | 4 | 4 | 1 |
计算出的权重向量分别为:
苏杭 | 北戴河 | 桂林 | |
景色 | 0.5954 | 0.2764 | 0.1283 |
苏杭 | 北戴河 | 桂林 | |
费用 | 0.0819 | 0.2363 | 0.6817 |
苏杭 | 北戴河 | 桂林 | |
居住 | 0.4286 | 0.4286 | 0.1429 |
苏杭 | 北戴河 | 桂林 | |
饮食 | 0.6337 | 0.1919 | 0.1744 |
苏杭 | 北戴河 | 桂林 | |
旅途 | 0.1667 | 0.1667 | 0.6667 |
因此,对于苏杭这个旅行地方案来说,总得分为:
苏杭在景色上的得分*景色的权重+苏杭在费用上的得分*费用的权重+苏杭在居住上的得分*居住的权重+苏杭在饮食上的得分*饮食的权重+苏杭在旅途上的得分*旅途的权重=0.5954*0.3104+0.819*0.0591+0.4286*0.1157+0.6337*0.4716+0.1667*0.0432=0.5889
同理算出,北戴河和桂林方案的得分为0.2471和0.2077
(这里就必须推荐SPSSPRO-免费专业的在线数据分析平台,真的非常好用,不用自己去计算,而且在代码里面引用比较方便)
代码部分
import numpy as np
from functools import reduce
def ahp_method(dataset, wd = 'm'):
# 随机一致性指标R.I.(inc_rat)
inc_rat = np.array([0, 0, 0, 0.58, 0.9, 1.12, 1.24, 1.32, 1.41, 1.45, 1.49, 1.51, 1.48, 1.56, 1.57, 1.59])
# 数据深复制
X = np.copy(dataset)
# 生成权重向量
weights = np.zeros(X.shape[1])
# 根据权重计算方法来确定各个权重
if (wd == 'm' or wd == 'mean'): #均值
weights = np.mean(X/np.sum(X, axis = 0), axis = 1)
elif (wd == 'g' or wd == 'geometric'): #几何
for i in range (0, X.shape[1]):
weights[i] = reduce( (lambda x, y: x * y), X[i,:])**(1/X.shape[1])
weights = weights/np.sum(weights)
# 计算特征根向量
vector = np.sum(X*weights, axis = 1)/weights
# 获得平均特征根
lamb_max = np.mean(vector)
# 计算一致性指标
cons_ind = (lamb_max - X.shape[1])/(X.shape[1] - 1)
# 一致性判断
rc = cons_ind/inc_rat[X.shape[1]]
return weights, rc
##判断矩阵和打分矩阵
A = np.array([
[1, 5, 5, 1 / 3, 8],
[1 / 5, 1, 1 / 4, 1 / 6, 2],
[1 / 5, 4, 1, 1 / 5, 3],
[3, 6, 5, 1, 6],
[1 / 8, 1 / 2, 1 / 3, 1 / 6, 1],
])
A_1 = np.array([
[1, 2, 5],
[1 / 2, 1, 2],
[1 / 5, 1 / 2, 1],
])
A_2 = np.array([
[1, 1 / 3, 1 / 8],
[3, 1, 1 / 3],
[8, 3, 1],
])
A_3 = np.array([
[1, 1, 3],
[1, 1, 3],
[1 / 3, 1 / 3, 1],
])
A_4 = np.array([
[1, 1 / 3, 4],
[1 / 3, 1, 1],
[1 / 4, 1, 1],
])
A_5 = np.array([
[1, 1, 1 / 4],
[1, 1, 1 / 4],
[4, 4, 1],
])
# 计算权重和RI
weight_A, RC_A = ahp_method(A)
print('A的权重为:', weight_A)
print('A的RC为:', RC_A)
print()
weight_A1, RC_A1 = ahp_method(A_1)
weight_A2, RC_A2 = ahp_method(A_2)
weight_A3, RC_A3 = ahp_method(A_3)
weight_A4, RC_A4 = ahp_method(A_4)
weight_A5, RC_A5 = ahp_method(A_5)
print('A1的权重为:', weight_A1)
print('A1的RC为:', RC_A1)
print('A2的权重为:', weight_A2)
print('A2的RC为:', RC_A2)
print('A3的权重为:', weight_A3)
print('A3的RC为:', RC_A3)
print('A4的权重为:', weight_A4)
print('A4的RC为:', RC_A4)
print('A5的权重为:', weight_A5)
print('A5的RC为:', RC_A5)
## 构建V矩阵
V = np.vstack((weight_A1, weight_A2, weight_A3, weight_A4, weight_A5))
print(V)
scores = np.matmul(weight_A, V)
print('综合评分为:', scores)
二、模糊层次分析法(FAHP)
背景:三角模糊数概念
三角模糊数 ,、和分别为下界、中值和上界,其隶属函数表示为:
假设有 和,则有:
1.建立三角模糊判断矩阵
已知第K个专家评价结果:
2.计算专家判断平均数,更新判断矩阵
当存在K个专家时,计算专家判断的平均数,表达式如下:
则更新后的判断矩阵为:
3.计算几何平均值
计算每个标准的模糊判断值的几何平均值,如下:
4.计算模糊权重
求解每个的矢量和,求矢量和向量的逆向量,计算与矢量和向量的逆向量,如下:
5.反模糊化计算
6.归一化处理
代码部分
import numpy as np
def fuzzy_ahp_method(dataset):
'''
dataset: 专家判断矩阵,n*n*3,n表示指标数
'''
row_sum = []
s_row = []
f_w = [] # 模糊权重
d_w = [] # 去模糊权重
# 一致性检测指标
inc_rat = np.array([0, 0, 0, 0.58, 0.9, 1.12, 1.24, 1.32, 1.41, 1.45, 1.49, 1.51, 1.48, 1.56, 1.57, 1.59])
# 模糊判断矩阵转为清晰判断矩阵
X = [(item[0] + 4 * item[1] + item[2]) / 6 for i in range(0, len(dataset)) for item in dataset[i]] # 三角数转为模糊数
X = np.asarray(X) # 列表转数组
X = np.reshape(X, (len(dataset), len(dataset))) # 转为n*n矩阵
# S4. 计算每个准则的模糊比较值的几何平均值r_i(公式4)
for i in range(0, len(dataset)):
a, b, c = 1, 1, 1
for j in range(0, len(dataset[i])):
d, e, f = dataset[i][j]
# 计算公式(4)的括号内部分: r_s = \prod_{j=1}^n d_ij
a, b, c = a * d, b * e, c * f
row_sum.append((a, b, c))
L, M, U = 0, 0, 0
for i in range(0, len(row_sum)):
a, b, c = row_sum[i]
# 计算公式(4)的括号外部分: s_r = (r_s)^(1/n)
a, b, c = a ** (1 / len(dataset)), b ** (1 / len(dataset)), c ** (1 / len(dataset))
s_row.append((a, b, c))
# 计算公式(5)中⨁运算部分:R5 = r1⨁r2⨁...⨁rn
L = L + a
M = M + b
U = U + c
for i in range(0, len(s_row)):
a, b, c = s_row[i]
# 计算公式公式(5)中⨂运算部分:wi = ri⨂R5
a, b, c = a * (U ** -1), b * (M ** -1), c * (L ** -1)
# 模糊权重
f_w.append((a, b, c))
# 计算公式(6):去模糊权重
d_w.append((a + b + c) / 3)
# 计算公式(7): 归一化权重
n_w = [item / sum(d_w) for item in d_w]
# 计算特征根向量
vector = np.sum(X * n_w, axis=1) / n_w
# 获得平均特征根
lamb_max = np.mean(vector)
# 计算一致性指标
cons_ind = (lamb_max - X.shape[1]) / (X.shape[1] - 1)
# 一致性判断
rc = cons_ind / inc_rat[X.shape[1]]
return f_w, d_w, n_w, rc
dataset = list([
[(1, 1, 1), (4, 5, 6), (3, 4, 5), (6, 7, 8)], # g1
[(1 / 6, 1 / 5, 1 / 4), (1, 1, 1), (1 / 3, 1 / 2, 1 / 1), (2, 3, 4)], # g2
[(1 / 5, 1 / 4, 1 / 3), (1, 2, 3), (1, 1, 1), (2, 3, 4)], # g3
[(1 / 8, 1 / 7, 1 / 6), (1 / 4, 1 / 3, 1 / 2), (1 / 4, 1 / 3, 1 / 2), (1, 1, 1)] # g4
])
fuzzy_weights, defuzzified_weights, normalized_weights, rc = fuzzy_ahp_method(dataset)
print('模糊权重')
for i in range(0, len(fuzzy_weights)):
print('g' + str(i + 1) + ': ', np.around(fuzzy_weights[i], 3))
print('清晰权重')
for i in range(0, len(defuzzified_weights)):
print('g' + str(i + 1) + ': ', round(defuzzified_weights[i], 3))
print('归一化权重')
for i in range(0, len(normalized_weights)):
print('g' + str(i + 1) + ': ', round(normalized_weights[i], 3))
print('一致性判断')
print('RC: ' + str(round(rc, 2)))
if (rc > 0.10):
print('The solution is inconsistent, the pairwise comparisons must be reviewed')
else:
print('The solution is consistent')