Press "Enter" to skip to content

JupyterNotebook做层次分析法(AHP)权重计算

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

1,本Notebook介绍

 

今天这个Notebook,基于简单的测试数据,进行层次分析法(AHP)权重计算算法测试。

 

1.1,层次分析法(AHP)介绍

 

参看《层次分析法(AHP)简介》 层次分析法(Analytic Hierarchy Process,简称 AHP)对一些较为复杂、较为模糊的问题作出决策的简易方法,它特别适用于那些难于完全定量分析的问题。它是美国运筹学家 T.L.Saaty教授于上世纪 70 年代初期提出的一种简便、灵活而又实用的多准则决策方法。层次分析法将与决策有关的元素分解成目标、准则、方案等层次,在此基础之上进行定性和定量分析的决策方法。

 

1.2,测试数据

 

参考《 【AHP】层次分析法原理与Python实现 》,我们假定有一个决策问题,就是某个部门经理要选一个副手,从3个人中选,选择的准则是品德、才能、资历、年龄、与同僚的关系。每个候选人在每个准则上都有对应的打分,即便都是准确的打分,要计算出来选谁也要费些周章。更大的问题是,面对这样的决策,就没法给每个人的每个准则打分,但是,我们可以两两比较给出一个比值,起码孰轻孰重的顺序看起来是对的。通过AHP计算方法,可以验证此前的估计是否符合一定的一致性要求,如果符合的话,得到一个总的评分顺序,也就是得到了最佳候选人。

2,引入numpy库

 

Numpy是一个常用的Python科学技术库,通过它可以快速对数组进行操作,包括形状操作、排序、选择、输入输出、离散傅立叶变换、基本线性代数,基本统计运算和随机模拟等。许多Python库和科学计算的软件包都使用Numpy数组作为操作对象,或者将传入的Python数组转化为Numpy数组,因此在Python中操作数据离不开Numpy。

 

Numpy的核心是ndarray对象,由Python的n维数组封装而来,但通过C语言预编译相关的数组操作,因此比原生Python具有更高的执行效率,但仍然使用Python语言编码,这样就同时具有简洁的代码和高效的运行速度。ndarry与数组有些区别值得注意,numpy数组中的元素都具有相同的类型,并且在创建时就确定了固定的大小,这与Python数组对象可以动态增长不同。

 

# coding:utf-8    
import numpy as np

 

3,定义AHP类

 

定义一个Python的类,主要目的是方便使用,因为同样的运算要用在准则层和方案层,如果准则有n个,方案有m个,那幺在方案层实际上要使用n次。所以,封装成一个类就方便了。

 

AHP类代码摘自《 python实现AHP算法(层次分析法)

 

3.1,AHP类定义的变量

 

array: 记录矩阵相关信息

 

n: 记录矩阵大小

 

RI_list: 初始化RI值,用于一致性检验

 

eig_val, eig_vector: 矩阵的特征值和特征向量

 

max_eig_val: 矩阵的最大特征值

 

max_eig_vector: 矩阵最大特征值对应的特征向量

 

CI_val: 矩阵的一致性指标CI

 

CR_val: 矩阵的一致性比例CR

 

3.2,AHP类定义的方法

 

一致性判断方法:test_consist

 

算术平均法求权重:cal_weight_by_arithmetic_method

 

几何平均法求权重:cal_weight__by_geometric_method

 

特征值法求权重:cal_weight__by_eigenvalue_method

 

class AHP:
    """
    相关信息的传入和准备
    """
​
    def __init__(self, array):
        ## 记录矩阵相关信息
        self.array = array
        ## 记录矩阵大小
        self.n = array.shape[0]
        # 初始化RI值,用于一致性检验
        self.RI_list = [0, 0, 0.52, 0.89, 1.12, 1.26, 1.36, 1.41, 1.46, 1.49, 1.52, 1.54, 1.56, 1.58,
                        1.59]
        # 矩阵的特征值和特征向量
        self.eig_val, self.eig_vector = np.linalg.eig(self.array)
        # 矩阵的最大特征值
        self.max_eig_val = np.max(self.eig_val)
        # 矩阵最大特征值对应的特征向量
        self.max_eig_vector = self.eig_vector[:, np.argmax(self.eig_val)].real
        # 矩阵的一致性指标CI
        self.CI_val = (self.max_eig_val - self.n) / (self.n - 1)
        # 矩阵的一致性比例CR
        self.CR_val = self.CI_val / (self.RI_list[self.n - 1])
​
    """
    一致性判断
    """
​
    def test_consist(self):
        # 打印矩阵的一致性指标CI和一致性比例CR
        print("判断矩阵的CI值为:",str(self.CI_val))
        print("判断矩阵的CR值为:",str(self.CR_val))
        # 进行一致性检验判断
        if self.n == 2:  # 当只有两个子因素的情况
            print("仅包含两个子因素,不存在一致性问题")
        else:
            if self.CR_val < 0.1:  # CR值小于0.1,可以通过一致性检验
                print("判断矩阵的CR值为",str(self.CR_val),",通过一致性检验")
                return True
            else:  # CR值大于0.1, 一致性检验不通过
                print("判断矩阵的CR值为",str(self.CR_val),"未通过一致性检验")
                return False
​
    """
    算术平均法求权重
    """
