熵值法


概述

熵值法是基于信息熵(或简称熵)的一种信息管理方法。根据熵的特性,可以据此判断出一个事件的随机性以及无序程度,也可以基于熵值判断某个指标的离散程度。离散程度越大,即信息量越大,不确定性就越小,熵也就越小;信息量越小,不确定性越大,熵也越大。基于该思想,熵值法只考虑数据内部的信息量大小,有效地避免了人为主观因素的影响。

熵值法原理及实例讲解

参考:熵值法原理及实例讲解

步骤:
(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]
*********************熵值法计算完毕!*********************
====================================================================================================
**********************************************熵值法计算完毕!**********************************************



posted @ 2020-08-18 14:00  LgRun  阅读(4253)  评论(0编辑  收藏  举报