熵值法
概述
熵值法是基于信息熵(或简称熵)的一种信息管理方法。根据熵的特性,可以据此判断出一个事件的随机性以及无序程度,也可以基于熵值判断某个指标的离散程度。离散程度越大,即信息量越大,不确定性就越小,熵也就越小;信息量越小,不确定性越大,熵也越大。基于该思想,熵值法只考虑数据内部的信息量大小,有效地避免了人为主观因素的影响。
熵值法原理及实例讲解
步骤:
(1). 数据的非负化处理;
(2). 计算第j个指标下第i个方案占该指标的比重;
(3). 计算第j箱指标的熵值
注:上述链接中存在一处错去:这里的常数k=1/ln(n).n
表示样本个数,而不是指标个数。
(4). 计算第j项指标的差异系数;
(对于第j箱指标,指标值的差异越大,对方案评价的作用越大,熵值就越小。)
(5). 求权数:保证权重之和为1;
(6). 计算各方案的得分。
代码实现
# -*- coding=utf-8-*-
# author :Han X.Y
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
import math
class EntropyWeights:
"""
这个类用来实现熵值法
"""
def __init__(self, store_path=None, data=None, vars_num=None, maxValue_vars=None,
minValue_vars=None):
"""
初始化
:param store_path: 数据文件的存储路径
:param data: 若无需导数据,则可指定到具体数据集
:param vars_num: 变量个数,默认是从前往后看
:param maxValue_vars: 高优指标个数
:param minValue_vars: 低优指标个数
"""
# 高优指标
self.maxValue_vars = maxValue_vars
# 低优指标
self.minValue_vars = minValue_vars
# 原始指标名称
self.raw_var_names = None
# 原始指标个数
self.vars_num = vars_num
# 基础数据集的存储路径
self.raw_data_store_path = store_path
self.raw_data = data
def getReadData(self):
"""
读入原始数据
:return:
"""
if self.raw_data is None:
data = pd.read_csv(self.raw_data_store_path, encoding='utf-8', index_col=0)
self.raw_data = data
data = self.raw_data
data_colnames = data.columns
if self.vars_num is None or \
self.maxValue_vars is None or \
self.minValue_vars is None:
print("请输入关键参数{vars_num,maxValue_vars,minValue_vars}")
# 其他
self.raw_var_names = data_colnames[:self.vars_num] # 变量指标
# self.maxValue_vars = self.raw_var_names[:2] # 高优指标
# self.minValue_vars = self.raw_var_names[2:] # 低优指标
# self.vars_num = len(data_colnames[:-1]) # 总的指标个数
# 基础数据
self.raw_data = data
# 非负化数据
self.non_neg_data = None
self.k = None
# 熵值
self.entropy_values = None
# 变异系数
self.G_values = None
# 最终的权重
self.final_weights = None
def precess_1_to_NNeg(self):
"""
进行非负化处理
:return:
"""
data = self.raw_data
colnames = self.raw_var_names
# tmp_data = data.copy()
# for name in colnames:
# tmp_data = tmp_data[tmp_data[name] > 0]
# if tmp_data.shape[0] == data.shape[0]:
# print(f"不存在负数,不需要进行非负化处理")
# self.non_neg_data = data[self.raw_var_names]
# else:
scaler = MinMaxScaler().fit(data[self.raw_var_names])
tmp_data = pd.DataFrame(scaler.transform(data[self.raw_var_names]), columns=self.raw_var_names,
index=self.raw_data.index)
print("tmp_data", tmp_data)
# 低优指标的计算方法与高优指标的计算不同
if len(self.minValue_vars) > 0:
for name in self.minValue_vars:
tmp_data[name] = tmp_data[[name]].apply(lambda x: 1 - x, axis=0)
print("分高优指标、和低优指标进行非负化处理")
self.non_neg_data = tmp_data
else:
self.non_neg_data = tmp_data
def calElementsProAndEntropy(self):
"""
计算各元素的比重和熵值
:return:
"""
self.k = 1 / math.log(self.raw_data.shape[0]) # 计算常数k
data = self.non_neg_data.copy()
for name in self.raw_var_names:
data[name] = data[[name]].apply(lambda x: (x + 1) / sum(x + 1), axis=0)
# 计算熵值
for name in self.raw_var_names:
data[name] = data[name].apply(lambda x: -(self.k * x * math.log(x)))
# 不同指标的熵值
entropy_list = data.apply(sum, axis=0).to_list()
self.entropy_values = entropy_list
print("".center(100, "="))
print(f"熵值:\n \t {entropy_list}")
print("".center(100, "="))
# 变异系数
G_list = [1 - i for i in entropy_list]
self.G_values = G_list
print("".center(100, "="))
print(f"变异系数:\n \t {G_list}")
print("".center(100, "="))
# 最终的权重
weights = [round(i / sum(G_list), 4) for i in G_list]
self.final_weights = dict([(i, j) for i, j in zip(self.raw_var_names, weights)])
print("".center(100, "="))
print(f"最终的权重:\n \t {self.final_weights}")
print("".center(100, "="))
def calTotalScores(self):
"""
计算综合得分指标
:return:
"""
data = self.non_neg_data
# scores = data.apply(lambda x, y: x, self.final_weights, axis=0)
scores = data.apply(lambda x: sum([i * j for i, j in zip(x, self.final_weights.values())]), axis=1).to_list()
# print(f'综合得分:{scores}')
self.raw_data['Total_Scores'] = scores
print("熵值法计算完毕!".center(50, "*"))
def main(self):
"""
实现熵值法
:return:
"""
print("熵值法计算:".center(100, "*"))
print("".center(100, "="))
self.getReadData()
self.precess_1_to_NNeg()
self.calElementsProAndEntropy()
self.calTotalScores()
print("".center(100, "="))
print("熵值法计算完毕!".center(100, "*"))
if __name__ == '__main__':
test = EntropyWeights()
test.main()
测试:测试数据来源于上述某参考文献案例:
A=[[85,70,20,20],
[70,70,60,50],
[80,60,80,90]]
A=pd.DataFrame(A,index=['A',"B","C"],columns=['甲','乙','丙',''])
test2=EntropyWeights(data=A,vars_num=4,maxValue_vars=['甲','乙','丙','丁'],minValue_vars=[])
test2.main()
测试输出:
***********************************************熵值法计算:***********************************************
====================================================================================================
熵值:[0.9657130652315669, 0.9602297178607612, 0.9657130652315666, 0.9648412112801078]
变异系数:[0.03428693476843314, 0.03977028213923883, 0.034286934768433364, 0.0351587887198922]
最终的权重:{'甲': 0.2389, '乙': 0.2771, '丙': 0.2389, '': 0.245}
综合得分:[0.31812579451118506, 0.3255810212000094, 0.32017663843929145]
*********************熵值法计算完毕!*********************
====================================================================================================
**********************************************熵值法计算完毕!**********************************************