目录
一、指标正向化
1.极小型指标->极大型指标
2.中间型指标->极大型指标
3.区间型指标->极大型指标
二、标准化处理
三、计算得分并归一化(不带权重)
四、计算得分并归一化(带权重)
熵权法
1)判断输入的矩阵是否存在负数
2)计算第j项指标下第i个样本所占的比重,并将其看作相对熵计算中用到的概率
3)计算每个指标的信息熵,并计算信息效用值,并归一化得到每个指标的熵权
五、代码
5.1 指标正向化
5.2 标准化处理
5.3 计算得分并排序(人工赋权重)
5.4 熵权法
5.5 数据可视化
TOPSIS法是一种常用的综合评价方法,其能充分利用原始数据的信息,其结果能精确反应各评价方案之间的差距。
用TOPSIS法来评定一个人是不是值得恋爱。比如,现在有4个人,他们分别为Terry,xiaofang,smike,jerry.以下为根据他们身边的好朋友对他们的评价得分:
简单的评分方法是直接按评价得分高低排名评分:
不过要用修正后的排名,因为评分越高越好
但是这样会出现一个问题,可以随便修改得分,只要排名不变,评分也不会改变。
所以,我们不能直接按得分排名评价,要构造计算评分的公式:
TOPSIS法步骤如下:
一、指标正向化
好友评分是越大(高)越好,这样的指标称为极大型指标(效益型指标)。
恋爱次数是越少(低)越好,这样的指标称为极小型指标(成本型指标)。
中间型指标:指标值既不要太大也不要太小,取某特定值最好(如水质量评估 PH 值 )
区间型指标:指标值落在某个区间内最好,例如人的体温在36°~37°这个区间比较好。
所以,我们必须的统一指标类型,将所有的指标转化为极大型,即指标正向化。
1.极小型指标->极大型指标
公式:
如果所有的元素均为正数,那么也可以使用
2.中间型指标->极大型指标
举例:
3.区间型指标->极大型指标
上面不好理解也可以看下面这个公式
二、标准化处理
为了消去不同指标量纲的影响,需要对已经正向化的矩阵进行标准化处理。
比如:
三、计算得分并归一化(不带权重)
归一化之后就可以根据数值大小进行排名
区别归一化和标准化:
归一化的目的:为了让结果更容易解释,对结果有一个更加清晰直观的印象。
标准化的目的:消除量纲的影响。
四、计算得分并归一化(带权重)
如何计算权重?
基于熵权法的赋值
熵权法
熵权法是一种客观赋权方法
原理:
指标的变异程度越小,所反映的信息量也越少,其对应的权值也应该越低。
如何度量信息量的大小?
越有可能发生的事情,信息量越少,
越不可能发生的事情,信息量就越多。
怎么衡量事情发生的可能性大小 ?
概率
如何度量信息量的大小?
信息熵越大,则它的值能补充的信息量越大,说明这个值已有的信息量越小,所以信息量越小
熵权法计算步骤:
1)判断输入的矩阵是否存在负数
如果存在负数,就要重新标准化到非负区间。
2)计算第j项指标下第i个样本所占的比重,并将其看作相对熵计算中用到的概率
3)计算每个指标的信息熵,并计算信息效用值,并归一化得到每个指标的熵权
五、代码
import numpy as np
import pandas as pd
data = pd.DataFrame(
{'人均专著': [0.1, 0.2, 0.4, 0.9, 1.2],
'生师比': [5, 6, 7, 10, 2],
'科研经费': [5000, 6000, 7000, 10000, 400],
'逾期毕业率': [4.7, 5.6, 6.7, 2.3, 1.8]},
index=['院校' + i for i in list('ABCDE')])
对五所研究生院进行评价,构造数据如下:
5.1 指标正向化
# 指标正向化
# 结合公式理解代码
# 需要根据题目选择具体的处理方法
# 极小型转为极大型指标
def dataDirection_1(datas, offset=0):
def normalization(data):
return 1 / (data + offset)
return list(map(normalization, datas))
# 中间型指标转为极大型指标
def dataDirection_2(datas, x_min, x_max):
def normalization(data):
if data <= x_min or data >= x_max:
return 0
elif data > x_min and data < (x_min + x_max) / 2:
return 2 * (data - x_min) / (x_max - x_min)
elif data < x_max and data >= (x_min + x_max) / 2:
return 2 * (x_max - data) / (x_max - x_min)
return list(map(normalization, datas))
# 区间型指标转为极大型指标
# [x_min, x_max]最佳稳定区间, [x_minimum, x_maximum]容忍区间
def dataDirection_3(datas, x_min, x_max, x_minimum, x_maximum):
def normalization(data):
if data >= x_min and data <= x_max:
return 1
elif data <= x_minimum or data >= x_maximum:
return 0
elif data > x_max and data < x_maximum:
return 1 - (data - x_max) / (x_maximum - x_max)
elif data < x_min and data > x_minimum:
return 1 - (x_min - data) / (x_min - x_minimum)
return list(map(normalization, datas))
例题数据处理:
# 极小型指标转为极大型
minimum_list = dataDirection_1(data.loc[:,"逾期毕业率"])
minimum_array = np.array(minimum_list)
minimum_4f = np.round(minimum_array, 6)
print(minimum_4f)
# 区间型指标转为极大型
maximum_list = dataDirection_3(data.loc[:,"生师比"], 5, 6, 2, 12)
maximum_array = np.array(maximum_list)
maximum_4f = np.round(maximum_array, 6)
print(maximum_4f)
结果:
[0.212766 0.178571 0.149254 0.434783 0.555556]
[1. 1. 0.833333 0.333333 0. ]
# 指标正向化结果
index_Isotropy = pd.DataFrame()
index_Isotropy["人均专著"] = data["人均专著"]
index_Isotropy["生师比"] = maximum_4f
index_Isotropy["科研经费"] = data["科研经费"]
index_Isotropy["逾期毕业率"] = minimum_4f
print(index_Isotropy)
5.2 标准化处理
# 这里采用归一化,数据处于0-1之间,便于可视化
data_normalization = index_Isotropy / np.sqrt((index_Isotropy ** 2).sum())
print(data_normalization)
5.3 计算得分并排序(人工赋权重)
def topsis(data, weight=None):
# 最优最劣方案(最大值Z^+ 和 最小值)
Z = pd.DataFrame([data.max(), data.min()], index=['正理想解', '负理想解'])
# 距离
weight = entropyWeight(data) if weight is None else np.array(weight)
Result = data.copy()
Result['正理想解'] = np.sqrt(((data - Z.loc['正理想解']) ** 2 * weight).sum(axis=1)) # 评价对象与最大值的距离
Result['负理想解'] = np.sqrt(((data - Z.loc['负理想解']) ** 2 * weight).sum(axis=1))
# 综合得分指数
Result['综合得分指数'] = Result['负理想解'] / (Result['负理想解'] + Result['正理想解'])
Result['排序'] = Result.rank(ascending=False)['综合得分指数']
return Result, Z, weight
# 人工赋权重的结果
weight = [0.2, 0.3, 0.4, 0.1]
Result, Z, weight = topsis(data_normalization, weight)
5.4 熵权法
def entropyWeight(data):
data = np.array(data)
# 计算第j个指标下第i个样本所占的比重,相对熵计算中用到的概率
P = data / data.sum(axis=0) # 压缩行
# 计算熵值
E = np.nansum(-P * np.log(P) / np.log(len(data)), axis=0)
# 信息效用值
d = (1 - E)
# 计算权系数
W = d / d.sum()
return W
entropyWeight(data)
结果:
array([0.41803075, 0.14492264, 0.28588943, 0.15115718])
# 将计算出来的权重代入5.3计算就可以
5.5 数据可视化
这里是对原始数据归一化后以及计算出来的正负理想解进行可视化,便于观察比较各院校特征
使用了雷达图
# 把归一化的结果列的顺序改一下,把‘生师比’放第一个,便于下图展示,不改也可以
data_normalization=data_normalization[['生师比','人均专著', '逾期毕业率', '科研经费']]
data_normalization
from math import pi
import matplotlib.pyplot as plt
# 目标数量
categories = list(data_normalization)[0:]
N = len(categories)
# 角度
angles = [n / float(N) * 2 * pi for n in range(N)]
angles += angles[:1]
# 绘图初始化
plt.figure(dpi=150)
plt.style.use('ggplot')
ax = plt.subplot(111, polar=True)
# 设置第一处
ax.set_theta_offset(pi / 2) # 设置最上面为0°
ax.set_theta_direction(-1) # 设置正方形为顺时针
# 添加背景信息
plt.title("研究生院试评估")
plt.xticks(angles[:-1], categories) # 改变轴标签rotation = 30
plt.xticks(rotation = pi/4,fontsize=6)
ax.set_rlabel_position(30) # 极径标签显示位置
# ax.set_rgrids(np.arange(0.1,0.9,0.1))
plt.yticks(np.arange(0.1,0.9,0.1), ["0.1", "0.2", "0.3","0.4","0.5","0.6","0.7","0.8"], color="grey", size=5) # 设置极径标签区间
plt.ylim(0, 0.8) # 设置极径范围
# 添加数据图
# 第一个
values = data_normalization.loc["院校A"].values.flatten().tolist()
values += values[:1] # 首尾相连
ax.plot(angles, values, linewidth=1, linestyle='solid', color='#d62728',marker='.',markersize=4,label="院校A")
ax.fill(angles, values, '#d62728', alpha=0.2) # 填充线条
# 第二个
values = data_normalization.loc["院校B"].values.flatten().tolist()
values += values[:1]
ax.plot(angles, values, linewidth=1, linestyle='solid',color='#1f77b4',marker='.',markersize=4, label="院校B")
ax.fill(angles, values, '#1f77b4', alpha=0.2)
# 第三个
values = data_normalization.loc["院校C"].values.flatten().tolist()
values += values[:1]
ax.plot(angles, values, linewidth=1, linestyle='solid', color='#9467bd',marker='.',markersize=4,label="院校C")
ax.fill(angles, values, '#9467bd', alpha=0.2)
# 第四个
values = data_normalization.loc["院校D"].values.flatten().tolist()
values += values[:1]
ax.plot(angles, values, linewidth=1, linestyle='solid',color='#7f7f7f', marker='.',markersize=4, label="院校D")
ax.fill(angles, values, '#7f7f7f', alpha=0.2)
# 第五个
values = data_normalization.loc["院校E"].values.flatten().tolist()
values += values[:1]
ax.plot(angles, values, linewidth=1, linestyle='solid',color='#ff7f0e',marker='.',markersize=4, label="院校E")
ax.fill(angles, values, '#ff7f0e', alpha=0.2)
# 最优解
values =Z.loc["正理想解"].values.flatten().tolist()
values += values[:1]
ax.plot(angles, values, linewidth=1, linestyle='solid',color='#2ca02c',marker='.',markersize=4, label="最优解")
ax.fill(angles, values, '#2ca02c', alpha=0.2)
# 最劣解
values =Z.loc["负理想解"].values.flatten().tolist()
values += values[:1]
ax.plot(angles, values, linewidth=1, linestyle='solid',color='#e377c2',marker='.',markersize=4, label="最劣解")
ax.fill(angles, values, '#e377c2', alpha=0.2)
# 添加图例
plt.legend(loc='upper right', bbox_to_anchor=(1.5, 1))
# 显示
plt.show()
可视化结果如下:
参考资料:
原理部分参考了清风数模视频和一篇博客,具体哪篇之前写的时候忘记下来了
代码部分参考了下面知乎这篇,原理讲的也很好,不过这篇没有雷达图的代码,本文补充了这部分代码
TOPSIS法(优劣解距离法)介绍及 python3 实现 - 知乎 (zhihu.com)