目录

一、指标正向化

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 npimport pandas as pddata = 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_max:return 0elif data > x_min and data < (x_min + x_max) / 2:return 2 * (data - x_min) / (x_max - x_min)elif 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 1elif data = x_maximum:return 0elif data > x_max and data < x_maximum:return 1 - (data - x_max) / (x_maximum - x_max)elif 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_4findex_Isotropy["科研经费"] = data["科研经费"]index_Isotropy["逾期毕业率"] = minimum_4fprint(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 WentropyWeight(data)结果:array([0.41803075, 0.14492264, 0.28588943, 0.15115718])# 将计算出来的权重代入5.3计算就可以

5.5 数据可视化

这里是对原始数据归一化后以及计算出来的正负理想解进行可视化,便于观察比较各院校特征

使用了雷达图

# 把归一化的结果列的顺序改一下,把‘生师比’放第一个,便于下图展示,不改也可以data_normalization=data_normalization[['生师比','人均专著','逾期毕业率', '科研经费']]data_normalization
from math import piimport 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 = 30plt.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)