从0自学数学建模算法日记1.1———评价决策类——熵权法

本文介绍了如何通过熵值分析消除主观赋值偏差,将多指标正向化和标准化,构建概率矩阵,计算熵权和变异系数,并给出了Python代码示例。同时提到熵权在实际应用中的局限性及可能的人为赋权调整方法如Topsis法。
摘要由CSDN通过智能技术生成

由于此文章是记录为了笔者的学习过程而写的,因为可能在形式上会有些臃肿,且有些废话,若有错误的地方,请指正。

1.介绍

在处理多指标赋权的问题时,可以消除人为主观赋值带来的结果偏差,规避主观因素的影响,提高评价结果的客观性和准确性。

熵的物理意义是体系混乱程度的度量,当一个指标所具有的熵越大,说明其变化的越不确定,便越没有参考价值。

指标的熵值越大 -> 指标信息混乱程度越高 -> 不确定性越大 -> 信息量越小 -> 变异指数越小 -> 指标信息综合评价能力越弱 -> 指标权重越小

熵权由数据本身得出的,但存在许多局限性,例如,指标分为一级指标,二级指标等等,需要人为进行分类,例如计算一个产品是否能增产,则需要从成本,销售情况等,而成本又可以分为二级指标:人工成本,运输成本等。

2.指标类型:

由于每个指标对应的类型可能不同,而为了方便计算,则将其全部正向化

指标类型分为极大型,极小型,中间型,区间型

极大型:即数据越大越好,例如颜值,肯定越好看越好

极小型:即数据越小越好,例如亏损,亏损越少越好

中间型指标:靠近某一个值越好,例如水的ph

区间型指标:靠近某一个区间越好

正向化:即将指标类型全部化为极大型

由于每个指标对应的类型可能不同,而为了方便计算,则将其全部正向化

3.基本步骤

假设有n个参与评价的项目,m个评价指标,则可构建n*m 的矩阵A

1.先将矩阵正向化:(图出自b站up数模加油站)

2.正向化后矩阵标准化

若矩阵中存在负值,由于后面会用到对数,所以不能有负数,则先利用

将矩阵里的值全部化为正数,然后进行标准化

3.计算概率矩阵p(对得到的Z进行归一化处理)

5.计算熵权

计算第j个指标的熵权:

6.计算变异系数

d_j = 1- e_j

7.计算熵权

第j个指标的权重为w_j

w_j = \frac{d_j}{\sum_{j=1}^{m}d_j}

3.python代码演示

1.先输入矩阵A

import numpy as np

print("请输入评价数目")
n = int(input())#由于input得到的为字符,则需要强制类型转化为int
print("请输入指标个数")
m = int(input())

A = np.zeros(shape=(n,m))#np.zeros()将A赋为0矩阵,shape则为A的行与列

print("请输入矩阵")
# 对A的每一行进行操作输入
for i in range(n):
    #将输入的数值按照" "的形式分开形成列表
    A[i] = input().split(" ")
    A[i] = list(map(float, A[i]))

代码解析:1.input().split(" ") 中split是将input中输入以" "空格来进行分割,并将分割后的数据放入一个列表中

a = input().split(" ")
print(a)
print(type(a))

此为运行结果

2.map函数

map()有许多用法,例如做数组的运算,这里只提一种,将数组的元素转化为同一类型

但需要注意的是,进行map()操作后并不会影响a,简单来说map函数是将a的值拿来进行操作,但不赋予a

a = [1,2,3]
print("map前a[0]的类型",type(a[0]))
b = list(map(float,a))
print("map后a[0]的类型",type(a[0]))
print("b的类型",type(b[0]))

运行结果为

而由于a的类型为list,在对a进行map函数操作后,拿出了a中的值,若要赋予给b,则要将值放到一个与a的结构相似的类型中,例如a为list,map函数操作后,由于list与tuple结构类似可将值赋予给元组

2.将矩阵正向化

1.极小型指标正向化

import numpy as np
def minTomax(x): #x为指标所对应的列
    max_1 = max(x)  #取出x中最大值
    #先转换为列表,才能进行列表操作遍历
    x = list(x)
    # 将x中的每一个元素进行 max -e的操作,e为x中元素的值,得到的ans为列表
    ans = [[(max - e)] for e in x]
    return np.array(ans)     #返回矩阵形式

