算法的背景
前两节讲到的层次分析法确定权重是通过主观给定的,那么有没有什么方法能够直接分配权重,这时候就提出了熵权法。
熵权法是一种客观的赋权方法,依靠数据本身来得出权重
原理:指标的变异程度越小,所反映的信息也越少,其对应的权值也应该越小
基本步骤
1.数据标准化
在对数据进行标准化之前,还需要对数据先进行正向化,可以参考上一节中的矩阵正向化求法
2.计算概率矩阵p
3.计算熵权
通过公式可以得到以下定理:当=
=……=
=
时,信息熵最大,数值为1,即无实用性
这里插播一个概念,信息熵:一个物理学概念,表示信息的不确定度,数值为1时表示信息全部相同。
定义信息效用值=1 -
再对信息效用值进行归一化处理得到熵权=
python代码
import numpy as np # 导入numpy库,并简称为np
def mylog(p):# 定义一个自定义的对数函数mylog,用于处理输入数组中的零元素
n = len(p) # 获取输入向量p的长度
lnp = np.zeros(n) # 创建一个长度为n,元素都为0的新数组lnp
for i in range(n): # 对向量p的每一个元素进行循环
if p[i] == 0: # 如果当前元素的值为0
lnp[i] = 0 # 则在lnp中对应位置也设置为0,因为log(0)是未定义的,这里我们规定为0
else:
lnp[i] = np.log(p[i]) # 如果p[i]不为0,则计算其自然对数并赋值给lnp的对应位置
return lnp # 返回计算后的对数数组
# 定义一个指标矩阵X
#X = np.array([[9, 0, 0, 0], [8, 3, 0.9, 0.5], [6, 7, 0.2, 1]])
print("请输入矩阵行数:")
n = int(input())
print("请输入矩阵列数:")
m = int(input())
print("请输入矩阵:")
X = np.zeros(shape=(n, m)) # 初始化一个n行m列的全零矩阵A
for i in range(n):
X[i] = input().split(" ") # 接收每行输入的数据,假设用户输入了 "1.5 2.3 3.7",则 input().split(" ") 返回 ["1.5", "2.3", "3.7"]
X[i] = list(map(float, X[i])) # 将接收到的字符串列表转换为浮点数列表,接下来,list(map(float, ["1.5", "2.3", "3.7"])) 将返回 [1.5, 2.3, 3.7],即一个浮点数列表。
print("输入矩阵为:\n{}".format(X)) # 打印输入的矩阵A
# 对矩阵X进行标准化处理,得到标准化矩阵Z
Z = X / np.sqrt(np.sum(X*X, axis=0))#按列求和
print("标准化矩阵 Z = ")
print(Z) # 打印标准化矩阵Z
# 计算熵权所需的变量和矩阵初始化
n, m = Z.shape # 获取标准化矩阵Z的行数和列数
D = np.zeros(m) # 初始化一个长度为m的数组D,用于保存每个指标的信息效用值
# 计算每个指标的信息效用值
for i in range(m): # 遍历Z的每一列
x = Z[:, i] # 获取Z的第i列,即第i个指标的所有数据
p = x / np.sum(x) # 对第i个指标的数据进行归一化处理,得到概率分布p
# 使用自定义的mylog函数计算p的对数。需要注意的是,如果p中含有0,直接使用np.log会得到-inf,这里使用自定义函数避免这个问题
e = -np.sum(p * mylog(p)) / np.log(n) # 根据熵的定义计算第i个指标的信息熵e
D[i] = 1 - e # 根据信息效用值的定义计算D[i]
# 根据信息效用值计算各指标的权重
W = D / np.sum(D) # 将信息效用值D归一化,得到各指标的权重W
print("权重 W = ")
print(W) # 打印得到的权重数组W