基于熵权法的TOPSIS模型
前言
TOPSIS(Technique for Order Preference by Similarity to Ideal Solution)是一种多准则决策分析方法,用于在多个方案之间进行排序。而熵权法是一种用于确定指标权重的方法,它考虑了指标之间的相关性。将这两种方法结合起来,就形成了基于熵权法的TOPSIS模型。
实施基于熵权法的TOPSIS模型的一般步骤:
- 确定决策矩阵: 收集相关的决策信息,形成一个决策矩阵。该矩阵的行代表各个决策方案,列代表不同的决策指标。
- 数据正向化:对于极小型指标、中间性指标、区间型指标,正向化处理的目的是将其转换为越大越好的形式,数据正向化处理在TOPSIS模型前的应用旨在提高决策分析的准确性和可解释性,确保不同类型的指标能够在相同的度量尺度上进行比较,为最终的综合排序提供更有意义的结果。
- 数据标准化: 对决策矩阵进行标准化,确保所有指标具有相同的度量单位。这可以通过将每个元素除以其列的总和来实现,以确保每个指标在[0, 1]的范围内。
- 确定指标权重: 使用熵权法确定每个指标的权重。熵权法考虑了指标的信息熵,指标熵越大,权重越小。计算每个指标的熵,然后计算相对熵,最后得到指标的权重。
- 构造加权决策矩阵: 将每个标准化后的元素乘以其对应的权重,得到加权决策矩阵。
- 确定正理想解和负理想解: 对于每个指标,确定最大值和最小值,分别构成正理想解和负理想解。
- 计算方案与正理想解的相似度和负理想解的相似度: 使用某种距离度量(通常是欧氏距离)计算每个决策方案与正理想解和负理想解的距离。
- 计算综合得分: 对于每个决策方案,计算其相对于正理想解和负理想解的综合得分。通常,综合得分越高,排名越靠前。
- 排序: 根据计算的综合得分对决策方案进行排序,得出最终的排序结果。
TOPSIS模型的基本数学公式:
- 正理想解(PIS):对于每个决策指标 ,正理想解的值 () 是所有方案中该指标的最大值
- 负理想解(NIS)计算每个方案与正理想解和负理想解的距离。通常使用欧氏距离(Euclidean Distance)或其他距离度量 其中 是方案 与正理想解的距离, 是方案 与负理想的距离
- 相似度得分:根据方案与正理想解和负理想解的距离,计算相似度得分 其中 是方案 的相似度得分,该得分越接近1表示方案越优
- 综合得分:根据相似度得分对方案进行排名。综合得分越高,排名越靠前
熵权法基本数学公式:
- 信息熵(Entropy):对于决策指标 ,计算其信息熵的公式如下: 其中, 是第 个方案在第 个指标上的取值, 是决策方案数量
- 信息熵向量:将各个指标的信息熵组成一个向量,即熵向量 其中, 是决策指标的数量
- 信息熵权重:计算每个指标的信息熵权重,即各个指标在整体信息熵中的贡献比例。 其中 表示第 个指标的信息熵权重, 是决策指标的数量
- 最终权重调整:最终,可以对信息熵权重进行归一化处理,确保它们的和为1 这里 是最终的指标权重
通过计算各个指标的信息熵,然后将信息熵转化为指标权重。
代码实现
import pandas as pd
data = pd.read_excel('水质数据.xlsx')
print(data.shape) # 数据维度
print(data.isnull().sum()) # 返回缺失值数量
data.head()
数据集为某四个水池(各15周)水质指标数据,其中总磷、COD(mg/l)、总氮、氨氮为极小型数据,PH为区间型数据(范围为[6,9])。
# 原始数据正向化
def func_1(x):
return(x.max()-x) # 极小型
def func_2(x,x_best):
M = (abs(x-x_best)).max()
return(1-abs(x-x_best)/M) # 中间性
def func_3(x,a,b):
M = max(a-min(x), max(x)-b)
y = []
for i in x:
if i < a:
y.append(1-(a-i)/M)
elif i > b:
y.append(1-(i-b)/M)
else:
y.append(1)
return(y) # 区间型
定义三个函数,函数用于进行原始数据的正向化处理。
func_1(x):
- 类型: 极小型
- 功能: 该函数对输入的数据向量 进行极小型的正向化处理。
- 实现: 对每个元素,计算它与该列的最大值的差,从而将较大的原始值转换为较小的正向化值。
- 公式:
func_2(x, x_best):
- 类型: 中间性
- 功能: 该函数对输入的数据向量 进行中间性的正向化处理,考虑了相对于某个“最佳”解的相对距离。
- 实现: 计算每个元素与对应元素在 中的差的绝对值,并对这些差异进行归一化,以保留相对距离信息。
- 公式:
func_3(x, a, b):
- 类型: 区间型
- 功能: 该函数对输入的数据向量x进行区间型的正向化处理,将元素分别考虑在给定范围内和范围之外的情况。
- 实现: 对于每个元素,根据它与给定范围 的关系,进行不同的正向化处理,使得在范围内的元素被正向化为1,而在范围之外的元素根据其离开范围的距离进行正向化。
- 公式:
如果 则正向化为 如果 则正向化为
如果 则正向化为
data['总磷'] = func_1(data['总磷']) # 极小型
data['总氮'] = func_1(data['总氮']) # 极小型
data['COD(mg/l)'] = func_1(data['COD(mg/l)']) # 极小型
data['氨氮'] = func_1(data['氨氮']) # 极小型
data['PH'] = func_3(data['PH'], 6, 9) # 区间型
通过调用特定的正向化函数,对DataFrame中的几列数据进行了不同类型的正向化处理,以便用于后续的数据分析或模型建设。
import numpy as np
# 标准化
def func(data):
tep_x1 = (data.iloc[:,0::]*data.iloc[:,0::]).sum() # 每个元素平方后按列相加
tep_x2 = np.tile(tep_x1,(data.shape[0], 1)) # 将tep_x1平铺a行
Z = data.iloc[:,::]/((tep_x2)**0.5) # 标准化
return(Z)
data_bzh = func(data)
data_bzh.head()
标准化,即将数据缩放到指定范围(通常是 ),公式为:
其中, 是标准化后的原始, 是原始数据框中的元素, 是第 列的最小值, 是第 列的最大值。
# 熵权法求每个指标权值
P = data_bzh/np.tile(data_bzh.sum(),(data_bzh.shape[0],1)) # 概率矩阵P
E = -1/np.log(data_bzh.shape[0]) * (P*np.log(P)).sum()
D = 1-E
W = D/D.sum() # 熵权
print(W)
代码使用熵权法,通过对标准化数据,计算每个指标的概率矩阵和信息熵,然后通过离散度计算得到每个指标的权值,最终输出一个权值向量 ,用于评估每个指标在多准则决策中的相对重要性。
tep_max = data_bzh.max()
tep_min = data_bzh.min()
D_P = ((((np.tile(tep_max, (data_bzh.shape[0],1))-data_bzh)**2)*np.tile(W, (data_bzh.shape[0],1))).sum(axis = 1))**0.5
D_N = ((((np.tile(tep_min, (data_bzh.shape[0],1))-data_bzh)**2)*np.tile(W, (data_bzh.shape[0],1))).sum(axis = 1))**0.5
S = D_N/(D_P+D_N) # 未归一化得分
代码计算了数据框 data_bzh
中每行的未归一化得分 S
,该得分反映了每个方案相对于理想解和负理想解的距离。具体而言,使用熵权法中的极大型指标,计算每行数据相对于最大值(理想解)和最小值(负理想解)的距离,最终得到未归一化得分。
import matplotlib.pylab as plt
plt.rcParams['font.sans-serif'] = 'SimHei' # 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
df = pd.DataFrame(S)
plt.figure(figsize=(8, 3), dpi = 300)
y1 = df.iloc[0:15, :]
y2 = df.iloc[15:30,:]
y3 = df.iloc[30:45,:]
y4 = df.iloc[45:60,:]
X = range(1, 16)
plt.scatter(X, y1, color= 'k', label='水池#1')
plt.scatter(X, y2, color= 'b', label='水池#2')
plt.scatter(X, y3, color= 'y', label='水池#3')
plt.scatter(X, y4, color= 'r', label='水池#4')
plt.legend(loc='upper left', numpoints=1, ncol=1, fontsize=8, bbox_to_anchor=(1, 1))
plt.title('各水池评价')
plt.xlabel('周数')
plt.ylabel('评价值')
plt.show()
绘制四个水池在不同周数的评价值散点图,展示四个水池每周的评价值分布情况,帮助比较它们的性能。
# 输出每个水池均值评分
print(df.iloc[0:15, :].mean())
print(df.iloc[15:30,:].mean())
print(df.iloc[30:45,:].mean())
print(df.iloc[45:60,:].mean())
本文章转载微信公众号@Python机器学习AI