2.中间型指标正向化

def midTomax(x):
    print("请输入最优值")
    best_n = eval(input())
    x = list(x)
    #abs为绝对值
    y = [abs(bestx -e)for e in x]
    max_y = max(y)
    if max_y == 0:
        max_y = 1 #防止最大差值为0,既这个指标全部数相同
    ans = [[(1-e/max_y)] for e in y]
    return np.array(ans) #返回矩阵形式

3.区间型指标正向化

import numpy as np

def regTomax(lowx,highx,x):
     print("请输入区间[a,b]的a:")
     low_a = eval(input())
     print("请输入区间[a,b]的b:")
     high_b = eval(input())
    x = list(x)
    max_1 = max(lowx - min(x),highx - max(x))#求出指标区间最大的距离
    if max_1 == 0:#防止指标全部数相同
        max_1 =1
    ans = []#创建一个空列表

    for i in range(len(x)):#循环x的含有的元素个数的次数

        if x[i] < lowx:    #若元素小于lowx,则计算其与lowx的距离比上max_1(最大距离)
            ans.append([1-(lowx - x[i])/max_1]) #append接长列表
        elif x[i] > highx:#若元素大于highx,则计算其与highx的距离max_1(最大距离)
            ans.append([1-(highx - x[i])/max_1])
        else:#在区间内为一
            ans.append([1])
    return np.array(ans)#返回矩阵形式

代码解析:  

1.eval():即将元素转化为你输入的对应的原本类型

例如:

n = input()
m = eval(input())
# type()函数可以用来检测数据类型
print(type(n))
print(type(m))
#利用eval()将字符串类型转为整形
print(type(eval(n)))

运行结果为:

再例如:

# 输入[1,2,3,4]
m = input()  # 得到一个字符串
n = eval(input())  # 得到一个列表
print(type(m))
print(type(n))
print(type(n[0]))

运行结果为:

由此我们便可以知道,eval函数便是将数据转化为我们所看见的,例如1就是1,不存在字符1,有[ ]就是列表,而不是字符串,其他形式也是如此,例如元组,字典等,以及计算

2.[表达式 for e in ] 

  在3-将正向化后的矩阵标准化中详细解释

3.append,用于接长列表

例:

a = [1,2,3]
print(a)
a.append(4)
print(a)

运行结果:

可以看到,对a接长是直接从a后接上去,改变了a的值,与map()函数不同。

3.将正向化后的矩阵标准化

import numpy as np
for i in range(m):
    min_a = min(A[: ,i])#取出第i列元素的最小值
    max_a = max(A[: ,i])#取出第i列元素的最大值
    if max_a == min_a:
        max_a = max_a +1#避免分母为0
    #防止有负数,全部化为正数
    ans = [ [(e - min_a) / (max_a - min_a)]  for e in A[:, i] ]
    #ans此时为列表形式,需转化为矩阵形式
    b = np.array(ans)
    if i == 0:
        z = b.reshape(-1,1)
    elif i !=0 :
        z = np.hstack([z, b.reshape(-1, 1)])

z = A/ np.sqrt(np.sum(A*A,axis = 0))

代码解析:利用for循环将A中的每一列拿出来进行标准化,A[: , i ]既为A的第i列

利用min()与max()拿出第i列中最小的元素与最大的元素,并进行利用 [表达式 for e in ] 来进行标准化。

e为x的第j个元素,拿出e并且进行运算再以列表的形式储存起来,既e为第j个元素,其进行运算后将其赋值给其创建的列表并也是第j个元素,但也同样不改变x中的元素值

例:

import numpy as np
x = np.array([[1,2,3],
              [3,4,5],
              [4,5,9]])
ans = [ [(e -1 ) / 2]   for e in x[: ,2] ]
print(type(ans))
print(x[:,1])

运行结果:

ans为列表形式,且得到为行向量形式,为了与我们的矩阵对齐,我们需要列向量形式,为转变为列向量形式,为此我们进行numpy的reshape操作,但由于只能对数组操作,则将ans转化为数组形式

