一、层次分析法
1、建立层次结构模型。在深入分析实际问题的基础上,将有关的各个因素按照不同属性自上而下地分解成若干层次,同一层的诸因素从属于上一层的因素或对上层因素有影响,同时又支配下一层的因素或受到下层因素的作用。最上层为目标层,通常只有1个因素,最下层通常为方案或对象层,中间可以有一个或几个层次,通常为准则或指标层。当准则过多时(譬如多于9个)应进一步分解出子准则层。
2、构造成对比较阵。从层次结构模型的第2层开始,对于从属于(或影响)上一层每个因素的同一层诸因素,用成对比较法和1—9比较尺度构造成对比较阵,直到最下层。
3、计算权向量并做一致性检验。对于每一个成对比较阵计算最大特征根及对应特征向量,利用一致性指标、随机一致性指标和一致性比率做一致性检验。若检验通过,特征向量(归一化后)即为权向量:若不通过,需重新构造成对比较阵。
4、计算组合权向量并做组合一致性检验。计算最下层对目标的组合权向量,并根据公式做组合一致性检验,若检验通过,则可按照组合权向量表示的结果进行决策,否则需要重新考虑模型或重新构造那些一致性比率较大的成对比较阵。
例如,某人准备选购一台电冰箱,他对市场上的6种不同类型的电冰箱进行了解后,在决定买那一款式时,往往不是直接拿电冰箱整体进行比较,因为存在许多不可比的因素,而是选取一些中间指标进行考察。例如电冰箱的容量、制冷级别、价格、型号、耗电量、外界信誉、售后服务等。然后再考虑各种型号冰箱在上述各中间标准下的优劣排序。借助这种排序,最终作出选购决策。在决策时,由于6种电冰箱对于每个中间标准的优劣排序一般是不一致的,因此,决策者首先要对这7个标准的重要度作一个估计,给出一种排序,然后把6种冰箱分别对每一个标准的排序权重找出来,最后把这些信息数据综合,得到针对总目标即购买电冰箱的排序权重。有了这个权重向量,决策就很容易了。
# -*- coding: utf-8 -*-
"""
Created on Tue Nov 13 15:37:12 2018
@author: user
"""
"""
AHP demo: 第一层:A, 第二层:B1 B2 B3, 第三层:C1 C2 C3, 完全相关性结构。
"""
import numpy as np
"""
1. 成对比较矩阵
"""
def comparision(W0): # W为每个信息值的权重
n = len(W0)
F = np.zeros([n, n])
for i in range(n):
for j in range(n):
if i == j:
F[i, j] = 1
else:
F[i, j] = W0[i] / W0[j]
return F
"""
2. 单层排序,相对重要度
"""
def ReImpo(F):
n = np.shape(F)[0]
W = np.zeros([1, n])
for i in range(n):
t = 1
for j in range(n):
t = F[i, j] * t
W[0, i] = t ** (1 / n)
W = W / sum(W[0, :]) # 归一化 W=[0.874,2.467,0.464]
return W.T
"""
3. 一致性检验
"""
def isConsist(F):
n = np.shape(F)[0]
a, b = np.linalg.eig(F)
maxlam = a[0].real
CI = (maxlam - n) / (n - 1)
if CI < 0.1:
return bool(1)
else:
return bool(0)
"""
4. 计算综合重要性
"""
def ComImpo(W12, W231, W232, W233): # 综合重要性
# F12=comparision(W12) # 实际应用中可以根据特征的权重求解成对比较矩阵。
# F231=comparision(W231)
# F232=comparision(W232)
# F233=comparision(W233)
F12 = np.array([[1, 1 / 3, 2], [3, 1, 5], [1 / 2, 1 / 5, 1]]) # 此处直接假设出成对比较矩阵
F231 = np.array([[1, 1 / 3, 1 / 5], [3, 1, 1 / 3], [5, 3, 1]])
F232 = np.array([[1, 2, 7], [1 / 2, 1, 5], [1 / 7, 1 / 5, 1]])
F233 = np.array([[1, 1 / 3, 1 / 7], [3, 1, 1 / 5], [7, 5, 1]])
if isConsist(F12) and isConsist(F231) and isConsist(F232) and isConsist(F233):
W12 = ReImpo(F12)
W231 = ReImpo(F231)
W232 = ReImpo(F232)
W233 = ReImpo(F233)
W23 = np.hstack([W231, W232, W233])
else:
print("成对比较矩阵不一致,请调整权重后重试!")
return 0
n = len(W12)
C = np.zeros([1, n])
for i in range(n):
t = W23[i, :]
C[0, i] = sum((W12.T * t)[0])
return C
def main():
print("这里是AHP的演示程序:")
w = np.ones([3]) # W 为成对比较矩阵
C = ComImpo(w, w, w, w)
print('最佳方案为第', np.argmax(C) + 1, '个方案.', '综合推荐指数为', max(C[0, :]))
if __name__ == '__main__':
main()
# print(__name__)
二、优劣解距离法
TOPSIS 法是一种常用的组内综合评价方法,能充分利用原始数据的信息,其结果能精确地反映各评价方案之间的差距。基本过程为基于归一化后的原始数据矩阵,采用余弦法找出有限方案中的最优方案和最劣方案,然后分别计算各评价对象与最优方案和最劣方案间的距离,获得各评价对象与最优方案的相对接近程度,以此作为评价优劣的依据。该方法对数据分布及样本含量没有严格限制,数据计算简单易行。
1、第一步将原始矩阵正向化
根据题意化为同一指标,一般化为极大型指标。
2、将正向化矩阵标准化(消除不同量纲的影响)
3、计算得分并归一化
Z+为每列元素的最大值,
Z-为每列元素的最小值。
Di+为第i行元素每列的元素减本列的最大值元素Z+平方和相加
Di-为第i行元素每列的元素减本列的最小值元素Z-平方和相加
Si为每行元素计算后的得分
要使标准化,则让Si除以所有Si相加后的和即可归一化。
import numpy as np
import xlrd
import pandas as pd
#从excel文件中读取数据
def read(file):
wb = xlrd.open_workbook(filename=file)#打开文件
sheet = wb.sheet_by_index(0)#通过索引获取表格
rows = sheet.nrows # 获取行数
all_content = [] #存放读取的数据
for j in range(1, 5): #取第1~第4列对的数据
temp = []
for i in range(1,rows) :
cell = sheet.cell_value(i, j) #获取数据
temp.append(cell)
all_content.append(temp) #按列添加到结果集中
temp = []
return np.array(all_content)
#极小型指标 -> 极大型指标
def dataDirection_1(datas):
return np.max(datas)-datas #套公式
#中间型指标 -> 极大型指标
def dataDirection_2(datas, x_best):
temp_datas = datas - x_best
M = np.max(abs(temp_datas))
answer_datas = 1 - abs(datas - x_best) / M #套公式
return answer_datas
#区间型指标 -> 极大型指标
def dataDirection_3(datas, x_min, x_max):
M = max(x_min - np.min(datas), np.max(datas) - x_max)
answer_list = []
for i in datas:
if(i < x_min):
answer_list.append(1 - (x_min-i) /M) #套公式
elif( x_min <= i <= x_max):
answer_list.append(1)
else:
answer_list.append(1 - (i - x_max)/M)
return np.array(answer_list)
#正向化矩阵标准化
def temp2(datas):
K = np.power(np.sum(pow(datas,2),axis =1),0.5)
for i in range(0,K.size):
for j in range(0,datas[i].size):
datas[i,j] = datas[i,j] / K[i] #套用矩阵标准化的公式
return datas
#计算得分并归一化
def temp3(answer2):
list_max = np.array([np.max(answer2[0,:]),np.max(answer2[1,:]),np.max(answer2[2,:]),np.max(answer2[3,:])]) #获取每一列的最大值
list_min = np.array([np.min(answer2[0,:]),np.min(answer2[1,:]),np.min(answer2[2,:]),np.min(answer2[3,:])]) #获取每一列的最小值
max_list = [] #存放第i个评价对象与最大值的距离
min_list = [] #存放第i个评价对象与最小值的距离
answer_list=[] #存放评价对象的未归一化得分
for k in range(0,np.size(answer2,axis = 1)): #遍历每一列数据
max_sum = 0
min_sum = 0
for q in range(0,4): #有四个指标
max_sum += np.power(answer2[q,k]-list_max[q],2) #按每一列计算Di+
min_sum += np.power(answer2[q,k]-list_min[q],2) #按每一列计算Di-
max_list.append(pow(max_sum,0.5))
min_list.append(pow(min_sum,0.5))
answer_list.append(min_list[k]/ (min_list[k] + max_list[k])) #套用计算得分的公式 Si = (Di-) / ((Di+) +(Di-))
max_sum = 0
min_sum = 0
answer = np.array(answer_list) #得分归一化
return (answer / np.sum(answer))
def main():
file = 'C:\\Users\\lenovo\Desktop\\数学建模\\TOPSIS法\\第2讲.TOPSIS法(优劣解距离法)7.17\\代码和例题数据\\20条河流的水质情况数据.xlsx'
answer1 = read(file) #读取文件
answer2 = []
for i in range(0, 4): #按照不同的列,根据不同的指标转换为极大型指标,因为只有四列
answer = None
if(i == 0): #本来就是极大型指标,不用转换
answer = answer1[0]
elif(i == 1): #中间型指标
answer = dataDirection_2(answer1[1],7)
elif(i==2): #极小型指标
answer = dataDirection_1(answer1[2])
else: #范围型指标
answer = dataDirection_3(answer1[3],10,20)
answer2.append(answer)
answer2 = np.array(answer2) #将list转换为numpy数组
answer3 = temp2(answer2) #数组正向化
answer4 = temp3(answer3) #标准化处理去钢
data = pd.DataFrame(answer4) #计算得分
#将得分输出到excel表格中
writer = pd.ExcelWriter('C:\\Users\\lenovo\Desktop\\数学建模\\TOPSIS法\\第2讲.TOPSIS法(优劣解距离法)7.17\\代码和例题数据\\A.xlsx') # 写入Excel文件
data.to_excel(writer, 'page_1', float_format='%.5f')#‘page_1’是写入excel的sheet名
writer.save()
writer.close()
main()