​
    def cal_weight_by_arithmetic_method(self):
        # 求矩阵的每列的和
        col_sum = np.sum(self.array, axis=0)
        # 将判断矩阵按照列归一化
        array_normed = self.array / col_sum
        # 计算权重向量
        array_weight = np.sum(array_normed, axis=1) / self.n
        # 打印权重向量
        print("算术平均法计算得到的权重向量为:
", array_weight)
        # 返回权重向量的值
        return array_weight
​
    """
    几何平均法求权重
    """
​
    def cal_weight__by_geometric_method(self):
        # 求矩阵的每列的积
        col_product = np.product(self.array, axis=0)
        # 将得到的积向量的每个分量进行开n次方
        array_power = np.power(col_product, 1 / self.n)
        # 将列向量归一化
        array_weight = array_power / np.sum(array_power)
        # 打印权重向量
        print("几何平均法计算得到的权重向量为:
", array_weight)
        # 返回权重向量的值
        return array_weight
​
    """
    特征值法求权重
    """
​
    def cal_weight__by_eigenvalue_method(self):
        # 将矩阵最大特征值对应的特征向量进行归一化处理就得到了权重
        array_weight = self.max_eig_vector / np.sum(self.max_eig_vector)
        # 打印权重向量
        print("特征值法计算得到的权重向量为:
", array_weight)
        # 返回权重向量的值
        return array_weight

 

4,构造判断矩阵

 

4.1,构造准则层的判断矩阵

 

针对目标,我们掂量掂量每个准则相互之间的轻重,用一个比值表示。比如,我们认为从重要性来说:

 

1. 品德是才能的2倍,品德是资历的7倍,品德是年龄的5倍,品德是同僚关系的5倍。那幺为构造出来的行向量就是[1, 2, 7, 5, 5]

 

2. 才能对品德的比较在上一步已经完成了,才能是资历的4倍,才能是年龄的3倍,才能是关系的3倍,那幺构造出来[1/2, 1, 4, 3, 3]

 

3. 以此类推,得到一下矩阵

 

a = np.array([[1, 2, 7, 5, 5],
             [1 / 2, 1, 4, 3, 3],
             [1 / 7, 1 / 4, 1, 1 / 2, 1 / 3],
             [1 / 5, 1 / 3, 2, 1, 1],
             [1 / 5, 1 / 3, 3, 1, 1]])

 

4.2,构造方案层判断矩阵

 

上层准则层有5个准则,需要针对每个准则,掂量掂量两个候选人之间的轻重,毕竟每个人的特长不一样。

上图画了一种情况,作为例子,我们针对品德,构造方案的判断矩阵。面对品德,我们认为两人的重要性来说:

 

1. 张三是李四的1/3倍,张三是李四的1/8倍,那幺行向量就是[1, 1/3, 1/8]

 

2. 剩下只需要比较李四对王五是1/3倍,那幺向量就是[3, 1, 1/3]

 

3. 对应位置取倒数,那幺最后一个向量是[8, 3, 1] 这样就构造出来对应第一个准则的方案的判断矩阵,命名为b1。类似方法用于构造b2, b3, b4, b5

 

b1 = np.array([[1, 1 / 3, 1 / 8], [3, 1, 1 / 3], [8, 3, 1]])
b2 = np.array([[1, 2, 5], [1 / 2, 1, 2], [1 / 5, 1 / 2, 1]])
b3 = np.array([[1, 1, 3], [1, 1, 3], [1 / 3, 1 / 3, 1]])
b4 = np.array([[1, 3, 4], [1 / 3, 1, 1], [1 / 4, 1, 1]])
b5 = np.array([[1, 4, 1 / 2], [1 / 4, 1, 1 / 4], [2, 4, 1]])

 

5,计算权重

 

上面构造的判断矩阵是一个正互反矩阵,在解决计算权重做决策这个问题时,应该出现过很多方法,比如,我们将尝试的算术平均值等,根据《 层次分析法中特征向量法确定权重向量的理论 》,求特征向量是最稳定的方法,为什幺这幺算就可以,看看《理论》那篇文章就能明白个大概。根据《 简述层次分析法(AHP) 》,把每层计算结果再综合在一起,就是最后的结果。

 

下面我们就探索一下。

 

5.1,测试算术平均法求权重

 

# 得到b1的AHP对象,便于后面使用
ahp1 = AHP(b1)
# 算术平均法求权重
weight1 = ahp1.cal_weight_by_arithmetic_method()

 

输出

 

算术平均法计算得到的权重向量为:
 [0.08199023 0.23644689 0.68156288]

 

5.2,测试几何平均法求权重

 

# 几何平均法求权重
weight2 = ahp1.cal_weight__by_geometric_method()

 

输出:

 

几何平均法计算得到的权重向量为:
 [0.68172455 0.2363407  0.08193475]

 

5.3,测试特征值法求权重并检查一致性

 

# 特征值法求权重
weight3 = ahp1.cal_weight__by_eigenvalue_method() 
ahp1.test_consist()

 

输出:

 

特征值法计算得到的权重向量为:
 [0.08193475 0.2363407  0.68172455]
判断矩阵的CI值为: (0.0007708125321126413+0j)
判断矩阵的CR值为: (0.0014823317925243102+0j)
判断矩阵的CR值为 (0.0014823317925243102+0j) ,通过一致性检验
True

 

6,求综合的权重并选出候选人

 

【AHP】层次分析法原理与Python实现 》有完整的实现,本Notebook不再赘述,有兴趣的可以把代码增补进来做实验。本Notebook仅演练一下计算权重向量和验证一致性,最后,算综合权重实际上就是逐层求加权和。如果一致性一直是True的,那幺选出的候选人最后可能是最佳的。

Be First to Comment

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注