b = np.array(ans)

reshape():重新定义数组的形状,reshape(-1,1)则为一列,自动组织行数,便将行向量形式转化为了列向量形式

hstack():水平堆叠函数,可以将行数相同的数组按水平方向堆叠在一起,便可以构造出我们的标准化矩阵。

import numpy as np
x = np.array([[1,2,3],[4,5,6]])
x_1 = x.reshape(-1,2)
print("reshape前 \n{}".format(x))
print("reshape后 \n{}".format(x_1))
y = np.array([[10],[11],[12]])
print(y)
x_2 = np.hstack([x_1 ,y])
print("水平堆叠后 \n{}".format(x_2))

运行结果为:

4.将标准化后的矩阵化为概率矩阵(归一化)并进而算出熵与变异系数

import numpy as np
d = np.zeros(shape=(m))#构建变异系数的数组来储存每个指标对应的变异系数

for i in range(m):
    x = z[:, i]
    x_sum = np.sum(x)
    if x_sum == 0 :
        x_sum = n
        x = np.ones(shape=(n,1))#构造全为一的列向量,由于x_sum要做分母,不能为0
    #概率矩阵p
    p = x / x_sum
    #算熵
    e = -np.sum(p * my_log(p))/np.log(n)
    #信息效用值d
    d[i] = 1-e

由于p_i可能为0,所以不能简单的直接写成ln(p_i),会报错,自定义一个函数my_log用于计算

def my_log(a):
    n = len(a)#算出传入p的长度,以决定循环次数
    lnp = np.zeros(n)
    for i in range(n):
        if p[i] == 0:
            lnp[i] = 0
        else:
            lnp[i] = np.log(p[i])
    return lnp

4.算出熵权

import numpy as np
W = d  / np.sum(d)

由于每个指标的对于人们的重要程度不同,有时数据往往不能真正反映人们对此指标的喜爱,因此也难以达到真正的客观,在此基础可以使用topsis法等赋权方法人为的赋予一个权重,再进行归一化,能真实一点。

  • 44
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,今天我们来学习Python中的字典(Dictionary)。 字典是一种无序的、可变的数据类型,它以键值对(key-value)的形式存储数据,其中键(key)必须是唯一的,而值(value)可以是任意数据类型。字典用花括号{}表示,每个键值对之间用逗号隔开。 下面是一个简单的字典示例: ``` my_dict = {'name': '张三', 'age': 18, 'gender': '男'} ``` 这个字典中,'name'、'age'、'gender'就是键,而'张三'、18、'男'就是相应的值。 可以使用`dict()`函数来创一个字典,也可以使用`{}`来创一个空字典。 接下来,我们来看一些常用的字典操作。 1. 访问字典元素 可以通过键来访问字典中的元素,例如: ``` print(my_dict['name']) # 输出:张三 ``` 如果键不存在,则会抛出KeyError异常。 2. 修改字典元素 可以通过键来修改字典中的元素,例如: ``` my_dict['age'] = 20 print(my_dict) # 输出:{'name': '张三', 'age': 20, 'gender': '男'} ``` 3. 添加字典元素 可以通过键来添加字典中的元素,例如: ``` my_dict['address'] = '北京市' print(my_dict) # 输出:{'name': '张三', 'age': 20, 'gender': '男', 'address': '北京市'} ``` 4. 删除字典元素 可以通过键来删除字典中的元素,例如: ``` del my_dict['gender'] print(my_dict) # 输出:{'name': '张三', 'age': 20, 'address': '北京市'} ``` 5. 字典长度 可以使用`len()`函数来获取字典的长度,例如: ``` print(len(my_dict)) # 输出:3 ``` 6. 字典遍历 可以使用`items()`方来遍历字典中的每一个键值对,例如: ``` for key, value in my_dict.items(): print(key, value) ``` 输出: ``` name 张三 age 20 address 北京市 ``` 通过上述操作,我们可以初步了解字典的基本用。在实际应用中,字典是非常重要的数据类型,它可以用来存储和处理各种复杂的数据结构。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值